Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- Author: Armon Dadgar
- Description:
- This module is designed to help dynamically link against other modules,
- and to provide a import like functionality in repy.
- Its main mechanism is dylink(). This call allows importing directly
- info the current context (ala from X import *) or as an encapsulated
- module (ala import X as Y).
- When modules are imported, they are provided with either the current
- context or a clean context that contains the stock API functions from
- the current context. They are called with callfunc set to "import" to
- allow modules to have special behavior. If the module performs some
- action on import, it is possible that dylink() never returns, as with
- import in Python.
- Module Requirements:
- - impr_virt.py module must be loaded!
- """
- # This cache maps a module name -> a VirtualNamespace object
- MODULE_CACHE = {}
- # These extensions will be tried when looking for a module to import
- COMMON_EXTENSIONS = ["", ".py", ".repy",".py.repy"]
- # These are the functions in the "stock" repy API,
- # also include "dylink" and "get_current_namespace" so that we allow recursive
- # dynamic imports
- STOCK_API = set(["gethostname_ex","getmyip","recvmess","sendmess","openconn","waitforconn",
- "stopcomm","open","listdir","removefile","exitall","getlock","getruntime",
- "randomfloat","settimer","canceltimer","sleep","VirtualNamespace","thread_local",
- "dylink","get_current_namespace"])
- # These are attributes we don't bind
- SKIP_BIND = set(["mycontext"])
- # We won't bind anything that starts with these characters
- SKIP_BIND_START = ["_"]
- # This class is used to simulate a module
- class ImportedModule:
- """
- Emulates a module object. The instance field
- _context refers to the dictionary of the module.
- """
- # Initiaze the module from the context it was evaluated in
- def __init__(self, context):
- # Store the context
- self._context = context
- # Check each key, and bind those we should...
- for attr in context:
- # If the attribute is in the stock api or skip list, don't bind
- if attr in STOCK_API or attr in SKIP_BIND:
- continue
- # Check each of the rules
- for rule in SKIP_BIND_START:
- if attr.startswith(rule):
- continue
- # Bind now
- setattr(self,attr,context[attr])
- # Returns a dictionary context to evaluate in based on the mode
- def _get_eval_context(mode):
- # Get the current context
- space = get_current_namespace()
- if space is None:
- raise Exception, "Fatal error! Currently running namespace not reported by get_current_namespace()!"
- context = space.get_context()
- # If we are using the "global" mode, we should use the current context
- if mode == "global":
- return context
- # In the module mode, we need a separate context based on the current context
- elif mode == "module":
- # Create a new context
- new_context = {}
- # Construct a new context based on the current one
- for func in STOCK_API:
- if func in context:
- new_context[func] = context[func]
- # Add mycontext and _context
- new_context["_context"] = new_context
- new_context["mycontext"] = {}
- return new_context
- # Main API call to link in new modules
- def dylink(module, mode="module",context=None):
- """
- <Purpose>
- Dynamically link in new modules at runtime.
- <Arguments>
- module:
- The name of a module to import. This should be excluding extensions,
- but may be the full name. e.g. for module foo.py use "foo"
- mode:
- (Optional, values: [module, global]) If the mode is "module"
- then dylink will return a module like object. If mode is "global",
- then dylink behaves like 'from foo import *'
- context:
- (Optional, dict) If the mode is "module" you can provide a
- custom dictionary to use for initializing the new module.
- <Exceptions>
- Raises an exception if the module cannot be found, or if there is a problem
- initializing a VirtualNamespace around the module. See VirtualNamespace.
- <Returns>
- If mode is "module", a module like object will be returned. Otherwise, nothing.
- """
- # Check the mode
- if not mode in ["module", "global"]:
- raise Exception, "Invalid mode specified! Must be 'module' or 'global'. Was: '" + mode + "'"
- # Strip the module name of all extensions
- module_name = module
- for extension in COMMON_EXTENSIONS:
- module_name = module_name.replace(extension, "")
- # Check if this module is cached
- if module_name in MODULE_CACHE:
- # Get the cached virtual namespace
- virt = MODULE_CACHE[module_name]
- # The module is not cached
- else:
- # Try to get a file handle to the module
- fileh = None
- for extension in COMMON_EXTENSIONS:
- try:
- fileh = open(module + extension)
- break
- except:
- pass
- # Was the file found?
- if fileh is None:
- raise Exception, "Failed to locate the module! Module: '" + module + "'"
- # Read in the code
- code = fileh.read()
- fileh.close()
- # Create a new virtual namespace
- try:
- virt = VirtualNamespace(code,module_name)
- except Exception, e:
- raise Exception, "Failed to initialize the module! Got the following exception: '" + str(e) + "'"
- # Cache the module
- MODULE_CACHE[module_name] = virt
- # Now we need to evaluate the module, so that it can define its methods/constants, etc.
- if context is None or mode == "global":
- context = _get_eval_context(mode)
- # Set the callfunc to "import"
- orig_callfunc = None
- if "callfunc" in context:
- orig_callfunc = context["callfunc"]
- context["callfunc"] = "import"
- try:
- virt.evaluate(context)
- except Exception, e:
- raise Exception, "Caught exception while initializing module! Exception: '" + str(e) + "'"
- # Restore the original callfunc
- if not orig_callfunc is None:
- context["callfunc"] = orig_callfunc
- # We are now done for global mode, but we need to construct a module for the module mode
- if mode == "module":
- return ImportedModule(context)
- # Modify the API on intialization
- if "callfunc" in _context and callfunc == "initialize":
- # Check that the get_current_namespace function is defined
- try:
- func = get_current_namespace
- except:
- raise Exception, "get_current_namespace() is not defined! Ensure the impr_virt module is loaded!"
- # Make dylink available
- MODIFIED_API["dylink"] = dylink
Add Comment
Please, Sign In to add comment