Guest User

Untitled

a guest
Jul 16th, 2018
343
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.51 KB | None | 0 0
  1. """
  2. Author: Armon Dadgar
  3. Description:
  4. This module is designed to help dynamically link against other modules,
  5. and to provide a import like functionality in repy.
  6.  
  7. Its main mechanism is dylink(). This call allows importing directly
  8. info the current context (ala from X import *) or as an encapsulated
  9. module (ala import X as Y).
  10.  
  11. When modules are imported, they are provided with either the current
  12. context or a clean context that contains the stock API functions from
  13. the current context. They are called with callfunc set to "import" to
  14. allow modules to have special behavior. If the module performs some
  15. action on import, it is possible that dylink() never returns, as with
  16. import in Python.
  17.  
  18. Module Requirements:
  19. - impr_virt.py module must be loaded!
  20. """
  21.  
  22. # This cache maps a module name -> a VirtualNamespace object
  23. MODULE_CACHE = {}
  24.  
  25. # These extensions will be tried when looking for a module to import
  26. COMMON_EXTENSIONS = ["", ".py", ".repy",".py.repy"]
  27.  
  28. # These are the functions in the "stock" repy API,
  29. # also include "dylink" and "get_current_namespace" so that we allow recursive
  30. # dynamic imports
  31. STOCK_API = set(["gethostname_ex","getmyip","recvmess","sendmess","openconn","waitforconn",
  32. "stopcomm","open","listdir","removefile","exitall","getlock","getruntime",
  33. "randomfloat","settimer","canceltimer","sleep","VirtualNamespace","thread_local",
  34. "dylink","get_current_namespace"])
  35.  
  36. # These are attributes we don't bind
  37. SKIP_BIND = set(["mycontext"])
  38.  
  39. # We won't bind anything that starts with these characters
  40. SKIP_BIND_START = ["_"]
  41.  
  42.  
  43. # This class is used to simulate a module
  44. class ImportedModule:
  45. """
  46. Emulates a module object. The instance field
  47. _context refers to the dictionary of the module.
  48. """
  49. # Initiaze the module from the context it was evaluated in
  50. def __init__(self, context):
  51. # Store the context
  52. self._context = context
  53.  
  54. # Check each key, and bind those we should...
  55. for attr in context:
  56. # If the attribute is in the stock api or skip list, don't bind
  57. if attr in STOCK_API or attr in SKIP_BIND:
  58. continue
  59.  
  60. # Check each of the rules
  61. for rule in SKIP_BIND_START:
  62. if attr.startswith(rule):
  63. continue
  64.  
  65. # Bind now
  66. setattr(self,attr,context[attr])
  67.  
  68.  
  69. # Returns a dictionary context to evaluate in based on the mode
  70. def _get_eval_context(mode):
  71. # Get the current context
  72. space = get_current_namespace()
  73. if space is None:
  74. raise Exception, "Fatal error! Currently running namespace not reported by get_current_namespace()!"
  75. context = space.get_context()
  76.  
  77. # If we are using the "global" mode, we should use the current context
  78. if mode == "global":
  79. return context
  80.  
  81. # In the module mode, we need a separate context based on the current context
  82. elif mode == "module":
  83. # Create a new context
  84. new_context = {}
  85.  
  86. # Construct a new context based on the current one
  87. for func in STOCK_API:
  88. if func in context:
  89. new_context[func] = context[func]
  90.  
  91. # Add mycontext and _context
  92. new_context["_context"] = new_context
  93. new_context["mycontext"] = {}
  94.  
  95. return new_context
  96.  
  97.  
  98. # Main API call to link in new modules
  99. def dylink(module, mode="module",context=None):
  100. """
  101. <Purpose>
  102. Dynamically link in new modules at runtime.
  103.  
  104. <Arguments>
  105. module:
  106. The name of a module to import. This should be excluding extensions,
  107. but may be the full name. e.g. for module foo.py use "foo"
  108.  
  109. mode:
  110. (Optional, values: [module, global]) If the mode is "module"
  111. then dylink will return a module like object. If mode is "global",
  112. then dylink behaves like 'from foo import *'
  113.  
  114. context:
  115. (Optional, dict) If the mode is "module" you can provide a
  116. custom dictionary to use for initializing the new module.
  117.  
  118. <Exceptions>
  119. Raises an exception if the module cannot be found, or if there is a problem
  120. initializing a VirtualNamespace around the module. See VirtualNamespace.
  121.  
  122. <Returns>
  123. If mode is "module", a module like object will be returned. Otherwise, nothing.
  124. """
  125. # Check the mode
  126. if not mode in ["module", "global"]:
  127. raise Exception, "Invalid mode specified! Must be 'module' or 'global'. Was: '" + mode + "'"
  128.  
  129. # Strip the module name of all extensions
  130. module_name = module
  131. for extension in COMMON_EXTENSIONS:
  132. module_name = module_name.replace(extension, "")
  133.  
  134. # Check if this module is cached
  135. if module_name in MODULE_CACHE:
  136. # Get the cached virtual namespace
  137. virt = MODULE_CACHE[module_name]
  138.  
  139. # The module is not cached
  140. else:
  141. # Try to get a file handle to the module
  142. fileh = None
  143. for extension in COMMON_EXTENSIONS:
  144. try:
  145. fileh = open(module + extension)
  146. break
  147. except:
  148. pass
  149.  
  150. # Was the file found?
  151. if fileh is None:
  152. raise Exception, "Failed to locate the module! Module: '" + module + "'"
  153.  
  154. # Read in the code
  155. code = fileh.read()
  156. fileh.close()
  157.  
  158. # Create a new virtual namespace
  159. try:
  160. virt = VirtualNamespace(code,module_name)
  161. except Exception, e:
  162. raise Exception, "Failed to initialize the module! Got the following exception: '" + str(e) + "'"
  163.  
  164. # Cache the module
  165. MODULE_CACHE[module_name] = virt
  166.  
  167.  
  168. # Now we need to evaluate the module, so that it can define its methods/constants, etc.
  169. if context is None or mode == "global":
  170. context = _get_eval_context(mode)
  171.  
  172. # Set the callfunc to "import"
  173. orig_callfunc = None
  174. if "callfunc" in context:
  175. orig_callfunc = context["callfunc"]
  176. context["callfunc"] = "import"
  177.  
  178. try:
  179. virt.evaluate(context)
  180. except Exception, e:
  181. raise Exception, "Caught exception while initializing module! Exception: '" + str(e) + "'"
  182.  
  183. # Restore the original callfunc
  184. if not orig_callfunc is None:
  185. context["callfunc"] = orig_callfunc
  186.  
  187. # We are now done for global mode, but we need to construct a module for the module mode
  188. if mode == "module":
  189. return ImportedModule(context)
  190.  
  191.  
  192. # Modify the API on intialization
  193. if "callfunc" in _context and callfunc == "initialize":
  194. # Check that the get_current_namespace function is defined
  195. try:
  196. func = get_current_namespace
  197. except:
  198. raise Exception, "get_current_namespace() is not defined! Ensure the impr_virt module is loaded!"
  199.  
  200. # Make dylink available
  201. MODIFIED_API["dylink"] = dylink
Add Comment
Please, Sign In to add comment