Repository URL to install this package:
|
Version:
2.11 ▾
|
import functools
import imp
import logging
import os
import py_compile
import shutil
import sys
import tempfile
import warnings
import pkg_resources
log = logging.getLogger('chameleon.loader')
from .utils import string_type
from .utils import encode_string
def cache(func):
def load(self, *args, **kwargs):
template = self.registry.get(args)
if template is None:
self.registry[args] = template = func(self, *args, **kwargs)
return template
return load
def abspath_from_asset_spec(spec):
pname, filename = spec.split(':', 1)
return pkg_resources.resource_filename(pname, filename)
if os.name == "nt":
def abspath_from_asset_spec(spec, f=abspath_from_asset_spec):
if spec[1] == ":":
return spec
return f(spec)
class TemplateLoader(object):
"""Template loader class.
To load templates using relative filenames, pass a sequence of
paths (or a single path) as ``search_path``.
To apply a default filename extension to inputs which do not have
an extension already (i.e. no dot), provide this as
``default_extension`` (e.g. ``'.pt'``).
Additional keyword-arguments will be passed on to the template
constructor.
"""
default_extension = None
def __init__(self, search_path=None, default_extension=None, **kwargs):
if search_path is None:
search_path = []
if isinstance(search_path, string_type):
search_path = [search_path]
if default_extension is not None:
self.default_extension = ".%s" % default_extension.lstrip('.')
self.search_path = search_path
self.registry = {}
self.kwargs = kwargs
@cache
def load(self, spec, cls=None):
if cls is None:
raise ValueError("Unbound template loader.")
spec = spec.strip()
if self.default_extension is not None and '.' not in spec:
spec += self.default_extension
if ':' in spec:
spec = abspath_from_asset_spec(spec)
if os.path.isabs(spec):
return cls(spec, **self.kwargs)
for path in self.search_path:
path = os.path.join(path, spec)
if os.path.exists(path):
return cls(path, **self.kwargs)
raise ValueError("Template not found: %s." % spec)
def bind(self, cls):
return functools.partial(self.load, cls=cls)
class MemoryLoader(object):
def build(self, source, filename):
code = compile(source, filename, 'exec')
env = {}
exec(code, env)
return env
def get(self, name):
return None
class ModuleLoader(object):
def __init__(self, path, remove=False):
self.path = path
self.remove = remove
def __del__(self, shutil=shutil):
if not self.remove:
return
try:
shutil.rmtree(self.path)
except:
warnings.warn("Could not clean up temporary file path: %s" % (self.path,))
def get(self, filename):
path = os.path.join(self.path, filename)
if os.path.exists(path):
log.debug("loading module from cache: %s." % filename)
base, ext = os.path.splitext(filename)
return self._load(base, path)
else:
log.debug('cache miss: %s' % filename)
def build(self, source, filename):
imp.acquire_lock()
try:
d = self.get(filename)
if d is not None:
return d
base, ext = os.path.splitext(filename)
name = os.path.join(self.path, base + ".py")
log.debug("writing source to disk (%d bytes)." % len(source))
fd, fn = tempfile.mkstemp(prefix=base, suffix='.tmp', dir=self.path)
temp = os.fdopen(fd, 'wb')
encoded = source.encode('utf-8')
header = encode_string("# -*- coding: utf-8 -*-" + "\n")
try:
try:
temp.write(header)
temp.write(encoded)
finally:
temp.close()
except:
os.remove(fn)
raise
os.rename(fn, name)
log.debug("compiling %s into byte-code..." % filename)
py_compile.compile(name)
return self._load(base, name)
finally:
imp.release_lock()
def _load(self, base, filename):
imp.acquire_lock()
try:
module = sys.modules.get(base)
if module is None:
f = open(filename, 'rb')
try:
assert base not in sys.modules
module = imp.load_source(base, filename, f)
finally:
f.close()
finally:
imp.release_lock()
return module.__dict__