Rev 2976: Ensure that setting attributes on ScopeReplacer objects works in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Nov 9 03:13:20 GMT 2007


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 2976
revision-id: pqm at pqm.ubuntu.com-20071109031316-n814a39wmtxvybyw
parent: pqm at pqm.ubuntu.com-20071107140948-l3p8njdhgwstdkri
parent: aaron.bentley at utoronto.ca-20071109022444-7pnank284u5prg5h
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2007-11-09 03:13:16 +0000
message:
  Ensure that setting attributes on ScopeReplacer objects works
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/lazy_import.py          lazy_import.py-20060910203832-f77c54gf3n232za0-1
  bzrlib/tests/test_lazy_import.py test_lazy_import.py-20060910203832-f77c54gf3n232za0-2
    ------------------------------------------------------------
    revno: 1551.2.49.1.40.1.22.1.42.1.31.1.39.1.17.1.77.1.3.1.23
    merged: aaron.bentley at utoronto.ca-20071109022444-7pnank284u5prg5h
    parent: aaron.bentley at utoronto.ca-20071109015537-q83rlmzstfggjebb
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: Aaron's mergeable stuff
    timestamp: Thu 2007-11-08 21:24:44 -0500
    message:
      Ensure that the attribute is actually set
    ------------------------------------------------------------
    revno: 1551.2.49.1.40.1.22.1.42.1.31.1.39.1.17.1.77.1.3.1.22
    merged: aaron.bentley at utoronto.ca-20071109015537-q83rlmzstfggjebb
    parent: aaron.bentley at utoronto.ca-20071109011256-g85ljjfbvpf9cc2j
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: Aaron's mergeable stuff
    timestamp: Thu 2007-11-08 20:55:37 -0500
    message:
      Fix exception when ScopeReplacer is assigned to before retrieving any members
    ------------------------------------------------------------
    revno: 1551.2.49.1.40.1.22.1.42.1.31.1.39.1.17.1.77.1.3.1.21
    merged: aaron.bentley at utoronto.ca-20071109011256-g85ljjfbvpf9cc2j
    parent: abentley at panoramicfeedback.com-20071019135148-7567ag3iu82is1xk
    parent: pqm at pqm.ubuntu.com-20071107140948-l3p8njdhgwstdkri
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: Aaron's mergeable stuff
    timestamp: Thu 2007-11-08 20:12:56 -0500
    message:
      Merge bzr.dev
=== modified file 'NEWS'
--- a/NEWS	2007-11-07 13:14:09 +0000
+++ b/NEWS	2007-11-09 01:55:37 +0000
@@ -67,6 +67,9 @@
    * Wrap medusa ftp test server as an FTPServer feature.
      (Vincent Ladeuil, #157752)
 
+   * Fix exception when ScopeReplacer is assigned to before any members have
+     been retrieved.  (Aaron Bentley)
+
   API BREAKS:
 
    * ``osutils.backup_file`` is deprecated. Actually it's not used in bzrlib

=== modified file 'bzrlib/lazy_import.py'
--- a/bzrlib/lazy_import.py	2007-04-12 21:33:07 +0000
+++ b/bzrlib/lazy_import.py	2007-11-09 01:55:37 +0000
@@ -64,10 +64,10 @@
             It will be passed (self, scope, name)
         :param name: The variable name in the given scope.
         """
-        self._scope = scope
-        self._factory = factory
-        self._name = name
-        self._real_obj = None
+        object.__setattr__(self, '_scope', scope)
+        object.__setattr__(self, '_factory', factory)
+        object.__setattr__(self, '_name', name)
+        object.__setattr__(self, '_real_obj', None)
         scope[name] = self
 
     def _replace(self):
@@ -88,7 +88,7 @@
                 extra=e)
         obj = factory(self, scope, name)
         if ScopeReplacer._should_proxy:
-            self._real_obj = obj
+            object.__setattr__(self, '_real_obj', obj)
         scope[name] = obj
         return obj
 
@@ -108,6 +108,15 @@
             _cleanup()
         return getattr(obj, attr)
 
+    def __setattr__(self, attr, value):
+        obj = object.__getattribute__(self, '_real_obj')
+        if obj is None:
+            _replace = object.__getattribute__(self, '_replace')
+            obj = _replace()
+            _cleanup = object.__getattribute__(self, '_cleanup')
+            _cleanup()
+        return setattr(obj, attr, value)
+
     def __call__(self, *args, **kwargs):
         _replace = object.__getattribute__(self, '_replace')
         obj = _replace()
@@ -165,9 +174,9 @@
             assert not children, \
                 'Cannot supply both a member and children'
 
-        self._import_replacer_children = children
-        self._member = member
-        self._module_path = module_path
+        object.__setattr__(self, '_import_replacer_children', children)
+        object.__setattr__(self, '_member', member)
+        object.__setattr__(self, '_module_path', module_path)
 
         # Indirecting through __class__ so that children can
         # override _import (especially our instrumented version)

=== modified file 'bzrlib/tests/test_lazy_import.py'
--- a/bzrlib/tests/test_lazy_import.py	2007-04-12 21:33:07 +0000
+++ b/bzrlib/tests/test_lazy_import.py	2007-11-09 02:24:44 +0000
@@ -150,6 +150,39 @@
                           ('foo', 2),
                          ], actions)
 
+    def test_setattr_replaces(self):
+        """ScopeReplacer can create an instance in local scope.
+
+        An object should appear in globals() by constructing a ScopeReplacer,
+        and it will be replaced with the real object upon the first request.
+        """
+        def factory(replacer, scope, name):
+            return TestClass()
+        try:
+            test_obj6
+        except NameError:
+            # test_obj6 shouldn't exist yet
+            pass
+        else:
+            self.fail('test_obj6 was not supposed to exist yet')
+
+        orig_globals = set(globals().keys())
+
+        lazy_import.ScopeReplacer(scope=globals(), name='test_obj6',
+                                  factory=factory)
+
+        new_globals = set(globals().keys())
+
+        # We can't use isinstance() because that uses test_obj6.__class__
+        # and that goes through __getattribute__ which would activate
+        # the replacement
+        self.assertEqual(lazy_import.ScopeReplacer,
+                         object.__getattribute__(test_obj6, '__class__'))
+        test_obj6.bar = 'test'
+        self.assertNotEqual(lazy_import.ScopeReplacer,
+                            object.__getattribute__(test_obj6, '__class__'))
+        self.assertEqual('test', test_obj6.bar)
+
     def test_replace_side_effects(self):
         """Creating a new object should only create one entry in globals.
 




More information about the bazaar-commits mailing list