Repository: Lightning-AI/pytorch-lightning
File: pytorch_lightning/utilities/parsing.py (Python)

Code before:
    "key2":    abc
    "mew_key": 42
    "my-key":  3.14
    """

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError as exp:
            raise AttributeError(f'Missing attribute "{key}"') from exp

    def __setattr__(self, key, val):
        self[key] = val

    def __repr__(self):
        if not len(self):
            return ""
        max_key_length = max([len(str(k)) for k in self])
        tmp_name = '{:' + str(max_key_length + 3) + 's} {}'
        rows = [tmp_name.format(f'"{n}":', self[n]) for n in sorted(self.keys())]
        out = '\n'.join(rows)
        return out


def lightning_get_all_attr_holders(model, attribute):
    """ Special attribute finding for lightning.  Gets all of the objects or dicts that holds attribute.
            Checks for attribute in model namespace, the old hparams namespace/dict, and the datamodule. """
    trainer = getattr(model, 'trainer', None)

    holders = []

    # Check if attribute in model
    if hasattr(model, attribute):
        holders.append(model)

    # Check if attribute in model.hparams, either namespace or dict
    if hasattr(model, 'hparams'):
        if attribute in model.hparams:
            holders.append(model.hparams)

    # Check if the attribute in datamodule (datamodule gets registered in Trainer)
    if trainer is not None and trainer.datamodule is not None and hasattr(trainer.datamodule, attribute):
        holders.append(trainer.datamodule)

    return holders


def lightning_get_first_attr_holder(model, attribute):
    """ Special attribute finding for lightning.  Gets the object or dict that holds attribute, or None. Checks for attribute in model namespace,
            the old hparams namespace/dict, and the datamodule, returns the last one that has it. """
    holders = lightning_get_all_attr_holders(model, attribute)

Review comment (suggestion):
be careful, this is API change
we are free to change anything which is protected (starting with _) but the remaining is public API
so even when we are adding new features, make a decision about what is meant to the public and protected api
cc: @PyTorchLightning/core-contributors 

Code after:
    "key1":    2
    "key2":    abc
    "mew_key": 42
    "my-key":  3.14
    """

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError as exp:
            raise AttributeError(f'Missing attribute "{key}"') from exp

    def __setattr__(self, key, val):
        self[key] = val

    def __repr__(self):
        if not len(self):
            return ""
        max_key_length = max([len(str(k)) for k in self])
        tmp_name = '{:' + str(max_key_length + 3) + 's} {}'
        rows = [tmp_name.format(f'"{n}":', self[n]) for n in sorted(self.keys())]
        out = '\n'.join(rows)
        return out


def lightning_get_all_attr_holders(model, attribute):
    """ Special attribute finding for lightning.  Gets all of the objects or dicts that holds attribute.
            Checks for attribute in model namespace, the old hparams namespace/dict, and the datamodule. """
    trainer = getattr(model, 'trainer', None)

    holders = []

    # Check if attribute in model
    if hasattr(model, attribute):
        holders.append(model)

    # Check if attribute in model.hparams, either namespace or dict
    if hasattr(model, 'hparams'):
        if attribute in model.hparams:
            holders.append(model.hparams)

    # Check if the attribute in datamodule (datamodule gets registered in Trainer)
    if trainer is not None and trainer.datamodule is not None and hasattr(trainer.datamodule, attribute):
        holders.append(trainer.datamodule)

    return holders


def lightning_get_first_attr_holder(model, attribute):
    """ Special attribute finding for lightning.  Gets the object or dict that holds attribute, or None. Checks for attribute in model namespace,
            the old hparams namespace/dict, and the datamodule, returns the last one that has it. """