Daniel Cohen Hillel
Daniel Cohen Hillel

Reputation: 13

Deprecate class to dictionary properties python

In python, I have a class, one of it's attributes is some other class that holds data, like this:

class A:
    class Params:
        def __init__(self):
            self.param1 = None
            self.param2 = None
            ...

    def __init__(self):
        self.parameters = self.Params()

This way, if anyone wants to change one of the parameters in self.parameters he can write self.parameters.param1 = ....

I want to change the class Params that holds the parameters into a dictionary

class A:
    def __init__(self):
        self.parameters = {
            'self.param1': None
            'self.param2': None
        }

This way if anyone wants to change anything he can write self.parameters['param1'] = ... instead. I've implemented this change (in a development branch) and it works. The problem is that other people use that code and if I make this change it will break their code (it's and simple fix, but still).

I wanted to know if there is any way I can make it so that if anyone writes in the old way (i.e. parameters.param1 = ...) it would still work but print a DEPRECATED message when he does, this way I can make a transition window where people go from the old way to the new way. The only way I came up with is if I change the name of the attribute I can keep the old code and add a log.warning, but I don't want to change the name of the attribute so if anyone can think of a way to do this it would be great :)

Upvotes: 0

Views: 279

Answers (1)

chepner
chepner

Reputation: 531625

You can define make Params implement the mapping protocol, then produce deprecation warnings on attribute access.

class Params:
    def __init__(self):
        ...  # As before

    def __setitem__(self, key, value):
        # This check is optional, to prevent creating new attributes
        if not hasattr(self, key):
            raise ValueError(f"No such parameter {key}")
        setattr(self, key, value)

    __getitem__ = getattr

    def __setattr__(self, attr, value):
        warnings.warn("Don't set attributes directly", DeprecationWarning)
        super().__setattr__(attr, value)

    def __getattribute__(self, attr):
        warnings.warn("Don't access attributes directly", DeprecationWarning)
        super().__getattribute__(self, attr)

Now your next version will support both techniques, but attribute access will raise the warning. In the version after that, you can get rid of the Params class.

class A:
    def __init__(self):
        self.parameters = {
            'param1': None
            'param2': None
        }

Upvotes: 1

Related Questions