__getattr__ on a python package

Viewed 43

I am not sure that this is really possible but I would like to apply __getattr__ on a package (like PEP 562). We require this to report some module attributes as deprecated.

Unfortunately, this looks like that in such scenario __getattr__ is not called at all. How can we check that some package attribute was called?

here is a package structure:

my-app/
├─ package/
│  ├─ __init__.py
├─ run.py
├─ setup.py

run.py

import package
from package import b

print(package.a)
print(b)

__init__.py

a = 1
b = 2

def __getattr__(name):
    print(name)
1 Answers

I found the root cause. Please submit another answer or comment here if I am wrong.

__getattr__ will be called only if attribute is not directly available in the module/package. Thus, we must raise an error if we do not recall another method/attribute in __getattr__

In my scenario we can do following. Assuming, that we would like to deprecate package attribute b, we replace it with _deprecated_b

and now the code in __init__.py looks like following:

a = 1
_deprecated_b = 2

def __getattr__(name):
    print(name)

deprecated_names = ["b"]


def __getattr__(name):
    if name in deprecated_names:
        print(f"{name} is deprecated, init")
        return globals()[f"_deprecated_{name}"]
    raise AttributeError(f"module {__name__} has no attribute {name}")

and we try to call

import package
package.b

we see printed error message.

Hope my post will be helpful for those who google around :D

Related