# $Id: csource.py 2133 2006-09-06 18:52:56Z dairiki $
# csource.py - component source objects for Myghty
# Copyright (C) 2005 Michael Bayer mike_mp@zzzcomputing.com
# Original Perl code and documentation copyright (c) 1998-2003 by Jonathan Swartz.
#
# This module is part of Myghty and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
#
import posixpath as unixpath
import time, re, os, stat, types, sys, string
import __builtin__ as builtin
import myghty.util as util
import myghty.importer as importer
import myghty.exception as exception
class ComponentSource(object):
"""a time-sensitive descriptor object for a Myghty component."""
def __init__(self, id, last_modified = None ):
"unique identifier of the component."
self.id = id
"for file components, the filename without path."
self.name = ""
"for file components, relative directory where the component lives."
self.dir_name = ""
"for file components, this is dir_name + name"
self.path = ""
"for file components, this is the real filesystem path of the component."
self.file_path = ""
"for file components, id of the path, i.e. the key in the component_root hash."
self.path_id = ""
"the module containing the actual code for the component."
self.module = None
"guesstimate of the size of the component. this is filled in by Interpreter."
self.modulesize = 0
if last_modified:
self.last_modified = last_modified
else:
self.last_modified = int(time.time())
def can_compile(self):return True
def get_component_source_file(self):raise NotImplementedError()
def get_component_source(self):raise NotImplementedError()
def get_object_code(self, compiler, file):
"""compiles the source of this component using the given compiler,
sending output to the given file"""
compiler.compile(
source = self.get_component_source(),
name = self.id,
file = file,
input_file = self.file_path,
)
class ModuleComponentSourceSingleton(type):
"""a metaclass for ModuleComponentSource which allows its constructor to cache the
inspection results of the "arg" constructor parameter. """
def __call__(self, **kwargs):
arg = kwargs.get('arg', None)
arg_cache = kwargs.pop('arg_cache', None)
use_static_source = kwargs.pop('use_static_source', False)
if arg_cache is not None and arg is not None:
try:
mc = arg_cache[arg]
except KeyError:
mc = type.__call__(self, **kwargs)
arg_cache[arg] = mc
return mc.copy(use_static_source=use_static_source)
else:
return type.__call__(self, **kwargs)
class ModuleComponentSource(ComponentSource):
"""represents a loadable module containing either a ModuleComponent class, a function, a class
instance which is callable or a method on a class instance. """
__metaclass__ = ModuleComponentSourceSingleton
def __init__(self,
arg = None,
module = None,
objpath = None,
name = None,
callable_ = None,
class_ = None,
last_modified = None):
if arg is not None:
if isinstance(arg, str):
(modname, objname) = arg.split(':')
module = importer.module(modname)
objpath = objname.split('.')
if objpath is not None:
arg = module
for t in objpath:
arg = getattr(arg, t)
name = self.inspect_target(arg, objpath)
if module is None:
if self.class_ is not None:
module = sys.modules[self.class_.__module__]
elif self.has_method:
module = importer.module(self.callable_.im_class.__module__)
else:
module = importer.module(self.callable_.__module__)
else:
self.class_ = class_
self.callable_ = callable_
self.has_method = callable_ is not None and (isinstance(arg, types.MethodType) or not isinstance(arg, types.FunctionType))
if last_modified is None:
last_modified = importer.mod_time(module)
ComponentSource.__init__(self, "module|%s:%s" % (module.__name__, name), last_modified = last_modified)
self.module = module
self.objpath = objpath
self.name = name
def reload(self, module):
# the "objpath" is a list of tokens that allow us to traverse from the
# module to the callable/class unit. if we dont have that, then we can't
# reload dynamically.
if self.objpath is None:
return
self.module = module
arg = module
for t in self.objpath:
arg = getattr(arg, t)
self.inspect_target(arg, self.objpath)
def inspect_target(self, arg, objpath):
self.has_method = False
self.class_ = None
self.callable_ = None
if isinstance(arg, types.TypeType) or isinstance(arg, types.ClassType):
self.class_ = arg
name = "class:" + arg.__name__
elif isinstance(arg, types.MethodType):
self.callable_ = arg
if objpath is not None:
name = "method:" + string.join(objpath, '_')
else:
name = "method:" + arg.im_func.__name__
self.has_method = True
elif isinstance(arg, types.FunctionType):
self.callable_ = arg
if objpath is not None:
name = "function:" + string.join(objpath, '_')
else:
name = "function:" + arg.__name__
elif callable(arg):
arg = arg.__call__
self.callable_ = arg
if objpath is not None:
name = "callable:" + string.join(objpath, '_')
else:
name = "callable:" + arg.__class__.__name__
self.has_method = True
else:
raise "arg is " + repr(arg)
return name
def copy(self, use_static_source = False):
if use_static_source:
last_modified = self.last_modified
else:
last_modified = importer.modulemodtime(self.module)
return ModuleComponentSource(module = self.module, objpath = self.objpath, callable_ = self.callable_, name=self.name, class_ = self.class_, last_modified = last_modified)
def can_compile(self):
return False
class MemoryComponentSource(ComponentSource):
def __init__(self, source, id = None, last_modified = None):
if id is None:
id = str(builtin.id(self))
ComponentSource.__init__(self, id, last_modified)
self.source = source
def get_component_source_file(self):
return util.StringIO(self.source)
def get_component_source(self):
return self.source
class FileComponentSource(ComponentSource):
def __init__(self, id, path_id, path, file_path, last_modified=None):
if last_modified is None:
last_modified = os.stat(file_path)[stat.ST_MTIME]
ComponentSource.__init__(self, id, last_modified)
self.file_path = file_path
self.path = path
self.path_id = path_id
(self.dir_name, self.name) = unixpath.split(path)
def get_component_source_file(self):
return open(self.file_path)
def get_component_source(self):
return self.get_component_source_file().read()
|