[PyObjC-svn] r2390 - in trunk/pyobjc/pyobjc-core: . Doc Doc/lib Lib/objc Modules/objc Modules/objc/test PyObjCTest
[email protected] Thu, 28 Jan 2010 04:44:28 -0600
| Newsgroups | gmane.comp.python.pyobjc.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: ronaldoussoren
Date: Thu Jan 28 04:44:28 2010
New Revision: 2390
Log:
Initial support for Objective-C style properties.
This adds a property class: objc.object_property
This also adds a lot of machinery to allow writing
that class in Python, in particular hooks that
get called during class setup and a way to define
hidden methods.
Open issues:
* The unittests for this are basicly just stubbed out
* Hidden selector support needs more work.
* Documentation for this feature sucks
Added:
trunk/pyobjc/pyobjc-core/Doc/index.rst
trunk/pyobjc/pyobjc-core/Lib/objc/_properties.py (contents, props changed)
trunk/pyobjc/pyobjc-core/Modules/objc/test/properties.m
trunk/pyobjc/pyobjc-core/PyObjCTest/test_propertiesforclass.py (contents, props changed)
Modified:
trunk/pyobjc/pyobjc-core/Doc/lib/module-objc.rst
trunk/pyobjc/pyobjc-core/Lib/objc/__init__.py
trunk/pyobjc/pyobjc-core/Lib/objc/_compat.py
trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py
trunk/pyobjc/pyobjc-core/Lib/objc/_descriptors.py
trunk/pyobjc/pyobjc-core/Lib/objc/_functions.py
trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py
trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.h
trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m
trunk/pyobjc/pyobjc-core/Modules/objc/instance-var.m
trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m
trunk/pyobjc/pyobjc-core/Modules/objc/module.m
trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.h
trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m
trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h
trunk/pyobjc/pyobjc-core/Modules/objc/selector.h
trunk/pyobjc/pyobjc-core/Modules/objc/selector.m
trunk/pyobjc/pyobjc-core/NEWS.txt
trunk/pyobjc/pyobjc-core/setup.py
Modified: trunk/pyobjc/pyobjc-core/Doc/lib/module-objc.rst
==============================================================================
--- trunk/pyobjc/pyobjc-core/Doc/lib/module-objc.rst (original)
+++ trunk/pyobjc/pyobjc-core/Doc/lib/module-objc.rst Thu Jan 28 04:44:28 2010
@@ -106,6 +106,66 @@
TODO
+
+.. function:: propertiesForClass(objcClass)
+
+ :type objcClass: an Objective-C class or formal protocol
+ :return: a list of properties from the Objective-C runtime
+
+ The return value is a list with information about
+ properties on this class or protocol from the Objective-C runtime. This
+ does not include properties superclasses.
+
+ Every entry in the list is dictionary with the following keys:
+
+ =============== =============================================================
+ Key Description
+ =============== =============================================================
+ ``name`` Name of the property (a string)
+ --------------- -------------------------------------------------------------
+ ``raw_attr`` Raw value of the attribute string (a byte string)
+ --------------- -------------------------------------------------------------
+ ``typestr`` The type string for this attribute (a byte string)
+ --------------- -------------------------------------------------------------
+ ``classname`` When the type string is ``objc._C_ID`` this is the
+ name of the Objective-C class (a string).
+ --------------- -------------------------------------------------------------
+ ``readonly`` True iff the property is read-only (bool)
+ --------------- -------------------------------------------------------------
+ ``copy`` True iff the property is copying the value (bool)
+ --------------- -------------------------------------------------------------
+ ``retain`` True iff the property is retaining the value (bool)
+ --------------- -------------------------------------------------------------
+ ``nonatomic`` True iff the property is not atomic (bool)
+ --------------- -------------------------------------------------------------
+ ``dynamic`` True iff the property is dynamic (bool)
+ --------------- -------------------------------------------------------------
+ ``weak`` True iff the property is weak (bool)
+ --------------- -------------------------------------------------------------
+ ``collectable`` True iff the property is collectable (bool)
+ --------------- -------------------------------------------------------------
+ ``getter`` Non-standard selector for the getter method (a byte string)
+ --------------- -------------------------------------------------------------
+ ``setter`` Non-standard selector for the setter method (a byte string)
+ =============== =============================================================
+
+ All values but ``name`` and ``raw_attr`` are optional. The other attributes
+ contain a decoded version of the ``raw_attr`` value. The boolean attributes
+ should be interpreted as ``False`` when the aren't present.
+
+ The documentation for the Objective-C runtime contains more information about
+ property definitions.
+
+ This function only returns information about properties as they are defined
+ in the Objective-C runtime, that is using ``@property`` definitions in an
+ Objective-C interface. Not all properties as they are commonly used in
+ Objective-C are defined using that syntax, especially properties in classes
+ that were introduced before MacOSX 10.5.
+
+ This function always returns an empty list on MacOS X 10.4.
+
+ .. versionadded:: 2.3
+
.. function:: listInstanceVariables
TODO
@@ -280,6 +340,29 @@
TODO
+.. function:: _setClassSetUpHook
+
+ This is a private hook that is called during the creation of a subclass.
+
+ WARNING: This hook is not part of the stable API.
+
+ .. versionadded:: 2.3
+
+.. function:: _setClassExtender
+
+ This is a private hook that's called during the creation of the proxy for
+ an Objective-C class.
+
+ WARNING: This hook is not part of the stable API.
+
+ .. versionadded:: 2.2
+
+ .. versionchanged:: 2.3
+ TODO: In version 2.2 the hook gets called any time the bridge rescans
+ a class, in 2.3 the hook only gets called during initial construction
+ and has less oportunity to change things.
+
+
Types
-----
@@ -712,3 +795,82 @@
Due to technical details it is not possible to pickle an Objective-C object,
unless someone explicitly implements the pickle protocol for such an object.
+
+Properties
+----------
+
+Introduction
+............
+
+Both Python and Objective-C have support for properties, which are object attributes
+that are accessed using attribute access syntax but which result in a method call.
+
+The Python built-in :class:`property <__builtin__.property__` is used to define new
+properties in plain Python code. These properties don't full interoperate with
+Objective-C code though because they do not necessarily implement the Objective-C
+methods that mechanisms like Key-Value Coding use to interact with a class.
+
+PyObjC therefore has a number of property classes that allow you to define new
+properties that do interact fully with the Key-Value Coding and Observation
+frameworks.
+
+TODO: Implement method for enabling properties on existing classes and tell
+why that is off by default and when it will be turned on by default.
+
+TODO: The description is way to minimal, even the design document contained
+more information.
+
+.. class:: object_property(name=None, read_only=False, copy=False, dynamic=False, ivar=None, typestr=_C_ID, depends_on=None)
+
+
+ :param name: Name of the property, the default is to extract the name from the class dictionary
+ :param read_only: Is this a read-only property? The default is a read-write property.
+ :param copy: Should the default setter method copy values? The default retains the new value without copying.
+ :param dynamic: If this argument is ``True`` the property will not generate default accessor,
+ but will rely on some external process to create them.
+ :param ivar: Name of the instance variable that's used to store the value. When this value is ``None``
+ the name will be calculated from the property name. If it is ``NULL`` there will be no instance variable.
+ :param typestr: The Objective-C type for this property, defaults to an arbitrary object.
+ :param depends_on: A sequence of names of properties the value of this property depends on.
+
+During the class definition you can add accessor methods by using the property as a decorator
+
+
+.. method:: object_property.getter
+
+ Decorator for defining the getter method for a property. The name of the method should be the
+ same as the property::
+
+ class MyObject (NSObject):
+
+ prop = objc.object_property()
+
+ @prop.getter
+ def prop(self):
+ return 42
+
+
+.. method:: object_property.setter
+
+ Decorator for defining the setter method for a property. The name of the method should be the
+ same as the property.
+
+
+.. method:: object_property.validate
+
+ Decorator for defining a Key-Value Coding validator for this property.
+
+
+It is possible to override property accessor in a subclass::
+
+ class MySubclass (MyObject):
+ @MyObject.prop.getter
+ def getter(self):
+ return "the world"
+
+This can also be used to convert a read-only property to a read-write one
+by adding a setter accessor.
+
+
+
+
Modified: trunk/pyobjc/pyobjc-core/Lib/objc/__init__.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/__init__.py (original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/__init__.py Thu Jan 28 04:44:28 2010
@@ -24,6 +24,8 @@
_update()
del _update
+#import objc._setup
+
from objc._convenience import *
from objc._bridgesupport import *
@@ -37,6 +39,7 @@
from objc._functions import *
from objc._locking import *
from objc._context import *
+from objc._properties import *
import objc._pycoder as _pycoder
Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_compat.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_compat.py (original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_compat.py Thu Jan 28 04:44:28 2010
@@ -1,4 +1,5 @@
__all__ = ['runtime', 'pluginBundle', 'registerPlugin']
+import warnings
class Runtime:
"""
@@ -8,7 +9,6 @@
older versions of PyObjC.
"""
def __getattr__(self, name):
- import warnings
warnings.warn("Deprecated: use objc.lookUpClass",
DeprecationWarning)
import objc
@@ -37,6 +37,7 @@
Register the current py2app plugin by name and return its bundle
"""
+ warnings.warn("Deprecated: use objc.currentBundle()", DeprecationWarning)
import os
import sys
path = os.path.dirname(os.path.dirname(os.environ['RESOURCEPATH']))
@@ -52,7 +53,6 @@
Return the main bundle for the named plugin. This should be used
only after it has been registered with registerPlugin
"""
- import warnings
warnings.warn("Deprecated: use currentBundle()", DeprecationWarning)
from Foundation import NSBundle
return NSBundle.bundleWithPath_(_PLUGINS[pluginName])
Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py (original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py Thu Jan 28 04:44:28 2010
@@ -17,7 +17,7 @@
set(['__cmp__'])
"""
-from objc._objc import setClassExtender, selector, lookUpClass, currentBundle, repythonify, splitSignature, _block_call
+from objc._objc import _setClassExtender, selector, lookUpClass, currentBundle, repythonify, splitSignature, _block_call
from itertools import imap
import sys
@@ -153,7 +153,7 @@
type_dict['_'] = property(kvc)
-setClassExtender(add_convenience_methods)
+_setClassExtender(add_convenience_methods)
#
Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_descriptors.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_descriptors.py (original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_descriptors.py Thu Jan 28 04:44:28 2010
@@ -91,11 +91,11 @@
return selector(func, signature=signature)
return _typedSelector
-def namedselector(name, signature=None):
+def namedSelector(name, signature=None):
"""
Python 2.4 decorator for overriding the Objective-C SEL for a method, usage:
- @namedselector("foo:bar:")
+ @namedSelector("foo:bar:")
def foobar(self, foo, bar):
return foo + bar
"""
@@ -108,6 +108,11 @@
return _namedselector
+def namedselector(name, signature=None):
+ import warnings
+ warnings.warn("use objc.namedSelector instead of objc.namedselector")
+ return namedSelector(name, signature)
+
def typedAccessor(typeSignature):
"""
Python 2.4 decorator for creating a typed accessor, usage:
Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_functions.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_functions.py (original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_functions.py Thu Jan 28 04:44:28 2010
@@ -1,31 +1,8 @@
-__all__ = ['inject', 'signature']
+__all__ = [ 'signature']
import os
import sys
-def _ensure_path(p):
- p = os.path.realpath(p)
- if isinstance(p, unicode):
- p = p.encode(sys.getfilesystemencoding())
- return p
-
-def inject(pid, bundle, useMainThread=True):
- """Loads the given MH_BUNDLE in the target process identified by pid"""
- try:
- from objc._objc import _inject
- from objc._dyld import dyld_find
- except ImportError:
- raise NotImplementedError("objc.inject is only supported on Mac OS X 10.3 and later")
- bundlePath = bundle
- systemPath = dyld_find('/usr/lib/libSystem.dylib')
- carbonPath = dyld_find('/System/Library/Frameworks/Carbon.framework/Carbon')
- paths = map(_ensure_path, (bundlePath, systemPath, carbonPath))
- return _inject(
- pid,
- useMainThread,
- *paths
- )
-
def signature(signature, **kw):
"""
A Python method decorator that allows easy specification
@@ -37,6 +14,8 @@
def methodWithX_andY_(self, x, y):
return 0
"""
+ import warnings
+ warnings.warn("Usage objc.typedSelector instead of objc.signature")
from objc._objc import selector
kw['signature'] = signature
def makeSignature(func):
Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py (original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py Thu Jan 28 04:44:28 2010
@@ -323,11 +323,11 @@
value.__dict__.update(state)
except RuntimeError:
for k, v in state.items():
- setattr(value, k, v)
+ setattr(value, intern(k), v)
if slotstate:
for k, v in slotstate.items():
- setattr(value, k, v)
+ setattr(value, intern(k), v)
return value
decode_dispatch[kOP_INST] = load_inst
@@ -363,11 +363,11 @@
except RuntimeError:
for k, v in state.items():
- setattr(value, k, v)
+ setattr(value, intern(k), v)
if slotstate:
for k, v in slotstate.items():
- setattr(value, k, v)
+ setattr(value, intern(k), v)
if listitems:
for a in listitems:
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.h (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.h Thu Jan 28 04:44:28 2010
@@ -1,78 +1,18 @@
#ifndef OBJC_CLASS_BUILDER
#define OBJC_CLASS_BUILDER
-/*!
- * @header class-builder.h
- * @abstract Module for creating Objective-C classes
- * @discussion
- * This module defines the functions that are used to create new
- * classes in the Objective-C runtime for subclasses of NSObject.
- *
- * The protocol for building a new class:
- * 1) Collect the necessary information (name, bases and class_dict)
- * 2) Call PyObjCClass_BuildClass
- * 3) Create the Python class (using type.__new__)
- * 4) Call PyObjCClass_FinishClass
- *
- * If step 3 fails: call PyObjCClass_UnbuildClass
- *
- * Note that it is not possible to remove classes from the Objective-C
- * runtime (at least with the Apple runtime, not sure about the GNU runtime).
- */
+extern PyObject* PyObjC_class_setup_hook;
-/*!
- * @function PyObjCClass_BuildClass
- * @abstract Create a new Objective-C class, but do not register it
- * @param super_class The super class for the new class
- * @param protocols The list of protocols that the class conforms to
- * @param name Name of the class
- * @param class_dict The __dict__ for the new class
- * @result Returns the newly created class, or nil.
- *
- * @discusssion
- * This function builds a new class based on the information passed in
- * the arguments. The methods and functions in the class_dict are
- * transformed into selector objects.
- *
- * The function will fail if the class does not in fact implement the
- * protocols in the protocol list, or does partially implement any other
- * known (informal) protocol.
- */
Class PyObjCClass_BuildClass(
Class super_class,
PyObject* protocols,
char* name,
PyObject* class_dict,
- PyObject* meta_dict);
+ PyObject* meta_dict,
+ PyObject* hiddenSelectors);
-/*!
- * @function PyObjCClass_UnbuildClass
- * @abstract Undo the work of PyObjCClass_BuildClass
- * @param Class A class created by PyObjCClass_BuildClass
- * @result 0 on success, -1 on failure
- * @discussion
- * This function destroys the class created by PyObjCClass_BuildClass. This
- * function can only be called when PyObjCClass_FinishClass has not been
- * called for the class.
- *
- * This limitation is necessary because it is not possible to remove classes
- * from the Objetive-C runtime on MacOS X.
- */
int PyObjCClass_UnbuildClass(Class new_class);
-
-
-/*!
- * @function PyObjCClass_FinishClass
- * @abstract Register the class in the Objective-C runtime
- * @param objc_class A class created by PyObjCClass_BuildClass
- * @result Returns 0 on success, -1 on failure.
- * @discussion
- * This function updates the bookkeeping information for objc_class and
- * then registers the class with the Objective-C runtime.
- */
int PyObjCClass_FinishClass(Class objc_class);
-
-
void PyObjC_RemoveInternalTypeCodes(char* buf);
#endif /* OBJC_CLASS_BUILDER */
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m Thu Jan 28 04:44:28 2010
@@ -6,6 +6,8 @@
#import <Foundation/NSInvocation.h>
+PyObject* PyObjC_class_setup_hook = NULL;
+
#if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4
/*
@@ -608,8 +610,10 @@
Class
PyObjCClass_BuildClass(Class super_class, PyObject* protocols,
- char* name, PyObject* class_dict, PyObject* meta_dict)
+ char* name, PyObject* class_dict, PyObject* meta_dict,
+ PyObject* hiddenSelectors)
{
+ PyObject* seq;
PyObject* key_list = NULL;
PyObject* key = NULL;
PyObject* value = NULL;
@@ -621,9 +625,11 @@
Class new_meta_class = NULL;
Class cur_class;
PyObject* py_superclass = NULL;
- Py_ssize_t item_size;
int have_intermediate = 0;
int need_intermediate = 0;
+ PyObject* instance_variables = NULL;
+ PyObject* instance_methods = NULL;
+ PyObject* class_methods = NULL;
if (!PyList_Check(protocols)) {
PyErr_Format(PyObjCExc_InternalError,
@@ -664,7 +670,26 @@
PyDict_SetItemString(class_dict, "__objc_python_subclass__", Py_True);
py_superclass = PyObjCClass_New(super_class);
- if (py_superclass == NULL) return NULL;
+ if (py_superclass == NULL) {
+ return NULL;
+ }
+
+ instance_variables = PySet_New(NULL);
+ if (instance_variables == NULL) {
+ return NULL;
+ }
+
+ instance_methods = PySet_New(NULL);
+ if (instance_methods == NULL) {
+ Py_DECREF(instance_variables);
+ return NULL;
+ }
+ class_methods = PySet_New(NULL);
+ if (class_methods == NULL) {
+ Py_DECREF(instance_variables);
+ Py_DECREF(instance_methods);
+ return NULL;
+ }
/* We must override copyWithZone: for python classes because the
* refcounts of python slots might be off otherwise. Yet it should
@@ -847,19 +872,77 @@
goto error_cleanup;
}
- /* First round, count new instance-vars and check for overridden
- * methods.
- */
+ /* First step: call class setup hooks of entries in the class dict */
for (i = 0; i < key_count; i++) {
key = PyList_GET_ITEM(key_list, i);
-#if 0
- if (PyErr_Occurred()) {
+
+ value = PyDict_GetItem(class_dict, key);
+ if (value == NULL) {
PyErr_SetString(PyObjCExc_InternalError,
"PyObjCClass_BuildClass: "
- "Cannot fetch key in keylist");
+ "Cannot fetch item in keylist");
goto error_cleanup;
}
-#endif
+
+ /*
+ * Check if the value has a class-setup hook, and if it does
+ * call said hook.
+ */
+ PyObject* m = PyObject_GetAttrString(value,
+ "__pyobjc_class_setup__");
+ if (m == NULL) {
+ PyErr_Clear();
+
+ } else {
+ PyObject* rv = PyObject_CallFunction(m, "OOOO",
+ key, class_dict,
+ instance_methods,
+ class_methods);
+ Py_DECREF(m);
+ if (rv == NULL) {
+ goto error_cleanup;
+ }
+ Py_DECREF(rv);
+ }
+ }
+
+ Py_DECREF(key_list);
+
+ /* Second step: call global class construction hook */
+ if (PyObjC_class_setup_hook != NULL) {
+ PyObject* rv = PyObject_CallFunction(
+ PyObjC_class_setup_hook,
+ "sOOOOO", name, py_superclass,
+ class_dict, instance_variables,
+ instance_methods, class_methods);
+ if (rv == NULL) {
+ goto error_cleanup;
+ }
+
+ /* Todo: do we need to do something with a result? */
+ Py_XDECREF(rv);
+ }
+
+
+ /* The class hooks can modify the class dict, recalculate the key list */
+ key_list = PyDict_Keys(class_dict);
+ if (key_list == NULL) {
+ goto error_cleanup;
+ }
+
+ key_count = PyList_Size(key_list);
+ if (PyErr_Occurred()) {
+ Py_DECREF(key_list);
+ goto error_cleanup;
+ }
+
+ /* Step 2b: Collect methods and instance variables in the class dict
+ * into the 3 sets.
+ *
+ * FIXME: This work should be done by the class setup hook instead.
+ */
+ for (i = 0; i < key_count; i++) {
+ key = PyList_GET_ITEM(key_list, i);
value = PyDict_GetItem(class_dict, key);
if (value == NULL) {
@@ -870,64 +953,89 @@
}
if (PyObjCInstanceVariable_Check(value)) {
- if (PyObjCInstanceVariable_SetName(value, key) == -1) {
+ if (PySet_Add(instance_variables, value) == -1) {
goto error_cleanup;
}
- if (class_getInstanceVariable(super_class,
- ((PyObjCInstanceVariable*)value)->name) != NULL) {
- PyErr_Format(PyObjCExc_Error,
- "a superclass already has an instance "
- "variable with this name: %s",
- ((PyObjCInstanceVariable*)value)->name);
+
+ } else if (PyObjCSelector_Check(value)) {
+ int r;
+
+ /* Check if the 'key' is the name as the python
+ * representation of our selector. If not: add the
+ * python representation of our selector to the
+ * dict as well to ensure that the ObjC interface works
+ * from Python as well.
+ *
+ * NOTE: This also allows one to add both a class
+ * and instance method for the same selector in one
+ * generation.
+ */
+ char buf[1024];
+ PyObject* pyname = PyText_FromString(
+ PyObjC_SELToPythonName(
+ PyObjCSelector_GetSelector(value),
+ buf, sizeof(buf)));
+ if (pyname == NULL) {
goto error_cleanup;
}
-
- if (((PyObjCInstanceVariable*)value)->isSlot) {
- item_size = sizeof(PyObject**);
- } else {
- item_size = PyObjCRT_SizeOfType(
- ((PyObjCInstanceVariable*)value)->type);
+ int shouldCopy = PyObject_RichCompareBool(pyname, key, Py_EQ);
+ if (shouldCopy == -1) {
+ goto error_cleanup;
+ } else if (!shouldCopy) {
+ Py_DECREF(pyname); pyname = NULL;
}
- if (item_size == -1) goto error_cleanup;
-
- } else if (PyObjCNativeSelector_Check(value)) {
- char methType = '-';
- if (PyObjCSelector_IsClassMethod(value)) {
- methType = '+';
+ if (PyObjCSelector_GetClass(value) != NULL) {
+ PyObject* new_value;
+ new_value = PyObjCSelector_Copy(value);
+ if (new_value == NULL) {
+ goto error_cleanup;
+ }
+ if (PyDict_SetItem(class_dict, key, new_value) == -1) {
+ Py_DECREF(new_value);
+ goto error_cleanup;
+ }
+ value = new_value;
+ Py_DECREF(new_value); /* The value is still in the dict, and hence safe to use */
}
- PyErr_Format(PyExc_TypeError,
- "native selector %c%s of %s",
- methType,
- sel_getName(PyObjCSelector_GetSelector(value)),
- class_getName(PyObjCSelector_GetClass(value)));
- goto error_cleanup;
- } else if (PyObjCSelector_Check(value)) {
- PyObjCSelector* sel = (PyObjCSelector*)value;
+ if (PyObjCSelector_IsClassMethod(value)) {
+ r = PySet_Add(class_methods, value);
+ if (r == -1) {
+ goto error_cleanup;
+ }
- /* If it already has a sel_class, create a copy */
-#if 0
- if (sel->sel_class != NULL) {
- value = PyObjCSelector_Copy(value);
- if (value == NULL) goto error_cleanup;
- if (PyDict_SetItem(class_dict, key, value) == -1) {
- Py_DECREF(value);
+ if (shouldCopy) {
+ r = PyDict_SetItem(meta_dict, pyname, value);
+ Py_DECREF(pyname);
+ if (r == -1) {
+ goto error_cleanup;
+ }
+ }
+ if (PyDict_SetItem(meta_dict, key, value) == -1) {
+ goto error_cleanup;
+ }
+ if (PyDict_DelItem(class_dict, key) == -1) {
goto error_cleanup;
}
- Py_DECREF(value);
- sel = (PyObjCSelector*)value;
+ } else {
+ r = PySet_Add(instance_methods, value);
+ if (shouldCopy) {
+ r = PyDict_SetItem(class_dict, pyname, value);
+ Py_DECREF(pyname);
+ if (r == -1) {
+ goto error_cleanup;
+ }
+ }
}
-#endif
- /* Set sel_class */
- sel->sel_class = new_class;
} else if (
PyMethod_Check(value)
|| PyFunction_Check(value)
|| PyObject_TypeCheck(value, &PyClassMethod_Type)){
+
PyObject* pyname;
char* ocname;
pyname = key;
@@ -955,39 +1063,169 @@
goto error_cleanup;
}
- if (ocname[0] == '_' && ocname[1] == '_') {
+ if (ocname[0] != '_' || ocname[1] != '_') {
/* Skip special methods (like __getattr__) to
* avoid confusing type().
*/
- Py_XDECREF(pyname_bytes);
- continue;
- }
+ PyObject* new_value;
- value = PyObjCSelector_FromFunction(
+ new_value = PyObjCSelector_FromFunction(
pyname,
value,
py_superclass,
protocols);
- if (value == NULL) {
- Py_XDECREF(pyname_bytes);
- goto error_cleanup;
- }
+ if (new_value == NULL) {
+ Py_CLEAR(pyname_bytes);
+ goto error_cleanup;
+ }
+ value = new_value;
- if (!PyObjCSelector_Check(value)) {
- Py_XDECREF(pyname_bytes);
- Py_DECREF(value);
- continue;
+ Py_CLEAR(pyname_bytes);
+
+ if (PyObjCSelector_Check(value)) {
+ int r;
+
+
+ if (PyObjCSelector_IsClassMethod(value)) {
+ if (PyDict_SetItem(meta_dict, key, value) == -1) {
+ goto error_cleanup;
+ }
+ if (PyDict_DelItem(class_dict, key) == -1) {
+ goto error_cleanup;
+ }
+
+ r = PySet_Add(class_methods, value);
+
+ } else {
+ if (PyDict_SetItem(class_dict, key, value) < 0) {
+ Py_CLEAR(value);
+ goto error_cleanup;
+ }
+
+ r = PySet_Add(instance_methods, value);
+ }
+ if (r == -1) {
+ goto error_cleanup;
+ }
+ }
}
+ Py_CLEAR(pyname_bytes);
+ }
+ }
- ((PyObjCSelector*)value)->sel_class = new_class;
+ /* Keylist is not needed anymore */
+ Py_DECREF(key_list); key_list = NULL;
- if (PyDict_SetItem(class_dict, key, value) < 0) {
- Py_XDECREF(pyname_bytes);
- Py_DECREF(value); value = NULL;
- goto error_cleanup;
+ /* Step 3: Check instance variables */
+
+ /* convert to 'fast sequence' to ensure stable order when accessing */
+ seq = PySequence_Fast(instance_variables, "converting instance variable set to sequence");
+ if (seq == NULL) {
+ goto error_cleanup;
+ }
+ Py_DECREF(instance_variables);
+ instance_variables = seq;
+ for (i = 0; i < PySequence_Fast_GET_SIZE(instance_variables); i++) {
+ value = PySequence_Fast_GET_ITEM(instance_variables, i);
+
+ if (!PyObjCInstanceVariable_Check(value)) {
+ continue;
+ }
+
+ /* Our only check for now is that instance variable names must be unique */
+ /* XXX: Is this really necessary? */
+ if (class_getInstanceVariable(super_class, PyObjCInstanceVariable_GetName(value)) != NULL) {
+ PyErr_Format(PyObjCExc_Error,
+ "a superclass already has an instance "
+ "variable with this name: %s",
+ PyObjCInstanceVariable_GetName(value));
+ goto error_cleanup;
+ }
+ }
+
+ /* Step 4: Verify instance and class methods sets */
+
+ /* first convert then to 'Fast' sequences for easier access */
+ seq = PySequence_Fast(instance_methods, "converting instance method set to sequence");
+ if (seq == NULL) {
+ goto error_cleanup;
+ }
+ Py_DECREF(instance_methods);
+ instance_methods = seq;
+
+ seq = PySequence_Fast(class_methods, "converting class method set to sequence");
+ if (seq == NULL) {
+ goto error_cleanup;
+ }
+ Py_DECREF(class_methods);
+ class_methods = seq;
+
+ for (i = 0; i < PySequence_Fast_GET_SIZE(instance_methods); i++) {
+ value = PySequence_Fast_GET_ITEM(instance_methods, i);
+
+ if (!PyObjCSelector_Check(value)) {
+ continue;
+ }
+
+ if (PyObjCSelector_IsClassMethod(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "class method in instance method set: -%s",
+ sel_getName(PyObjCSelector_GetSelector(value)));
+ goto error_cleanup;
+ }
+
+ if (PyObjCNativeSelector_Check(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "native selector -%s of %s",
+ sel_getName(PyObjCSelector_GetSelector(value)),
+ class_getName(PyObjCSelector_GetClass(value)));
+ goto error_cleanup;
+ } else if (PyObjCSelector_Check(value)) {
+ PyObjCSelector* sel = (PyObjCSelector*)value;
+
+ /* Set sel_class */
+ sel->sel_class = new_class;
+
+ if (sel->sel_flags & PyObjCSelector_kHIDDEN) {
+ PyObject* v = PyBytes_InternFromString(
+ sel_getName(PyObjCSelector_GetSelector(value)));
+ if (v == NULL) {
+ goto error_cleanup;
+ }
+ int r = PySet_Add(hiddenSelectors, v);
+ Py_DECREF(v);
+ if (r == -1) {
+ goto error_cleanup;
+ }
}
- Py_XDECREF(pyname_bytes);
- Py_DECREF(value); value = NULL;
+ }
+ }
+ for (i = 0; i < PySequence_Fast_GET_SIZE(class_methods); i++) {
+ value = PySequence_Fast_GET_ITEM(class_methods, i);
+
+ if (!PyObjCSelector_Check(value)) {
+ continue;
+ }
+
+ if (!PyObjCSelector_IsClassMethod(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "instance method in class method set: -%s",
+ sel_getName(PyObjCSelector_GetSelector(value)));
+ goto error_cleanup;
+ }
+
+
+ if (PyObjCNativeSelector_Check(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "native selector +%s of %s",
+ sel_getName(PyObjCSelector_GetSelector(value)),
+ class_getName(PyObjCSelector_GetClass(value)));
+ goto error_cleanup;
+ } else if (PyObjCSelector_Check(value)) {
+ PyObjCSelector* sel = (PyObjCSelector*)value;
+
+ /* Set sel_class */
+ sel->sel_class = new_class;
}
}
@@ -1115,161 +1353,136 @@
#undef METH
}
- for (i = 0; i < key_count; i++) {
- key = PyList_GetItem(key_list, i);
- if (key == NULL) {
- PyErr_SetString(PyObjCExc_InternalError,
- "PyObjCClass_BuildClass: "
- "Cannot fetch key in keylist");
- goto error_cleanup;
+ /* add instance variables */
+ for (i = 0; i < PySequence_Fast_GET_SIZE(instance_variables); i++) {
+ value = PySequence_Fast_GET_ITEM(instance_variables, i);
+
+ if (!PyObjCInstanceVariable_Check(value)) {
+ continue;
}
- value = PyDict_GetItem(class_dict, key);
- if (value == NULL) {
- PyErr_SetString(PyObjCExc_InternalError,
- "PyObjCClass_BuildClass: "
- "Cannot fetch item in keylist");
+ char* type;
+ size_t size;
+ size_t align;
+
+
+ if (PyObjCInstanceVariable_IsSlot(value)) {
+ type = @encode(PyObject*);
+ size = sizeof(PyObject*);
+ } else {
+ type = PyObjCInstanceVariable_GetType(value);
+ size = PyObjCRT_SizeOfType(type);
+ }
+ align = PyObjCRT_AlignOfType(type);
+
+
+ if (PyObjCInstanceVariable_GetName(value) == NULL) {
+ PyErr_SetString(PyObjCExc_Error,
+ "instance variable without a name");
goto error_cleanup;
}
- if (PyObjCInstanceVariable_Check(value)) {
- char* type;
- size_t size;
- size_t align;
+ if (!preclass_addIvar(new_class,
+ PyObjCInstanceVariable_GetName(value),
+ size,
+ align,
+ type
+ )) {
+ goto error_cleanup;
+ }
+ }
- if (PyObjCInstanceVariable_IsSlot(value)) {
- type = @encode(PyObject*);
- size = sizeof(PyObject*);
- } else {
- type = PyObjCInstanceVariable_GetType(value);
- size = PyObjCRT_SizeOfType(type);
- }
- align = PyObjCRT_AlignOfType(type);
+ /* instance methods */
+ for (i = 0; i < PySequence_Fast_GET_SIZE(instance_methods); i++) {
+ value = PySequence_Fast_GET_ITEM(instance_methods, i);
- if (!preclass_addIvar(new_class,
- PyObjCInstanceVariable_GetName(value),
- size,
- align,
- type
- )) {
+ if (!PyObjCSelector_Check(value)) {
+ continue;
+ }
+ Method meth;
+ int is_override = 0;
+ IMP imp;
+
+ meth = class_getInstanceMethod(super_class,
+ PyObjCSelector_GetSelector(value));
+ if (meth) {
+ is_override = 1;
+ if (!same_signature(method_getTypeEncoding(meth),
+ PyObjCSelector_GetNativeSignature(value))) {
+
+ PyErr_Format(PyObjCExc_BadPrototypeError,
+ "%R has signature that is not compatible with super-class",
+ value);
goto error_cleanup;
}
+ }
+ if (is_override) {
+ imp = PyObjC_MakeIMP(new_class, super_class, value, value);
+ } else {
+ imp = PyObjC_MakeIMP(new_class, nil, value, value);
+ }
+ if (imp == NULL) {
+ goto error_cleanup;
+ }
- } else if (PyObjCSelector_Check(value)) {
- PyObjCSelector* sel = (PyObjCSelector*)value;
- Method meth;
- int is_override = 0;
- Class cls;
- IMP imp;
-
- /* Check if the 'key' is the name as the python
- * representation of our selector. If not: add the
- * python representation of our selector to the
- * dict as well to ensure that the ObjC interface works
- * from Python as well.
- *
- * NOTE: This also allows one to add both a class
- * and instance method for the same selector in one
- * generation.
- */
- char buf[1024];
- PyObject* pyname = PyText_FromString(
- PyObjC_SELToPythonName(sel->sel_selector, buf, sizeof(buf)));
- if (pyname == NULL) goto error_cleanup;
- int shouldCopy = PyObject_RichCompareBool(pyname, key, Py_EQ);
- if (shouldCopy == -1) goto error_cleanup;
-
-
- if (sel->sel_flags & PyObjCSelector_kCLASS_METHOD) {
- meth = class_getClassMethod(super_class,
- sel->sel_selector);
- if (meth) {
- is_override = 1;
-
- if (!same_signature(method_getTypeEncoding(meth),
- sel->sel_native_signature)) {
-
- PyErr_Format(PyObjCExc_BadPrototypeError,
- "%R has signature that is not compatible with super-class",
- sel);
- goto error_cleanup;
- }
- }
- cls = new_meta_class;
-
- /* Class method: the value should be in the
- * metadict instead of the regular dict.
- * Make it so.
- */
- if (shouldCopy) {
- if (PyDict_SetItem(meta_dict, pyname, value) == -1) {
- Py_DECREF(pyname);
- goto error_cleanup;
- }
- }
- Py_DECREF(pyname);
+ if (!preclass_addMethod(new_class, PyObjCSelector_GetSelector(value), imp,
+ PyObjCSelector_GetNativeSignature(value))) {
+ goto error_cleanup;
+ }
+ }
- if (PyDict_SetItem(meta_dict, key, value) == -1)
- goto error_cleanup;
- if (PyDict_DelItem(class_dict, key) == -1)
- goto error_cleanup;
+ /* class methods */
+ for (i = 0; i < PySequence_Fast_GET_SIZE(class_methods); i++) {
+ value = PySequence_Fast_GET_ITEM(class_methods, i);
+ if (!PyObjCSelector_Check(value)) {
+ continue;
+ }
+ Method meth;
+ int is_override = 0;
+ IMP imp;
- } else {
- meth = class_getInstanceMethod(super_class,
- sel->sel_selector);
- if (meth) {
- is_override = 1;
- if (!same_signature(method_getTypeEncoding(meth),
- sel->sel_native_signature)) {
-
- PyErr_Format(PyObjCExc_BadPrototypeError,
- "%R has signature that is not compatible with super-class",
- sel);
- goto error_cleanup;
- }
- }
- cls = new_class;
- if (shouldCopy) {
- if (PyDict_SetItem(class_dict, pyname, value) == -1) {
- Py_DECREF(pyname);
- goto error_cleanup;
- }
- }
- Py_DECREF(pyname);
- }
-
- if (is_override) {
- imp = PyObjC_MakeIMP(cls, super_class, value, value);
- } else {
- imp = PyObjC_MakeIMP(cls, nil, value, value);
- }
- if (imp == NULL) {
- goto error_cleanup;
+ meth = class_getClassMethod(super_class, PyObjCSelector_GetSelector(value));
+ if (meth) {
+ is_override = 1;
+
+ if (!same_signature(method_getTypeEncoding(meth),
+ PyObjCSelector_GetNativeSignature(value))) {
+
+ PyErr_Format(PyObjCExc_BadPrototypeError,
+ "%R has signature that is not compatible with super-class",
+ value);
+ goto error_cleanup;
}
+ }
- if (!preclass_addMethod(cls, sel->sel_selector, imp,
- sel->sel_native_signature)) {
- goto error_cleanup;
- }
+ if (is_override) {
+ imp = PyObjC_MakeIMP(new_meta_class, super_class, value, value);
+ } else {
+ imp = PyObjC_MakeIMP(new_meta_class, nil, value, value);
+ }
+ if (imp == NULL) {
+ goto error_cleanup;
+ }
- if (sel->sel_class == NULL) {
- sel->sel_class = new_class;
- }
- } /* XXX: else if (PyObjCIMP_Check(value)) */
+ if (!preclass_addMethod(new_meta_class, PyObjCSelector_GetSelector(value), imp,
+ PyObjCSelector_GetNativeSignature(value))) {
+ goto error_cleanup;
+ }
}
- Py_DECREF(key_list);
- key_list = NULL;
Py_XDECREF(py_superclass); py_superclass = NULL;
if (PyDict_DelItemString(class_dict, "__dict__") < 0) {
PyErr_Clear();
}
+ Py_XDECREF(instance_variables); instance_variables = NULL;
+ Py_XDECREF(instance_methods); instance_methods = NULL;
+ Py_XDECREF(class_methods); class_methods = NULL;
/*
* NOTE: Class is not registered yet, we do that as lately as possible
@@ -1279,6 +1492,9 @@
return new_class;
error_cleanup:
+ Py_XDECREF(instance_variables);
+ Py_XDECREF(instance_methods);
+ Py_XDECREF(class_methods);
Py_XDECREF(py_superclass);
if (key_list) {
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/instance-var.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/instance-var.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/instance-var.m Thu Jan 28 04:44:28 2010
@@ -266,6 +266,48 @@
return 0;
}
+static PyObject*
+ivar_class_setup(PyObject* _self, PyObject* args, PyObject* kwds)
+{
+static char* keywords[] = { "name", "class_dict", "instance_method_list", "class_method_list", NULL };
+ PyObjCInstanceVariable* self = (PyObjCInstanceVariable*)_self;
+ char* name;
+ PyObject* class_dict;
+ PyObject* instance_method_list;
+ PyObject* class_method_list;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO!O!O!", keywords,
+ &name,
+ &PyDict_Type, &class_dict,
+ &PySet_Type, &instance_method_list,
+ &PySet_Type, &class_method_list
+ )){
+ return NULL;
+ }
+
+ if (self->name == NULL) {
+ self->name = PyObjCUtil_Strdup(name);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyMethodDef ivar_methods[] = {
+ {
+ "__pyobjc_class_setup__",
+ (PyCFunction)ivar_class_setup,
+ METH_VARARGS|METH_KEYWORDS,
+ NULL
+ },
+
+ {
+ NULL, NULL, 0, NULL
+ }
+};
+
+
PyDoc_STRVAR(ivar_doc,
"ivar(name, type='@', isOutlet=False) -> instance-variable\n"
"\n"
@@ -307,7 +349,7 @@
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_selectors */
+ ivar_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m Thu Jan 28 04:44:28 2010
@@ -156,6 +156,7 @@
#if PY_VERSION_HEX < 0x03000000
static void cleanup_ffitype_capsule(void* ptr, void* context __attribute__((__unused__)))
+
{
free_type(ptr);
}
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/module.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/module.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/module.m Thu Jan 28 04:44:28 2010
@@ -25,6 +25,7 @@
int PyObjC_VerboseLevel = 0;
int PyObjC_HideProtected = 1;
BOOL PyObjC_useKVO = YES;
+BOOL PyObjC_nativeProperties = NO;
PyObject* PyObjCClass_DefaultModule = NULL;
PyObject* PyObjC_NSNumberWrapper = NULL;
@@ -1527,7 +1528,7 @@
"C. This object has no useable interface from Python.\n"
);
#if PY_VERSION_HEX < 0x03000000
-static void _callback_cleanup(void* closure, void* unused __attribute__((__unused__)))
+static void _callback_cleanup(void* closure)
{
PyObjCFFI_FreeIMP((IMP)closure);
}
@@ -1645,16 +1646,46 @@
return object;
}
+static PyObject*
+mod_propertiesForClass(PyObject* mod __attribute__((__unused__)), PyObject* object)
+{
+ return PyObjCClass_ListProperties(object);
+}
+
+static PyObject*
+mod_setClassSetupHook(PyObject* mod __attribute__((__unused__)), PyObject* hook)
+{
+ PyObject* curval = PyObjC_class_setup_hook;
+
+ PyObjC_class_setup_hook = hook;
+ Py_INCREF(hook);
+
+ return curval;
+}
+
static PyMethodDef mod_methods[] = {
{
+ "_setClassSetUpHook",
+ (PyCFunction)mod_setClassSetupHook,
+ METH_O,
+ "Private: set hook used during subclass creation",
+ },
+
+ {
+ "propertiesForClass",
+ (PyCFunction)mod_propertiesForClass,
+ METH_O,
+ "Return information about properties from the runtim",
+ },
+ {
"splitSignature",
(PyCFunction)objc_splitSignature,
METH_VARARGS|METH_KEYWORDS,
objc_splitSignature_doc
},
{
- "_splitStruct",
+ "splitStruct",
(PyCFunction)objc_splitStruct,
METH_VARARGS|METH_KEYWORDS,
objc_splitStruct_doc,
@@ -1673,7 +1704,7 @@
},
{ "currentBundle", (PyCFunction)currentBundle, METH_NOARGS, currentBundle_doc },
{ "getClassList", (PyCFunction)getClassList, METH_NOARGS, getClassList_doc },
- { "setClassExtender", (PyCFunction)set_class_extender, METH_VARARGS|METH_KEYWORDS, set_class_extender_doc },
+ { "_setClassExtender", (PyCFunction)set_class_extender, METH_VARARGS|METH_KEYWORDS, set_class_extender_doc },
{ "setSignatureForSelector", (PyCFunction)set_signature_for_selector, METH_VARARGS|METH_KEYWORDS, set_signature_for_selector_doc },
{ "recycleAutoreleasePool", (PyCFunction)recycle_autorelease_pool, METH_VARARGS|METH_KEYWORDS, recycle_autorelease_pool_doc },
{ "removeAutoreleasePool", (PyCFunction)remove_autorelease_pool, METH_VARARGS|METH_KEYWORDS, remove_autorelease_pool_doc },
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.h (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.h Thu Jan 28 04:44:28 2010
@@ -94,6 +94,7 @@
int generation;
int useKVO;
PyObject* protectedMethods;
+ PyObject* hiddenSelectors;
struct _PyObjCClassObject* meta_class; /* To be dropped */
} PyObjCClassObject;
@@ -109,5 +110,9 @@
void PyObjCClass_SetDelMethod(PyObject* cls, PyObject* newval);
int PyObjCClass_HasPythonImplementation(PyObject* cls);
PyObject* PyObjCClass_ClassForMetaClass(PyObject* meta);
+BOOL PyObjCClass_HiddenSelector(PyObject* tp, SEL sel);
+
+PyObject* PyObjCClass_ListProperties(PyObject* cls);
+
#endif /* PyObjC_OBJC_CLASS_H */
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m Thu Jan 28 04:44:28 2010
@@ -7,6 +7,41 @@
#include <stddef.h>
+
+BOOL PyObjCClass_HiddenSelector(PyObject* tp, SEL sel)
+{
+ PyObject* mro = ((PyTypeObject*)tp)->tp_mro;
+ int i, n;
+
+ if (mro == NULL) {
+ return NO;
+ }
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ PyObject* base = PyTuple_GET_ITEM(mro, i);
+ if (PyObjCClass_Check(base)) {
+ PyObject* hidden = ((PyObjCClassObject*)base)->hiddenSelectors;
+ if (hidden != NULL) {
+ PyObject* v = PyBytes_InternFromString(sel_getName(sel));
+ if (v == NULL) {
+ PyErr_Clear();
+ } else {
+ int r = PySet_Contains(hidden, v);
+ Py_DECREF(v);
+ if (r == -1) {
+ PyErr_Clear();
+ } else if (r == 1) {
+ return YES;
+ }
+ }
+ }
+ }
+ }
+
+ return NO;
+}
+
/*
* Support for NSData/NSMutableData to have buffer API
*
@@ -119,7 +154,7 @@
PyObject* PyObjC_ClassExtender = NULL;
-static int add_class_fields(Class objc_class, PyObject* dict, PyObject* protDict, PyObject* classDict);
+static int add_class_fields(Class objc_class, PyObject* py_class, PyObject* dict, PyObject* protDict, PyObject* classDict);
static int add_convenience_methods(Class cls, PyObject* type_dict);
static int update_convenience_methods(PyObject* cls);
@@ -342,6 +377,7 @@
PyObject* useKVOObj;
Ivar var;
PyObject* protectedMethods = NULL;
+ PyObject* hiddenSelectors = NULL;
BOOL isCFProxyClass = NO;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "sOO:__new__",
@@ -390,6 +426,13 @@
return NULL;
}
+ hiddenSelectors = PySet_New(NULL);
+ if (hiddenSelectors == NULL) {
+ Py_DECREF(protectedMethods);
+ return NULL;
+ }
+
+
/*
* __pyobjc_protocols__ contains the list of protocols supported
* by an existing class.
@@ -399,7 +442,11 @@
if (protocols == NULL) {
PyErr_Clear();
protocols = PyList_New(0);
- if (protocols == NULL) return NULL;
+ if (protocols == NULL) {
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
+ return NULL;
+ }
} else {
PyObject* seq;
Py_ssize_t protocols_len;
@@ -407,6 +454,8 @@
seq = PySequence_Fast(protocols,
"__pyobjc_protocols__ not a sequence?");
if (seq == NULL) {
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
Py_DECREF(protocols);
return NULL;
}
@@ -415,6 +464,8 @@
protocols_len = PySequence_Fast_GET_SIZE(seq);
protocols = PyList_New(protocols_len);
if (protocols == NULL) {
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
for (i = 0; i < protocols_len; i++) {
@@ -428,10 +479,14 @@
real_bases = PyList_New(0);
if (real_bases == NULL) {
Py_DECREF(protocols);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
PyList_Append(real_bases, py_super_class);
if (PyErr_Occurred()) {
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
Py_DECREF(protocols);
Py_DECREF(real_bases);
return NULL;
@@ -440,11 +495,17 @@
for (i = 1; i < len; i++) {
v = PyTuple_GET_ITEM(bases, i);
if (v == NULL) {
+ Py_DECREF(protocols);
+ Py_DECREF(real_bases);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
if (PyObjCClass_Check(v)) {
Py_DECREF(protocols);
Py_DECREF(real_bases);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
PyErr_SetString(PyExc_TypeError,
"multiple objective-C bases");
return NULL;
@@ -461,6 +522,8 @@
if (metadict == NULL) {
Py_DECREF(protocols);
Py_DECREF(real_bases);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
@@ -471,11 +534,13 @@
/* First generate the objective-C class. This may change the
* class dict.
*/
- objc_class = PyObjCClass_BuildClass(super_class, protocols, name, dict, metadict);
+ objc_class = PyObjCClass_BuildClass(super_class, protocols, name, dict, metadict, hiddenSelectors);
if (objc_class == NULL) {
Py_DECREF(protocols);
Py_DECREF(metadict);
Py_DECREF(real_bases);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
@@ -487,6 +552,8 @@
Py_DECREF(protocols);
Py_DECREF(real_bases);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
} else {
PyObjCClass_CheckMethodList(py_super_class, 1);
@@ -504,6 +571,8 @@
Py_DECREF(metadict);
Py_DECREF(protocols);
Py_DECREF(real_bases);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
Py_DECREF(real_bases);
@@ -527,6 +596,8 @@
Py_DECREF(real_bases);
Py_DECREF(protocols);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
(void)PyObjCClass_UnbuildClass(objc_class);
return NULL;
}
@@ -536,6 +607,8 @@
Py_DECREF(real_bases);
Py_DECREF(protocols);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
(void)PyObjCClass_UnbuildClass(objc_class);
return NULL;
}
@@ -550,6 +623,8 @@
Py_DECREF(real_bases);
Py_DECREF(protocols);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
(void)PyObjCClass_UnbuildClass(objc_class);
return NULL;
}
@@ -576,6 +651,8 @@
Py_DECREF(protocols);
Py_DECREF(real_bases);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
} else {
if (PyDict_DelItemString(dict, "__del__") < 0) {
@@ -585,6 +662,8 @@
Py_DECREF(protocols);
Py_DECREF(real_bases);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
}
@@ -602,6 +681,8 @@
Py_DECREF(protocols);
Py_DECREF(real_bases);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
@@ -612,6 +693,8 @@
Py_DECREF(protocols);
Py_DECREF(real_bases);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
}
@@ -626,6 +709,8 @@
Py_DECREF(protocols);
Py_DECREF(real_bases);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
if (PyDict_Update(metatype->tp_dict, metadict) == -1) {
@@ -633,6 +718,8 @@
Py_DECREF(protocols);
Py_DECREF(real_bases);
Py_DECREF(metadict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
return NULL;
}
} else {
@@ -654,6 +741,8 @@
Py_DECREF(real_bases);
Py_DECREF(protocols);
Py_DECREF(old_dict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
(void)PyObjCClass_UnbuildClass(objc_class);
return NULL;
}
@@ -675,6 +764,8 @@
PyObjC_UnregisterPythonProxy(objc_class, res);
Py_DECREF(res);
Py_DECREF(old_dict);
+ Py_DECREF(protectedMethods);
+ Py_DECREF(hiddenSelectors);
(void)PyObjCClass_UnbuildClass(objc_class);
return NULL;
}
@@ -696,6 +787,7 @@
info->hasPythonImpl = 1;
info->isCFWrapper = 0;
info->protectedMethods = protectedMethods;
+ info->hiddenSelectors = hiddenSelectors;
var = class_getInstanceVariable(objc_class, "__dict__");
@@ -795,6 +887,7 @@
r = add_class_fields(
info->class,
+ cls,
((PyTypeObject*)cls)->tp_dict,
info->protectedMethods,
Py_TYPE(cls)->tp_dict);
@@ -1348,7 +1441,7 @@
* surprising)
*/
static int
-add_class_fields(Class objc_class, PyObject* pubDict, PyObject* protDict, PyObject* classDict)
+add_class_fields(Class objc_class, PyObject* py_class, PyObject* pubDict, PyObject* protDict, PyObject* classDict)
{
Class cls;
Method* methods;
@@ -1374,6 +1467,12 @@
dict = protDict;
}
}
+
+ /* Check if the selector should be hidden */
+ if (PyObjCClass_HiddenSelector(py_class, method_getName(methods[i]))) {
+ continue;
+ }
+
name = (char*)PyObjC_SELToPythonName(
method_getName(methods[i]),
selbuf,
@@ -1474,6 +1573,7 @@
PyObjCClassObject* info;
Ivar var;
PyObject* protectedMethods;
+ PyObject* hiddenSelectors;
PyTypeObject* metaclass;
const char* className;
@@ -1482,10 +1582,6 @@
return result;
}
- protectedMethods = PyDict_New();
- if (protectedMethods == NULL) {
- return NULL;
- }
if (class_isMetaClass(objc_class)) {
result = (PyObject*)PyObjCClass_NewMetaClass(objc_class);
@@ -1493,13 +1589,26 @@
return result;
}
+ protectedMethods = PyDict_New();
+ if (protectedMethods == NULL) {
+ return NULL;
+ }
+
+ hiddenSelectors = PySet_New(NULL);
+ if (hiddenSelectors == NULL) {
+ Py_DECREF(protectedMethods);
+ return NULL;
+ }
+
metaclass = PyObjCClass_NewMetaClass(objc_class);
if (metaclass == NULL) {
+ Py_DECREF(hiddenSelectors);
Py_DECREF(protectedMethods);
return NULL;
}
+
dict = PyDict_New();
PyDict_SetItemString(dict, "__slots__", PyTuple_New(0));
@@ -1521,7 +1630,11 @@
result = PyType_Type.tp_new(metaclass, args, NULL);
Py_DECREF(args); Py_DECREF(metaclass);
- if (result == NULL) return NULL;
+ if (result == NULL) {
+ Py_DECREF(hiddenSelectors);
+ Py_DECREF(protectedMethods);
+ return NULL;
+ }
info = (PyObjCClassObject*)result;
info->class = objc_class;
@@ -1533,6 +1646,7 @@
info->hasPythonImpl = 0;
info->isCFWrapper = 0;
info->protectedMethods = protectedMethods;
+ info->hiddenSelectors = hiddenSelectors;
/*
* Support the buffer protocol in the wrappers for NSData and
@@ -1564,6 +1678,218 @@
return result;
}
+PyObject*
+PyObjCClass_ListProperties(PyObject* aClass)
+{
+ Class cls = Nil;
+ Protocol* proto = nil;
+
+ if (PyObjCClass_Check(aClass)) {
+ cls = PyObjCClass_GetClass(aClass);
+ if (cls == Nil) {
+ return NULL;
+ }
+ } else if (PyObjCFormalProtocol_Check(aClass)) {
+ proto = PyObjCFormalProtocol_GetProtocol(aClass);
+ if (proto == nil) {
+ return NULL;
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "class must be an Objective-C class or formal protocol");
+ return NULL;
+ }
+
+ objc_property_t* props;
+ unsigned int propcount, i;
+ char buf[128];
+
+ if (cls == Nil) {
+ return NULL;
+ }
+
+ PyObject* result = PyList_New(0);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ if (class_copyPropertyList == NULL) {
+ /* System without the 2.0 runtime and hence without
+ * native properties
+ */
+ return result;
+ }
+
+ if (cls) {
+ props = class_copyPropertyList(cls, &propcount);
+ } else {
+ props = protocol_copyPropertyList(proto, &propcount);
+ }
+ if (props == NULL) {
+ return result;
+ }
+
+ for (i = 0; i < propcount; i++) {
+ PyObject* item;
+ PyObject* v;
+ const char* name = property_getName(props[i]);
+ const char* attr = property_getAttributes(props[i]);
+ const char* e;
+
+ item = Py_BuildValue(
+#if PY_VERSION_HEX < 0x03000000
+ "{ssss}",
+#else
+ "{sssy}",
+#endif
+ "name", name,
+ "raw_attr", attr);
+ if (item == NULL) {
+ goto error;
+ }
+ if (PyList_Append(result, item) == -1) {
+ Py_DECREF(item);
+ goto error;
+ }
+ Py_DECREF(item);
+
+ if (*attr != 'T') {
+ /* Attribute string doesn't conform to the
+ * 2.0 protocol, don't try to process it.
+ */
+ continue;
+ }
+
+ e = PyObjCRT_SkipTypeSpec(attr+1);
+ if (e == NULL) {
+ goto error;
+ }
+ if (e - (attr+1) > 127) {
+ v = PyBytes_InternFromStringAndSize(attr+1, e - (attr+1));
+ } else {
+ PyObjCRT_RemoveFieldNames(buf, attr+1);
+ v = PyBytes_InternFromString(buf);
+ }
+ if (v == NULL) {
+ goto error;
+ }
+
+ if (PyDict_SetItemString(item, "typestr", v) == -1) {
+ Py_DECREF(v);
+ goto error;
+ }
+ Py_DECREF(v); v = NULL;
+
+ attr = e;
+ if (*attr == '"') {
+ e = strchr(attr+1, '"');
+ v = PyText_FromStringAndSize(attr+1, e-(attr+1));
+ if (v == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(item, "classname", v) == -1) {
+ Py_DECREF(v);
+ goto error;
+ }
+ Py_DECREF(v); v = NULL;
+ attr = e + 1;
+ }
+
+ if (*attr++ != ',') {
+ /* Value doesn't conform to 2.0 protocol */
+ continue;
+ }
+
+ while (attr && *attr != '\0') {
+ switch (*attr++) {
+ case 'R':
+ if (PyDict_SetItemString(item, "readonly", Py_True) < 0) {
+ goto error;
+ }
+ break;
+ case 'C':
+ if (PyDict_SetItemString(item, "copy", Py_True) < 0) {
+ goto error;
+ }
+ break;
+ case '&':
+ if (PyDict_SetItemString(item, "retain", Py_True) < 0) {
+ goto error;
+ }
+ break;
+ case 'N':
+ if (PyDict_SetItemString(item, "nonatomic", Py_True) < 0) {
+ goto error;
+ }
+ break;
+ case 'D':
+ if (PyDict_SetItemString(item, "dynamic", Py_True) < 0) {
+ goto error;
+ }
+ break;
+ case 'W':
+ if (PyDict_SetItemString(item, "weak", Py_True) < 0) {
+ goto error;
+ }
+ break;
+ case 'P':
+ if (PyDict_SetItemString(item, "collectable", Py_True) < 0) {
+ goto error;
+ }
+ break;
+ case 'G':
+ e = strchr(attr, ',');
+ if (e == NULL) {
+ v = PyBytes_FromString(attr);
+ attr = e;
+ } else {
+ v = PyBytes_FromStringAndSize(
+ attr, e - attr);
+ attr = e;
+ }
+ if (v == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(item, "getter", v) < 0){
+ Py_DECREF(v);
+ goto error;
+ }
+ break;
+ case 'S':
+ e = strchr(attr, ',');
+ if (e == NULL) {
+ v = PyBytes_FromString(attr);
+ attr = e;
+ } else {
+ v = PyBytes_FromStringAndSize(
+ attr, e - attr);
+ attr = e;
+ }
+ if (v == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(item, "setter", v) < 0){
+ Py_DECREF(v);
+ goto error;
+ }
+ break;
+ case 'V':
+ attr = NULL;
+ break;
+ }
+ }
+ }
+ free(props); props = NULL;
+
+ return result;
+error:
+ if (props) {
+ free(props);
+ }
+ Py_XDECREF(result);
+ return NULL;
+}
+
Class
PyObjCClass_GetClass(PyObject* cls)
@@ -1572,7 +1898,7 @@
PyErr_Format(PyObjCExc_InternalError,
"PyObjCClass_GetClass called for non-class (%s)",
Py_TYPE(cls)->tp_name);
- return nil;
+ return Nil;
}
return ((PyObjCClassObject*)cls)->class;
@@ -1925,3 +2251,4 @@
return PyObjCClass_New(objc_metaclass_locate(meta));
}
+
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h Thu Jan 28 04:44:28 2010
@@ -88,6 +88,7 @@
extern BOOL PyObjC_useKVO;
+extern BOOL PyObjC_nativeProperties;
extern int PyObjC_VerboseLevel;
extern int PyObjC_HideProtected;
#if PY_VERSION_HEX < 0x03000000
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/selector.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/selector.h (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/selector.h Thu Jan 28 04:44:28 2010
@@ -7,6 +7,7 @@
*/
#define PyObjCSelector_kCLASS_METHOD 0x000001
+#define PyObjCSelector_kHIDDEN 0x000002
#define PyObjCSelector_kREQUIRED 0x000004
#define PyObjCSelector_kRETURNS_UNINITIALIZED 0x000010
@@ -56,6 +57,7 @@
PyObject* PyObjCSelector_Copy(PyObject* obj);
char* PyObjCSelector_Signature(PyObject* obj);
+#define PyObjCSelector_GetNativeSignature(obj) (((PyObjCSelector*)obj)->sel_native_signature)
SEL PyObjCSelector_GetSelector(PyObject* obj);
int PyObjCSelector_GetFlags(PyObject* obj);
Class PyObjCSelector_GetClass(PyObject* obj);
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/selector.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/selector.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/selector.m Thu Jan 28 04:44:28 2010
@@ -148,6 +148,16 @@
return NULL;
}
+ if (((PyObjCSelector*)self)->sel_flags & PyObjCSelector_kHIDDEN) {
+ r = PyDict_SetItemString(result, "hidden", Py_True);
+ } else {
+ r = PyDict_SetItemString(result, "hidden", Py_False);
+ }
+ if (r == -1) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
if (((PyObjCSelector*)self)->sel_flags & PyObjCSelector_kRETURNS_UNINITIALIZED) {
r = PyDict_SetItemString(result, "return_uninitialized_object", Py_True);
if (r == -1) {
@@ -193,6 +203,7 @@
return PyBytes_FromString(self->sel_python_signature);
}
+
PyDoc_STRVAR(base_native_signature_doc, "original Objective-C signature for the method");
static PyObject*
base_native_signature(PyObject* _self, void* closure __attribute__((__unused__)))
@@ -227,6 +238,23 @@
return 0;
}
+PyDoc_STRVAR(base_hidden_doc, "If True the method is not directly accessible as an object attribute");
+static PyObject*
+base_hidden(PyObject* _self, void* closure __attribute__((__unused__)))
+{
+ return PyBool_FromLong(((PyObjCSelector*)_self)->sel_flags & PyObjCSelector_kHIDDEN);
+}
+static int
+base_hidden_setter(PyObject* _self, PyObject* newVal, void* closure __attribute__((__unused__)))
+{
+ if (PyObject_IsTrue(newVal)) {
+ ((PyObjCSelector*)_self)->sel_flags |= PyObjCSelector_kHIDDEN;
+ } else {
+ ((PyObjCSelector*)_self)->sel_flags &= ~PyObjCSelector_kHIDDEN;
+ }
+ return 0;
+}
+
PyDoc_STRVAR(base_selector_doc, "Objective-C name for the method");
static PyObject*
base_selector(PyObject* _self, void* closure __attribute__((__unused__)))
@@ -270,6 +298,13 @@
static PyGetSetDef base_getset[] = {
{
+ "isHidden",
+ base_hidden,
+ base_hidden_setter,
+ base_hidden_doc,
+ 0
+ },
+ {
"isRequired",
base_required,
0,
@@ -931,9 +966,12 @@
} else {
/* Should not happen... */
- result->argcount = -1;
- abort();
-
+ result->argcount = 0;
+ char* s = sel_getName(selector);
+ while ((s = strchr(s, ':')) != NULL) {
+ result->argcount++;
+ s++;
+ }
}
if (class_method) {
@@ -1840,6 +1878,7 @@
return NULL;
}
+
if (PyObjCPythonSelector_Check(callable)) {
PyObjCPythonSelector* result;
@@ -2022,6 +2061,10 @@
is_class_method,
oc_class);
}
+ if (PyObjCClass_HiddenSelector(template_class, selector)) {
+ ((PyObjCSelector*)value)->sel_flags |= PyObjCSelector_kHIDDEN;
+ }
+
return value;
}
Modified: trunk/pyobjc/pyobjc-core/NEWS.txt
==============================================================================
--- trunk/pyobjc/pyobjc-core/NEWS.txt (original)
+++ trunk/pyobjc/pyobjc-core/NEWS.txt Thu Jan 28 04:44:28 2010
@@ -7,12 +7,6 @@
Version 2.3a0
-------------
-- The (undocument) module ``PyObjCTools.TestSupport`` is no longer
- present.
-
-- Converting a negative value to an unsigned integer now causes
- a deprecation warning, this will be a hard error once I update
- all framework wrapper metadata.
- Initial port to Python 3.x
@@ -31,10 +25,14 @@
TODO:
- * Implement new style buffer support
+ * Implement new style buffer support when depythonifying an array of
+ C structures.
* Documentation updates
+ * Implement python3 dict, list, ... APIs for NSDictionary and friends,
+ with unittests.
+
- The Python 3.x port does not support transparent proxies for 'FILE*'
"objects" because the ``file`` type in Python3 is not implemented on
top of the C library stdio.
@@ -64,13 +62,75 @@
``assertFoo`` methods and deprecated the ``failIfFoo`` and ``failUnlessFoo``
methods (simularly to what's happening in the stdlib).
+- Added ``objc.propertiesForClass``. This function returns information about
+ properties for a class from the Objective-C runtime. The information does
+ not include information about properties in superclasses.
+
- TODO: ``objc.kvo_property`` support
+ Implementation plan:
+
+ * Add class setup hook for entries in the dict::
+
+ class kvo_property (object):
+ def __pyobjc_class_setup__(self, name, class_dict,
+ instance_method_list, class_method_list):
+ class_dict[self.__ivar_name] = objc.ivar(self.__ivar_name)
+ instance_method_list.append(
+ selector(self.__setter_func, hidden=True))
+
+ (The method body is bogus, but the idea should be clear enough).
+
+ DONE, but the API is not yet stable. I'll probably add an ivar_list
+ argument as well to enable adding instance variables that aren't directly
+ visible to python code.
+
+ * Add 'hidden' flag to selectors. If a selector is hidden you will not be
+ able to access it directly, only through pyobjc_instanceMethods or
+ pyobjc_classMethods.
+
+ * Later: objc.objc_class.__pyobjc_set_builder__(callable).
+ This callable is called when a subclass is created and does most of
+ the setup-work in class-builder.m.
+
+ Interface of the builder::
+
+ builder(name, bases, dict, protocols,
+ instance_method_list, class_method_list) -> bases
+
+ The protocols list and the two method lists are empty when calling,
+ the builder must add methods and protocols to the appopriate lists.
+
+ The return value is the bases tuple for the created class, calculated
+ from the bases tuple passed in (e.g. remove protocols, possibly
+ introduce and intermediate class)
+
+ The build is responsible for converting function objects in the class
+ dict to ``objc.selector`` instances and adding them to the appropriate
+ list, the C code will not do that.
+
+ NOTE: This API is not stable and might change in future versions of PyObjC.
+
+ * Later: automaticly parse the property definitions in the objc runtime
+ and do the right thing (but: also add global flag to enable/disable this)
+
+ Partially done: there is a function for parsing property definitions, but
+ that isn't used yet.
+
+ * Later: add metadata hooks + the data itself to define properties (again:
+ using the global flag to enable/disable properties on existing classes)
+
+ * The plan: flag == False in 2.3, flag == True in 2.4, remove flag in 2.5.
+ (and: add hooks to py2app to enable setting the flag in setup.py)
+
- TODO: compile bridgesupport files into something more efficient, drop
libxml support code (to because of libxml on 10.6 and 10.5 mess)
- (At the very least least: the PyObjCMethodSignature objects can be shared more than
- they are now).
+ (At the very least least: the PyObjCMethodSignature objects can be shared
+ more than they are now).
+
+ This needs further investigation to determine why we use more memory
+ than Ruby.
- TODO: Drop support for 2.5 and
@@ -84,7 +144,16 @@
This should improve performance and reduce memory usage (when proper caching
is used).
-- TODO: Rebuild documentation using sphynx (sp?)
+- TODO: Rebuild documentation using Sphinx
+
+ (In progress)
+
+- The (undocument) module ``PyObjCTools.DistUtilsSupport`` is no longer
+ present.
+
+- Converting a negative value to an unsigned integer now causes
+ a deprecation warning, this will be a hard error once I update
+ all framework wrapper metadata.
Version 2.2 (2009-11-24)
Modified: trunk/pyobjc/pyobjc-core/setup.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/setup.py (original)
+++ trunk/pyobjc/pyobjc-core/setup.py Thu Jan 28 04:44:28 2010
@@ -37,7 +37,6 @@
def run_tests(self):
import sys, os
rootdir = os.path.dirname(os.path.abspath(__file__))
- print ("*"*5, rootdir)
if rootdir in sys.path:
sys.path.remove(rootdir)
from PyObjCTest.loader import makeTestSuite
------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com