lazyimport.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # This module is from mx/DateTime/LazyModule.py and is
  2. # distributed under the terms of the eGenix.com Public License Agreement
  3. # http://www.egenix.com/products/eGenix.com-Public-License-1.1.0.pdf
  4. """ Helper to enable simple lazy module import.
  5. 'Lazy' means the actual import is deferred until an attribute is
  6. requested from the module's namespace. This has the advantage of
  7. allowing all imports to be done at the top of a script (in a
  8. prominent and visible place) without having a great impact
  9. on startup time.
  10. Copyright (c) 1999-2005, Marc-Andre Lemburg; mailto:mal@lemburg.com
  11. See the documentation for further information on copyrights,
  12. or contact the author. All Rights Reserved.
  13. """
  14. ### Constants
  15. _debug = 0
  16. ###
  17. class LazyModule:
  18. """ Lazy module class.
  19. Lazy modules are imported into the given namespaces whenever a
  20. non-special attribute (there are some attributes like __doc__
  21. that class instances handle without calling __getattr__) is
  22. requested. The module is then registered under the given name
  23. in locals usually replacing the import wrapper instance. The
  24. import itself is done using globals as global namespace.
  25. Example of creating a lazy load module:
  26. ISO = LazyModule('ISO',locals(),globals())
  27. Later, requesting an attribute from ISO will load the module
  28. automatically into the locals() namespace, overriding the
  29. LazyModule instance:
  30. t = ISO.Week(1998,1,1)
  31. """
  32. # Flag which inidicates whether the LazyModule is initialized or not
  33. __lazymodule_init = 0
  34. # Name of the module to load
  35. __lazymodule_name = ""
  36. # Flag which indicates whether the module was loaded or not
  37. __lazymodule_loaded = 0
  38. # Locals dictionary where to register the module
  39. __lazymodule_locals = None
  40. # Globals dictionary to use for the module import
  41. __lazymodule_globals = None
  42. def __init__(self, name, locals, globals=None):
  43. """ Create a LazyModule instance wrapping module name.
  44. The module will later on be registered in locals under the
  45. given module name.
  46. globals is optional and defaults to locals.
  47. """
  48. self.__lazymodule_locals = locals
  49. if globals is None:
  50. globals = locals
  51. self.__lazymodule_globals = globals
  52. mainname = globals.get("__name__", "")
  53. if mainname:
  54. self.__name__ = mainname + "." + name
  55. self.__lazymodule_name = name
  56. else:
  57. self.__name__ = self.__lazymodule_name = name
  58. self.__lazymodule_init = 1
  59. def __lazymodule_import(self):
  60. """ Import the module now.
  61. """
  62. # Load and register module
  63. name = self.__lazymodule_name
  64. if self.__lazymodule_loaded:
  65. return self.__lazymodule_locals[name]
  66. if _debug:
  67. print("LazyModule: Loading module %r" % name)
  68. self.__lazymodule_locals[name] = module = __import__(
  69. name, self.__lazymodule_locals, self.__lazymodule_globals, "*"
  70. )
  71. # Fill namespace with all symbols from original module to
  72. # provide faster access.
  73. self.__dict__.update(module.__dict__)
  74. # Set import flag
  75. self.__dict__["__lazymodule_loaded"] = 1
  76. if _debug:
  77. print("LazyModule: Module %r loaded" % name)
  78. return module
  79. def __getattr__(self, name):
  80. """ Import the module on demand and get the attribute.
  81. """
  82. if self.__lazymodule_loaded:
  83. raise AttributeError(name)
  84. if _debug:
  85. print(
  86. "LazyModule: "
  87. "Module load triggered by attribute %r read access" % name
  88. )
  89. module = self.__lazymodule_import()
  90. return getattr(module, name)
  91. def __setattr__(self, name, value):
  92. """ Import the module on demand and set the attribute.
  93. """
  94. if not self.__lazymodule_init:
  95. self.__dict__[name] = value
  96. return
  97. if self.__lazymodule_loaded:
  98. self.__lazymodule_locals[self.__lazymodule_name] = value
  99. self.__dict__[name] = value
  100. return
  101. if _debug:
  102. print(
  103. "LazyModule: "
  104. "Module load triggered by attribute %r write access" % name
  105. )
  106. module = self.__lazymodule_import()
  107. setattr(module, name, value)
  108. def __repr__(self):
  109. return "<LazyModule '%s'>" % self.__name__