Skip to content

Commit 6f2ff06

Browse files
authored
feat: ✨ load_modules_with_keywords function
1 parent fedf3b9 commit 6f2ff06

File tree

15 files changed

+75
-37
lines changed

15 files changed

+75
-37
lines changed

injection/integrations/__init__.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +0,0 @@
1-
from importlib.util import find_spec
2-
from typing import Literal
3-
4-
__all__ = ("_is_installed",)
5-
6-
7-
def _is_installed(package: str, needed_for: object, /) -> Literal[True]:
8-
if find_spec(package) is None:
9-
raise RuntimeError(f"To use `{needed_for}`, {package} must be installed.")
10-
11-
return True

injection/integrations/fastapi.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22
from types import GenericAlias
33
from typing import Any, TypeAliasType
44

5+
from fastapi import Depends
6+
57
from injection import Module, mod
68
from injection.exceptions import InjectionError
7-
from injection.integrations import _is_installed
89

910
__all__ = ("Inject",)
1011

11-
if _is_installed("fastapi", __name__):
12-
from fastapi import Depends
13-
1412

1513
def Inject[T]( # noqa: N802
1614
cls: type[T] | TypeAliasType | GenericAlias,

injection/utils.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
from collections.abc import Callable, Iterator
1+
from collections.abc import Callable, Iterable, Iterator
22
from contextlib import contextmanager
33
from importlib import import_module
4+
from importlib.util import find_spec
45
from pkgutil import walk_packages
56
from types import ModuleType as PythonModule
67
from typing import ContextManager
78

9+
from injection import __name__ as injection_package_name
810
from injection import mod
911

10-
__all__ = ("load_packages", "load_profile")
12+
__all__ = ("load_modules_with_keywords", "load_packages", "load_profile")
1113

1214

1315
def load_profile(*names: str) -> ContextManager[None]:
@@ -33,6 +35,36 @@ def cleaner() -> Iterator[None]:
3335
return cleaner()
3436

3537

38+
def load_modules_with_keywords(
39+
*packages: PythonModule | str,
40+
keywords: Iterable[str] | None = None,
41+
) -> dict[str, PythonModule]:
42+
"""
43+
Function to import modules from a Python package if one of the keywords is contained in the Python script.
44+
The default keywords are:
45+
- `from injection`
46+
- `import injection`
47+
"""
48+
49+
if keywords is None:
50+
keywords = f"from {injection_package_name}", f"import {injection_package_name}"
51+
52+
b_keywords = tuple(keyword.encode() for keyword in keywords)
53+
54+
def predicate(module_name: str) -> bool:
55+
if (spec := find_spec(module_name)) and (module_path := spec.origin):
56+
with open(module_path, "rb") as script:
57+
for line in script:
58+
line = b" ".join(line.split(b" ")).strip()
59+
60+
if line and any(keyword in line for keyword in b_keywords):
61+
return True
62+
63+
return False
64+
65+
return load_packages(*packages, predicate=predicate)
66+
67+
3668
def load_packages(
3769
*packages: PythonModule | str,
3870
predicate: Callable[[str], bool] = lambda module_name: True,
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

tests/utils/package2/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)