Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/chameleon/loader.py : 33%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import functools
2import logging
3import os
4import py_compile
5import shutil
6import sys
7import tempfile
8import warnings
9import pkg_resources
11try:
12 from importlib.machinery import SourceFileLoader
13 from threading import RLock
14 lock = RLock()
15 acquire_lock = lock.acquire
16 release_lock = lock.release
17 del lock
18except ImportError:
19 from imp import acquire_lock, release_lock, load_source
21 class SourceFileLoader:
22 def __init__(self, base, filename):
23 self.base = base
24 self.filename = filename
26 def load_module(self):
27 try:
28 acquire_lock()
29 assert self.base not in sys.modules
30 with open(self.filename, 'rb') as f:
31 return load_source(self.base, self.filename, f)
32 finally:
33 release_lock()
35log = logging.getLogger('chameleon.loader')
37from .utils import string_type
38from .utils import encode_string
41def cache(func):
42 def load(self, *args, **kwargs):
43 template = self.registry.get(args)
44 if template is None:
45 self.registry[args] = template = func(self, *args, **kwargs)
46 return template
47 return load
50def abspath_from_asset_spec(spec):
51 pname, filename = spec.split(':', 1)
52 return pkg_resources.resource_filename(pname, filename)
54if os.name == "nt":
55 def abspath_from_asset_spec(spec, f=abspath_from_asset_spec):
56 if spec[1] == ":":
57 return spec
58 return f(spec)
61class TemplateLoader(object):
62 """Template loader class.
64 To load templates using relative filenames, pass a sequence of
65 paths (or a single path) as ``search_path``.
67 To apply a default filename extension to inputs which do not have
68 an extension already (i.e. no dot), provide this as
69 ``default_extension`` (e.g. ``'.pt'``).
71 Additional keyword-arguments will be passed on to the template
72 constructor.
73 """
75 default_extension = None
77 def __init__(self, search_path=None, default_extension=None, **kwargs):
78 if search_path is None:
79 search_path = []
80 if isinstance(search_path, string_type):
81 search_path = [search_path]
82 if default_extension is not None:
83 self.default_extension = ".%s" % default_extension.lstrip('.')
84 self.search_path = search_path
85 self.registry = {}
86 self.kwargs = kwargs
88 @cache
89 def load(self, spec, cls=None):
90 if cls is None:
91 raise ValueError("Unbound template loader.")
93 spec = spec.strip()
95 if self.default_extension is not None and '.' not in spec:
96 spec += self.default_extension
98 if ':' in spec:
99 spec = abspath_from_asset_spec(spec)
101 if not os.path.isabs(spec):
102 for path in self.search_path:
103 path = os.path.join(path, spec)
104 if os.path.exists(path):
105 spec = path
106 break
107 else:
108 raise ValueError("Template not found: %s." % spec)
110 return cls(spec, search_path=self.search_path, **self.kwargs)
112 def bind(self, cls):
113 return functools.partial(self.load, cls=cls)
116class MemoryLoader(object):
117 def build(self, source, filename):
118 code = compile(source, filename, 'exec')
119 env = {}
120 exec(code, env)
121 return env
123 def get(self, name):
124 return None
127class ModuleLoader(object):
128 def __init__(self, path, remove=False):
129 self.path = path
130 self.remove = remove
132 def __del__(self, shutil=shutil):
133 if not self.remove:
134 return
135 try:
136 shutil.rmtree(self.path)
137 except:
138 warnings.warn("Could not clean up temporary file path: %s" % (self.path,))
140 def get(self, filename):
141 path = os.path.join(self.path, filename)
142 if os.path.exists(path):
143 log.debug("loading module from cache: %s." % filename)
144 base, ext = os.path.splitext(filename)
145 return self._load(base, path)
146 else:
147 log.debug('cache miss: %s' % filename)
149 def build(self, source, filename):
150 acquire_lock()
151 try:
152 d = self.get(filename)
153 if d is not None:
154 return d
156 base, ext = os.path.splitext(filename)
157 name = os.path.join(self.path, base + ".py")
159 log.debug("writing source to disk (%d bytes)." % len(source))
160 fd, fn = tempfile.mkstemp(prefix=base, suffix='.tmp', dir=self.path)
161 temp = os.fdopen(fd, 'wb')
162 encoded = source.encode('utf-8')
163 header = encode_string("# -*- coding: utf-8 -*-" + "\n")
165 try:
166 try:
167 temp.write(header)
168 temp.write(encoded)
169 finally:
170 temp.close()
171 except:
172 os.remove(fn)
173 raise
175 os.rename(fn, name)
176 log.debug("compiling %s into byte-code..." % filename)
177 py_compile.compile(name)
179 return self._load(base, name)
180 finally:
181 release_lock()
183 def _load(self, base, filename):
184 acquire_lock()
185 try:
186 module = sys.modules.get(base)
187 if module is None:
188 module = SourceFileLoader(base, filename).load_module()
189 finally:
190 release_lock()
192 return module.__dict__