~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lazy_import.py

  • Committer: Patch Queue Manager
  • Date: 2011-12-19 17:14:34 UTC
  • mfrom: (6378.1.5 config-si-unit)
  • Revision ID: pqm@pqm.ubuntu.com-20111219171434-i0b4ir0invs9il2v
(vila) Migrate add.maximum_file_size configuration option. (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
 
54
54
    __slots__ = ('_scope', '_factory', '_name', '_real_obj')
55
55
 
56
 
    # If you to do x = y, setting this to False will disallow access to
57
 
    # members from the second variable (i.e. x). This should normally
58
 
    # be enabled for reasons of thread safety and documentation, but
59
 
    # will be disabled during the selftest command to check for abuse.
60
 
    _should_proxy = True
 
56
    # Setting this to True will allow you to do x = y, and still access members
 
57
    # from both variables. This should not normally be enabled, but is useful
 
58
    # when building documentation.
 
59
    _should_proxy = False
61
60
 
62
61
    def __init__(self, scope, factory, name):
63
62
        """Create a temporary object in the specified scope.
74
73
        object.__setattr__(self, '_real_obj', None)
75
74
        scope[name] = self
76
75
 
77
 
    def _resolve(self):
78
 
        """Return the real object for which this is a placeholder"""
 
76
    def _replace(self):
 
77
        """Actually replace self with other in the given scope"""
79
78
        name = object.__getattribute__(self, '_name')
80
 
        real_obj = object.__getattribute__(self, '_real_obj')
81
 
        if real_obj is None:
82
 
            # No obj generated previously, so generate from factory and scope.
 
79
        try:
83
80
            factory = object.__getattribute__(self, '_factory')
84
81
            scope = object.__getattribute__(self, '_scope')
85
 
            obj = factory(self, scope, name)
86
 
            if obj is self:
87
 
                raise errors.IllegalUseOfScopeReplacer(name, msg="Object tried"
88
 
                    " to replace itself, check it's not using its own scope.")
89
 
 
90
 
            # Check if another thread has jumped in while obj was generated.
91
 
            real_obj = object.__getattribute__(self, '_real_obj')
92
 
            if real_obj is None:
93
 
                # Still no prexisting obj, so go ahead and assign to scope and
94
 
                # return. There is still a small window here where races will
95
 
                # not be detected, but safest to avoid additional locking.
96
 
                object.__setattr__(self, '_real_obj', obj)
97
 
                scope[name] = obj
98
 
                return obj
99
 
 
100
 
        # Raise if proxying is disabled as obj has already been generated.
101
 
        if not ScopeReplacer._should_proxy:
 
82
        except AttributeError, e:
 
83
            # Because ScopeReplacer objects only replace a single
 
84
            # item, passing them to another variable before they are
 
85
            # replaced would cause them to keep getting replaced
 
86
            # (only they are replacing the wrong variable). So we
 
87
            # make it forbidden, and try to give a good error.
102
88
            raise errors.IllegalUseOfScopeReplacer(
103
 
                name, msg="Object already replaced, did you assign it"
104
 
                          " to another variable?")
105
 
        return real_obj
 
89
                name, msg="Object already cleaned up, did you assign it"
 
90
                          " to another variable?",
 
91
                extra=e)
 
92
        obj = factory(self, scope, name)
 
93
        if obj is self:
 
94
            raise errors.IllegalUseOfScopeReplacer(name, msg="Object tried"
 
95
                " to replace itself, check it's not using its own scope.")
 
96
        if ScopeReplacer._should_proxy:
 
97
            object.__setattr__(self, '_real_obj', obj)
 
98
        scope[name] = obj
 
99
        return obj
 
100
 
 
101
    def _cleanup(self):
 
102
        """Stop holding on to all the extra stuff"""
 
103
        try:
 
104
            del self._factory
 
105
        except AttributeError:
 
106
            # Oops, we just lost a race with another caller of _cleanup.  Just
 
107
            # ignore it.
 
108
            pass
 
109
 
 
110
        try:
 
111
            del self._scope
 
112
        except AttributeError:
 
113
            # Another race loss.  See above.
 
114
            pass
 
115
 
 
116
        # We keep _name, so that we can report errors
 
117
        # del self._name
106
118
 
107
119
    def __getattribute__(self, attr):
108
 
        obj = object.__getattribute__(self, '_resolve')()
 
120
        obj = object.__getattribute__(self, '_real_obj')
 
121
        if obj is None:
 
122
            _replace = object.__getattribute__(self, '_replace')
 
123
            obj = _replace()
 
124
            _cleanup = object.__getattribute__(self, '_cleanup')
 
125
            _cleanup()
109
126
        return getattr(obj, attr)
110
127
 
111
128
    def __setattr__(self, attr, value):
112
 
        obj = object.__getattribute__(self, '_resolve')()
 
129
        obj = object.__getattribute__(self, '_real_obj')
 
130
        if obj is None:
 
131
            _replace = object.__getattribute__(self, '_replace')
 
132
            obj = _replace()
 
133
            _cleanup = object.__getattribute__(self, '_cleanup')
 
134
            _cleanup()
113
135
        return setattr(obj, attr, value)
114
136
 
115
137
    def __call__(self, *args, **kwargs):
116
 
        obj = object.__getattribute__(self, '_resolve')()
 
138
        _replace = object.__getattribute__(self, '_replace')
 
139
        obj = _replace()
 
140
        _cleanup = object.__getattribute__(self, '_cleanup')
 
141
        _cleanup()
117
142
        return obj(*args, **kwargs)
118
143
 
119
144
 
120
 
def disallow_proxying():
121
 
    """Disallow lazily imported modules to be used as proxies.
122
 
 
123
 
    Calling this function might cause problems with concurrent imports
124
 
    in multithreaded environments, but will help detecting wasteful
125
 
    indirection, so it should be called when executing unit tests.
126
 
 
127
 
    Only lazy imports that happen after this call are affected.
128
 
    """
129
 
    ScopeReplacer._should_proxy = False
130
 
 
131
 
 
132
145
class ImportReplacer(ScopeReplacer):
133
146
    """This is designed to replace only a portion of an import list.
134
147