1414
1515import ast
1616import builtins
17- from collections .abc import Mapping , Sequence
17+ from collections .abc import Mapping
1818import functools
19- import importlib .abc
20- from importlib .machinery import ModuleSpec
21- import importlib .util
2219import inspect
2320import io
2421import os
2724import string
2825import sys
2926import tomllib
30- import types
3127from typing import Any , Callable , Literal , TypedDict , get_args , get_origin
3228import warnings
3329
3430
35- class Tracker ( importlib . abc . MetaPathFinder ) :
31+ class Tracker :
3632 """Track files that are read, written or imported.
3733
3834 This can then be used for generating dependency lists. Note that the tracker does
39- not filter the files; that is up to the user.
40-
41- Note that any imports that occur prior to the tracker being installed will not be
42- tracked. Any code which loads a file opener prior to it being wrapped for tracking
43- will also avoid tracking.
35+ not filter the files; that is up to the user. Functions must be wrapped before use.
4436
4537 """
4638
47- # Files that have imported.
48- imported : set [Path ]
39+ @property
40+ def imported (self ) -> set [Path ]:
41+ """Absolute paths to modules that were imported.
42+
43+ This iterates over all modules cached in `sys.modules` and finds the paths to
44+ each module. Any modules which don't have a filesystem path specified will be
45+ ignored.
46+
47+ """
48+ paths = set ()
49+
50+ for mod in sys .modules .values ():
51+ if mod .__spec__ is None or mod .__spec__ .origin is None :
52+ continue
53+
54+ path = Path (mod .__spec__ .origin )
55+ if path .exists () and path .is_file ():
56+ paths .add (path .resolve ())
57+
58+ return paths
4959
5060 # Files that were opened in a read mode.
5161 read : set [Path ]
@@ -61,12 +71,9 @@ class Tracker(importlib.abc.MetaPathFinder):
6171
6272 def __init__ (self ):
6373 super ().__init__ ()
64- self ._avoid_recursion = set ()
65- self .imported = set ()
6674 self .read = set ()
6775 self .explicit_dependencies = set ()
6876 self .written = set ()
69- sys .meta_path .insert (0 , self )
7077
7178 def add_dependencies (self , * args : os .PathLike [str ] | str ):
7279 """Add a file dependency for the current figure.
@@ -87,36 +94,6 @@ def add_dependencies(self, *args: os.PathLike[str] | str):
8794 for fn in args :
8895 self .explicit_dependencies .add (Path (fn ).resolve ())
8996
90- def find_spec (
91- self ,
92- fullname : str ,
93- path : Sequence [str ] | None ,
94- target : types .ModuleType | None = None ,
95- ) -> ModuleSpec | None :
96- # According to PEP451, this is mostly intended for a reload. I can't see a way
97- # (without calling importlib._bootstrap._find_spec, which should not be imported
98- # according to the note at the top of the module) to pass this information on.
99- # Hence, lets skip tracking in this case.
100- if target is not None : # pragma: no cover
101- return None
102-
103- # We use importlib to find the actual spec, so we need to avoid recursing when
104- # this finder is called again.
105- if fullname in self ._avoid_recursion :
106- return None
107-
108- # Find the spec.
109- self ._avoid_recursion .add (fullname )
110- spec = importlib .util ._find_spec_from_path (fullname , path )
111- self ._avoid_recursion .remove (fullname )
112-
113- # If it has an origin in one of our tracked dirs, log it.
114- if spec is not None and spec .origin is not None and spec .origin != "built-in" :
115- self .imported .add (spec .origin )
116-
117- # And return the result.
118- return spec
119-
12097 def wrap_file_opener [** P , R ](self , opener : Callable [P , R ]) -> Callable [P , R ]:
12198 """Wrap a function which opens files for tracking.
12299
@@ -178,7 +155,7 @@ def wrapper(*args, **kwargs):
178155io .open = tracker .wrap_file_opener (io .open )
179156
180157# Now we can import Matplotlib. We couldn't do so earlier as it brings in NumPy, which
181- # in turn caches references to io.open() and so we prevent us reliably tracking data
158+ # in turn caches references to io.open() and so would prevent us reliably tracking data
182159# files it opens.
183160import matplotlib # noqa: E402
184161
0 commit comments