55import contextlib
66import types
77import importlib
8+ import inspect
9+ import itertools
810
911from typing import Union , Optional , cast
1012from .abc import ResourceReader , Traversable
1517Anchor = Package
1618
1719
18- def files (package : Anchor ) -> Traversable :
20+ def files (package : Optional [ Anchor ] = None ) -> Traversable :
1921 """
2022 Get a Traversable resource for an anchor.
2123 """
@@ -39,7 +41,7 @@ def get_resource_reader(package: types.ModuleType) -> Optional[ResourceReader]:
3941
4042
4143@functools .singledispatch
42- def resolve (cand : Anchor ) -> types .ModuleType :
44+ def resolve (cand : Optional [ Anchor ] ) -> types .ModuleType :
4345 return cast (types .ModuleType , cand )
4446
4547
@@ -48,6 +50,28 @@ def _(cand: str) -> types.ModuleType:
4850 return importlib .import_module (cand )
4951
5052
53+ @resolve .register
54+ def _ (cand : None ) -> types .ModuleType :
55+ return resolve (_infer_caller ().f_globals ['__name__' ])
56+
57+
58+ def _infer_caller ():
59+ """
60+ Walk the stack and find the frame of the first caller not in this module.
61+ """
62+
63+ def is_this_file (frame_info ):
64+ return frame_info .filename == __file__
65+
66+ def is_wrapper (frame_info ):
67+ return frame_info .function == 'wrapper'
68+
69+ not_this_file = itertools .filterfalse (is_this_file , inspect .stack ())
70+ # also exclude 'wrapper' due to singledispatch in the call stack
71+ callers = itertools .filterfalse (is_wrapper , not_this_file )
72+ return next (callers ).frame
73+
74+
5175def from_package (package : types .ModuleType ):
5276 """
5377 Return a Traversable object for the given package.
0 commit comments