Ronald Oussoren avatar Ronald Oussoren committed 94acf25

Add objc.autorelease_pool and use that to avoid a crash in a test case

(Still need to investigate the root case of that crash, and even with
the update the test itself fails...)

Comments (0)

Files changed (4)

pyobjc-core/Doc/api/module-objc.rst

    embedding application.
 
 
+.. function:: autorelease_pool()
+
+   A context manager that runs the body of the block with a fresh autorelease
+   pool. The actual release pool is not accessible.
+
+   Usage::
+
+        with autorelease_pool():
+            pass
+
+   .. todo:: insert links to documentation explaining why you'd want to use this.
+
 Test support
 ------------
 

pyobjc-core/Lib/objc/__init__.py

         m = getattr(m, k)
 
     return getattr(m, name)
+
+
+
+_NSAutoreleasePool = None
+class autorelease_pool(object):
+    """
+    A context manager that implements the same feature as
+    @synchronized statements in Objective-C. Locking can also
+    be done manually using the ``lock`` and ``unlock`` methods.
+
+    The mutex for object ``anObject`` is represented by
+    ``objc.object_lock(anObject)``.
+    """
+    def __init__(self):
+        global _NSAutoreleasePool
+        if _NSAutoreleasePool is None:
+            _NSAutoreleasePool = objc.lookUpClass('NSAutoreleasePool')
+
+    def __enter__(self):
+        self._pool = _NSAutoreleasePool.alloc().init()
+
+    def __exit__(self, type, value, tp):
+        del self._pool

pyobjc-core/NEWS.txt

 Version 3.0
 -----------
 
+* Addd ``objc.autorelease_pool``, a context manager for managing an
+  autorelease pool. Usage::
+
+       with objc.autorelease_pool():
+          pass
+
+
+  This is equivalent to::
+
+       _pool = NSAutoreleasePool.alloc().init()
+       try:
+           pass
+
+       finally:
+           del _pool
+
 * Added ``objc.registerABCForClass`` to make it possible to register
   a class with a number of ABC classes when the class becomes available.
 

pyobjc-core/PyObjCTest/test_keyvalue.py

         # Check for using KVO in python.
 
         def testAutomaticObserving(self):
+            with objc.autorelease_pool():
+                observer = PyObjCTestObserver.alloc().init()
+                o = PyObjCTestObserved2.alloc().init()
+                with objc.autorelease_pool():
+                    self.assertEqual(o.foo, None)
+                    self.assertEqual(o.bar, None)
+
+                    o.foo = 'foo'
+                    self.assertEqual(o.foo, 'foo')
+
+                    o.bar = 'bar'
+                    self.assertEqual(o.bar, 'bar')
+
+                    o.addObserver_forKeyPath_options_context_(observer, 'bar',
+                        (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld),
+                        0)
+                    o.addObserver_forKeyPath_options_context_(observer, 'foo',
+                        (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld),
+                        0)
+                    try:
+                        o.bar = "world"
+                        self.assertEqual(o.bar, "world")
+
+                        o.foo = "xxx"
+                        self.assertEqual(o.foo, "xxx")
+                    finally:
+                        o.removeObserver_forKeyPath_(observer, "bar")
+                        o.removeObserver_forKeyPath_(observer, "foo")
+                    self.assertEqual(len(observer.observed), 2)
+
+                    self.assertEqual(observer.observed[0],
+                        ('bar', o,  { 'kind': 1, 'new': 'world', 'old': 'bar' }, 0))
+                    self.assertEqual(observer.observed[1],
+                        ('foo', o, { 'kind': 1, 'new': 'xxx', 'old': 'foo' }, 0))
+
+                    del observer
+
+                before = DEALLOCS
+                del o
+
+            self.assertEqual(DEALLOCS, before+1, "Leaking an observed object")
+
+        def _testAutomaticObserving(self):
             outer_pool = NSAutoreleasePool.alloc().init()
             observer = PyObjCTestObserver.alloc().init()
             o = PyObjCTestObserved2.alloc().init()
             finally:
                 o.removeObserver_forKeyPath_(observer, "bar")
                 o.removeObserver_forKeyPath_(observer, "foo")
-
             self.assertEqual(len(observer.observed), 2)
 
             self.assertEqual(observer.observed[0],
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.