5
5
import contextlib
6
6
import types
7
7
import importlib
8
+ import inspect
9
+ import itertools
8
10
9
11
from typing import Union , Optional , cast
10
12
from .abc import ResourceReader , Traversable
15
17
Anchor = Package
16
18
17
19
18
- def files (package : Anchor ) -> Traversable :
20
+ def files (package : Optional [ Anchor ] = None ) -> Traversable :
19
21
"""
20
22
Get a Traversable resource for an anchor.
21
23
"""
@@ -39,7 +41,7 @@ def get_resource_reader(package: types.ModuleType) -> Optional[ResourceReader]:
39
41
40
42
41
43
@functools .singledispatch
42
- def resolve (cand : Anchor ) -> types .ModuleType :
44
+ def resolve (cand : Optional [ Anchor ] ) -> types .ModuleType :
43
45
return cast (types .ModuleType , cand )
44
46
45
47
@@ -48,6 +50,28 @@ def _(cand: str) -> types.ModuleType:
48
50
return importlib .import_module (cand )
49
51
50
52
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
+
51
75
def from_package (package : types .ModuleType ):
52
76
"""
53
77
Return a Traversable object for the given package.
0 commit comments