Spaces:
Running
Running
import sys | |
from typing import Any, Callable, Iterable, List, Tuple | |
__all__ = ["trace_dependencies"] | |
def trace_dependencies( | |
callable: Callable[[Any], Any], inputs: Iterable[Tuple[Any, ...]] | |
) -> List[str]: | |
"""Trace the execution of a callable in order to determine which modules it uses. | |
Args: | |
callable: The callable to execute and trace. | |
inputs: The input to use during tracing. The modules used by 'callable' when invoked by each set of inputs | |
are union-ed to determine all modules used by the callable for the purpooses of packaging. | |
Returns: A list of the names of all modules used during callable execution. | |
""" | |
modules_used = set() | |
def record_used_modules(frame, event, arg): | |
# If the event being profiled is not a Python function | |
# call, there is nothing to do. | |
if event != "call": | |
return | |
# This is the name of the function that was called. | |
name = frame.f_code.co_name | |
module = None | |
# Try to determine the name of the module that the function | |
# is in: | |
# 1) Check the global namespace of the frame. | |
# 2) Check the local namespace of the frame. | |
# 3) To handle class instance method calls, check | |
# the attribute named 'name' of the object | |
# in the local namespace corresponding to "self". | |
if name in frame.f_globals: | |
module = frame.f_globals[name].__module__ | |
elif name in frame.f_locals: | |
module = frame.f_locals[name].__module__ | |
elif "self" in frame.f_locals: | |
method = getattr(frame.f_locals["self"], name, None) | |
module = method.__module__ if method else None | |
# If a module was found, add it to the set of used modules. | |
if module: | |
modules_used.add(module) | |
try: | |
# Attach record_used_modules as the profiler function. | |
sys.setprofile(record_used_modules) | |
# Execute the callable with all inputs. | |
for inp in inputs: | |
callable(*inp) | |
finally: | |
# Detach the profiler function. | |
sys.setprofile(None) | |
return list(modules_used) | |