Skip to content

Commit 2db3a58

Browse files
committed
Fixed function/class vs module autocomplete priority
1 parent 5cfd654 commit 2db3a58

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

stumpy/__init__.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,53 @@ def __getattr__(name): # pragma: no cover
278278
globals()[_name] = replacement
279279

280280

281+
# Lightweight lazy proxy objects so the attribute exists in the
282+
# module dict immediately. This helps REPLs and completers that
283+
# inspect `module.__dict__` or `dir(module)` prefer the callable/class
284+
# export over a same-named submodule while still deferring the real
285+
# import until first use.
286+
def _resolve_lazy(name, submodule): # pragma: no cover
287+
full_module_path = f"{__package__}.{submodule}"
288+
module = importlib.import_module(full_module_path)
289+
obj = getattr(module, name)
290+
globals()[name] = obj
291+
return obj
292+
293+
294+
# Eagerly import exports that would otherwise collide with
295+
# same-named submodules. This keeps lazy imports for most names but
296+
# ensures that when a top-level exported name exactly matches its
297+
# submodule (e.g., `stump` -> `stump.py`), the exported attribute is
298+
# available immediately so REPL completers prefer the callable/class
299+
# instead of the module.
300+
for _name, _sub in _lazy_imports.items(): # pragma: no cover
301+
try:
302+
if _name == _sub:
303+
filepath = pathlib.Path(__file__).parent / f"{_sub}.py"
304+
if filepath.exists():
305+
module = importlib.import_module(f"{__package__}.{_sub}")
306+
try:
307+
globals()[_name] = getattr(module, _name)
308+
except AttributeError:
309+
# If the submodule doesn't define the attribute, keep it lazy
310+
pass
311+
except Exception:
312+
# Be conservative: don't let eager-import attempts raise during package import
313+
pass
314+
315+
281316
def __dir__(): # pragma: no cover
282317
# Expose lazy names in dir() for discoverability
283-
return sorted(list(globals().keys()) + list(_lazy_imports.keys()))
318+
# Also include __all__ so tools that consult it will see the intended
319+
# top-level exports (this helps some REPL completers prefer the
320+
# callable/class exports over same-named submodules).
321+
all_names = list(globals().keys()) + list(_lazy_imports.keys())
322+
all_names += list(globals().get("__all__", []))
323+
return sorted(all_names)
324+
325+
326+
# Make the lazy-exported names explicit for tools that respect __all__.
327+
# This helps REPL tab-completion prefer functions/classes over submodules
328+
# when names collide (e.g., `stumpy.stump` should point to the function
329+
# rather than the module during completion).
330+
__all__ = sorted(list(_lazy_imports.keys()))

0 commit comments

Comments
 (0)