~bzr-pqm/bzr/bzr.dev

5452.4.3 by John Arbash Meinel
Merge bzr.dev to resolve bzr-2.3.txt (aka NEWS)
1
# Copyright (C) 2006-2010 Canonical Ltd
1911.4.1 by John Arbash Meinel
Creating a factory that can load modules on demand.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1911.4.1 by John Arbash Meinel
Creating a factory that can load modules on demand.
16
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
17
"""Classes to provide name-to-object registry-like support."""
18
19
5436.2.1 by Andrew Bennetts
Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.
20
from bzrlib.pyutils import get_named_object
21
22
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
23
class _ObjectGetter(object):
1911.4.15 by John Arbash Meinel
Updated HACKING and docstrings per Martin's suggestions
24
    """Maintain a reference to an object, and return the object on request.
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
25
26
    This is used by Registry to make plain objects function similarly
27
    to lazily imported objects.
28
29
    Objects can be any sort of python object (class, function, module,
30
    instance, etc)
31
    """
32
33
    __slots__ = ['_obj']
34
35
    def __init__(self, obj):
36
        self._obj = obj
37
38
    def get_obj(self):
39
        """Get the object that was saved at creation time"""
40
        return self._obj
41
42
43
class _LazyObjectGetter(_ObjectGetter):
1911.4.16 by John Arbash Meinel
cleanup doc strings as recommended by Aaron and Martin
44
    """Keep a record of a possible object.
45
46
    When requested, load and return it.
47
    """
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
48
49
    __slots__ = ['_module_name', '_member_name', '_imported']
50
51
    def __init__(self, module_name, member_name):
52
        self._module_name = module_name
53
        self._member_name = member_name
54
        self._imported = False
55
        super(_LazyObjectGetter, self).__init__(None)
56
57
    def get_obj(self):
58
        """Get the referenced object.
59
1911.4.16 by John Arbash Meinel
cleanup doc strings as recommended by Aaron and Martin
60
        Upon first request, the object will be imported. Future requests will
61
        return the imported object.
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
62
        """
63
        if not self._imported:
5436.2.1 by Andrew Bennetts
Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.
64
            self._obj = get_named_object(self._module_name, self._member_name)
65
            self._imported = True
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
66
        return super(_LazyObjectGetter, self).get_obj()
67
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
68
    def __repr__(self):
5436.2.1 by Andrew Bennetts
Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.
69
        return "<%s.%s object at %x, module=%r attribute=%r imported=%r>" % (
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
70
            self.__class__.__module__, self.__class__.__name__, id(self),
5436.2.1 by Andrew Bennetts
Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.
71
            self._module_name, self._member_name, self._imported)
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
72
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
73
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
74
class Registry(object):
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
75
    """A class that registers objects to a name.
76
1911.4.15 by John Arbash Meinel
Updated HACKING and docstrings per Martin's suggestions
77
    There are many places that want to collect related objects and access them
78
    by a key. This class is designed to allow registering the mapping from key
79
    to object. It goes one step further, and allows registering a name to a
80
    hypothetical object which has not been imported yet. It also supports
81
    adding additional information at registration time so that decisions can be
82
    made without having to import the object (which may be expensive).
83
84
    The functions 'get', 'get_info', and 'get_help' also support a
85
    'default_key' (settable through my_registry.default_key = XXX, XXX must
86
    already be registered.) Calling my_registry.get() or my_registry.get(None),
87
    will return the entry for the default key.
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
88
    """
1911.4.1 by John Arbash Meinel
Creating a factory that can load modules on demand.
89
1911.4.6 by John Arbash Meinel
first_is_default was not a good design
90
    def __init__(self):
91
        """Create a new Registry."""
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
92
        self._default_key = None
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
93
        # Map from key => (is_lazy, info)
1911.4.1 by John Arbash Meinel
Creating a factory that can load modules on demand.
94
        self._dict = {}
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
95
        self._help_dict = {}
96
        self._info_dict = {}
