22from importlib import import_module
33from inspect import isclass
44from os import path
5+ from pathlib import Path
56from pkgutil import iter_modules
67from typing import List , Optional , Type , TypeVar
78
89
10+ SRC_DIR = Path (__file__ ).parent .parent .resolve ()
11+
912T = TypeVar ('T' )
1013
1114
@@ -27,35 +30,42 @@ def load(interface: Type[T], module: Optional[str] = None) -> List[Type[T]]:
2730 Args:
2831 interface (Type[T]): the type (ie class) that the imported classes
2932 should 'inherit' (subclass) from
30- module (str): module containing the modules to inspect. Defaults to the
33+ module (str): module dotted-path containing the modules to inspect. Defaults to the
3134 same module (directory) as the one where the module of the invoking
3235 code resides.
3336 """
34- project_package_location = path .dirname (
35- path .realpath (path .dirname (path .realpath (__file__ )))
36- )
37+ lib_dir : str
38+ dotted_lib_path : str #
3739 if module is None : # set path as the dir where the invoking code is
3840 namespace = sys ._getframe (1 ).f_globals # caller's globals
39- directory : str = path .dirname (path .realpath (namespace ['__file__' ]))
40- relative_path = path .relpath (directory , start = project_package_location )
41- _module = relative_path .replace ('\\ ' , '/' ).replace ('/' , '.' )
41+ # Set as Lib the directory where the invoker module is located at runtime
42+ lib_dir = path .dirname (path .realpath (namespace ['__file__' ]))
43+ dotted_lib_path = '.' .join (
44+ Path (lib_dir ).relative_to (SRC_DIR ).parts
45+ ) # pragma: no mutate
4246 else :
43- directory = str (module ).replace ('/' , '.' )
44- # find the distro path as installed at runtime
45- module_object = import_module (directory )
47+ # Import input module
48+ # module_object = import_module(module.replace('/', '.'))
49+ module_object = import_module (module ) # TODO: read __file__ without importing
50+
51+ # Set as Lib the directory where the INPUT module is located at runtime
52+ lib_dir = str (Path (str (module_object .__file__ )).parent )
4653 # if top-level init is at '/site-packages/some_python_package/__init__.py'
4754 # then distro_path is '/site-packages/some_python_package'
48- from pathlib import Path
4955
50- distro_path : Path = Path (str (module_object .__file__ )).parent
51- directory = str (distro_path )
52- _module = module
56+ dotted_lib_path = module
57+
58+ if not Path (lib_dir ).exists ():
59+ raise FileNotFoundError
5360
5461 objects = []
55- # iterate through the modules inside the directory
56- for _ , module_name , _ in iter_modules ([directory ]):
62+
63+ # iterate through the modules inside the LIB directory
64+ for _ , module_name , _ in iter_modules ([lib_dir ]):
65+ # if module has a register_as_subclass decorator then the below import
66+ # will cause the class to be registered in the Facility/Factory Registry
5767 module_object = import_module (
58- '{package}.{module}' .format (package = _module , module = module_name )
68+ '{package}.{module}' .format (package = dotted_lib_path , module = module_name )
5969 )
6070
6171 for attribute_name in dir (module_object ):
@@ -66,7 +76,5 @@ def load(interface: Type[T], module: Optional[str] = None) -> List[Type[T]]:
6676 and isclass (attribute )
6777 and issubclass (attribute , interface )
6878 ):
69- # Add the class to this package's variables
70- globals ()[attribute_name ] = attribute
7179 objects .append (attribute )
7280 return objects
0 commit comments