Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python-2.7 execute code on object import

I'm trying to make a deprecation system that allows code to run transparently for regular users, but flag deprecated objects in developer mode.

One issue that I'm having is that I can import a deprecated object into another module even if I'm in developer mode. This means that I'm missing places where the deprecated object is used.

For example in module1.py:

class MyObject(object):
    pass
MyObject = MyObject if not dev_mode() else DeprecatedObject

Then in module2.py:

from module1 import MyObject

I already have DeprecatedObject set up so that any interaction with it raises a DeprecationWarning - is there any way that I can make it error on import? ie. even importing module2.py would raise an exception.

I'm imagining something like:

import warnings

class DeprecatedObject(object):
    ...
    def __onimport__(self):
        warnings.warn("deprecated", DeprecationWarning)
like image 982
ninhenzo64 Avatar asked Jun 16 '26 04:06

ninhenzo64


2 Answers

The module level __getattr__ feature allows, among other things, for module level names to undergo a correct deprecation process at import time. This feature is coming in Python 3.7, see PEP 562 for details (since you've tagged with Python 2.7, it can't help you, but I mention it for the benefit of future readers).

On Python 2.7 you have two inferior options:

  • Trigger deprecation warning in the object __init__.
  • Use Guido's hack to replace the module with a patched version of itself after import. Wrapping a proxy object around the module allows you to control name resolution.
like image 80
wim Avatar answered Jun 18 '26 17:06

wim


First off, I recommend looking into the built-in warnings module. It has tools made specifically for this type of thing. Having a non-fatal warning in place makes more sense than raising an exception.

Now, for your case, one possible course of action would be to "replace" the deprecated class with a function. This means renaming the class to something else, and having a function with the original name which checks whether or not developer mode is enabled and acts accordingly. The result would be something like:

class MyDeprecatedClass:
    pass

def MyClass(*args, **kwargs):
    if dev_mode():
        raise DeprecationWarning
    else:
        return MyDeprecatedClass(*args, **kwargs)

Or, with warnings:

def MyClass(*args, **kwargs):
    from warnings import warn
    if dev_mode():
        warn("Dont use this!!!!!!!!!")
    else:
        return MyDeprecatedClass(*args, **kwargs)

What this does is it checks whether or not developer mode is enabled, and only raises the exception (or warning) if it is. Otherwise, it passes all the arguments given to it to the constructor of the renamed class, meaning all old that relies on it will work fine.

like image 30
stelioslogothetis Avatar answered Jun 18 '26 19:06

stelioslogothetis