1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
import sys
import pkg_resources
import inspect
import logging
log = logging.getLogger(__name__)
class PecanExtensionMissing(ImportError):
pass
class PecanExtensionImporter(object):
"""
Short circuits imports for extensions.
This is used in combination with ``pecan.ext`` so that when a user does
``from pecan.ext import foo``, it will attempt to map ``foo`` to a
registered setuptools entry point in some other (Pecan extension) project.
Conversely, an extension developer may define an entry point in his
``setup.py``, e.g.,
setup(
...
entry_points='''
[pecan.extension]
celery = pecancelery.lib.core
'''
)
This is mostly for convenience and consistency. In this way, Pecan can
maintain an ecosystem of extensions that share a common namespace,
``pecan.ext``, while still maintaining backwards compatability for simple
package names (e.g., ``pecancelery``).
"""
extension_module = 'pecan.ext'
prefix = extension_module + '.'
def install(self):
if self not in sys.meta_path:
sys.meta_path.append(self)
def __eq__(self, b):
return self.__class__.__module__ == b.__class__.__module__ and \
self.__class__.__name__ == b.__class__.__name__
def __ne__(self, b):
return not self.__eq__(b)
def find_module(self, fullname, path=None):
if fullname.startswith(self.prefix):
return self
def load_module(self, fullname):
if fullname in sys.modules:
return self
extname = fullname.split(self.prefix)[1]
module = self.find_module_for_extension(extname)
realname = module.__name__
try:
__import__(realname)
except ImportError:
raise sys.exc_info()
module = sys.modules[fullname] = sys.modules[realname]
if '.' not in extname:
setattr(sys.modules[self.extension_module], extname, module)
return module
def find_module_for_extension(self, name):
for ep in pkg_resources.iter_entry_points('pecan.extension'):
if ep.name != name:
continue
log.debug('%s loading extension %s', self.__class__.__name__, ep)
module = ep.load()
if not inspect.ismodule(module):
log.debug('%s is not a module, skipping...' % module)
continue
return module
raise PecanExtensionMissing(
'The `pecan.ext.%s` extension is not installed.' % name
)
|