Skip to content

Commit

Permalink
Lazy module imports
Browse files Browse the repository at this point in the history
Via #39
  • Loading branch information
albertz committed Oct 27, 2021
1 parent 50f42c3 commit cf08b4a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
10 changes: 10 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,21 @@
datasets, etc.
"""

from typing import TYPE_CHECKING as _TYPE_CHECKING
import sys as _sys
from ._lazy_loader import LazyLoader as _LazyLoader

# We require at least Python 3.7.
# See https://github.com/rwth-i6/returnn_common/issues/43.
# Current features we use:
# - Our code expects that the order of dict is deterministic, or even insertion order specifically.
# - Type annotations.
assert _sys.version_info[:2] >= (3, 7)

# Now all the imports.
# Use lazy imports, but only when not type checking.
if _TYPE_CHECKING:
from . import nn # noqa

else:
nn = _LazyLoader("nn", globals())
42 changes: 42 additions & 0 deletions _lazy_loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

"""
Lazy module loader.
Code adapted from TensorFlow.
"""

import importlib
import types
from typing import Dict, Any


class LazyLoader(types.ModuleType):
"""Lazily import a module, mainly to avoid pulling in large dependencies.
"""

def __init__(self, local_name: str, parent_module_globals: Dict[str, Any]):
self._local_name = local_name
self._parent_module_globals = parent_module_globals
name = f'{parent_module_globals["__package__"]}.{local_name}'
super(LazyLoader, self).__init__(name)

def _load(self):
"""Load the module and insert it into the parent's globals."""
# Import the target module and insert it into the parent's namespace
module = importlib.import_module(self.__name__)
self._parent_module_globals[self._local_name] = module

# Update this object's dict so that if someone keeps a reference to the
# LazyLoader, lookups are efficient (__getattr__ is only called on lookups
# that fail).
self.__dict__.update(module.__dict__)

return module

def __getattr__(self, item):
module = self._load()
return getattr(module, item)

def __dir__(self):
module = self._load()
return dir(module)

0 comments on commit cf08b4a

Please sign in to comment.