Imports and Modules

Discovery of Dependencies


Get the imports at the top-level of the given Python module.

Parameters:module – An actual module; not the name.
Returns list:The absolute names of everything imported,
metatools.imports.discovery.parse_imports(source, package=None, module=None, path=None, toplevel=True)[source]

Get the imports at the top-level of the given Python module.

  • source (str) – Python source code.
  • package (str) – The __package__ this source is from.
  • module (str) – The __name__ this source is from.
  • toplevel (bool) – Walk the full AST, or only look at the top-level?
Returns list:

The names of everything imported; absolute if package and module are provided.

metatools.imports.discovery.path_is_in_directories(path, directories)[source]

Is the given path within the given directory?

  • path (str) – The path to test.
  • directory (str) – The directory to test if the path is in.
Returns bool:

Reloading Code in Production

Automatically reloading modules when their source has been updated.

This also allows for some state retention in reloaded modules, for modules to specify dependencies that must be checked for being outdated as well, and to unload those dependencies on reload.

There are two ways that we use to track if something should be reloaded, the last modification time of a file, and the last time we reloaded a module.

The modification time is to determine if a module has actually changed, and if it is newer than a previously seen time, then that module will be reloaded.

Every module reload will store the time at which it reloads (determined at the start of an autoreload cycle). Then, in another autoreload cycle, another module can see when it’s dependencies changes by comparing its reload time with the dependency’s. If a dependency was reloaded, then reload ourselves as well.

This is not perfect, and it is known to cause numerous issues (e.g. circular imports cause some strange problems), however we have found that the problems it brings up are minor in comparison to the speed boost it tends to give us while in active development.

A better algorithm would construct a full module graph (it would not be acyclic), and iteratively expand the region that must be reloaded. Then it would linearize the dependencies and reload everything in a big chain.

The tricky part is since module discovery <discovery> does not reveal the actual intensions of the code, e.g.:

digraph actual_graph {
{rank=same; "core" "gui" "utils"}

"__init__" -> "core"

"core" -> "utils"

"gui" -> "core"
"gui" -> "utils"

but all the dependancies that it is actually capable of, e.g.:

digraph discovered_graph {
{rank=same; "core" "gui" "utils"}

"__init__" -> "core"

"core" -> "__init__" [constraint=false]
"core" -> "utils"

"gui" -> "__init__" [constraint=false]
"gui" -> "core"
"gui" -> "utils"

metatools.imports.reload.is_outdated(module, recursive=True)[source]
metatools.imports.reload.reload(module, _time=None)[source]
metatools.imports.reload.autoreload(module, visited=None, force_self=None, _depth=0, _time=None)[source]

Rewriting Imports

class metatools.imports.rewrite.Rewriter(mapping, module_name)[source]
metatools.imports.rewrite.diff_texts(a, b, filename)[source]

Return a unified diff of two strings.

metatools.imports.rewrite.resolve_relative(relative, module)[source]
metatools.imports.rewrite.rewrite(source, mapping, module_name=None, non_source=False)[source]


metatools.imports.utils.resolve_relative_name(package, module, relative)[source]

Convert a relative import path into an absolute one.

  • package (str) – The __package__ that we are in.
  • module (str) – The __name__ of the module we are in.
  • relative (str) – The module name to resolve.

Absolute names are passed through untouched.

Read the Docs v: latest
On Read the Docs
Project Home

Free document hosting provided by Read the Docs.