-------------
This is a fairly large larger update due to rewriting part of the core
logic in Python (where the previous version used C). This does result in
some minor semantic changes, but those should only affect edge cases and
not normal user code.
These changes were done because it simplifies the code base, and makes it
easier to evolve the code (which has already led to a number of easy-of-use
improvements as described below).
* :issue:`306`: The code that converts a Python callable into an ``objc.selector``
when creating an Objective-C class is now written in Python instead of
Objective-C.
Note that the interface that the C extension uses to invoke Python
code is not a public API and can change in minor releases.
The rewrite found a number of edge cases where the older implementation
in C was incorrect or inconsistent. Those problems have been fixed as
part of this effort (see below for details).
* The BadPrototypeError raised when a method is not compatible with number
of arguments expected by Objective-C now mentions the number of
arguments excluding the "self" argument, instead of including it.
* The new code will accept callables other than functions and bound
method as a possible source of ``objc.selector`` objects, this
can affect code storing a callable object (other than types) as
a class attribute.
Wrap these in an ``objc.python_method`` to avoid conversion.
* Added ``objc_objc_method`` that can be used to decorate functions
that must be converted to an ``objc.selector``. The decorator has
optional keyword arguments to affect the conversion.
* ``objc.python_method`` is now implemented in Python.
The ``callable`` attribute is deprecated, use ``__wrapped__`` instead
to access the wrapped callable.
The new implementation requires that the wrapped value is either
a callable or a classmethod and won't work with arbitrary values.
* Coroutines (generators, async method) are no longer wrapped in
an ``objc.selector`` by default.
* Using a callable that's not compatible with use a selector due
to having the wrong number of positional arguments or having
keyword-only arguments will now raise consistently during
class construction.
* objc.python_method is now implemewnted in Python. Due to the
reimplementation the ``callable`` attribute has been renamed
to the more standard ``__wrapped__`` attribute.
* For native selectors the ``signature`` attribute no longer
contains the raw signature, but a cleaned up copy.
* Added private function to look for an informal protocol related
to a selector name.
* Added private function to look registered metadata for a
selector name.
* PEP-8 compatible multi-word method names are no longer converted
to selectors, e.g.:
.. sourcecode:: python
class MyObject(NSObject):
def some_method(self, a, b):
pass
In previous versions this required using the ``objc.python_method``
decorator.
* Method names containing double underscores are no longer converted
to selectors, e.g:
.. sourcecode:: python
class MyObject(NSObject):
def spam__(self, a, b):
pass
def spam__ham_(self, a, b, c):
pass
In previous versions these were converted to, nonsensical,
selectors: ``spam::`` and ``spam::ham:``.
* Introduce a new optional subkey in ``__metadata__()``: ``full_signature``
contains the complete signature for a method.
* Setting dunder names in a class will no longer create a selector:
.. sourcecode:: python
def __dir__(self):
return []
NSObject.__dir__ = __dir__
In PyObjC 9.0 or earlier this resulted in a new selector on
``NSObject``, in PyObjC 9.1 this results a new Python-only method.
This matches the behaviour of defining dunder methods in a class
definition.
* Wrapping a python_method in a classmethod now works:
.. sourcecode:: python
class MyClass(NSObject):
classmethod
python_method
def spam_spam(self):
pass
* Method definitions with varargs are now accepted for selectors
when the number of arguments expected in Objective-C "fits":
.. sourcecode:: python
class MyClass(NSObject):
def correctMethod_(self, *args):
Args will be a 1-tuple when called
from Objective-C
pass
def correctMethod2_(self, value, *args):
'args' will always be empty when
called from Objective-C
pass
def incorrectMethod2_(self, value, value2, *args):
Objective-C will pass exactly one argument,
this method needs at least 2.
pass
* If a python class overrides a method in the superclass it will
now use the selector of the superclass method instead of
defaulting to a transformation of the method name.
.. sourcecode:: python
class SuperClass(NSObject):
objc.selector(selector=b"buttonPressed:")
def pressed(self):
...
class SubClass(SuperClass):
def pressed(self):
...
In previous versions of PyObjC ``SubClass.pressed`` would have
been a selector with name ``b"pressed"``, in PyObjC 9.1 the
selector name is inherited from the super class (``b"buttonPressed:"``).
* Subclassing an ``NSCoder`` has an incompatible change. In previous
version of PyObjC the "at" argument for, for example ``-[NSCoder decodeValueOfObjCType:at:]``
was not passed to Python, e.g.:
.. sourcecode:: python
class MyCoder(NSCoder):
def decodeValueOfObjCType_at_(self, encoding):
...
As of PyObjC 9.1 the "at" argument must be present in the
the python argument list, and will always be passed None:
.. sourcecode:: python
class MyCoder(NSCoder):
def decodeValueOfObjCType_at_(self, encoding, at):
...
The same is also true for ``-[NSCoder decodeBytesWithReturnedLength:]``.
This makes these methods consistent with the general convention
for implementing Objective-C method. This change was missed
at earlier cleanups because implementing these NSCoder methods
uses custom logic in C.
* Added ``objc._C_PythonObject`` with the encoding for ``PyObject*``.
This is primarily for internal use by PyObjC, using PyObjC
as an FFI tool for calling CPython APIs is not supported.
* Added ``isSlot`` argument to ``objc.ivar`` to define Python variable
slots.
This is primairly here for internal use of the bridge, use
``__slots__`` to define slots.
* ``objc.ivar`` instances can now be compared for equality. Two
instances are considered equal if the tuple ``(name, type, isOutlet, isSlot)``
for the two values are equal.
* When ``__slots__`` is a string the class will have a single slot
with that name. In previous versions the class would have a number
of slots with single-character names.
The new behaviour matches that of regular Python classes.
* The ``objc.objc_class`` type now has a ``__hasdict__`` attribute that is
True if instances of the class have a ``__dict__`` attribute and is
False otherwise.
* It is now an error when two instance variables (``objc.ivar``, including those
defined through ``__slots__``) have the same Objective-C name, and that includes
redefining a slot in a superclass.
In previous versions this was not an error and the two ``objc.ivar`` objects
would use the same memory in the instance, which could lead to crashes if
the two did not have the same type encoding.
* Fix longstanding bug in class construction:
.. sourcecode:: python
class MyClass(NSObject):
objc.objc_method(selector="foobar")
def method(self):
pass
In previous versions only ``MyClass.method`` is defined, whereas the
code in the bridge intended to define ``MyClass.foobar`` as well.
* Fix type encoding for ``respondsToSelector:`` method that's implicitly defined
by the bridge.
* In previous versions accessing a hidden selector showed an ``objc.native_selector``
instead of an ``objc.selector`` for hidden selectors implemented in Python, and those
objects did not have the ``isHidden`` attribute set to true.
* :issue:`506`: Code no longer uses ``PySlice_GetIndicesEx``, which was deprecated
by CPython in 3.6.
* Tweak pyobjc_setup.py to re-enable the error message when trying to install
framework bindings on systems other than macOS.
* "Hidden" selectors implemented in Python can now be introspected though ``pyobjc_instanceMethods`` and
``pyobjc_classMethod``. In previous versions the following assertion would fail:
.. sourcecode:: python
class MyClass(NSObject):
def hidden(self):
pass
hidden = objc.selector(hidden, isHidden=True)
assert isinstance(MyClass.pyobjc_instanceMethods.hidden)
A side effect of this is that calling hidden methods implemented in Python from
Python now uses the "python to python" code path and won't translate argument and
return values from Python to Objective-C and back again.
Also note that (as usual) Key-Value Observing (KVO) complicates the picture, if
the hidden method is a property accessor (for KVO) and the object is observed accessing
the method will result in a "native" selector, not the original one due to the
way KVO is implemented in the system.
* :issue:`522`: Remove the implementation of ``respondsToSector:`` and ``methodSignatureForSelector:``.
In previous versions PyObjC included custom implementation of these methods for
subclasses of ``NSObject`` implemented in Python, but the default implementation
in ``NSObject`` works just as well for Python classes.
* Creating an ``objc.ivar`` will now raise an exception if the specified type encoding
is not valid. Previous versions would raise on the first use of the instance variable.
* :issue:`522`: Reimplemented ``objc.informal_protocol`` in Python
The new implementation adds a number of new methods to give ``objc.informal_protocol`` the
same interface as ``objc.formal_protocol``, which simplifies the implementation of
code using protocols.
That said, ``objc.informal_protocol`` still has a ``selectors`` attribute that is not
present on ``objc.formal_protocol``. This will not change.
* :issue:`522`: The code that validates if a new class conforms to all protocols it claims to
conform to is now written in Python.
As a side effect of this the error message for an invalid protocol conformance definition
no longer mentions with definition was invalid (the ``protocols`` keyword or the
``__pyobjc_protocols__`` class attribute).
The new implementation is also more strict in the values of selectors that are accepted,
all selectors not be instances of ``objc.native_selector`` and must have a ``callable``
attribute that is not ``None``.
* :issue:`523`: PyObjC's default implementation for ``-forwardInvocation:`` now calls the
method stub (``IMP``) through libffi, instead of trying to reproduce the logic
of the method stub in the implementation for ``-forwardInvocation:``. This removes about
300 lines of C code and makes sure the semantics of message forwarding match that of
regular method calls.
This only affects subclasses of ``NSObject`` implemented in Python, the bridge contains
a second implementation of ``forwardInvocation:`` for regular Python class with limited
functionality (and very low performance).
* In previous versions PyObjC would introduce an intermediate class between a pure Objective-C
super class and the first Python sub class when this was needed for correctness. This class
is now always introduced.
There are two reasons for this:
1. Adding some methods (such as ``copyWithZone_``) to a class after it was constructed
caused problems in older version because the intermediate class wasn't present.
2. Simplifies the code for building a class
The intermediate class is named ``_PyObjCIntermediate_{NAME}`` where ``{NAME}`` is the name
of the super class, in previous versions it was named ``_PyObjCCopying_{NAME}``.
* Fix ``objc.listInstanceVariables`` failure when one of the classes in the class hierarchy
does not have instance variables.
* Fix crash when the filter for the ``UninitializedDeallocWarning`` warning is set to "error".
* Fix conversion of float subclasses with custom ``__repr__`` to ``objc.NSDecimal``.
* Fix handling ``objc.NSDecimal`` in boolean contexts: In previous versions
``objc.NSDecimal(0)`` was interpreted as true-ish in boolean contexts, it now
is interpreted as false-ish just like other number types.
* :issue:`381`: Add bindings for the IOBluetooth and IOBluetoothUI frameworks
* Add bindings for the PHASE framework
* 363: Support possible buffer overrun in NSCoder API helpers
The implementations for NSCoder APIs that have a type encoding argument assumed
that the ``Py_buffer`` representation of the type encoding is a NUL-terminated string.
This is a valid assumption for the ``bytes`` and ``bytesarray`` types, but is
not guaranteed by the buffer API and could result in reading past the end of the
buffer when an incomplete type encoding is passed to these APIs.
As a side effect of this fix there is minor change in the API for these methods:
- Type encodings containing unions and bitfields now error out early;
- Type encodings for structs cannot contain embedded field names;
- The APIs are slightly slower due to validating the type encoding.
* Calling ``-[SFAuthorizationView authorizationRights]`` now works, in previous
version the support code was present but enabled for a non-existing method name.
* :issue:`527`: The type of ``objc.NULL`` is now created with ``PyType_FromSpec``.
This has the unfortunate side effect of making it possible to change type
attributes on Python 3.9 or earlier. Do not do this, the type is immutable
in Python 3.10 or later.
* :issue:`527`: A number of types are now created with ``PyType_FromSpec``:
* ``objc.PyObjCPointer``
* ``objc.FILE``
* ``objc.formal_protocol``
* ``objc.function``
* ``objc.NSDecimal``
* ``objc.varlist``
* ``objc.WeakRef``
* ``objc.super``
* ``objc.IMP``
* ``objc.FSRef``
* ``objc.selector``
* ``objc.native_selector``
* ``objc.python_selector``
* all types created by ``objc.createStructType``
* ``CoreAudio.AudioBuffer``
* ``CoreAudio.AudioBufferList``
* ``CoreAudio.AudioChannelDescription``
* ``CoreAudio.AudioChannelLayout``
* ``CoreAudio.AudioValueTranslation``
For these types the class can be changed in Python 3.9 earlier, but not
in 3.10 or later. The ability to change class attributes in Python 3.9 and earlier
is due to a limitation in ``PyType_FromSpec`` in those versions, don't rely on this.
This is a small step towards supporting subinterpreters, although it is unclear at
this time when PyObjC will support this in part due to CPython missing some API
functionality required by the implementation of ``objc.objc_object`` and ``objc.objc_class``
when using ``PyType_FromSpec``.
* :issue:`423`: ``objc.ivar`` is now created with ``PyType_FromSpec``. Because of
that the private method ``objc.ivar._add_attribute`` has been removed.
* The creation of ``objc.super`` is now less hacky although it still
relies on implementation details of ``builtins.super``.
* Fixed bug that could result in a crash when the proxy for a Python iterator
ended up being deallocated after the Python interpreter is finalized.
* Code cleanup for ``objc._objc`` continues, in this version the module initialisation
code was much simplified, most of it is now table-driven. This has no user visible
effects.
* Types created by ``objc.createStructType`` now have a (read-only) ``__packed__`` attribute
that's ``-1`` if the C struct has default packing, and positive integer when
the C struct has some other packing.
* :issue:`382`: Add bindings for APIs defined in header ``xpc/xpc.h``
This is a low-level API to perform RPCs using the XPC protocol on macOS.
* :issue:`376`: Updated libdispatch bindings, fixing a number of issues with automatic
retaincount management.
* The python package name in ``pyobjc-framework-libdispatch`` is now ``dispatch`` instead
of ``libdispatch``. The old name also works, with no plans to remove it.
* :issue:`113`: Implement ``JavaScriptCore.JSExportAs``
This required some change to pyobjc-core as well. The exact interface used
by ``JSExportAs`` is for now considered a private implementation detail.
XXX: As this time actually using JSExportAs doesn't work, even though
the shape of the protocol looks correctly.
* The ``Metal`` bindings now contain definitions for ``MTLPackedFloat3``,
``MTLPackedFloat4x3``, ``MTLAccelerationStructureInstanceDescriptor``
and ``MTLPackedFloat3Make``.
* Upgraded framework bindings for Xcode 14.3 (macOS 13.3 SDK)
* Dropped custom implementation of ``protocol_getMethodDescription``
FB11984735: In earlier versions of macOS there were problems with actually
registering protocols in some cases. A custom implementation of this
function allowed tests to pass. Turns out that debugging code that uses
``protocol_getMethodDescription`` during protocol construction caused problems...
* :issue:`535`: Speed up standalone tests with ``assertCallableMetadataIsSane``
This assertion method is very slow because it looks at all callable attributes,
sped up considerably for standalone tests by only looking at attribute names
that might be callable (by poking in implementation details of the lazy loader).
This halves the time needed to run the check for the Cocoa bindings (from
over 200 seconds to just over 100 seconds). That's still too slow, but does help.
The method is also smarter about iterating over methods, shaving another 20 seconds
from this test.
* :issue:`539`: Fix incorrect metadata for ``IOSurfaceCreate`` that resulted in a crash
when that API was used.
* :issue:`537`: Switch from ``pkg_resources`` to ``importlib`` in the support for
bridgesupport XML files because the setuptools project has deprecated the
``pkg_resources`` module.