In python, how can I error intelligibly when a removed class is subclassed by the user?

时间:2015-07-28 23:08:48

标签: python

I'm trying to update django_pyodbc for django 1.8 and it turns out that SQLDateCompiler was removed from django completely in version 1.8. django_pyodbc is extending SQLDateCompiler (let's call it SQLDateCompilerPrime) which now no longer exists.

I want to issue a deprecation error/exception when a user inherits from SQLDateCompiler before the class is instantiated.

I'm aware of how to use python's warnings library to raise an exception, but how can I raise an intelligible exception before the class is even used. I.e. as soon as a subclass is defined.

I could do:

class SQLDateCompilerPrime(object):
    def __init__(self, *args, **kwargs):
        warnings.warn(
            'In the 1.8 release of django, `SQLDateCompiler` was removed.  ' +
            'This was the basis of `SQLDateCompilerPrime`, and thus ' +
            '`SQLDateCompilerPrime` is no longer available.',
            DeprecationWarning, stacklevel=2)

However, this will only fail when an instance of a subclass is created. I want to fail when the subclass is defined and issue the warning straight away. Removing the definition entirely would certainly cause a failure, but I don't want the user to have to look in other django_pyodbc to figure out that it is no longer defined and that it just disappeared right out from under them.

1 个答案:

答案 0 :(得分:1)

You can use a metaclass for this:

class DeprecatedMeta(type):
    def __new__(cls, name, bases, attrs):
        # if the metaclass is defined on the current class, it's not
        # a subclass so we don't want to warn.
        if attrs.get('__metaclass__') is not cls:
            print 'deprecated:', name
        return super(DeprecatedMeta, cls).__new__(cls, name, bases, attrs)


class Foo(object):
    __metaclass__ = DeprecatedMeta


class Bar(Foo):
    pass


class FooBar(Bar):
    pass

This example results in the following output:

deprecated: Bar
deprecated: FooBar