1911.4.1 by John Arbash Meinel
Creating a factory that can load modules on demand.
97
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
98
    def register(self, key, obj, help=None, info=None,
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
99
                 override_existing=False):
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
100
        """Register a new object to a name.
101
102
        :param key: This is the key to use to request the object later.
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
103
        :param obj: The object to register.
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
104
        :param help: Help text for this entry. This may be a string or
1911.4.9 by John Arbash Meinel
A help callable should take the registry as the first parameter
105
                a callable. If it is a callable, it should take two
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
106
                parameters (registry, key): this registry and the key that
1911.4.16 by John Arbash Meinel
cleanup doc strings as recommended by Aaron and Martin
107
                the help was registered under.
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
108
        :param info: More information for this entry. Registry.get_info()
1911.4.16 by John Arbash Meinel
cleanup doc strings as recommended by Aaron and Martin
109
                can be used to get this information. Registry treats this as an
110
                opaque storage location (it is defined by the caller).
111
        :param override_existing: Raise KeyErorr if False and something has
112
                already been registered for that key. If True, ignore if there
113
                is an existing key (always register the new value).
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
114
        """
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
115
        if not override_existing:
116
            if key in self._dict:
117
                raise KeyError('Key %r already registered' % key)
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
118
        self._dict[key] = _ObjectGetter(obj)
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
119
        self._add_help_and_info(key, help=help, info=info)
120
121
    def register_lazy(self, key, module_name, member_name,
122
                      help=None, info=None,
123
                      override_existing=False):
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
124
        """Register a new object to be loaded on request.
125
126
        :param module_name: The python path to the module. Such as 'os.path'.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
127
        :param member_name: The member of the module to return.  If empty or
1911.4.16 by John Arbash Meinel
cleanup doc strings as recommended by Aaron and Martin
128
                None, get() will return the module itself.
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
129
        :param help: Help text for this entry. This may be a string or
130
                a callable.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
131
        :param info: More information for this entry. Registry
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
132
        :param override_existing: If True, replace the existing object
133
                with the new one. If False, if there is already something
134
                registered with the same key, raise a KeyError
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
135
        """
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
136
        if not override_existing:
137
            if key in self._dict:
138
                raise KeyError('Key %r already registered' % key)
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
139
        self._dict[key] = _LazyObjectGetter(module_name, member_name)
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
140
        self._add_help_and_info(key, help=help, info=info)
141
142
    def _add_help_and_info(self, key, help=None, info=None):
143
        """Add the help and information about this key"""
144
        self._help_dict[key] = help
145
        self._info_dict[key] = info
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
146
1912.5.6 by Adeodato Simó
Kill fallback_key parameter in Registry.get(), as discussed with John.
147
    def get(self, key=None):
148
        """Return the object register()'ed to the given key.
149
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
150
        May raise ImportError if the object was registered lazily and
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
151
        there are any problems, or AttributeError if the module does not
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
152
        have the supplied member.
153
1912.5.6 by Adeodato Simó
Kill fallback_key parameter in Registry.get(), as discussed with John.
154
        :param key: The key to obtain the object for. If no object has been
155
            registered to that key, the object registered for self.default_key
156
            will be returned instead, if it exists. Otherwise KeyError will be
157
            raised.
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
158
        :return: The previously registered object.
1911.4.15 by John Arbash Meinel
Updated HACKING and docstrings per Martin's suggestions
159
        :raises ImportError: If the object was registered lazily, and there are
160
            problems during import.
161
        :raises AttributeError: If registered lazily, and the module does not
162
            contain the registered member.
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
163
        """
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
164
        return self._dict[self._get_key_or_default(key)].get_obj()
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
165
3251.3.1 by Aaron Bentley
Add support for directory services
166
    def get_prefix(self, fullname):
3251.3.2 by Aaron Bentley
Add testing of Registry.get_prefix
167
        """Return an object whose key is a prefix of the supplied value.
168
169
        :fullname: The name to find a prefix for
170
        :return: a tuple of (object, remainder), where the remainder is the
171
            portion of the name that did not match the key.
172
        """
4000.3.1 by Jelmer Vernooij
Avoid unnecessarily resolving lazy objects in Registry.get_prefix().
173
        for key in self.keys():
