lazyimport.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. from __future__ import print_function
  15. ### Constants
  16. _debug = 0
  17. ###
  18. class LazyModule:
  19. """ Lazy module class.
  20. Lazy modules are imported into the given namespaces whenever a
  21. non-special attribute (there are some attributes like __doc__
  22. that class instances handle without calling __getattr__) is
  23. requested. The module is then registered under the given name
  24. in locals usually replacing the import wrapper instance. The
  25. import itself is done using globals as global namespace.
  26. Example of creating a lazy load module:
  27. ISO = LazyModule('ISO',locals(),globals())
  28. Later, requesting an attribute from ISO will load the module
  29. automatically into the locals() namespace, overriding the
  30. LazyModule instance:
  31. t = ISO.Week(1998,1,1)
  32. """
  33. # Flag which inidicates whether the LazyModule is initialized or not
  34. __lazymodule_init = 0
  35. # Name of the module to load
  36. __lazymodule_name = ''
  37. # Flag which indicates whether the module was loaded or not
  38. __lazymodule_loaded = 0
  39. # Locals dictionary where to register the module
  40. __lazymodule_locals = None
  41. # Globals dictionary to use for the module import
  42. __lazymodule_globals = None
  43. def __init__(self, name, locals, globals=None):
  44. """ Create a LazyModule instance wrapping module name.
  45. The module will later on be registered in locals under the
  46. given module name.
  47. globals is optional and defaults to locals.
  48. """
  49. self.__lazymodule_locals = locals
  50. if globals is None:
  51. globals = locals
  52. self.__lazymodule_globals = globals
  53. mainname = globals.get('__name__', '')
  54. if mainname:
  55. self.__name__ = mainname + '.' + name
  56. self.__lazymodule_name = name
  57. else:
  58. self.__name__ = self.__lazymodule_name = name
  59. self.__lazymodule_init = 1
  60. def __lazymodule_import(self):
  61. """ Import the module now.
  62. """
  63. # Load and register module
  64. name = self.__lazymodule_name
  65. if self.__lazymodule_loaded:
  66. return self.__lazymodule_locals[name]
  67. if _debug:
  68. print('LazyModule: Loading module %r' % name)
  69. self.__lazymodule_locals[name] = module = __import__(
  70. name, self.__lazymodule_locals, self.__lazymodule_globals, '*'
  71. )
  72. # Fill namespace with all symbols from original module to
  73. # provide faster access.
  74. self.__dict__.update(module.__dict__)
  75. # Set import flag
  76. self.__dict__['__lazymodule_loaded'] = 1
  77. if _debug:
  78. print('LazyModule: Module %r loaded' % name)
  79. return module
  80. def __getattr__(self, name):
  81. """ Import the module on demand and get the attribute.
  82. """
  83. if self.__lazymodule_loaded:
  84. raise AttributeError(name)
  85. if _debug:
  86. print(
  87. 'LazyModule: '
  88. 'Module load triggered by attribute %r read access' % name
  89. )
  90. module = self.__lazymodule_import()
  91. return getattr(module, name)
  92. def __setattr__(self, name, value):
  93. """ Import the module on demand and set the attribute.
  94. """
  95. if not self.__lazymodule_init:
  96. self.__dict__[name] = value
  97. return
  98. if self.__lazymodule_loaded:
  99. self.__lazymodule_locals[self.__lazymodule_name] = value
  100. self.__dict__[name] = value
  101. return
  102. if _debug:
  103. print(
  104. 'LazyModule: '
  105. 'Module load triggered by attribute %r write access' % name
  106. )
  107. module = self.__lazymodule_import()
  108. setattr(module, name, value)
  109. def __repr__(self):
  110. return "<LazyModule '%s'>" % self.__name__