Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deprecate usage of a class as a parent class in Python

I'm working with a Python 2.x framework, and a recent version of the framework has moved some widely used base classes from module A to module B (and the classes have been renamed to a clearer names in the process). Module A defines a backward compatible identifiers for the new class names.

B.py:

class BaseClass(object):
    __metaclass__ = framework_meta # handles registration etc.

A.py:

import B
oldbase = B.BaseClass

Now in order to help people migrate their code, I would like to be able to issue a DeprecationWarning (using warnings.warn) whenever code using the framework defines a class deriving from A.oldbase telling the programmer to directly inherit from B.BaseClass.

I expect this can be achieved with a metaclass. I tried to declare a new metaclass deriving from the framework metaclass

class deprecated_base_class(framework_meta):
    def __new__(meta, name, bases, attrs):
        warning = '%(class)s is deprecated'
        for b in bases:
            warning =  getattr(b, '__deprecation_warning__', None) or warning
        warn(warning % {'class': name}, DeprecationWarning, stacklevel=2)
        return super(deprecated_base_class, meta).__new__(meta, name, bases, attrs)

together with:

A.py:

class oldbase(B.BaseClass):
    __metaclass__ = deprecated_base_class
    __deprecation_warning__ = 'class oldbase is deprecated. Use B.BaseClass instead'

clientcode.py

class FooBar(oldbase):
    pass

The problem I have now, is that I get a DeprecationWarning for the definition of oldbase. How can I fix this?

like image 449
gurney alex Avatar asked Sep 17 '12 14:09

gurney alex


1 Answers

You want to display the warning if any of the bases are deprecated:

class deprecated_base_class(framework_meta):
    def __new__(meta, name, bases, attrs):
        for b in bases:
            if isinstance(b, deprecated_base_class):
                warning = getattr(b, '__deprecation_warning__', '%(class)s is deprecated')
                warn(warning % {'class': b.__name__}, DeprecationWarning, stacklevel=2)
        return super(deprecated_base_class, meta).__new__(meta, name, bases, attrs)
like image 93
ecatmur Avatar answered Sep 23 '22 17:09

ecatmur