51
51
from typing import Any , Callable , Dict , List , Optional , Type , overload
52
52
53
53
# 3rd party
54
- from typing_extensions import Literal
54
+ from typing_extensions import Literal , TypedDict
55
55
56
56
# this package
57
57
from domdf_python_tools .compat import importlib_metadata
58
58
59
59
__all__ = ["discover" , "discover_entry_points" , "discover_entry_points_by_name" ]
60
60
61
61
62
+ class _DiscoverKwargsType (TypedDict ):
63
+ match_func : Optional [Callable [[Any ], bool ]]
64
+ exclude_side_effects : bool
65
+
66
+
62
67
@overload
63
68
def discover (
64
69
package : ModuleType ,
@@ -81,45 +86,66 @@ def discover(
81
86
exclude_side_effects : bool = True ,
82
87
) -> List [Any ]:
83
88
"""
84
- Returns a list of objects in the given module,
85
- optionally filtered by ``match_func``.
89
+ Returns a list of objects in the given package, optionally filtered by ``match_func``.
86
90
87
91
:param package: A Python package
88
92
:param match_func: Function taking an object and returning :py:obj:`True` if the object is to be included in the output.
89
93
:default match_func: :py:obj:`None`, which includes all objects.
90
94
:param exclude_side_effects: Don't include objects that are only there because of an import side effect.
91
95
92
- :return: List of matching objects.
93
-
94
96
.. versionchanged:: 1.0.0
95
97
96
98
Added the ``exclude_side_effects`` parameter.
99
+ """
97
100
98
- .. TODO:: raise better exception when passing a module rather than a package.
99
- Or just return the contents of the module?
100
- """ # noqa D400
101
+ kwargs : _DiscoverKwargsType = dict (exclude_side_effects = exclude_side_effects , match_func = match_func )
101
102
102
- matching_objects = []
103
+ matching_objects = _discover_in_module ( package , ** kwargs )
103
104
104
- for _ , module_name , _ in pkgutil . walk_packages (
105
+ if hasattr ( package , "__path__" ):
105
106
# https://github.com/python/mypy/issues/1422
106
107
# Stalled PRs: https://github.com/python/mypy/pull/3527
107
108
# https://github.com/python/mypy/pull/5212
108
- package .__path__ , # type: ignore
109
- prefix = package .__name__ + '.' ,
110
- ):
111
- module = __import__ (module_name , fromlist = ["__trash" ], level = 0 )
109
+ package_path = package .__path__ # type: ignore
110
+
111
+ for _ , module_name , _ in pkgutil .walk_packages (package_path , prefix = f'{ package .__name__ } .' ):
112
+ module = __import__ (module_name , fromlist = ["__trash" ], level = 0 )
113
+
114
+ matching_objects .extend (_discover_in_module (module , ** kwargs ))
115
+
116
+ return matching_objects
117
+
118
+
119
+ def _discover_in_module (
120
+ module : ModuleType ,
121
+ match_func : Optional [Callable [[Any ], bool ]] = None ,
122
+ exclude_side_effects : bool = True ,
123
+ ) -> List [Any ]:
124
+ """
125
+ Returns a list of objects in the given module, optionally filtered by ``match_func``.
126
+
127
+ :param module: A Python module.
128
+ :param match_func: Function taking an object and returning :py:obj:`True` if the object is to be included in the output.
129
+ :default match_func: :py:obj:`None`, which includes all objects.
130
+ :param exclude_side_effects: Don't include objects that are only there because of an import side effect.
131
+
132
+ .. versionadded:: 2.6.0
133
+
134
+ .. TODO:: make this public in that version
135
+ """
136
+
137
+ matching_objects = []
112
138
113
- # Check all the functions in that module
114
- for _ , imported_objects in inspect .getmembers (module , match_func ):
139
+ # Check all the functions in that module
140
+ for _ , imported_object in inspect .getmembers (module , match_func ):
115
141
116
- if exclude_side_effects :
117
- if not hasattr (imported_objects , "__module__" ):
118
- continue
119
- if imported_objects .__module__ != module .__name__ :
120
- continue
142
+ if exclude_side_effects :
143
+ if not hasattr (imported_object , "__module__" ):
144
+ continue
145
+ if imported_object .__module__ != module .__name__ :
146
+ continue
121
147
122
- matching_objects .append (imported_objects )
148
+ matching_objects .append (imported_object )
123
149
124
150
return matching_objects
125
151
0 commit comments