Package: import-tracker
Import TrackerImport Trackeris a Python package offering a number of capabilities related to tracking and managing optional dependencies in Python projects. Specifically, this project enables developers to:Track the dependencies of a python project to map each module within the project to the set of dependencies it relies on. This can be useful for debugging of dependencies in large projects.Enable lazy import errors in a python projects to prevent code from crashing when uninstalled imports are imported, but not utilized. This can be helpful in large projects, especially those which incorporate lots of hierarchical wild imports, as importing the top level package of such projects can often bring a lot of heavy dependencies intosys.modules.Programmatically determine theinstall_requiresandextras_requirearguments tosetuptools.setupwhere the extras sets are determined by a set of modules that should be optional.Table of contentsTable of contentsRunning Import TrackerIntegratingimport_trackerinto a projectEnablinglazy_import_errorsUsingsetup_tools.parse_requirementsGotchasMinor issue with zshRunning Import TrackerTo runimport_trackeragainst a project, simply invoke the module's main:python3 -m import_tracker --name <my_module>The main supports the following additional arguments:--package: Allows--nameto be a relative import (seeimportlib.import_module)--indent: Indent the output json for pretty printing--log_level: Set the level of logging (up todebug4) to debug unexpected behavior--submodules: List of sub-modules to recurse on (or full recursion when no args given)--track_import_stack: Store the stack trace of imports belonging to the tracked module--detect_transitive: Mark each dependency as either "direct" (imported directly) or "transitive" (inherited from a direct import)--full_depth: Track all dependencies, including transitive dependencies of direct third-party deps--show_optional: Show whether each dependency is optional or requiredIntegratingimport_trackerinto a projectWhen usingimport_trackerto implement optional dependencies in a project, there are two steps to take:Enablelazy_import_errorsfor the set of modules that should be managed as optionalUsesetup_tools.parse_requirementsinsetup.pyto determine theinstall_requiresandextras_requireargumentsIn the following examples, we'll use a fictitious project with the following structure:my_module/
├── __init__.py
├── utils.py
└── widgets
    ├── __init__.py
    ├── widget1.py
    └── widget2.pyEnablinglazy_import_errorsTheimport_tracker.lazy_import_errorsfunction can be invoked directly to enable lazy import errors globally, or used as a context manager to enable them only for a selcted set of modules.To globally enable lazy import errors,my_module/__init__.pywould look like the following:# Globally enable lazy import errorsfromimport_trackerimportlazy_import_errorslazy_import_errors()from.importutils,widgetsAlternately, applying lazy import error semantics only to thewidgetswould look like the following:fromimport_trackerimportlazy_import_errors# Require all downstream imports from utils to existfrom.importutils# Enable lazy import errors for widgetswithlazy_import_errors():from.importwidgetsWhen using lazy import errors, there are two ways to customize the error message that is raised when a failed import is used:Theget_extras_modulesargument takes a function which returns aSet[str]of the module names that are tracked as extras. If the import error is triggered within a module that is managed as an extras set, the error message is updated to include instructions on which extras set needs to be installed.Themake_error_messageargument allows the caller to specify a fully custom error message generation function.Usingsetup_tools.parse_requirementsTo take advantage of the automatic dependency parsing when building a package, thesetup.pywould look like the following:importimport_trackerimportosimportsetuptools# Determine the path to the requirements.txt for the projectrequirements_file=os.path.join(os.path.dirname(__file__),"requirements.txt")# Parse the requirement setsinstall_requires,extras_require=import_tracker.setup_tools.parse_requirements(requirements_file=requirements_file,library_name="my_module",extras_modules=["my_module.widgets.widget1","my_module.widgets.widget2",],)# Perform the standard setup callsetuptools.setup(name="my_module",author="me",version="1.2.3",license="MIT",install_requires=install_requires,extras_require=extras_require,packages=setuptools.find_packages(),)GotchasMinor issue with zshAs mentioned before, when using lazy import errors inimport_tracker, if the import error is triggered within a module that is managed as an extras set, the error message is updated to include instructions on which extras set needs to be installed. The error message might look something like this:ModuleNotFoundError:Nomodulenamed'example_module'.

Toinstallthemissingdependencies,run`pipinstallmy_module[my_module.example_module]`There might be an issue when runningpip install my_module[my_module.example_module]within azshenvironment, since square brackets inzshhave special meanings. We have to escape them by putting \ (backslash) before them. So forzsh, something like this will work:pip install my_module\[my_module.example_module\]