1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2006, 2008 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""Classes to provide name-to-object registry-like support."""
19
from __future__ import absolute_import
21
from .pyutils import get_named_object
23
from .sixish import viewitems
26
20
class _ObjectGetter(object):
27
21
"""Maintain a reference to an object, and return the object on request.
73
58
return the imported object.
75
60
if not self._imported:
76
self._obj = get_named_object(self._module_name, self._member_name)
78
62
return super(_LazyObjectGetter, self).get_obj()
66
segments = self._member_name.split('.')
69
names = [self._member_name]
70
obj = __import__(self._module_name, globals(), locals(), names)
72
for segment in segments:
73
obj = getattr(obj, segment)
80
77
def __repr__(self):
81
return "<%s.%s object at %x, module=%r attribute=%r imported=%r>" % (
78
return "<%s.%s object at %x, module=%r attribute=%r>" % (
82
79
self.__class__.__module__, self.__class__.__name__, id(self),
83
self._module_name, self._member_name, self._imported)
80
self._module_name, self._member_name)
86
83
class Registry(object):
104
101
self._default_key = None
105
102
# Map from key => (is_lazy, info)
108
104
self._help_dict = {}
109
105
self._info_dict = {}
112
"""Return a set of the format names which are aliases."""
113
return dict(viewitems(self._aliases))
117
for alias, target in viewitems(self._aliases):
118
ret.setdefault(target, []).append(alias)
121
107
def register(self, key, obj, help=None, info=None,
122
108
override_existing=False):
123
109
"""Register a new object to a name.
146
132
override_existing=False):
147
133
"""Register a new object to be loaded on request.
149
:param key: This is the key to use to request the object later.
150
135
:param module_name: The python path to the module. Such as 'os.path'.
151
136
:param member_name: The member of the module to return. If empty or
152
137
None, get() will return the module itself.
153
138
:param help: Help text for this entry. This may be a string or
155
:param info: More information for this entry. Registry.get_info()
156
can be used to get this information. Registry treats this as an
157
opaque storage location (it is defined by the caller).
140
:param info: More information for this entry. Registry
158
141
:param override_existing: If True, replace the existing object
159
142
with the new one. If False, if there is already something
160
143
registered with the same key, raise a KeyError
165
148
self._dict[key] = _LazyObjectGetter(module_name, member_name)
166
149
self._add_help_and_info(key, help=help, info=info)
168
def register_alias(self, key, target, info=None):
169
"""Register an alias.
171
:param key: Alias name
172
:param target: Target key name
174
if key in self._dict and key not in self._aliases:
175
raise KeyError('Key %r already registered and not an alias' % key)
176
self._dict[key] = self._dict[target]
177
self._aliases[key] = target
179
info = self._info_dict[target]
180
self._add_help_and_info(key, help=self._help_dict[target], info=info)
182
151
def _add_help_and_info(self, key, help=None, info=None):
183
152
"""Add the help and information about this key"""
184
153
self._help_dict[key] = help
204
173
return self._dict[self._get_key_or_default(key)].get_obj()
206
def _get_module(self, key):
207
"""Return the module the object will be or was loaded from.
209
:param key: The key to obtain the module for.
210
:return: The name of the module
212
return self._dict[key].get_module()
214
175
def get_prefix(self, fullname):
215
176
"""Return an object whose key is a prefix of the supplied value.
256
217
"""Get a list of registered entries"""
257
return sorted(self._dict)
218
return sorted(self._dict.keys())
259
220
def iteritems(self):
260
for key in self._dict:
261
yield key, self._dict[key].get_obj()
221
for key, getter in self._dict.iteritems():
222
yield key, getter.get_obj()
264
225
# We should not use the iteritems() implementation below (see bug
266
return [(key, self._dict[key].get_obj()) for key in self.keys()]
227
return sorted([(key, getter.get_obj())
228
for key, getter in self._dict.items()])
268
230
def _set_default_key(self, key):
269
if key not in self._dict:
231
if not self._dict.has_key(key):
270
232
raise KeyError('No object registered under key %s.' % key)
272
234
self._default_key = key
275
237
return self._default_key
277
239
default_key = property(_get_default_key, _set_default_key,
278
doc="Current value of the default key."
279
" Can be set to any existing key.")
240
doc="Current value of the default key."
241
" Can be set to any existing key.")
282
244
class FormatRegistry(Registry):
286
248
Registry.__init__(self)
287
249
self._other_registry = other_registry
289
def register(self, key, obj, help=None, info=None,
290
override_existing=False):
291
Registry.register(self, key, obj, help=help, info=info,
292
override_existing=override_existing)
293
if self._other_registry is not None:
294
self._other_registry.register(key, obj, help=help,
295
info=info, override_existing=override_existing)
297
251
def register_lazy(self, key, module_name, member_name,
298
252
help=None, info=None,
299
253
override_existing=False):
300
254
# Overridden to allow capturing registrations to two seperate
301
255
# registries in a single call.
302
256
Registry.register_lazy(self, key, module_name, member_name,
303
help=help, info=info, override_existing=override_existing)
257
help=help, info=info, override_existing=override_existing)
304
258
if self._other_registry is not None:
305
259
self._other_registry.register_lazy(key, module_name, member_name,
306
help=help, info=info, override_existing=override_existing)
308
def remove(self, key):
309
Registry.remove(self, key)
310
if self._other_registry is not None:
311
self._other_registry.remove(key)
260
help=help, info=info, override_existing=override_existing)
313
262
def get(self, format_string):
314
263
r = Registry.get(self, format_string)