Skip to content

Commit 2cf220b

Browse files
authored
Merge pull request #9 from stefanv/lazy-attr-takes-preference-over-submodule
Avoid conflicts when function is implemented in same-named submodule
2 parents 0150d2e + b3d4f87 commit 2cf220b

File tree

6 files changed

+36
-4
lines changed

6 files changed

+36
-4
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ jobs:
3434

3535
- name: Test
3636
run: |
37-
pytest
37+
PYTHONPATH=. pytest

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ repos:
99
- id: end-of-file-fixer
1010
- id: trailing-whitespace
1111
- repo: https://github.com/psf/black
12-
rev: 22.1.0
12+
rev: 22.3.0
1313
hooks:
1414
- id: black
1515
- repo: https://gitlab.com/pycqa/flake8

lazy_loader/__init__.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,18 @@ def __getattr__(name):
7171
if name in submodules:
7272
return importlib.import_module(f"{package_name}.{name}")
7373
elif name in attr_to_modules:
74-
submod = importlib.import_module(f"{package_name}.{attr_to_modules[name]}")
75-
return getattr(submod, name)
74+
submod_path = f"{package_name}.{attr_to_modules[name]}"
75+
submod = importlib.import_module(submod_path)
76+
attr = getattr(submod, name)
77+
78+
# If the attribute lives in a file (module) with the same
79+
# name as the attribute, ensure that the attribute and *not*
80+
# the module is accessible on the package.
81+
if name == attr_to_modules[name]:
82+
pkg = sys.modules[package_name]
83+
pkg.__dict__[name] = attr
84+
85+
return attr
7686
else:
7787
raise AttributeError(f"No {package_name} attribute {name}")
7888

tests/fake_pkg/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import lazy_loader as lazy
2+
3+
__getattr__, __lazy_dir__, __all__ = lazy.attach(
4+
__name__, submod_attrs={"some_func": ["some_func"]}
5+
)

tests/fake_pkg/some_func.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def some_func():
2+
"""Function with same name as submodule."""
3+
pass

tests/test_lazy_loader.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,17 @@ def test_lazy_attach():
9494
for k, v in expected.items():
9595
if v is not None:
9696
assert locls[k] == v
97+
98+
99+
def test_attach_same_module_and_attr_name():
100+
import fake_pkg
101+
102+
# Grab attribute twice, to ensure that importing it does not
103+
# override function by module
104+
assert isinstance(fake_pkg.some_func, types.FunctionType)
105+
assert isinstance(fake_pkg.some_func, types.FunctionType)
106+
107+
# Ensure imports from submodule still work
108+
from fake_pkg.some_func import some_func
109+
110+
assert isinstance(some_func, types.FunctionType)

0 commit comments

Comments
 (0)