3251.3.1 by Aaron Bentley
Add support for directory services
174
            if fullname.startswith(key):
4000.3.1 by Jelmer Vernooij
Avoid unnecessarily resolving lazy objects in Registry.get_prefix().
175
                return self.get(key), fullname[len(key):]
3251.3.1 by Aaron Bentley
Add support for directory services
176
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
177
    def _get_key_or_default(self, key=None):
178
        """Return either 'key' or the default key if key is None"""
179
        if key is not None:
180
            return key
181
        if self.default_key is None:
182
            raise KeyError('Key is None, and no default key is set')
183
        else:
184
            return self.default_key
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
185
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
186
    def get_help(self, key=None):
187
        """Get the help text associated with the given key"""
188
        the_help = self._help_dict[self._get_key_or_default(key)]
189
        if callable(the_help):
1911.4.9 by John Arbash Meinel
A help callable should take the registry as the first parameter
190
            return the_help(self, key)
1911.4.7 by John Arbash Meinel
Add help and info parameters, and tests for them
191
        return the_help
192
193
    def get_info(self, key=None):
194
        """Get the extra information associated with the given key"""
195
        return self._info_dict[self._get_key_or_default(key)]
196
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
197
    def remove(self, key):
198
        """Remove a registered entry.
199
200
        This is mostly for the test suite, but it can be used by others
201
        """
202
        del self._dict[key]
203
204
    def __contains__(self, key):
205
        return key in self._dict
206
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
207
    def keys(self):
208
        """Get a list of registered entries"""
209
        return sorted(self._dict.keys())
210
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
211
    def iteritems(self):
1911.4.12 by John Arbash Meinel
Use helper objects to handle lazy importing
212
        for key, getter in self._dict.iteritems():
213
            yield key, getter.get_obj()
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
214
3882.1.2 by Martin Pool
Add Registry.items()
215
    def items(self):
4691.1.1 by Vincent Ladeuil
Respect items() protocol for registry objects.
216
        # We should not use the iteritems() implementation below (see bug
217
        # #430510)
218
        return sorted([(key, getter.get_obj())
219
                       for key, getter in self._dict.items()])
3882.1.2 by Martin Pool
Add Registry.items()
220
1912.5.2 by Adeodato Simó
Morph John's LazyFactory into a generalized Registry class, and
221
    def _set_default_key(self, key):
222
        if not self._dict.has_key(key):
223
            raise KeyError('No object registered under key %s.' % key)
224
        else:
225
            self._default_key = key
226
227
    def _get_default_key(self):
228
        return self._default_key
229
1911.4.5 by John Arbash Meinel
Make a Registry look more like a dict, and allow anyone to register stuff lazily.
230
    default_key = property(_get_default_key, _set_default_key,
231
                            doc="Current value of the default key."
1911.4.15 by John Arbash Meinel
Updated HACKING and docstrings per Martin's suggestions
232
                                " Can be set to any existing key.")
4032.3.1 by Robert Collins
Add a BranchFormat.network_name() method as preparation for creating branches via RPC calls.
233
234
235
class FormatRegistry(Registry):
236
    """Registry specialised for handling formats."""
237
238
    def __init__(self, other_registry=None):
239
        Registry.__init__(self)
240
        self._other_registry = other_registry
241
242
    def register_lazy(self, key, module_name, member_name,
243
                      help=None, info=None,
244
                      override_existing=False):
245
        # Overridden to allow capturing registrations to two seperate
246
        # registries in a single call.
247
        Registry.register_lazy(self, key, module_name, member_name,
248
                help=help, info=info, override_existing=override_existing)
249
        if self._other_registry is not None:
250
            self._other_registry.register_lazy(key, module_name, member_name,
251
                help=help, info=info, override_existing=override_existing)
252
253
    def get(self, format_string):
254
        r = Registry.get(self, format_string)
255
        if callable(r):
256
            r = r()
257
        return r
4032.3.6 by Robert Collins
Fix test_source errors.
258
4032.3.1 by Robert Collins
Add a BranchFormat.network_name() method as preparation for creating branches via RPC calls.
259