From 334a7a6980ab15e487478cb3b0e9b729393e823e Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 14 Apr 2024 20:27:21 +0200 Subject: [PATCH 01/23] First stab at adding a generic __new__ This just adds some machinery with just enough support in data structures to be able to instantiate classes without keyword arguments. TODO: - Add machinery for framework bindings - Add support code to _transform (automaticly initialize the data structure based on init methods) - Add tests - Finally: update framework bindings --- pyobjc-core/Lib/objc/__init__.py | 6 ++++ pyobjc-core/Lib/objc/_convenience.py | 4 +++ pyobjc-core/Lib/objc/_new.py | 54 ++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 pyobjc-core/Lib/objc/_new.py diff --git a/pyobjc-core/Lib/objc/__init__.py b/pyobjc-core/Lib/objc/__init__.py index d0b85ecd85..d27213839a 100644 --- a/pyobjc-core/Lib/objc/__init__.py +++ b/pyobjc-core/Lib/objc/__init__.py @@ -44,6 +44,7 @@ def _update(g): from . import _callable_docstr # noqa: F401, F403, E402 from . import _pycoder # noqa: F401, F403, E402 from ._informal_protocol import * # noqa: F401, F403, E402 +from . import _new # noqa: E402 # Helper function for new-style metadata modules @@ -83,3 +84,8 @@ def __enter__(self): def __exit__(self, exc_type, value, tp): del self._pool + + +_new.NEW_MAP[lookUpClass("NSObject")] = { # noqa: F405 + (): "init", +} diff --git a/pyobjc-core/Lib/objc/_convenience.py b/pyobjc-core/Lib/objc/_convenience.py index 87e7f7fd8b..8cbbacbb9d 100644 --- a/pyobjc-core/Lib/objc/_convenience.py +++ b/pyobjc-core/Lib/objc/_convenience.py @@ -13,6 +13,7 @@ selector, ) import PyObjCTools.KeyValueCoding as kvc +from objc._new import _make_new __all__ = ("addConvenienceForClass", "registerABCForClass") @@ -54,6 +55,9 @@ class name to a list of Python method names and implementation. Matching entries from both mappings are added to the 'type_dict'. """ + if type_dict.get("__new__") is None: + type_dict["__new__"] = _make_new(cls) + for nm, value in CLASS_METHODS.get(cls.__name__, ()): type_dict[nm] = value diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py new file mode 100644 index 0000000000..a6ccb48d53 --- /dev/null +++ b/pyobjc-core/Lib/objc/_new.py @@ -0,0 +1,54 @@ +""" +Implementation of `__new__` for arbitrary Cocoa classes +""" + +__all__ = () + +NEW_MAP = {} +UNSET = object() + +# XXX: Need to find a way to dynamically set the docstring + + +def _make_new(cls): + def __new__(cls, **kwds): + """ + Generic implementation for Objective-C `__new__`. + """ + # XXX: should this sort the keywords? + key = tuple(kwds.keys()) + + for c in cls.__mro__: + new_map = NEW_MAP.get(c, UNSET) + if new_map is UNSET: + continue + + name = new_map.get(key, UNSET) + if name is UNSET: + continue + + if name is None: + if key: + raise TypeError( + f"{cls.__name__}() does not support keyword arguments {', '.join(repr(k) for k in key)}" + ) + else: + raise TypeError(f"{cls.__name__}() requires keyword arguments") + + if name.startswith("init") and len(name) == 4 or name[4].isupper(): + return getattr(cls.alloc(), name)(**kwds) + + else: + return getattr(cls, name)(**kwds) + + if key: + raise TypeError( + f"{cls.__name__}() does not support keyword arguments {', '.join(repr(k) for k in key)}" + ) + else: + raise TypeError(f"{cls.__name__}() requires keyword arguments") + + __new__.__name__ = cls.__name__ + ".__new__" + __new__.__qualname__ = cls.__name__ + ".__new__" + __new__.__module__ = cls.__module__ + return __new__ From 0099a90a2686b649b5fbae60a5aa61c4ffa99b6e Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 14 Apr 2024 21:05:12 +0200 Subject: [PATCH 02/23] Add docstring for __new__ The docstring is calculated dynamicly to keep the cost of this feature down. --- pyobjc-core/Lib/objc/_convenience.py | 3 +- pyobjc-core/Lib/objc/_new.py | 64 +++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/pyobjc-core/Lib/objc/_convenience.py b/pyobjc-core/Lib/objc/_convenience.py index 8cbbacbb9d..4831d89a39 100644 --- a/pyobjc-core/Lib/objc/_convenience.py +++ b/pyobjc-core/Lib/objc/_convenience.py @@ -55,8 +55,7 @@ class name to a list of Python method names and implementation. Matching entries from both mappings are added to the 'type_dict'. """ - if type_dict.get("__new__") is None: - type_dict["__new__"] = _make_new(cls) + type_dict["__new__"] = _make_new(cls) for nm, value in CLASS_METHODS.get(cls.__name__, ()): type_dict[nm] = value diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index a6ccb48d53..e05eb61b97 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -2,12 +2,70 @@ Implementation of `__new__` for arbitrary Cocoa classes """ +# TODO: +# - Document- +# - Maybe: somehow add __doc__ to classes that reflect the +# __new__ API. +# - Determine how to interact with the new classes +# that already have an __new__ +# - Update _transform to add entries to NEW_MAP +# (baesd on init methods) +# - Update support code for framework bindings +# - Update framework binding tooling (and then the +# bindings themselves) +# - Add tests + __all__ = () NEW_MAP = {} UNSET = object() -# XXX: Need to find a way to dynamically set the docstring + +class _function: + """ + Wrapper for the __new__ function to generate the + docstring dynamically. + """ + + __slots__ = ("_function", "_cls") + + def __init__(self, function, cls): + self._function = function + self._cls = cls + + @property + def __class__(self): + return self._function.__class__ + + @property + def __doc__(self): + result = {} + for c in reversed(self._cls.__mro__): + new_map = NEW_MAP.get(c, UNSET) + if new_map is UNSET: + continue + + for kwds, selector in new_map.items(): + if selector is None: + result.pop(kwds, None) + + if not kwds: + result[kwds] = f"{self._cls.__name__}(): " + else: + result[kwds] = f"{self._cls.__name__}(*, " + ", ".join(kwds) + "): " + if selector.startswith("init"): + result[kwds] += f" returns 'cls.alloc().{selector}()'\n\n" + else: + result[kwds] += f" returns 'cls.{selector}()'\n\n" + return "".join(sorted(result.values()))[:-1] + + def __getattr__(self, name): + return getattr(self._function, name) + + def __setattr__(self, name, value): + if name in ("_function", "_cls"): + object.__setattr__(self, name, value) + return setattr(self._function, name, value) def _make_new(cls): @@ -48,7 +106,9 @@ def __new__(cls, **kwds): else: raise TypeError(f"{cls.__name__}() requires keyword arguments") + # XXX: Settings these helps, but does not yet result in the correct + # output from help() __new__.__name__ = cls.__name__ + ".__new__" __new__.__qualname__ = cls.__name__ + ".__new__" __new__.__module__ = cls.__module__ - return __new__ + return _function(__new__, cls) From 739873a6887898dbf3d0667c346891cb649e5039 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 14 Apr 2024 21:17:10 +0200 Subject: [PATCH 03/23] Some documentation updates --- pyobjc-core/Lib/objc/_new.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index e05eb61b97..39cbf55f46 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -1,5 +1,15 @@ """ Implementation of `__new__` for arbitrary Cocoa classes + +The __new__ method just translates invocations into the +corresponding invocation of the Cocoa pattern ( +`cls.alloc().init()` or `cls.new()`), based on a mapping +maintaind in this file. + +The mapping is updated in two ways: + 1. From framework bindings for native classes + 2. Based on `init` methods in Python subclasses + """ # TODO: @@ -13,13 +23,32 @@ # - Update support code for framework bindings # - Update framework binding tooling (and then the # bindings themselves) +# - Check interaction with manually defined __new__ +# and/or __init__ in Python classes # - Add tests __all__ = () +# Mapping: cls -> { kwds: selector_name } +# +# That is, keys are Objective-C classes, values +# are mappings from keyword argument names to +# the name of a selector. +# +# The selector_name can be `None` to disable a +# mapping in a subclass. +# +# The complete mapping for a class is a chain map +# for the submaps of all classes on the MRO. NEW_MAP = {} + + +# Sentinel value UNSET = object() +# Added to the docstring for __new__ +DOC_SUFFIX = "The order of keyword arguments is significant\n" + class _function: """ @@ -54,10 +83,10 @@ def __doc__(self): else: result[kwds] = f"{self._cls.__name__}(*, " + ", ".join(kwds) + "): " if selector.startswith("init"): - result[kwds] += f" returns 'cls.alloc().{selector}()'\n\n" + result[kwds] += f" returns cls.alloc().{selector}()\n\n" else: - result[kwds] += f" returns 'cls.{selector}()'\n\n" - return "".join(sorted(result.values()))[:-1] + result[kwds] += f" returns cls.{selector}()\n\n" + return "".join(sorted(result.values())) + DOC_SUFFIX def __getattr__(self, name): return getattr(self._function, name) From c61d44fdbabc000c52f78e5b33de06890fe0fb7e Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Tue, 16 Apr 2024 21:55:00 +0200 Subject: [PATCH 04/23] Autoregister keyword arguments based on init selectors for Python subclases With this change the following works: ```python class MyObject(NSObject): def initWithX_y_(self, x, y): self = super().init() self.x = x self.y = y return self o = MyObject(x=4, y=5) print(o.x, o.y) ``` The code is not ideal at this point, and needs to be synced with the final algorithm for calculating the keyword arguments. This is a good first step though. --- pyobjc-core/Lib/objc/_new.py | 11 +++++---- pyobjc-core/Lib/objc/_transform.py | 35 +++++++++++++++++++++++++++ pyobjc-core/Modules/objc/objc-class.m | 13 ++++++++++ pyobjc-core/Modules/objc/options.h | 1 + pyobjc-core/Modules/objc/options.m | 3 +++ 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 39cbf55f46..03c2c8b089 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -13,19 +13,17 @@ """ # TODO: -# - Document- -# - Maybe: somehow add __doc__ to classes that reflect the -# __new__ API. # - Determine how to interact with the new classes # that already have an __new__ -# - Update _transform to add entries to NEW_MAP -# (baesd on init methods) # - Update support code for framework bindings # - Update framework binding tooling (and then the # bindings themselves) # - Check interaction with manually defined __new__ # and/or __init__ in Python classes +# - Document- # - Add tests +# - Maybe: somehow add __doc__ to classes that reflect the +# __new__ API. __all__ = () @@ -96,6 +94,9 @@ def __setattr__(self, name, value): object.__setattr__(self, name, value) return setattr(self._function, name, value) + def __call__(self, *args, **kwds): + return self._function(*args, **kwds) + def _make_new(cls): def __new__(cls, **kwds): diff --git a/pyobjc-core/Lib/objc/_transform.py b/pyobjc-core/Lib/objc/_transform.py index 59cced4220..46e0b3d7ee 100644 --- a/pyobjc-core/Lib/objc/_transform.py +++ b/pyobjc-core/Lib/objc/_transform.py @@ -15,6 +15,7 @@ import warnings import sys from ._informal_protocol import _informal_protocol_for_selector +from . import _new # only public objc_method until the python_method implementation # in C is gone @@ -24,6 +25,39 @@ NO_VALUE = object() +def _isSelectorPrefix(name, prefix): + return name.startswith(prefix) and ( + len(name) == len(prefix) | name[len(prefix)].isupper() + ) + + +def setupSubClass( + class_object, + class_dict, +): + + new_map = {} + + for name, value in class_dict.items(): + if not name.startswith("init"): + continue + if len(name) > 4 and not name[4].isupper(): + continue + if not isinstance(value, objc.selector): + continue + + parts = value.selector[4:].decode().split(":") + if parts[0].startswith("With"): + parts[0] = parts[0][4:] + parts[0] = parts[0][:1].lower() + parts[0][1:] + new_map[tuple(parts[:-1])] = name + + if not new_map: + return + + _new.NEW_MAP[class_object] = new_map + + def processClassDict( class_dict, meta_dict, @@ -699,3 +733,4 @@ def callable(self): # noqa: A003 objc.options._transformAttribute = transformAttribute objc.options._processClassDict = processClassDict +objc.options._setupSubClass = setupSubClass diff --git a/pyobjc-core/Modules/objc/objc-class.m b/pyobjc-core/Modules/objc/objc-class.m index 4b466ecdb1..2706396a12 100644 --- a/pyobjc-core/Modules/objc/objc-class.m +++ b/pyobjc-core/Modules/objc/objc-class.m @@ -1021,6 +1021,19 @@ static Class _Nullable objc_metaclass_locate(PyObject* meta_class) PyObjC_Assert(info->hasPythonImpl, NULL); + if (PyObjC_setupSubClass != NULL && PyObjC_setupSubClass != Py_None) { + PyObject* args[3] = {NULL, res, ((PyTypeObject*)res)->tp_dict}; + PyObject* rv; + + rv = PyObject_Vectorcall(PyObjC_setupSubClass, args + 1, + 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + if (rv == NULL) { + Py_DECREF(res); + return NULL; + } + Py_DECREF(rv); + } + Py_INCREF(res); return res; } diff --git a/pyobjc-core/Modules/objc/options.h b/pyobjc-core/Modules/objc/options.h index 543ca0f741..4d761dd730 100644 --- a/pyobjc-core/Modules/objc/options.h +++ b/pyobjc-core/Modules/objc/options.h @@ -26,6 +26,7 @@ extern PyObject* _Nullable PyObjC_getKeyPath; extern PyObject* _Nullable PyObjC_setKeyPath; extern PyObject* _Nullable PyObjC_transformAttribute; extern PyObject* _Nullable PyObjC_processClassDict; +extern PyObject* _Nullable PyObjC_setupSubClass; extern PyObject* _Nullable PyObjC_DictLikeTypes; extern PyObject* _Nullable PyObjC_ListLikeTypes; diff --git a/pyobjc-core/Modules/objc/options.m b/pyobjc-core/Modules/objc/options.m index 1ea4f36787..8dd15e541d 100644 --- a/pyobjc-core/Modules/objc/options.m +++ b/pyobjc-core/Modules/objc/options.m @@ -163,6 +163,7 @@ OBJECT_PROP(_setKeyPath, PyObjC_setKeyPath, NULL) OBJECT_PROP(_transformAttribute, PyObjC_transformAttribute, NULL) OBJECT_PROP(_processClassDict, PyObjC_processClassDict, NULL) +OBJECT_PROP(_setupSubClass, PyObjC_setupSubClass, NULL) static PyObject* bundle_hack_get(PyObject* s __attribute__((__unused__)), @@ -299,6 +300,8 @@ "Private helper used for transforming attributes for Objective-C classes"), GETSET(_processClassDict, "Private helper used for splitting a class dict into parts"), + GETSET(_setupSubClass, + "Private helper used for finishing setup of a new Python subclass"), { .name = "deprecation_warnings", .get = deprecation_warnings_get, From 901f6b3be32b31dbe6c58a738ead4fb6f913e475 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 17 Apr 2024 08:31:29 +0200 Subject: [PATCH 05/23] Actually ensure the keyword arguments for new works --- pyobjc-core/Lib/objc/_new.py | 5 +++-- pyobjc-core/Lib/objc/_transform.py | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 03c2c8b089..0f014066bf 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -123,11 +123,12 @@ def __new__(cls, **kwds): else: raise TypeError(f"{cls.__name__}() requires keyword arguments") + args = [kwds[n] for n in key] if name.startswith("init") and len(name) == 4 or name[4].isupper(): - return getattr(cls.alloc(), name)(**kwds) + return getattr(cls.alloc(), name)(*args) else: - return getattr(cls, name)(**kwds) + return getattr(cls, name)(*args) if key: raise TypeError( diff --git a/pyobjc-core/Lib/objc/_transform.py b/pyobjc-core/Lib/objc/_transform.py index 46e0b3d7ee..0a14e211f6 100644 --- a/pyobjc-core/Lib/objc/_transform.py +++ b/pyobjc-core/Lib/objc/_transform.py @@ -31,6 +31,18 @@ def _isSelectorPrefix(name, prefix): ) +def _selectorToKeywords(selector): + assert selector.startswith("init") + selector = selector[4:] + + parts = selector.split(":")[:-1] + if parts[0].startswith("With"): + parts[0] = parts[0][4:] + parts[0] = parts[0][:1].lower() + parts[0][1:] + + return tuple(parts) + + def setupSubClass( class_object, class_dict, @@ -46,11 +58,7 @@ def setupSubClass( if not isinstance(value, objc.selector): continue - parts = value.selector[4:].decode().split(":") - if parts[0].startswith("With"): - parts[0] = parts[0][4:] - parts[0] = parts[0][:1].lower() + parts[0][1:] - new_map[tuple(parts[:-1])] = name + new_map[_selectorToKeywords(value.selector.decode())] = name if not new_map: return From 693b4f6feb79bbbcf3741d9a95a4dd11c04d0edd Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Wed, 17 Apr 2024 22:01:41 +0200 Subject: [PATCH 06/23] Some improvements to the generic __new__ - Ensure that an explicit `__new__` is used instead of the generic one - Add some tests - Update the TODO list --- pyobjc-core/Lib/objc/_convenience.py | 11 +- pyobjc-core/Lib/objc/_new.py | 17 +-- pyobjc-core/Lib/objc/_transform.py | 2 +- pyobjc-core/PyObjCTest/test_generic_new.py | 117 +++++++++++++++++++++ 4 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 pyobjc-core/PyObjCTest/test_generic_new.py diff --git a/pyobjc-core/Lib/objc/_convenience.py b/pyobjc-core/Lib/objc/_convenience.py index 4831d89a39..18e18b3cc0 100644 --- a/pyobjc-core/Lib/objc/_convenience.py +++ b/pyobjc-core/Lib/objc/_convenience.py @@ -3,6 +3,7 @@ add Python special methods to Objective-C classes with a suitable interface. """ +import types from objc._objc import ( _block_call, _rescanClass, @@ -55,7 +56,15 @@ class name to a list of Python method names and implementation. Matching entries from both mappings are added to the 'type_dict'. """ - type_dict["__new__"] = _make_new(cls) + + # To ensure that an explicit implementation of __new__ wins + # only add __new__ when: + # - The current new is a C implemented method, or + # - The current new is a generic new implementation + if isinstance(cls.__new__, types.BuiltinMethodType): + type_dict["__new__"] = _make_new(cls) + if getattr(cls.__new__, "_oc_generic_new", False): + type_dict["__new__"] = _make_new(cls) for nm, value in CLASS_METHODS.get(cls.__name__, ()): type_dict[nm] = value diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 0f014066bf..f52ea94044 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -13,17 +13,21 @@ """ # TODO: -# - Determine how to interact with the new classes -# that already have an __new__ # - Update support code for framework bindings # - Update framework binding tooling (and then the # bindings themselves) -# - Check interaction with manually defined __new__ -# and/or __init__ in Python classes -# - Document- -# - Add tests +# - Document +# - Add tests [in progress] # - Maybe: somehow add __doc__ to classes that reflect the # __new__ API. +# - Maybe: In 3.13 switch to MultiSignature instead of +# __doc__ (assuming #117671 is merged) +# +# FIXME: __init__ invocation is a mess, consider trying +# to suppress its invocation. Currently: __init__ is +# invoked by the interpreter when __new__ is called, unless +# __new__ returns more than one value (e.g. has some output +# arguments, such as -[FooClass initWithValue:(int)value error:(NSError**)error] __all__ = () @@ -142,4 +146,5 @@ def __new__(cls, **kwds): __new__.__name__ = cls.__name__ + ".__new__" __new__.__qualname__ = cls.__name__ + ".__new__" __new__.__module__ = cls.__module__ + __new__._oc_generic_new = True return _function(__new__, cls) diff --git a/pyobjc-core/Lib/objc/_transform.py b/pyobjc-core/Lib/objc/_transform.py index 0a14e211f6..86648bc5be 100644 --- a/pyobjc-core/Lib/objc/_transform.py +++ b/pyobjc-core/Lib/objc/_transform.py @@ -116,7 +116,7 @@ def processClassDict( # First call all class setup hooks. Those can # update the class dictiory, which is why this - # loop# cannot be merged into the next one. + # loop cannot be merged into the next one. for key, value in list(class_dict.items()): setup = getattr(value, "__pyobjc_class_setup__", NO_VALUE) if setup is not NO_VALUE: diff --git a/pyobjc-core/PyObjCTest/test_generic_new.py b/pyobjc-core/PyObjCTest/test_generic_new.py new file mode 100644 index 0000000000..961bc2eb70 --- /dev/null +++ b/pyobjc-core/PyObjCTest/test_generic_new.py @@ -0,0 +1,117 @@ +import objc +from PyObjCTools.TestSupport import TestCase +from objc import super # noqa: A004 +import objc._new as new_mod + +NSObject = objc.lookUpClass("NSObject") + + +class TestDefaultNewForPythonClass(TestCase): + def test_nsobject(self): + v = NSObject() + self.assertIsInstance(v, NSObject) + + self.assertEqual(new_mod.NEW_MAP[NSObject], {(): "init"}) + + with self.assertRaisesRegex( + TypeError, r"NSObject\(\) does not support keyword arguments 'y', 'x'" + ): + NSObject(y=3, x=4) + + def test_basic(self): + class OCPyNew1(NSObject): + def initWithX_y_(self, x_val, y_val): + self = super().init() + self.x = x_val + self.y = y_val + return self + + def initPoint_(self, p): + self = super().init() + self.x, self.y = p + return self + + def initializeZ_(self, z): + self.z = 0 + + v = OCPyNew1(x=1, y=2) + self.assertIsInstance(v, OCPyNew1) + self.assertEqual(v.x, 1) + self.assertEqual(v.y, 2) + + v = OCPyNew1(point=(3, 4)) + self.assertIsInstance(v, OCPyNew1) + self.assertEqual(v.x, 3) + self.assertEqual(v.y, 4) + + with self.assertRaisesRegex( + TypeError, r"OCPyNew1\(\) does not support keyword arguments 'y', 'x'" + ): + OCPyNew1(y=3, x=4) + + with self.assertRaisesRegex( + TypeError, r"OCPyNew1\(\) does not support keyword arguments 'z'" + ): + OCPyNew1(z=4) + + def test_explicit_new(self): + # Test that an explicit __new__ overrides the default + # implementation. + class OCPyNew2(NSObject): + def __new__(self, *, z): + return self.alloc().initWithValue_(z) + + def initWithValue_(self, value): + self = super().init() + self.value = value + return self + + v = OCPyNew2(z=4) + self.assertEqual(v.value, 4) + + with self.assertRaisesRegex(TypeError, "got an unexpected keyword argument"): + OCPyNew2(value=9) + + def test_dunder_init(self): + class OCPyNew3(NSObject): + def initWithValue_(self, v): + self = super().init() + self.value = v + return self + + def __init__(self, **kwds): + # __init__ will be called when __new__ + # is invoked, but not when the instance + # is created regularly. + self.value += 1 + + v = OCPyNew3.alloc().initWithValue_(3) + self.assertEqual(v.value, 3) + + v = OCPyNew3(value=4) + self.assertEqual(v.value, 5) + + def test_dunder_init_with_error(self): + class OCPyNew4(NSObject): + def initWithValue_error_(self, v, error): + self = super().init() + self.value = v + return self, None + + def __init__(self, **kwds): + # __init__ will not be called when the + # init method returns 2 values. + self.value += 1 + + v, e = OCPyNew4.alloc().initWithValue_error_(3, None) + self.assertEqual(v.value, 3) + self.assertIs(e, None) + + v, e = OCPyNew4(value=4, error=None) + self.assertEqual(v.value, 4) + self.assertIs(e, None) + + +# TODO: TestDefaultNewForObjectiveCClass +# Need the metadata update interface before implementing this. +# Also check interaction with __init__ From b7370d3c70af04c4c1565eb6e618295f78466c75 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 18 Apr 2024 21:25:10 +0200 Subject: [PATCH 07/23] Some code cleanup - The NEW_MAP is now keyed on the class name instead of the class itself, which allows updating it in _transform.processClassDict. - processClassDict now calculates whether __new__ is necessary, used to call a helper for setting __new__ only when needed. - The convenience hook now only sets __new__ for native classes (not python subclasses) --- pyobjc-core/Lib/objc/__init__.py | 7 +--- pyobjc-core/Lib/objc/_convenience.py | 12 +++---- pyobjc-core/Lib/objc/_new.py | 21 ++++++++---- pyobjc-core/Lib/objc/_transform.py | 39 +++++++++++----------- pyobjc-core/Modules/objc/class-builder.h | 2 +- pyobjc-core/Modules/objc/class-builder.m | 15 ++++++--- pyobjc-core/Modules/objc/objc-class.m | 11 +++--- pyobjc-core/Modules/objc/options.h | 2 +- pyobjc-core/Modules/objc/options.m | 6 ++-- pyobjc-core/PyObjCTest/test_generic_new.py | 2 +- 10 files changed, 62 insertions(+), 55 deletions(-) diff --git a/pyobjc-core/Lib/objc/__init__.py b/pyobjc-core/Lib/objc/__init__.py index d27213839a..d8bc9a72e3 100644 --- a/pyobjc-core/Lib/objc/__init__.py +++ b/pyobjc-core/Lib/objc/__init__.py @@ -44,7 +44,7 @@ def _update(g): from . import _callable_docstr # noqa: F401, F403, E402 from . import _pycoder # noqa: F401, F403, E402 from ._informal_protocol import * # noqa: F401, F403, E402 -from . import _new # noqa: E402 +from . import _new # noqa: F401, E402 # Helper function for new-style metadata modules @@ -84,8 +84,3 @@ def __enter__(self): def __exit__(self, exc_type, value, tp): del self._pool - - -_new.NEW_MAP[lookUpClass("NSObject")] = { # noqa: F405 - (): "init", -} diff --git a/pyobjc-core/Lib/objc/_convenience.py b/pyobjc-core/Lib/objc/_convenience.py index 18e18b3cc0..ca752b75b6 100644 --- a/pyobjc-core/Lib/objc/_convenience.py +++ b/pyobjc-core/Lib/objc/_convenience.py @@ -3,7 +3,6 @@ add Python special methods to Objective-C classes with a suitable interface. """ -import types from objc._objc import ( _block_call, _rescanClass, @@ -57,13 +56,10 @@ class name to a list of Python method names and implementation. Matching entries from both mappings are added to the 'type_dict'. """ - # To ensure that an explicit implementation of __new__ wins - # only add __new__ when: - # - The current new is a C implemented method, or - # - The current new is a generic new implementation - if isinstance(cls.__new__, types.BuiltinMethodType): - type_dict["__new__"] = _make_new(cls) - if getattr(cls.__new__, "_oc_generic_new", False): + # Only add the generic __new__ to pure ObjC classes, + # __new__ will be added to Python subclasses by + # ._transform. + if not cls.__has_python_implementation__: type_dict["__new__"] = _make_new(cls) for nm, value in CLASS_METHODS.get(cls.__name__, ()): diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index f52ea94044..6f60fad576 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -13,16 +13,24 @@ """ # TODO: +# - Make sure __init__ is never invoked implicitly (it +# currently is when __new__ is invoked). There is a slight +# risks this breaks code that implements a custom __new__ +# and relies on the invocation of __init__ +# (Implement by overriding tp_call in objc-class) # - Update support code for framework bindings # - Update framework binding tooling (and then the # bindings themselves) -# - Document +# - Document the feature # - Add tests [in progress] # - Maybe: somehow add __doc__ to classes that reflect the # __new__ API. # - Maybe: In 3.13 switch to MultiSignature instead of # __doc__ (assuming #117671 is merged) # +# - Later: generate class/module documentation for framework +# bindings, including the generated __new__ signatures. +# # FIXME: __init__ invocation is a mess, consider trying # to suppress its invocation. Currently: __init__ is # invoked by the interpreter when __new__ is called, unless @@ -31,9 +39,9 @@ __all__ = () -# Mapping: cls -> { kwds: selector_name } +# Mapping: class name -> { kwds: selector_name } # -# That is, keys are Objective-C classes, values +# That is, keys are names of Objective-C classes, values # are mappings from keyword argument names to # the name of a selector. # @@ -42,7 +50,9 @@ # # The complete mapping for a class is a chain map # for the submaps of all classes on the MRO. -NEW_MAP = {} +NEW_MAP = { + "NSObject": {(): "init"}, +} # Sentinel value @@ -111,7 +121,7 @@ def __new__(cls, **kwds): key = tuple(kwds.keys()) for c in cls.__mro__: - new_map = NEW_MAP.get(c, UNSET) + new_map = NEW_MAP.get(c.__name__, UNSET) if new_map is UNSET: continue @@ -146,5 +156,4 @@ def __new__(cls, **kwds): __new__.__name__ = cls.__name__ + ".__new__" __new__.__qualname__ = cls.__name__ + ".__new__" __new__.__module__ = cls.__module__ - __new__._oc_generic_new = True return _function(__new__, cls) diff --git a/pyobjc-core/Lib/objc/_transform.py b/pyobjc-core/Lib/objc/_transform.py index 86648bc5be..572f722fb9 100644 --- a/pyobjc-core/Lib/objc/_transform.py +++ b/pyobjc-core/Lib/objc/_transform.py @@ -43,30 +43,14 @@ def _selectorToKeywords(selector): return tuple(parts) -def setupSubClass( +def setDunderNew( class_object, - class_dict, ): - - new_map = {} - - for name, value in class_dict.items(): - if not name.startswith("init"): - continue - if len(name) > 4 and not name[4].isupper(): - continue - if not isinstance(value, objc.selector): - continue - - new_map[_selectorToKeywords(value.selector.decode())] = name - - if not new_map: - return - - _new.NEW_MAP[class_object] = new_map + class_object.__new__ = _new._make_new(class_object) def processClassDict( + class_name, class_dict, meta_dict, class_object, @@ -196,10 +180,25 @@ def processClassDict( elif sel.isHidden: hidden_class_methods[sel.selector] = sel + new_kw_map = {} + + for name, value in class_dict.items(): + if not name.startswith("init"): + continue + if len(name) > 4 and not name[4].isupper(): + continue + if not isinstance(value, objc.selector): + continue + + new_kw_map[_selectorToKeywords(value.selector.decode())] = name + if new_kw_map: + _new.NEW_MAP[class_name] = new_kw_map + return ( instance_variables, instance_methods, class_methods, + "__new__" in class_dict, ) @@ -741,4 +740,4 @@ def callable(self): # noqa: A003 objc.options._transformAttribute = transformAttribute objc.options._processClassDict = processClassDict -objc.options._setupSubClass = setupSubClass +objc.options._setDunderNew = setDunderNew diff --git a/pyobjc-core/Modules/objc/class-builder.h b/pyobjc-core/Modules/objc/class-builder.h index 3d266c5adf..57e0f047f8 100644 --- a/pyobjc-core/Modules/objc/class-builder.h +++ b/pyobjc-core/Modules/objc/class-builder.h @@ -4,7 +4,7 @@ NS_ASSUME_NONNULL_BEGIN extern Class _Nullable PyObjCClass_BuildClass(Class, PyObject*, char*, PyObject*, - PyObject*, PyObject*, PyObject*); + PyObject*, PyObject*, PyObject*, int*); extern int PyObjCClass_UnbuildClass(Class); extern int PyObjCClass_FinishClass(Class); diff --git a/pyobjc-core/Modules/objc/class-builder.m b/pyobjc-core/Modules/objc/class-builder.m index 21266f7555..87eb8f07be 100644 --- a/pyobjc-core/Modules/objc/class-builder.m +++ b/pyobjc-core/Modules/objc/class-builder.m @@ -226,7 +226,8 @@ static Class _Nullable build_intermediate_class(Class base_class, char* name) Class _Nullable PyObjCClass_BuildClass(Class super_class, PyObject* protocols, char* name, PyObject* class_dict, PyObject* meta_dict, PyObject* hiddenSelectors, - PyObject* hiddenClassSelectors) + PyObject* hiddenClassSelectors, + int* has_dunder_new) { PyObject* value = NULL; Py_ssize_t i; @@ -264,14 +265,19 @@ Class _Nullable PyObjCClass_BuildClass(Class super_class, PyObject* protocols, c "Cannot create class because 'objc.options._processClassDict' is not set"); goto error_cleanup; } - PyObject* args[] = {NULL, class_dict, meta_dict, py_superclass, + PyObject* py_name = PyUnicode_FromString(name); + if (py_name == NULL) { + goto error_cleanup; + } + PyObject* args[] = {NULL, py_name, class_dict, meta_dict, py_superclass, protocols, hiddenSelectors, hiddenClassSelectors}; PyObject* rv = PyObject_Vectorcall(PyObjC_processClassDict, args + 1, - 6 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + 7 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + Py_DECREF(py_name); if (rv == NULL) { goto error_cleanup; } - if (!PyTuple_Check(rv) || PyTuple_GET_SIZE(rv) != 3) { + if (!PyTuple_Check(rv) || PyTuple_GET_SIZE(rv) != 4) { Py_DECREF(rv); PyErr_SetString( PyObjCExc_InternalError, @@ -284,6 +290,7 @@ Class _Nullable PyObjCClass_BuildClass(Class super_class, PyObject* protocols, c Py_INCREF(instance_methods); class_methods = PyTuple_GET_ITEM(rv, 2); Py_INCREF(class_methods); + *has_dunder_new = PyObject_IsTrue(PyTuple_GET_ITEM(rv, 3)); Py_DECREF(rv); PyObjC_Assert(instance_variables != NULL, Nil); PyObjC_Assert(instance_methods != NULL, Nil); diff --git a/pyobjc-core/Modules/objc/objc-class.m b/pyobjc-core/Modules/objc/objc-class.m index 2706396a12..72bdcdaf65 100644 --- a/pyobjc-core/Modules/objc/objc-class.m +++ b/pyobjc-core/Modules/objc/objc-class.m @@ -396,6 +396,7 @@ static Class _Nullable objc_metaclass_locate(PyObject* meta_class) BOOL isCFProxyClass = NO; int r; int final = 0; + int has_dunder_new = 0; if (!PyArg_ParseTupleAndKeywords(args, kwds, "sOO|Op", keywords, &name, &bases, &dict, &arg_protocols, &final)) { @@ -624,7 +625,7 @@ static Class _Nullable objc_metaclass_locate(PyObject* meta_class) * class dict. */ objc_class = PyObjCClass_BuildClass(super_class, protocols, name, dict, metadict, - hiddenSelectors, hiddenClassSelectors); + hiddenSelectors, hiddenClassSelectors, &has_dunder_new); if (objc_class == Nil) { Py_XDECREF(orig_slots); Py_DECREF(protocols); @@ -1021,12 +1022,12 @@ static Class _Nullable objc_metaclass_locate(PyObject* meta_class) PyObjC_Assert(info->hasPythonImpl, NULL); - if (PyObjC_setupSubClass != NULL && PyObjC_setupSubClass != Py_None) { - PyObject* args[3] = {NULL, res, ((PyTypeObject*)res)->tp_dict}; + if (!has_dunder_new && PyObjC_setDunderNew != NULL && PyObjC_setDunderNew != Py_None) { + PyObject* args[2] = {NULL, res}; PyObject* rv; - rv = PyObject_Vectorcall(PyObjC_setupSubClass, args + 1, - 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + rv = PyObject_Vectorcall(PyObjC_setDunderNew, args + 1, + 1 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (rv == NULL) { Py_DECREF(res); return NULL; diff --git a/pyobjc-core/Modules/objc/options.h b/pyobjc-core/Modules/objc/options.h index 4d761dd730..da27a1af32 100644 --- a/pyobjc-core/Modules/objc/options.h +++ b/pyobjc-core/Modules/objc/options.h @@ -26,7 +26,7 @@ extern PyObject* _Nullable PyObjC_getKeyPath; extern PyObject* _Nullable PyObjC_setKeyPath; extern PyObject* _Nullable PyObjC_transformAttribute; extern PyObject* _Nullable PyObjC_processClassDict; -extern PyObject* _Nullable PyObjC_setupSubClass; +extern PyObject* _Nullable PyObjC_setDunderNew; extern PyObject* _Nullable PyObjC_DictLikeTypes; extern PyObject* _Nullable PyObjC_ListLikeTypes; diff --git a/pyobjc-core/Modules/objc/options.m b/pyobjc-core/Modules/objc/options.m index 8dd15e541d..041de1b778 100644 --- a/pyobjc-core/Modules/objc/options.m +++ b/pyobjc-core/Modules/objc/options.m @@ -163,7 +163,7 @@ OBJECT_PROP(_setKeyPath, PyObjC_setKeyPath, NULL) OBJECT_PROP(_transformAttribute, PyObjC_transformAttribute, NULL) OBJECT_PROP(_processClassDict, PyObjC_processClassDict, NULL) -OBJECT_PROP(_setupSubClass, PyObjC_setupSubClass, NULL) +OBJECT_PROP(_setDunderNew, PyObjC_setDunderNew, NULL) static PyObject* bundle_hack_get(PyObject* s __attribute__((__unused__)), @@ -300,8 +300,8 @@ "Private helper used for transforming attributes for Objective-C classes"), GETSET(_processClassDict, "Private helper used for splitting a class dict into parts"), - GETSET(_setupSubClass, - "Private helper used for finishing setup of a new Python subclass"), + GETSET(_setDunderNew, + "Private helper used for setting __new__ of a new Python subclass"), { .name = "deprecation_warnings", .get = deprecation_warnings_get, diff --git a/pyobjc-core/PyObjCTest/test_generic_new.py b/pyobjc-core/PyObjCTest/test_generic_new.py index 961bc2eb70..83da457ad6 100644 --- a/pyobjc-core/PyObjCTest/test_generic_new.py +++ b/pyobjc-core/PyObjCTest/test_generic_new.py @@ -11,7 +11,7 @@ def test_nsobject(self): v = NSObject() self.assertIsInstance(v, NSObject) - self.assertEqual(new_mod.NEW_MAP[NSObject], {(): "init"}) + self.assertEqual(new_mod.NEW_MAP["NSObject"], {(): "init"}) with self.assertRaisesRegex( TypeError, r"NSObject\(\) does not support keyword arguments 'y', 'x'" From 00b24b22aaf6e0ba059c9b1cd157bd905271ccad Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 18 Apr 2024 22:50:08 +0200 Subject: [PATCH 08/23] Fix most test issues Primarily changes to deal with the changed interface in _transform. One bug left over: a custom __new__ is silently replaced by the generic interface in subclasses. --- pyobjc-core/Lib/objc/_convenience_nsarray.py | 5 +- pyobjc-core/Lib/objc/_convenience_nsdata.py | 1 + pyobjc-core/Lib/objc/_convenience_nsstring.py | 5 ++ pyobjc-core/Lib/objc/_new.py | 14 ++++- pyobjc-core/Lib/objc/_transform.py | 4 +- pyobjc-core/PyObjCTest/test_transform.py | 59 ++++++++++++++++--- .../PyObjCTest/test_transform_integration.py | 26 +++++--- 7 files changed, 95 insertions(+), 19 deletions(-) diff --git a/pyobjc-core/Lib/objc/_convenience_nsarray.py b/pyobjc-core/Lib/objc/_convenience_nsarray.py index a834f4c130..d0fcdf96fd 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsarray.py +++ b/pyobjc-core/Lib/objc/_convenience_nsarray.py @@ -401,7 +401,10 @@ def nsarray__iter__(self): ): addConvenienceForClass( cls, - (("pop", nsarray_pop),), + ( + ("__new__", staticmethod(nsarray_new)), + ("pop", nsarray_pop), + ), ) diff --git a/pyobjc-core/Lib/objc/_convenience_nsdata.py b/pyobjc-core/Lib/objc/_convenience_nsdata.py index ecc841601d..60ef179e9e 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsdata.py +++ b/pyobjc-core/Lib/objc/_convenience_nsdata.py @@ -421,6 +421,7 @@ def nsmutabledata_clear(self): addConvenienceForClass( "NSMutableData", ( + ("__new__", staticmethod(nsdata__new__)), ("__setitem__", nsmutabledata__setitem__), ("__delitem__", nsmutabledata__delitem__), ("__iadd__", nsmutabledata__iadd__), diff --git a/pyobjc-core/Lib/objc/_convenience_nsstring.py b/pyobjc-core/Lib/objc/_convenience_nsstring.py index d57ed35a7d..500fbea8df 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsstring.py +++ b/pyobjc-core/Lib/objc/_convenience_nsstring.py @@ -25,3 +25,8 @@ def nsstring_new(cls, value=_no_value): ("__new__", staticmethod(nsstring_new)), ), ) + +addConvenienceForClass( + "NSMutableString", + (("__new__", staticmethod(nsstring_new)),), +) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 6f60fad576..57d308417b 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -12,7 +12,15 @@ """ +import objc + # TODO: +# - Interaction with custom __new__ is not entirely correct: +# subclases will overwrite __new__ using the generic implementation +# - Calculate __new__.__doc__ statically for Python subclasses +# - Allow setting 'init' and 'new' to None in subclasses to +# support subclasses where those methods are not available +# (actual implementation to be determined) # - Make sure __init__ is never invoked implicitly (it # currently is when __new__ is invoked). There is a slight # risks this breaks code that implements a custom __new__ @@ -54,7 +62,6 @@ "NSObject": {(): "init"}, } - # Sentinel value UNSET = object() @@ -144,6 +151,11 @@ def __new__(cls, **kwds): else: return getattr(cls, name)(*args) + if key in (("cobject",), ("c_void_p",)): + # Support for creating instances from raw pointers in the default + # __new__ implementation. + return objc.objc_object.__new__(cls, **kwds) + if key: raise TypeError( f"{cls.__name__}() does not support keyword arguments {', '.join(repr(k) for k in key)}" diff --git a/pyobjc-core/Lib/objc/_transform.py b/pyobjc-core/Lib/objc/_transform.py index 572f722fb9..87dd2441a6 100644 --- a/pyobjc-core/Lib/objc/_transform.py +++ b/pyobjc-core/Lib/objc/_transform.py @@ -34,6 +34,8 @@ def _isSelectorPrefix(name, prefix): def _selectorToKeywords(selector): assert selector.startswith("init") selector = selector[4:] + if not selector: + return () parts = selector.split(":")[:-1] if parts[0].startswith("With"): @@ -183,7 +185,7 @@ def processClassDict( new_kw_map = {} for name, value in class_dict.items(): - if not name.startswith("init"): + if not isinstance(name, str) or not name.startswith("init"): continue if len(name) > 4 and not name[4].isupper(): continue diff --git a/pyobjc-core/PyObjCTest/test_transform.py b/pyobjc-core/PyObjCTest/test_transform.py index 05886f3d87..53719c63e7 100644 --- a/pyobjc-core/PyObjCTest/test_transform.py +++ b/pyobjc-core/PyObjCTest/test_transform.py @@ -1332,10 +1332,11 @@ class TestClassDictProcessor(TestCase): def assertValidResult(self, rval): # Sanity check of the return value of the processor self.assertIsInstance(rval, tuple) - self.assertEqual(len(rval), 3) + self.assertEqual(len(rval), 4) self.assertIsInstance(rval[0], tuple) self.assertIsInstance(rval[1], tuple) self.assertIsInstance(rval[2], tuple) + self.assertIsInstance(rval[3], bool) for item in rval[0]: self.assertIsInstance(item, objc.ivar) @@ -1358,6 +1359,7 @@ def test_empty_dict(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "SomeClass", class_dict, meta_dict, NSObject, @@ -1372,6 +1374,7 @@ def test_empty_dict(self): (objc.ivar("__dict__", objc._C_PythonObject, isSlot=True),), (), (), + False, ), ) self.assertTrue(class_dict["__objc_python_subclass__"]) @@ -1386,6 +1389,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1400,6 +1404,7 @@ def test_slots(self): (objc.ivar("__dict__", objc._C_PythonObject, isSlot=True),), (), (), + False, ), ) self.assertEqual(class_dict["__slots__"], ()) @@ -1413,6 +1418,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1421,7 +1427,7 @@ def test_slots(self): hidden_class_methods, ) self.assertValidResult(rval) - self.assertEqual(rval, ((), (), ())) + self.assertEqual(rval, ((), (), (), False)) self.assertEqual(class_dict["__slots__"], ()) self.assertEqual(meta_dict, {}) self.assertEqual(len(hidden_instance_methods), 0) @@ -1433,6 +1439,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1450,6 +1457,7 @@ def test_slots(self): ), (), (), + False, ), ) self.assertEqual(class_dict["__slots__"], ()) @@ -1463,6 +1471,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1480,6 +1489,7 @@ def test_slots(self): ), (), (), + False, ), ) self.assertEqual(class_dict["__slots__"], ()) @@ -1493,6 +1503,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1503,7 +1514,7 @@ def test_slots(self): self.assertValidResult(rval) self.assertEqual( rval, - ((objc.ivar("ab", objc._C_PythonObject, isSlot=True),), (), ()), + ((objc.ivar("ab", objc._C_PythonObject, isSlot=True),), (), (), False), ) self.assertEqual(class_dict["__slots__"], ()) self.assertEqual(meta_dict, {}) @@ -1516,6 +1527,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1533,6 +1545,7 @@ def test_slots(self): ), (), (), + False, ), ) self.assertEqual(class_dict["__slots__"], ()) @@ -1547,6 +1560,7 @@ def test_slots(self): hidden_class_methods = {} with self.assertRaisesRegex(TypeError, "not iterable"): self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1567,6 +1581,7 @@ def test_slots(self): hidden_class_methods = {} with self.assertRaisesRegex(TypeError, r"must be str, not int"): self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1587,6 +1602,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWithDict, @@ -1595,7 +1611,7 @@ def test_slots(self): hidden_class_methods, ) self.assertValidResult(rval) - self.assertEqual(rval, ((), (), ())) + self.assertEqual(rval, ((), (), (), False)) self.assertEqual(class_dict["__slots__"], ()) self.assertEqual(meta_dict, {}) self.assertEqual(len(hidden_instance_methods), 0) @@ -1607,6 +1623,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWithDict, @@ -1624,6 +1641,7 @@ def test_slots(self): ), (), (), + False, ), ) self.assertEqual(class_dict["__slots__"], ()) @@ -1637,6 +1655,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWithoutDict, @@ -1651,6 +1670,7 @@ def test_slots(self): (objc.ivar("__dict__", objc._C_PythonObject, isSlot=True),), (), (), + False, ), ) self.assertEqual(class_dict["__slots__"], ()) @@ -1664,6 +1684,7 @@ def test_slots(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWithoutDict, @@ -1681,6 +1702,7 @@ def test_slots(self): ), (), (), + False, ), ) self.assertEqual(class_dict["__slots__"], ()) @@ -1698,6 +1720,7 @@ def test_slots(self): "objc.ivar 'a' overrides instance variable in super class", ): self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWitIvarA, @@ -1719,6 +1742,7 @@ def test_slots(self): "slot 'a' redefines 42", ): self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWitIvarA, @@ -1737,6 +1761,7 @@ def test_slots(self): "slot 'a' redefines 42", ): self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWitIvarA, @@ -1753,6 +1778,7 @@ def test_ivars(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1761,7 +1787,7 @@ def test_ivars(self): hidden_class_methods, ) self.assertValidResult(rval) - self.assertEqual(rval, ((ivar,), (), ())) + self.assertEqual(rval, ((ivar,), (), (), False)) self.assertEqual(ivar.__name__, "var") self.assertIs(ivar, class_dict["var"]) self.assertIs(ivar, rval[0][0]) @@ -1776,6 +1802,7 @@ def test_ivars(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1784,7 +1811,7 @@ def test_ivars(self): hidden_class_methods, ) self.assertValidResult(rval) - self.assertEqual(rval, ((ivar,), (), ())) + self.assertEqual(rval, ((ivar,), (), (), False)) self.assertEqual(ivar.__name__, "var") self.assertIs(ivar, class_dict["var"]) self.assertIs(ivar, rval[0][0]) @@ -1799,6 +1826,7 @@ def test_ivars(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1807,7 +1835,7 @@ def test_ivars(self): hidden_class_methods, ) self.assertValidResult(rval) - self.assertEqual(rval, ((ivar,), (), ())) + self.assertEqual(rval, ((ivar,), (), (), False)) self.assertEqual(ivar.__name__, "varname") self.assertIs(ivar, class_dict["var"]) self.assertIs(ivar, rval[0][0]) @@ -1824,6 +1852,7 @@ def test_ivars(self): hidden_class_methods = {} with self.assertRaisesRegex(objc.error, "'b' reimplements objc.ivar 'a'"): self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1841,6 +1870,7 @@ def test_ivars(self): hidden_class_methods = {} with self.assertRaisesRegex(objc.error, "'a' redefines <"): self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1860,6 +1890,7 @@ def test_ivars(self): objc.error, "objc.ivar 'iv' overrides instance variable in super class" ): self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWithIvar, @@ -1879,6 +1910,7 @@ def test_ivars(self): objc.error, "objc.ivar 'iv' overrides instance variable in super class" ): self.processor( + "ClassName", class_dict, meta_dict, OC_TransformWithSlot, @@ -1907,6 +1939,7 @@ def method_(self, arg): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -1951,6 +1984,7 @@ def method_(self, value): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -2000,6 +2034,7 @@ def method(self, a): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -2046,6 +2081,7 @@ def method(self, a): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -2096,6 +2132,7 @@ def method(self): hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -2104,7 +2141,7 @@ def method(self): hidden_class_methods, ) self.assertValidResult(rval) - self.assertEqual(rval, ((), (), ())) + self.assertEqual(rval, ((), (), (), False)) self.assertIs(class_dict["method"], method) self.assertEqual(meta_dict, {}) self.assertEqual(len(hidden_instance_methods), 0) @@ -2122,6 +2159,7 @@ def __pyobjc_class_setup__( hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -2150,6 +2188,7 @@ def __pyobjc_class_setup__( hidden_instance_methods = {} hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -2177,6 +2216,7 @@ def test_rename_selector(self): hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSMutableArray, @@ -2213,6 +2253,7 @@ def test_class_dict_is_transformed(self): side_effect=_transform.transformAttribute, ) as mck: rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -2246,6 +2287,7 @@ def method(self): hidden_class_methods = {} rval = self.processor( + "ClassName", class_dict, meta_dict, NSObject, @@ -2276,6 +2318,7 @@ def test_invalid_protocols(self): hidden_instance_methods = {} hidden_class_methods = {} self.processor( + "ClassName", class_dict, meta_dict, NSObject, diff --git a/pyobjc-core/PyObjCTest/test_transform_integration.py b/pyobjc-core/PyObjCTest/test_transform_integration.py index f7f61e2bcd..46562247f6 100644 --- a/pyobjc-core/PyObjCTest/test_transform_integration.py +++ b/pyobjc-core/PyObjCTest/test_transform_integration.py @@ -29,10 +29,13 @@ def tetst_unset(self): type(name, (NSObject,), {}) def test_not_tuple(self): - for idx, value in enumerate((42, (True, (), (), (), ()), [True, (), ()])): + for idx, value in enumerate( + (42, (True, (), (), (), (), False), [True, (), (), False]) + ): with self.subTest(value): def helper( + class_name, class_dict, meta_dict, class_object, @@ -60,6 +63,7 @@ def test_invalid_ivar(self): with self.subTest(value): def helper( + class_name, class_dict, meta_dict, class_object, @@ -67,7 +71,7 @@ def helper( hidden_instance_methods, hidden_class_methods, ): - return (value,), (), () # noqa: B023 + return (value,), (), (), False # noqa: B023 with patch(helper): with self.assertRaisesRegex( @@ -80,6 +84,7 @@ def helper( idx += 1 def helper( + class_name, class_dict, meta_dict, class_object, @@ -87,7 +92,7 @@ def helper( hidden_instance_methods, hidden_class_methods, ): - return (objc.ivar(),), (), () # noqa: B023 + return (objc.ivar(),), (), (), False # noqa: B023 with patch(helper): with self.assertRaisesRegex(objc.error, "instance variable without a name"): @@ -111,6 +116,7 @@ def test_invalid_instance_methods(self): with self.subTest(value): def helper( + class_name, class_dict, meta_dict, class_object, @@ -118,7 +124,7 @@ def helper( hidden_instance_methods, hidden_class_methods, ): - return (), (value,), () # noqa: B023 + return (), (value,), (), False # noqa: B023 with patch(helper): with self.assertRaisesRegex( @@ -145,6 +151,7 @@ def test_invalid_class_methods(self): with self.subTest(value): def helper( + class_name, class_dict, meta_dict, class_object, @@ -152,7 +159,7 @@ def helper( hidden_instance_methods, hidden_class_methods, ): - return (), (), (value,) # noqa: B023 + return (), (), (value,), False # noqa: B023 with patch(helper): with self.assertRaisesRegex( @@ -167,6 +174,7 @@ def test_not_tuples(self): with self.subTest("ivars"): def helper( + class_name, class_dict, meta_dict, class_object, @@ -174,7 +182,7 @@ def helper( hidden_instance_methods, hidden_class_methods, ): - return 42, (), () # noqa: B023 + return 42, (), (), False # noqa: B023 with patch(helper): with self.assertRaisesRegex( @@ -188,6 +196,7 @@ def helper( with self.subTest("instance methods"): def helper( + class_name, class_dict, meta_dict, class_object, @@ -195,7 +204,7 @@ def helper( hidden_instance_methods, hidden_class_methods, ): - return (), 42, () # noqa: B023 + return (), 42, (), False # noqa: B023 with patch(helper): with self.assertRaisesRegex( @@ -209,6 +218,7 @@ def helper( with self.subTest("class methods"): def helper( + class_name, class_dict, meta_dict, class_object, @@ -216,7 +226,7 @@ def helper( hidden_instance_methods, hidden_class_methods, ): - return (), (), 42 # noqa: B023 + return (), (), 42, False # noqa: B023 with patch(helper): with self.assertRaisesRegex( From 4b69ffc20c7b289cf3832d69e39722c7513448dc Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 18 Apr 2024 22:52:13 +0200 Subject: [PATCH 09/23] Update todo list --- pyobjc-core/Lib/objc/_new.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 57d308417b..3e701ea3d3 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -27,6 +27,8 @@ # and relies on the invocation of __init__ # (Implement by overriding tp_call in objc-class) # - Update support code for framework bindings +# - Update the __new__ implementation for _convenience* to +# also support the generic __new__ interface. # - Update framework binding tooling (and then the # bindings themselves) # - Document the feature From 58542d9bcc100d20ea9c22213fdc9fb2ee9ab5a5 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 28 Apr 2024 21:26:53 +0200 Subject: [PATCH 10/23] Use NS_UNAVAIBLE annotations This adds new APIs to make use the information NS_UNAVAILABLE macros in Cocoa headers, and updates the framework bindings to make use of that information. --- docs/metadata/manual.rst | 32 +++ pyobjc-core/Lib/objc/_convenience.py | 56 +++- pyobjc-core/Lib/objc/_new.py | 8 - pyobjc-core/Lib/objc/_transform.py | 9 +- pyobjc-core/PyObjCTest/test_generic_new.py | 21 ++ .../Lib/AVFoundation/__init__.py | 256 ++++++++++++++++++ pyobjc-framework-AVKit/Lib/AVKit/__init__.py | 8 + .../Lib/AVRouting/__init__.py | 6 + .../Lib/Accessibility/__init__.py | 20 ++ .../Lib/AppTrackingTransparency/__init__.py | 6 + .../Lib/AudioVideoBridging/__init__.py | 6 + .../Lib/AuthenticationServices/__init__.py | 72 +++++ .../__init__.py | 8 + .../Lib/BackgroundAssets/__init__.py | 12 + .../Lib/BrowserEngineKit/__init__.py | 39 +++ .../Lib/CallKit/__init__.py | 18 ++ .../Lib/Cinematic/__init__.py | 26 ++ .../Lib/ClassKit/__init__.py | 12 + .../Lib/CloudKit/__init__.py | 73 +++++ pyobjc-framework-Cocoa/Lib/AppKit/__init__.py | 69 +++++ .../Lib/Foundation/__init__.py | 15 + .../Lib/Contacts/__init__.py | 8 + .../Lib/CoreBluetooth/__init__.py | 8 + .../Lib/CoreData/__init__.py | 18 ++ .../Lib/CoreHaptics/__init__.py | 11 + .../Lib/CoreLocation/__init__.py | 16 ++ .../Lib/CoreMIDI/__init__.py | 10 + .../Lib/CoreML/__init__.py | 61 +++++ .../Lib/CoreMediaIO/__init__.py | 28 ++ .../Lib/CoreMotion/__init__.py | 3 + .../Lib/CoreSpotlight/__init__.py | 6 + .../Lib/CryptoTokenKit/__init__.py | 19 ++ .../Lib/DataDetection/__init__.py | 3 + .../Lib/EventKit/__init__.py | 10 + .../Lib/FileProvider/__init__.py | 3 + .../Lib/FileProviderUI/__init__.py | 8 + .../Lib/GameController/__init__.py | 12 + .../Lib/GameKit/__init__.py | 3 + .../Lib/HealthKit/__init__.py | 63 +++++ .../Lib/Intents/__init__.py | 46 ++++ .../Lib/IntentsUI/__init__.py | 10 + .../Lib/LinkPresentation/__init__.py | 6 + .../Lib/LocalAuthentication/__init__.py | 14 + .../LocalAuthenticationEmbeddedUI/__init__.py | 6 + .../Lib/MLCompute/__init__.py | 36 +++ .../Lib/MailKit/__init__.py | 30 ++ .../Lib/MapKit/__init__.py | 16 ++ .../Lib/MediaPlayer/__init__.py | 24 ++ .../Lib/MetalKit/__init__.py | 9 + .../Lib/MetalPerformanceShaders/__init__.py | 239 ++++++++++++++++ .../Lib/ModelIO/__init__.py | 8 + .../Lib/NaturalLanguage/__init__.py | 6 + pyobjc-framework-OSLog/Lib/OSLog/__init__.py | 3 + pyobjc-framework-PHASE/Lib/PHASE/__init__.py | 103 +++++++ .../Lib/PassKit/__init__.py | 33 +++ .../Lib/PencilKit/__init__.py | 7 + .../Lib/Photos/__init__.py | 14 + .../Lib/PhotosUI/__init__.py | 24 ++ .../Lib/PushKit/__init__.py | 3 + .../Lib/Quartz/QuartzCore/__init__.py | 3 + .../Lib/QuickLookThumbnailing/__init__.py | 7 + .../Lib/SafariServices/__init__.py | 18 ++ .../Lib/SafetyKit/__init__.py | 6 + .../Lib/SceneKit/__init__.py | 3 + .../Lib/ScreenCaptureKit/__init__.py | 16 ++ .../Lib/ScreenTime/__init__.py | 10 + .../Lib/SharedWithYou/__init__.py | 14 + .../Lib/SharedWithYouCore/__init__.py | 22 ++ .../Lib/ShazamKit/__init__.py | 14 + .../Lib/SoundAnalysis/__init__.py | 16 ++ .../Lib/Speech/__init__.py | 3 + .../Lib/StoreKit/__init__.py | 14 + .../Lib/Symbols/__init__.py | 10 + .../Lib/SystemExtensions/__init__.py | 6 + .../Lib/ThreadNetwork/__init__.py | 6 + .../Lib/UniformTypeIdentifiers/__init__.py | 6 + .../Lib/UserNotifications/__init__.py | 14 + .../Lib/VideoSubscriberAccount/__init__.py | 12 + .../Lib/Virtualization/__init__.py | 104 +++++++ .../Lib/Vision/__init__.py | 48 ++++ .../Lib/WebKit/__init__.py | 14 + .../Lib/iTunesLibrary/__init__.py | 3 + 82 files changed, 2054 insertions(+), 14 deletions(-) diff --git a/docs/metadata/manual.rst b/docs/metadata/manual.rst index ca0e1ae069..f5177f7d1c 100644 --- a/docs/metadata/manual.rst +++ b/docs/metadata/manual.rst @@ -491,6 +491,38 @@ Metadata for Objective-C methods and classes .. versionadded:: 3.0 +.. function:: registerUnavailableMethod(classname, selector) + + Register the selector (a byte string with the Objective-C name for the selector) + as being unavailable in the named class. Calling this method later will + result in an exception being raised. + + This is primairly meant to be used to mirror the effects + of ``NS_UNAVAILABLE`` in Objective-C headers. + + .. versionadded: 10.4 + +.. function:: registerNewKeywordsFromSelector(classname, selector) + + Register keywords calculated from *selector* as passible + keyword arguments for ``__new__`` for class *classname*. The + selector should start with "init". + + .. versionadded: 10.4 + +.. function:: registerNewKeywords(classname, keywords, methodname) + + Register the keyword tuple *keywords* as a set of keyword + arguments for ``__new__`` for class *classname* that will result + in the invocation the method named *methodname*. + + If the *methodname* startswith "init" invocation of ``__new__`` + with this tuple of keywords is equivalent to ``classname.alloc().methodname()``, + otherwise it is equivalent to ``classname.methodname()``. + + .. versionadded: 10.4 + + Register proxy types .................... diff --git a/pyobjc-core/Lib/objc/_convenience.py b/pyobjc-core/Lib/objc/_convenience.py index ca752b75b6..f20def62f3 100644 --- a/pyobjc-core/Lib/objc/_convenience.py +++ b/pyobjc-core/Lib/objc/_convenience.py @@ -13,9 +13,16 @@ selector, ) import PyObjCTools.KeyValueCoding as kvc -from objc._new import _make_new - -__all__ = ("addConvenienceForClass", "registerABCForClass") +from objc._new import _make_new, NEW_MAP +from objc._transform import _selectorToKeywords + +__all__ = ( + "addConvenienceForClass", + "registerABCForClass", + "registerUnavailableMethod", + "registerNewKeywords", + "registerNewKeywordsFromSelector", +) CLASS_METHODS = {} CLASS_ABC = {} @@ -59,7 +66,9 @@ class name to a list of Python method names and implementation. # Only add the generic __new__ to pure ObjC classes, # __new__ will be added to Python subclasses by # ._transform. - if not cls.__has_python_implementation__: + if not cls.__has_python_implementation__ and type( # noqa: E721 + cls.__mro__[1].__new__ + ) != type(lambda: None): type_dict["__new__"] = _make_new(cls) for nm, value in CLASS_METHODS.get(cls.__name__, ()): @@ -87,6 +96,45 @@ def bundleForClass(cls): return selector(bundleForClass, isClassMethod=True) +def registerUnavailableMethod(classname, selector): + """ + Mark *selector* as unavailable for *classname*. + """ + selname = selector.decode() + + # This adds None as a replacement value instead of + # registering metadata because NS_UNAVAILABLE is + # used to mark abstract base classes with concrete + # public subclasses. + addConvenienceForClass(classname, ((selname.replace(":", "_"), None),)) + + if selname.startswith("init"): + kw = _selectorToKeywords(selname) + NEW_MAP.setdefault(classname, {})[kw] = None + + +def registerNewKeywordsFromSelector(classname, selector): + """ + Register keywords calculated from 'selector' as passible + keyword arguments for __new__ for the given class. The + selector should be an 'init' method. + """ + selname = selector.decode() + kw = _selectorToKeywords(selname) + NEW_MAP.setdefault(classname, {})[kw] = selname.replace(":", "_") + + +def registerNewKeywords(classname, keywords, methodname): + """ + Register the keyword tuple 'keywords' as a set of keyword + arguments for __new__ for the given class that will result + in the invocation of the given method. + + Method should be either an init method or a class method. + """ + NEW_MAP.setdefault(classname, {})[keywords] = method + + def registerABCForClass(classname, *abc_class): """ Register *classname* with the *abc_class*-es when diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 3e701ea3d3..7459af9597 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -15,22 +15,14 @@ import objc # TODO: -# - Interaction with custom __new__ is not entirely correct: -# subclases will overwrite __new__ using the generic implementation # - Calculate __new__.__doc__ statically for Python subclasses -# - Allow setting 'init' and 'new' to None in subclasses to -# support subclasses where those methods are not available -# (actual implementation to be determined) # - Make sure __init__ is never invoked implicitly (it # currently is when __new__ is invoked). There is a slight # risks this breaks code that implements a custom __new__ # and relies on the invocation of __init__ # (Implement by overriding tp_call in objc-class) -# - Update support code for framework bindings # - Update the __new__ implementation for _convenience* to # also support the generic __new__ interface. -# - Update framework binding tooling (and then the -# bindings themselves) # - Document the feature # - Add tests [in progress] # - Maybe: somehow add __doc__ to classes that reflect the diff --git a/pyobjc-core/Lib/objc/_transform.py b/pyobjc-core/Lib/objc/_transform.py index 87dd2441a6..281ae1cab3 100644 --- a/pyobjc-core/Lib/objc/_transform.py +++ b/pyobjc-core/Lib/objc/_transform.py @@ -189,7 +189,10 @@ def processClassDict( continue if len(name) > 4 and not name[4].isupper(): continue - if not isinstance(value, objc.selector): + if value is None and name == "init": + new_kw_map[()] = None + continue + elif not isinstance(value, objc.selector): continue new_kw_map[_selectorToKeywords(value.selector.decode())] = name @@ -200,7 +203,9 @@ def processClassDict( instance_variables, instance_methods, class_methods, - "__new__" in class_dict, + # Either __new__ in this class, or a custom new in a parent class + ("__new__" in class_dict) + or type(class_object.__new__) == type(lambda: 1), # noqa: E721 ) diff --git a/pyobjc-core/PyObjCTest/test_generic_new.py b/pyobjc-core/PyObjCTest/test_generic_new.py index 83da457ad6..75ede66dc2 100644 --- a/pyobjc-core/PyObjCTest/test_generic_new.py +++ b/pyobjc-core/PyObjCTest/test_generic_new.py @@ -44,6 +44,9 @@ def initializeZ_(self, z): self.assertEqual(v.x, 3) self.assertEqual(v.y, 4) + v = OCPyNew1() + self.assertIsInstance(v, OCPyNew1) + with self.assertRaisesRegex( TypeError, r"OCPyNew1\(\) does not support keyword arguments 'y', 'x'" ): @@ -111,6 +114,24 @@ def __init__(self, **kwds): self.assertEqual(v.value, 4) self.assertIs(e, None) + def test_init_is_none(self): + class OCPyNew5(NSObject): + init = None + + def initWithValue_(self, new_value): + self = super().init() + self.value = new_value + return self + + with self.assertRaisesRegex( + TypeError, r"OCPyNew5\(\) requires keyword arguments" + ): + OCPyNew5() + + v = OCPyNew5(value=3) + self.assertIsInstance(v, OCPyNew5) + self.assertEqual(v.value, 3) + # TODO: TestDefaultNewForObjectiveCClass # Need the metadata update interface before implementing this. diff --git a/pyobjc-framework-AVFoundation/Lib/AVFoundation/__init__.py b/pyobjc-framework-AVFoundation/Lib/AVFoundation/__init__.py index 11fa9ac5f8..dde13b5cde 100644 --- a/pyobjc-framework-AVFoundation/Lib/AVFoundation/__init__.py +++ b/pyobjc-framework-AVFoundation/Lib/AVFoundation/__init__.py @@ -31,6 +31,262 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("AVAssetDownloadTask", b"originalRequest"), + ("AVAssetDownloadTask", b"currentRequest"), + ("AVAssetDownloadTask", b"response"), + ("AVAggregateAssetDownloadTask", b"originalRequest"), + ("AVAggregateAssetDownloadTask", b"currentRequest"), + ("AVAggregateAssetDownloadTask", b"response"), + ("AVAssetDownloadURLSession", b"sharedSession"), + ("AVAssetDownloadURLSession", b"sessionWithConfiguration:"), + ("AVAssetDownloadURLSession", b"sessionWithConfiguration:delegate:"), + ("AVAssetDownloadURLSession", b"dataTaskWithRequest:"), + ("AVAssetDownloadURLSession", b"dataTaskWithURL:"), + ("AVAssetDownloadURLSession", b"uploadTaskWithRequest:fromFile:"), + ("AVAssetDownloadURLSession", b"uploadTaskWithRequest:fromData:"), + ("AVAssetDownloadURLSession", b"uploadTaskWithStreamedRequest:"), + ("AVAssetDownloadURLSession", b"downloadTaskWithRequest:"), + ("AVAssetDownloadURLSession", b"downloadTaskWithURL:"), + ("AVAssetDownloadURLSession", b"downloadTaskWithResumeData:"), + ("AVAssetDownloadURLSession", b"dataTaskWithRequest:completionHandler:"), + ("AVAssetDownloadURLSession", b"dataTaskWithURL:completionHandler:"), + ( + "AVAssetDownloadURLSession", + b"uploadTaskWithRequest:fromFile:completionHandler:", + ), + ( + "AVAssetDownloadURLSession", + b"uploadTaskWithRequest:fromData:completionHandler:", + ), + ("AVAssetDownloadURLSession", b"downloadTaskWithRequest:completionHandler:"), + ("AVAssetDownloadURLSession", b"downloadTaskWithURL:completionHandler:"), + ("AVAssetDownloadURLSession", b"downloadTaskWithResumeData:completionHandler:"), + ("AVAudioSourceNode", b"init"), + ("AVAudioChannelLayout", b"init"), + ("AVAudioEnvironmentDistanceAttenuationParameters", b"init"), + ("AVAudioEnvironmentReverbParameters", b"init"), + ("AVAudioSinkNode", b"init"), + ("AVAudioConnectionPoint", b"init"), + ("AVAudioApplication", b"init"), + ("AVSpeechSynthesisProviderVoice", b"init"), + ("AVSpeechSynthesisProviderVoice", b"new"), + ("AVSpeechSynthesisProviderRequest", b"init"), + ("AVSpeechSynthesisProviderRequest", b"new"), + ("AVAudioRoutingArbiter", b"init"), + ("AVAudioRoutingArbiter", b"new"), + ("AVAudioInputNode", b"init"), + ("AVAudioOutputNode", b"init"), + ("AVAudioUnitEQFilterParameters", b"init"), + ("AVAudioMixingDestination", b"init"), + ("AVAssetCache", b"init"), + ("AVAssetCache", b"new"), + ("AVAssetPlaybackAssistant", b"init"), + ("AVAssetPlaybackAssistant", b"new"), + ("AVCaptureInput", b"init"), + ("AVCaptureInput", b"new"), + ("AVCaptureInputPort", b"init"), + ("AVCaptureInputPort", b"new"), + ("AVAssetDownloadTask", b"init"), + ("AVAssetDownloadTask", b"new"), + ("AVAssetDownloadConfiguration", b"init"), + ("AVAssetDownloadConfiguration", b"new"), + ("AVAggregateAssetDownloadTask", b"init"), + ("AVAggregateAssetDownloadTask", b"new"), + ("AVAssetDownloadURLSession", b"init"), + ("AVAssetDownloadURLSession", b"new"), + ("AVAssetWriterInput", b"init"), + ("AVAssetWriterInput", b"new"), + ("AVAssetWriterInputPassDescription", b"init"), + ("AVAssetWriterInputPassDescription", b"new"), + ("AVAssetWriterInputPixelBufferAdaptor", b"init"), + ("AVAssetWriterInputPixelBufferAdaptor", b"new"), + ("AVAssetWriterInputTaggedPixelBufferGroupAdaptor", b"init"), + ("AVAssetWriterInputTaggedPixelBufferGroupAdaptor", b"new"), + ("AVAssetWriterInputMetadataAdaptor", b"init"), + ("AVAssetWriterInputMetadataAdaptor", b"new"), + ("AVAssetWriterInputCaptionAdaptor", b"init"), + ("AVAssetWriterInputCaptionAdaptor", b"new"), + ("AVAssetWriter", b"init"), + ("AVAssetWriter", b"new"), + ("AVAssetWriterInputGroup", b"init"), + ("AVAssetWriterInputGroup", b"new"), + ("AVPortraitEffectsMatte", b"init"), + ("AVPortraitEffectsMatte", b"new"), + ("AVSampleCursor", b"init"), + ("AVSampleCursor", b"new"), + ("AVAssetImageGenerator", b"init"), + ("AVAssetImageGenerator", b"new"), + ("AVAssetVariant", b"init"), + ("AVAssetVariant", b"new"), + ("AVAssetVariantVideoAttributes", b"init"), + ("AVAssetVariantVideoAttributes", b"new"), + ("AVAssetVariantVideoLayoutAttributes", b"init"), + ("AVAssetVariantVideoLayoutAttributes", b"new"), + ("AVAssetVariantAudioAttributes", b"init"), + ("AVAssetVariantAudioAttributes", b"new"), + ("AVAssetVariantQualifier", b"init"), + ("AVAssetVariantQualifier", b"new"), + ("AVCoordinatedPlaybackSuspension", b"init"), + ("AVCoordinatedPlaybackSuspension", b"new"), + ("AVPlaybackCoordinator", b"init"), + ("AVPlaybackCoordinator", b"new"), + ("AVPlayerPlaybackCoordinator", b"init"), + ("AVPlayerPlaybackCoordinator", b"new"), + ("AVDelegatingPlaybackCoordinatorPlaybackControlCommand", b"init"), + ("AVDelegatingPlaybackCoordinatorPlaybackControlCommand", b"new"), + ("AVDelegatingPlaybackCoordinatorPlayCommand", b"init"), + ("AVDelegatingPlaybackCoordinatorPlayCommand", b"new"), + ("AVDelegatingPlaybackCoordinatorBufferingCommand", b"init"), + ("AVDelegatingPlaybackCoordinatorBufferingCommand", b"new"), + ("AVDelegatingPlaybackCoordinatorPauseCommand", b"init"), + ("AVDelegatingPlaybackCoordinatorPauseCommand", b"new"), + ("AVDelegatingPlaybackCoordinatorSeekCommand", b"init"), + ("AVDelegatingPlaybackCoordinatorSeekCommand", b"new"), + ("AVCaptionConversionValidator", b"init"), + ("AVCaptionConversionValidator", b"new"), + ("AVCaptionConversionWarning", b"init"), + ("AVCaptionConversionWarning", b"new"), + ("AVCaptionConversionAdjustment", b"init"), + ("AVCaptionConversionAdjustment", b"new"), + ("AVCaptionConversionTimeRangeAdjustment", b"init"), + ("AVCaptionConversionTimeRangeAdjustment", b"new"), + ("AVAssetTrackSegment", b"init"), + ("AVAssetTrackSegment", b"new"), + ("AVTextStyleRule", b"init"), + ("AVTextStyleRule", b"new"), + ("AVCaptureDataOutputSynchronizer", b"init"), + ("AVCaptureDataOutputSynchronizer", b"new"), + ("AVCaptureSynchronizedDataCollection", b"init"), + ("AVCaptureSynchronizedDataCollection", b"new"), + ("AVCaptureSynchronizedData", b"init"), + ("AVCaptureSynchronizedData", b"new"), + ("AVURLAsset", b"init"), + ("AVURLAsset", b"new"), + ("AVAssetSegmentReport", b"init"), + ("AVAssetSegmentReport", b"new"), + ("AVAssetSegmentTrackReport", b"init"), + ("AVAssetSegmentTrackReport", b"new"), + ("AVAssetSegmentReportSampleInformation", b"init"), + ("AVAssetSegmentReportSampleInformation", b"new"), + ("AVAssetReaderTrackOutput", b"init"), + ("AVAssetReaderTrackOutput", b"new"), + ("AVAssetReaderAudioMixOutput", b"init"), + ("AVAssetReaderAudioMixOutput", b"new"), + ("AVAssetReaderVideoCompositionOutput", b"init"), + ("AVAssetReaderVideoCompositionOutput", b"new"), + ("AVAssetReaderOutputMetadataAdaptor", b"init"), + ("AVAssetReaderOutputMetadataAdaptor", b"new"), + ("AVAssetReaderOutputCaptionAdaptor", b"init"), + ("AVAssetReaderOutputCaptionAdaptor", b"new"), + ("AVAssetReaderSampleReferenceOutput", b"init"), + ("AVAssetReaderSampleReferenceOutput", b"new"), + ("AVSemanticSegmentationMatte", b"init"), + ("AVSemanticSegmentationMatte", b"new"), + ("AVContentKeySession", b"init"), + ("AVContentKeySession", b"new"), + ("AVCaptureConnection", b"init"), + ("AVCaptureConnection", b"new"), + ("AVCaptureAudioChannel", b"init"), + ("AVCaptureAudioChannel", b"new"), + ("AVCaptureBracketedStillImageSettings", b"init"), + ("AVCaptureBracketedStillImageSettings", b"new"), + ("AVCaptureOutput", b"init"), + ("AVCaptureOutput", b"new"), + ("AVPlayerLooper", b"init"), + ("AVPlayerLooper", b"new"), + ("AVExternalStorageDevice", b"init"), + ("AVExternalStorageDevice", b"new"), + ("AVExternalStorageDeviceDiscoverySession", b"init"), + ("AVExternalStorageDeviceDiscoverySession", b"new"), + ("AVCameraCalibrationData", b"init"), + ("AVCameraCalibrationData", b"new"), + ("AVVideoPerformanceMetrics", b"init"), + ("AVVideoPerformanceMetrics", b"new"), + ("AVCaptionRendererScene", b"init"), + ("AVCaptionRendererScene", b"new"), + ("AVOutputSettingsAssistant", b"init"), + ("AVOutputSettingsAssistant", b"new"), + ("AVCaptureSystemPressureState", b"init"), + ("AVCaptureSystemPressureState", b"new"), + ("AVPlayerVideoOutput", b"init"), + ("AVPlayerVideoOutput", b"new"), + ("AVVideoOutputSpecification", b"init"), + ("AVVideoOutputSpecification", b"new"), + ("AVPlayerVideoOutputConfiguration", b"init"), + ("AVPlayerVideoOutputConfiguration", b"new"), + ("AVCapturePhotoOutputReadinessCoordinator", b"init"), + ("AVCapturePhotoOutputReadinessCoordinator", b"new"), + ("AVCaptureResolvedPhotoSettings", b"init"), + ("AVCaptureResolvedPhotoSettings", b"new"), + ("AVCapturePhoto", b"init"), + ("AVCapturePhoto", b"new"), + ("AVCaptureDeferredPhotoProxy", b"init"), + ("AVCaptureDeferredPhotoProxy", b"new"), + ("AVAssetReader", b"init"), + ("AVAssetReader", b"new"), + ("AVMetadataObject", b"init"), + ("AVMetadataObject", b"new"), + ("AVSampleBufferGenerator", b"init"), + ("AVSampleBufferGenerator", b"new"), + ("AVSampleBufferRequest", b"init"), + ("AVSampleBufferRequest", b"new"), + ("AVSampleBufferGeneratorBatch", b"init"), + ("AVSampleBufferGeneratorBatch", b"new"), + ("AVMediaDataStorage", b"init"), + ("AVMediaDataStorage", b"new"), + ("AVAssetExportSession", b"init"), + ("AVAssetExportSession", b"new"), + ("AVPlayerInterstitialEvent", b"init"), + ("AVPlayerInterstitialEvent", b"new"), + ("AVCaption", b"init"), + ("AVCaption", b"new"), + ("AVCaptionRuby", b"init"), + ("AVCaptionRuby", b"new"), + ("AVAssetTrack", b"init"), + ("AVAssetTrack", b"new"), + ("AVCaptionFormatConformer", b"init"), + ("AVCaptionFormatConformer", b"new"), + ("AVCaptureDevice", b"init"), + ("AVCaptureDevice", b"new"), + ("AVCaptureDeviceDiscoverySession", b"init"), + ("AVCaptureDeviceDiscoverySession", b"new"), + ("AVCaptureDeviceRotationCoordinator", b"init"), + ("AVCaptureDeviceRotationCoordinator", b"new"), + ("AVFrameRateRange", b"init"), + ("AVFrameRateRange", b"new"), + ("AVZoomRange", b"init"), + ("AVZoomRange", b"new"), + ("AVCaptureDeviceFormat", b"init"), + ("AVCaptureDeviceFormat", b"new"), + ("AVCaptureDeviceInputSource", b"init"), + ("AVCaptureDeviceInputSource", b"new"), + ("AVPlayerItem", b"init"), + ("AVPlayerItem", b"new"), + ("AVPlayerItemAccessLog", b"init"), + ("AVPlayerItemAccessLog", b"new"), + ("AVPlayerItemErrorLog", b"init"), + ("AVPlayerItemAccessLogEvent", b"new"), + ("AVPlayerItemAccessLogEvent", b"init"), + ("AVPlayerItemErrorLogEvent", b"new"), + ("AVPlayerItemErrorLogEvent", b"init"), + ("AVAssetResourceLoader", b"new"), + ("AVAssetResourceLoader", b"init"), + ("AVAssetResourceLoadingRequestor", b"new"), + ("AVAssetResourceLoadingRequestor", b"init"), + ("AVAssetResourceLoadingRequest", b"new"), + ("AVAssetResourceLoadingRequest", b"init"), + ("AVAssetResourceLoadingContentInformationRequest", b"new"), + ("AVAssetResourceLoadingContentInformationRequest", b"init"), + ("AVAssetResourceLoadingDataRequest", b"new"), + ("AVAssetResourceLoadingDataRequest", b"init"), + ("AVContinuityDevice", b"new"), + ("AVContinuityDevice", b"init"), + ("AVDepthData", b"new"), + ("AVDepthData", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["AVFoundation._metadata"] diff --git a/pyobjc-framework-AVKit/Lib/AVKit/__init__.py b/pyobjc-framework-AVKit/Lib/AVKit/__init__.py index 67502cba83..b97ec7e529 100644 --- a/pyobjc-framework-AVKit/Lib/AVKit/__init__.py +++ b/pyobjc-framework-AVKit/Lib/AVKit/__init__.py @@ -29,6 +29,14 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("AVPictureInPictureControllerContentSource", b"init"), + ("AVPictureInPictureControllerContentSource", b"new"), + ("AVPlaybackSpeed", b"init"), + ("AVPlaybackSpeed", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["AVKit._metadata"] diff --git a/pyobjc-framework-AVRouting/Lib/AVRouting/__init__.py b/pyobjc-framework-AVRouting/Lib/AVRouting/__init__.py index d6b7c301bf..a3181fa3be 100644 --- a/pyobjc-framework-AVRouting/Lib/AVRouting/__init__.py +++ b/pyobjc-framework-AVRouting/Lib/AVRouting/__init__.py @@ -28,6 +28,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("AVCustomRoutingPartialIP", b"init"), + ("AVCustomRoutingPartialIP", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["AVRouting._metadata"] diff --git a/pyobjc-framework-Accessibility/Lib/Accessibility/__init__.py b/pyobjc-framework-Accessibility/Lib/Accessibility/__init__.py index 3ae783fa67..b928b01cd0 100644 --- a/pyobjc-framework-Accessibility/Lib/Accessibility/__init__.py +++ b/pyobjc-framework-Accessibility/Lib/Accessibility/__init__.py @@ -39,6 +39,26 @@ def _setup(): except objc.error: pass + for cls, sel in ( + ("AXNumericDataAxisDescriptor", b"init"), + ("AXNumericDataAxisDescriptor", b"new"), + ("AXCategoricalDataAxisDescriptor", b"init"), + ("AXCategoricalDataAxisDescriptor", b"new"), + ("AXDataPointValue", b"init"), + ("AXDataPointValue", b"new"), + ("AXDataPoint", b"init"), + ("AXDataPoint", b"new"), + ("AXDataSeriesDescriptor", b"init"), + ("AXDataSeriesDescriptor", b"new"), + ("AXChartDescriptor", b"init"), + ("AXChartDescriptor", b"new"), + ("AXCustomContent", b"init"), + ("AXCustomContent", b"new"), + ("AXBrailleMap", b"init"), + ("AXBrailleMap", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Accessibility._metadata"] diff --git a/pyobjc-framework-AppTrackingTransparency/Lib/AppTrackingTransparency/__init__.py b/pyobjc-framework-AppTrackingTransparency/Lib/AppTrackingTransparency/__init__.py index e6eb73775a..20d2ce50fb 100644 --- a/pyobjc-framework-AppTrackingTransparency/Lib/AppTrackingTransparency/__init__.py +++ b/pyobjc-framework-AppTrackingTransparency/Lib/AppTrackingTransparency/__init__.py @@ -28,6 +28,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("ATTrackingManager", b"init"), + ("ATTrackingManager", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["AppTrackingTransparency._metadata"] diff --git a/pyobjc-framework-AudioVideoBridging/Lib/AudioVideoBridging/__init__.py b/pyobjc-framework-AudioVideoBridging/Lib/AudioVideoBridging/__init__.py index 017c52d272..6abc172d52 100644 --- a/pyobjc-framework-AudioVideoBridging/Lib/AudioVideoBridging/__init__.py +++ b/pyobjc-framework-AudioVideoBridging/Lib/AudioVideoBridging/__init__.py @@ -31,6 +31,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("AVB1722ControlInterface", b"init"), + ("AVBInterface", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["AudioVideoBridging._metadata"] diff --git a/pyobjc-framework-AuthenticationServices/Lib/AuthenticationServices/__init__.py b/pyobjc-framework-AuthenticationServices/Lib/AuthenticationServices/__init__.py index c41ffe1e8a..27d7f4158a 100644 --- a/pyobjc-framework-AuthenticationServices/Lib/AuthenticationServices/__init__.py +++ b/pyobjc-framework-AuthenticationServices/Lib/AuthenticationServices/__init__.py @@ -28,6 +28,78 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("ASAuthorizationProviderExtensionLoginManager", b"init"), + ("ASAuthorizationProviderExtensionLoginManager", b"new"), + ("ASAuthorizationPublicKeyCredentialLargeBlobRegistrationInput", b"init"), + ("ASAuthorizationPublicKeyCredentialLargeBlobRegistrationInput", b"new"), + ("ASAuthorizationSecurityKeyPublicKeyCredentialAssertion", b"init"), + ("ASAuthorizationSecurityKeyPublicKeyCredentialAssertion", b"new"), + ("ASAuthorizationPlatformPublicKeyCredentialAssertion", b"init"), + ("ASAuthorizationPlatformPublicKeyCredentialAssertion", b"new"), + ("ASPasskeyCredentialIdentity", b"init"), + ( + "ASCredentialProviderExtensionContext", + b"completeRequestReturningItems:completionHandler:", + ), + ("ASAuthorizationWebBrowserPlatformPublicKeyCredential", b"init"), + ("ASAuthorizationWebBrowserPlatformPublicKeyCredential", b"new"), + ("ASAuthorization", b"init"), + ("ASAuthorization", b"new"), + ("ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest", b"init"), + ("ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest", b"new"), + ("ASAuthorizationPublicKeyCredentialLargeBlobAssertionInput", b"init"), + ("ASAuthorizationPublicKeyCredentialLargeBlobAssertionInput", b"new"), + ("ASAuthorizationSecurityKeyPublicKeyCredentialProvider", b"init"), + ("ASAuthorizationSecurityKeyPublicKeyCredentialProvider", b"new"), + ("ASAuthorizationPlatformPublicKeyCredentialAssertionRequest", b"init"), + ("ASAuthorizationPlatformPublicKeyCredentialAssertionRequest", b"new"), + ("ASPasskeyCredentialRequest", b"init"), + ("ASPublicKeyCredentialClientData", b"init"), + ("ASPublicKeyCredentialClientData", b"new"), + ("ASWebAuthenticationSessionCallback", b"init"), + ("ASWebAuthenticationSessionCallback", b"new"), + ("ASSettingsHelper", b"init"), + ("ASSettingsHelper", b"new"), + ("ASCredentialIdentityStore", b"init"), + ("ASAuthorizationRequest", b"init"), + ("ASAuthorizationRequest", b"new"), + ("ASPasskeyCredentialRequestParameters", b"init"), + ("ASPasswordCredentialRequest", b"init"), + ("ASAuthorizationAppleIDCredential", b"init"), + ("ASAuthorizationAppleIDCredential", b"new"), + ("ASAuthorizationController", b"init"), + ("ASAuthorizationController", b"new"), + ("ASAuthorizationSecurityKeyPublicKeyCredentialRegistrationRequest", b"init"), + ("ASAuthorizationSecurityKeyPublicKeyCredentialRegistrationRequest", b"new"), + ("ASWebAuthenticationSession", b"init"), + ("ASWebAuthenticationSession", b"new"), + ("ASAuthorizationSingleSignOnProvider", b"init"), + ("ASAuthorizationSingleSignOnProvider", b"new"), + ("ASAuthorizationPlatformPublicKeyCredentialProvider", b"init"), + ("ASAuthorizationPlatformPublicKeyCredentialProvider", b"new"), + ("ASWebAuthenticationSessionRequest", b"init"), + ("ASWebAuthenticationSessionRequest", b"new"), + ("ASAuthorizationProviderExtensionLoginConfiguration", b"init"), + ("ASAuthorizationProviderExtensionLoginConfiguration", b"new"), + ("ASAuthorizationPlatformPublicKeyCredentialDescriptor", b"init"), + ("ASAuthorizationPlatformPublicKeyCredentialDescriptor", b"new"), + ("ASAuthorizationSecurityKeyPublicKeyCredentialDescriptor", b"init"), + ("ASAuthorizationSecurityKeyPublicKeyCredentialDescriptor", b"new"), + ("ASAuthorizationProviderExtensionUserLoginConfiguration", b"init"), + ("ASAuthorizationProviderExtensionUserLoginConfiguration", b"new"), + ("ASAuthorizationSingleSignOnCredential", b"init"), + ("ASAuthorizationSingleSignOnCredential", b"new"), + ("ASPasswordCredentialIdentity", b"init"), + ("ASAuthorizationPlatformPublicKeyCredentialRegistration", b"init"), + ("ASAuthorizationPlatformPublicKeyCredentialRegistration", b"new"), + ("ASAuthorizationPublicKeyCredentialLargeBlobAssertionOutput", b"init"), + ("ASAuthorizationPublicKeyCredentialLargeBlobAssertionOutput", b"new"), + ("ASAuthorizationPublicKeyCredentialParameters", b"init"), + ("ASAuthorizationPublicKeyCredentialParameters", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["AuthenticationServices._metadata"] diff --git a/pyobjc-framework-AutomaticAssessmentConfiguration/Lib/AutomaticAssessmentConfiguration/__init__.py b/pyobjc-framework-AutomaticAssessmentConfiguration/Lib/AutomaticAssessmentConfiguration/__init__.py index 2ea417d51f..ca27964cf0 100644 --- a/pyobjc-framework-AutomaticAssessmentConfiguration/Lib/AutomaticAssessmentConfiguration/__init__.py +++ b/pyobjc-framework-AutomaticAssessmentConfiguration/Lib/AutomaticAssessmentConfiguration/__init__.py @@ -31,6 +31,14 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("AEAssessmentApplication", b"init"), + ("AEAssessmentApplication", b"new"), + ("AEAssessmentSession", b"init"), + ("AEAssessmentSession", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["AutomaticAssessmentConfiguration._metadata"] diff --git a/pyobjc-framework-BackgroundAssets/Lib/BackgroundAssets/__init__.py b/pyobjc-framework-BackgroundAssets/Lib/BackgroundAssets/__init__.py index 0f96914f0c..9d71ce04ba 100644 --- a/pyobjc-framework-BackgroundAssets/Lib/BackgroundAssets/__init__.py +++ b/pyobjc-framework-BackgroundAssets/Lib/BackgroundAssets/__init__.py @@ -28,6 +28,18 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("BADownloadManager", b"init"), + ("BADownloadManager", b"new"), + ("BAURLDownload", b"init"), + ("BAURLDownload", b"new"), + ("BAAppExtensionInfo", b"init"), + ("BAAppExtensionInfo", b"new"), + ("BADownload", b"init"), + ("BADownload", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["BackgroundAssets._metadata"] diff --git a/pyobjc-framework-BrowserEngineKit/Lib/BrowserEngineKit/__init__.py b/pyobjc-framework-BrowserEngineKit/Lib/BrowserEngineKit/__init__.py index 6a2e4d9a48..86fca9e66e 100644 --- a/pyobjc-framework-BrowserEngineKit/Lib/BrowserEngineKit/__init__.py +++ b/pyobjc-framework-BrowserEngineKit/Lib/BrowserEngineKit/__init__.py @@ -28,6 +28,45 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("BETextDocumentRequest", b"init"), + ("BETextDocumentRequest", b"new"), + ("BELayerHierarchyHandle", b"init"), + ("BELayerHierarchyHandle", b"new"), + ("BEAutoFillTextSuggestion", b"init"), + ("BEAutoFillTextSuggestion", b"new"), + ("BEKeyEntryContext", b"init"), + ("BEKeyEntryContext", b"new"), + ( + "BEContextMenuConfiguration", + b"configurationWithIdentifier:previewProvider:actionProvider:", + ), + ("BETextAlternatives", b"init"), + ("BETextAlternatives", b"new"), + ("BEWebAppManifest", b"init"), + ("BEMediaEnvironment", b"init"), + ("BEMediaEnvironment", b"new"), + ("BERenderingProcess", b"init"), + ("BERenderingProcess", b"new"), + ("BETextSuggestion", b"init"), + ("BETextSuggestion", b"new"), + ("BELayerHierarchyHostingTransactionCoordinator", b"init"), + ("BELayerHierarchyHostingTransactionCoordinator", b"new"), + ("BELayerHierarchy", b"init"), + ("BELayerHierarchy", b"new"), + ("BENetworkingProcess", b"init"), + ("BENetworkingProcess", b"new"), + ("BEScrollViewScrollUpdate", b"init"), + ("BEScrollViewScrollUpdate", b"new"), + ("BEKeyEntry", b"init"), + ("BEKeyEntry", b"new"), + ("BEWebContentProcess", b"init"), + ("BEWebContentProcess", b"new"), + ("BETextDocumentContext", b"init"), + ("BETextDocumentContext", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["BrowserEngineKit._metadata"] diff --git a/pyobjc-framework-CallKit/Lib/CallKit/__init__.py b/pyobjc-framework-CallKit/Lib/CallKit/__init__.py index 68366d8656..a060424110 100644 --- a/pyobjc-framework-CallKit/Lib/CallKit/__init__.py +++ b/pyobjc-framework-CallKit/Lib/CallKit/__init__.py @@ -28,6 +28,24 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CXProvider", b"init"), + ("CXProvider", b"new"), + ("CXCall", b"init"), + ( + "CXCallDirectoryExtensionContext", + b"completeRequestReturningItems:completionHandler:", + ), + ("CXSetMutedCallAction", b"initWithCallUUID:"), + ("CXPlayDTMFCallAction", b"initWithCallUUID:"), + ("CXSetHeldCallAction", b"initWithCallUUID:"), + ("CXSetGroupCallAction", b"initWithCallUUID:"), + ("CXStartCallAction", b"initWithCallUUID:"), + ("CXCallAction", b"init"), + ("CXHandle", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CallKit._metadata"] diff --git a/pyobjc-framework-Cinematic/Lib/Cinematic/__init__.py b/pyobjc-framework-Cinematic/Lib/Cinematic/__init__.py index 253e85f6c8..6428ebf9bc 100644 --- a/pyobjc-framework-Cinematic/Lib/Cinematic/__init__.py +++ b/pyobjc-framework-Cinematic/Lib/Cinematic/__init__.py @@ -32,6 +32,32 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CNDetection", b"init"), + ("CNDetection", b"new"), + ("CNScript", b"init"), + ("CNScript", b"new"), + ("CNScriptChanges", b"init"), + ("CNScriptChanges", b"new"), + ("CNScriptFrame", b"init"), + ("CNScriptFrame", b"new"), + ("CNDetectionTrack", b"init"), + ("CNDetectionTrack", b"new"), + ("CNDecision", b"init"), + ("CNDecision", b"new"), + ("CNObjectTracker", b"init"), + ("CNObjectTracker", b"new"), + ("CNAssetInfo", b"init"), + ("CNAssetInfo", b"new"), + ("CNRenderingSessionAttributes", b"init"), + ("CNRenderingSessionAttributes", b"new"), + ("CNRenderingSessionFrameAttributes", b"init"), + ("CNRenderingSessionFrameAttributes", b"new"), + ("CNRenderingSession", b"init"), + ("CNRenderingSession", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Cinematic._metadata"] diff --git a/pyobjc-framework-ClassKit/Lib/ClassKit/__init__.py b/pyobjc-framework-ClassKit/Lib/ClassKit/__init__.py index 3b261d9535..46bd1504d0 100644 --- a/pyobjc-framework-ClassKit/Lib/ClassKit/__init__.py +++ b/pyobjc-framework-ClassKit/Lib/ClassKit/__init__.py @@ -31,6 +31,18 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CLSObject", b"init"), + ("CLSObject", b"new"), + ("CLSContext", b"init"), + ("CLSContext", b"new"), + ("CLSDataStore", b"init"), + ("CLSDataStore", b"new"), + ("CLSActivityItem", b"init"), + ("CLSActivityItem", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["ClassKit._metadata"] diff --git a/pyobjc-framework-CloudKit/Lib/CloudKit/__init__.py b/pyobjc-framework-CloudKit/Lib/CloudKit/__init__.py index 628c6cf021..30ea2904a4 100644 --- a/pyobjc-framework-CloudKit/Lib/CloudKit/__init__.py +++ b/pyobjc-framework-CloudKit/Lib/CloudKit/__init__.py @@ -36,6 +36,79 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CKDatabase", b"init"), + ("CKDatabase", b"new"), + ("CKNotification", b"init"), + ("CKNotification", b"new"), + ("CKServerChangeToken", b"init"), + ("CKServerChangeToken", b"new"), + ("CKQuery", b"init"), + ("CKQuery", b"new"), + ("CKReference", b"init"), + ("CKReference", b"new"), + ("CKShareParticipant", b"init"), + ("CKShareParticipant", b"new"), + ("CKRecordZoneID", b"init"), + ("CKRecordZoneID", b"new"), + ("CKSystemSharingUIObserver", b"init"), + ("CKSystemSharingUIObserver", b"new"), + ("CKSyncEngineState", b"init"), + ("CKSyncEngineState", b"new"), + ("CKSyncEngineStateSerialization", b"init"), + ("CKSyncEngineStateSerialization", b"new"), + ("CKSyncEnginePendingRecordZoneChange", b"init"), + ("CKSyncEnginePendingRecordZoneChange", b"new"), + ("CKSyncEnginePendingDatabaseChange", b"init"), + ("CKSyncEnginePendingDatabaseChange", b"new"), + ("CKSyncEngineConfiguration", b"init"), + ("CKSyncEngineConfiguration", b"new"), + ("CKSyncEngineEvent", b"init"), + ("CKSyncEngineEvent", b"new"), + ("CKSyncEngineFetchedRecordDeletion", b"init"), + ("CKSyncEngineFetchedRecordDeletion", b"new"), + ("CKSyncEngineFetchedZoneDeletion", b"init"), + ("CKSyncEngineFetchedZoneDeletion", b"new"), + ("CKSyncEngineFailedRecordSave", b"init"), + ("CKSyncEngineFailedRecordSave", b"new"), + ("CKSyncEngineFailedZoneSave", b"init"), + ("CKSyncEngineFailedZoneSave", b"new"), + ("CKRecordZone", b"init"), + ("CKRecordZone", b"new"), + ("CKRecordID", b"init"), + ("CKRecordID", b"new"), + ("CKShare", b"init"), + ("CKShare", b"new"), + ("CKShare", b"initWithRecordType:"), + ("CKShare", b"initWithRecordType:recordID:"), + ("CKShare", b"initWithRecordType:zoneID:"), + ("CKLocationSortDescriptor", b"init"), + ("CKLocationSortDescriptor", b"new"), + ("CKQueryCursor", b"init"), + ("CKQueryCursor", b"new"), + ("CKSubscription", b"init"), + ("CKSubscription", b"new"), + ("CKRecord", b"init"), + ("CKRecord", b"new"), + ("CKContainer", b"init"), + ("CKContainer", b"new"), + ("CKAsset", b"init"), + ("CKAsset", b"new"), + ("CKUserIdentityLookupInfo", b"init"), + ("CKUserIdentityLookupInfo", b"new"), + ("CKSyncEngineRecordZoneChangeBatch", b"init"), + ("CKSyncEngineRecordZoneChangeBatch", b"new"), + ("CKUserIdentity", b"init"), + ("CKUserIdentity", b"new"), + ("CKSyncEngine", b"init"), + ("CKSyncEngine", b"new"), + ("CKSyncEngineFetchChangesContext", b"init"), + ("CKSyncEngineFetchChangesContext", b"new"), + ("CKSyncEngineSendChangesContext", b"init"), + ("CKSyncEngineSendChangesContext", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CloudKit._metadata"] for clsname in ( diff --git a/pyobjc-framework-Cocoa/Lib/AppKit/__init__.py b/pyobjc-framework-Cocoa/Lib/AppKit/__init__.py index 0c1b0ed786..0b8a13942a 100644 --- a/pyobjc-framework-Cocoa/Lib/AppKit/__init__.py +++ b/pyobjc-framework-Cocoa/Lib/AppKit/__init__.py @@ -33,6 +33,75 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("NSTouchBarItem", b"init"), + ("NSTextFieldCell", b"initImageCell:"), + ("NSTextViewportLayoutController", b"init"), + ("NSTextViewportLayoutController", b"new"), + ("NSFormCell", b"initImageCell:"), + ("NSTextListElement", b"initWithAttributedString:"), + ("NSTextSelectionNavigation", b"init"), + ("NSTextSelectionNavigation", b"new"), + ("NSTextRange", b"init"), + ("NSTextRange", b"new"), + ("NSTextCheckingController", b"init"), + ("NSFontAssetRequest", b"init"), + ("NSDictionaryControllerKeyValuePair", b"init"), + ("NSSharingService", b"init"), + ("NSSharingServicePicker", b"init"), + ("NSMenuItemBadge", b"init"), + ("NSTextInputContext", b"init"), + ("NSAccessibilityCustomRotorItemResult", b"init"), + ("NSAccessibilityCustomRotorItemResult", b"new"), + ("NSWindow", b"initWithCoder:"), + ("NSCollectionViewDiffableDataSource", b"init"), + ("NSCollectionViewDiffableDataSource", b"new"), + ("NSDraggingImageComponent", b"init"), + ("NSDraggingItem", b"init"), + ("NSSearchToolbarItem", b"view"), + ("NSTableViewDiffableDataSource", b"init"), + ("NSTableViewDiffableDataSource", b"new"), + ("NSSearchFieldCell", b"initImageCell:"), + ("NSDataAsset", b"init"), + ("NSRulerMarker", b"init"), + ("NSTextSelection", b"init"), + ("NSDatePickerCell", b"initWithImageCell:"), + ("NSCollectionViewCompositionalLayout", b"init"), + ("NSCollectionViewCompositionalLayout", b"new"), + ("NSCollectionLayoutSection", b"init"), + ("NSCollectionLayoutSection", b"new"), + ("NSCollectionLayoutItem", b"init"), + ("NSCollectionLayoutItem", b"new"), + ("NSCollectionLayoutGroupCustomItem", b"init"), + ("NSCollectionLayoutGroupCustomItem", b"new"), + ("NSCollectionLayoutGroup", b"init"), + ("NSCollectionLayoutGroup", b"new"), + ("NSCollectionLayoutDimension", b"init"), + ("NSCollectionLayoutDimension", b"new"), + ("NSCollectionLayoutSize", b"init"), + ("NSCollectionLayoutSize", b"new"), + ("NSCollectionLayoutSpacing", b"init"), + ("NSCollectionLayoutSpacing", b"new"), + ("NSCollectionLayoutEdgeSpacing", b"init"), + ("NSCollectionLayoutEdgeSpacing", b"new"), + ("NSCollectionLayoutSupplementaryItem", b"init"), + ("NSCollectionLayoutSupplementaryItem", b"new"), + ("NSCollectionLayoutBoundarySupplementaryItem", b"init"), + ("NSCollectionLayoutBoundarySupplementaryItem", b"new"), + ("NSCollectionLayoutDecorationItem", b"init"), + ("NSCollectionLayoutDecorationItem", b"new"), + ("NSCollectionLayoutAnchor", b"init"), + ("NSCollectionLayoutAnchor", b"new"), + ("NSTextLineFragment", b"init"), + ("NSPreviewRepresentingActivityItem", b"init"), + ("NSPreviewRepresentingActivityItem", b"new"), + ("NSTextLayoutFragment", b"init"), + ("NSBindingSelectionMarker", b"init"), + ("NSTextAttachmentViewProvider", b"init"), + ("NSTextAttachmentViewProvider", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["AppKit._metadata"] def fontdescriptor_get(self, key, default=None): diff --git a/pyobjc-framework-Cocoa/Lib/Foundation/__init__.py b/pyobjc-framework-Cocoa/Lib/Foundation/__init__.py index a08b729ad0..f326d682c0 100644 --- a/pyobjc-framework-Cocoa/Lib/Foundation/__init__.py +++ b/pyobjc-framework-Cocoa/Lib/Foundation/__init__.py @@ -34,6 +34,21 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("NSPresentationIntent", b"init"), + ("NSURLSessionWebSocketMessage", b"init"), + ("NSURLSessionWebSocketMessage", b"new"), + ("NSURLSessionWebSocketTask", b"init"), + ("NSURLSessionWebSocketTask", b"new"), + ("NSInflectionRule", b"init"), + ("NSMorphologyPronoun", b"init"), + ("NSMorphologyPronoun", b"new"), + ("NSTermOfAddress", b"init"), + ("NSTermOfAddress", b"new"), + ("NSObject", b"poseAsClass:"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Foundation._metadata"] objc.addConvenienceForClass( diff --git a/pyobjc-framework-Contacts/Lib/Contacts/__init__.py b/pyobjc-framework-Contacts/Lib/Contacts/__init__.py index 50338c5f3a..4bb8c686d0 100644 --- a/pyobjc-framework-Contacts/Lib/Contacts/__init__.py +++ b/pyobjc-framework-Contacts/Lib/Contacts/__init__.py @@ -36,6 +36,14 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CNFetchResult", b"init"), + ("CNFetchResult", b"new"), + ("CNContactFetchRequest", b"init"), + ("CNContactFetchRequest", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Contacts._metadata"] diff --git a/pyobjc-framework-CoreBluetooth/Lib/CoreBluetooth/__init__.py b/pyobjc-framework-CoreBluetooth/Lib/CoreBluetooth/__init__.py index d66eb49341..e07a17380c 100644 --- a/pyobjc-framework-CoreBluetooth/Lib/CoreBluetooth/__init__.py +++ b/pyobjc-framework-CoreBluetooth/Lib/CoreBluetooth/__init__.py @@ -31,6 +31,14 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CBManager", b"init"), + ("CBPeer", b"init"), + ("CBATTRequest", b"init"), + ("CBAttribute", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreBluetooth._metadata"] diff --git a/pyobjc-framework-CoreData/Lib/CoreData/__init__.py b/pyobjc-framework-CoreData/Lib/CoreData/__init__.py index a36476270d..b35605d827 100644 --- a/pyobjc-framework-CoreData/Lib/CoreData/__init__.py +++ b/pyobjc-framework-CoreData/Lib/CoreData/__init__.py @@ -31,6 +31,24 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("NSLightweightMigrationStage", b"init"), + ("NSPersistentCloudKitContainerEvent", b"init"), + ("NSPersistentCloudKitContainerEvent", b"new"), + ("NSPersistentCloudKitContainerOptions", b"init"), + ("NSCoreDataCoreSpotlightDelegate", b"init"), + ("NSManagedObjectModelReference", b"init"), + ("NSStagedMigrationManager", b"init"), + ("NSBatchDeleteRequest", b"init"), + ("NSPersistentCloudKitContainerEventResult", b"init"), + ("NSPersistentCloudKitContainerEventResult", b"new"), + ("NSPersistentStore", b"init"), + ("NSMergeConflict", b"init"), + ("NSMergePolicy", b"init"), + ("NSCustomMigrationStage", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreData._metadata"] diff --git a/pyobjc-framework-CoreHaptics/Lib/CoreHaptics/__init__.py b/pyobjc-framework-CoreHaptics/Lib/CoreHaptics/__init__.py index 928a053351..8cb08f0156 100644 --- a/pyobjc-framework-CoreHaptics/Lib/CoreHaptics/__init__.py +++ b/pyobjc-framework-CoreHaptics/Lib/CoreHaptics/__init__.py @@ -28,6 +28,17 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CHHapticPattern", b"init"), + ("CHHapticEvent", b"init"), + ("CHHapticEngine", b"init"), + ("CHHapticEventParameter", b"init"), + ("CHHapticDynamicParameter", b"init"), + ("CHHapticParameterCurveControlPoint", b"init"), + ("CHHapticParameterCurve", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreHaptics._metadata"] diff --git a/pyobjc-framework-CoreLocation/Lib/CoreLocation/__init__.py b/pyobjc-framework-CoreLocation/Lib/CoreLocation/__init__.py index ac7390e8ea..3d1d3774e7 100644 --- a/pyobjc-framework-CoreLocation/Lib/CoreLocation/__init__.py +++ b/pyobjc-framework-CoreLocation/Lib/CoreLocation/__init__.py @@ -31,6 +31,22 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CLMonitor", b"init"), + ("CLMonitor", b"new"), + ("CLMonitoringRecord", b"init"), + ("CLMonitoringRecord", b"new"), + ("CLMonitoringEvent", b"init"), + ("CLMonitoringEvent", b"new"), + ("CLBackgroundActivitySession", b"init"), + ("CLBackgroundActivitySession", b"new"), + ("CLCondition", b"init"), + ("CLCondition", b"new"), + ("CLLocationUpdater", b"init"), + ("CLLocationUpdater", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreLocation._metadata"] diff --git a/pyobjc-framework-CoreMIDI/Lib/CoreMIDI/__init__.py b/pyobjc-framework-CoreMIDI/Lib/CoreMIDI/__init__.py index 06a28a29a7..bdaabe037d 100644 --- a/pyobjc-framework-CoreMIDI/Lib/CoreMIDI/__init__.py +++ b/pyobjc-framework-CoreMIDI/Lib/CoreMIDI/__init__.py @@ -32,6 +32,16 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("MIDICIDeviceInfo", b"init"), + ("MIDICIProfile", b"init"), + ("MIDICIProfileState", b"init"), + ("MIDICIDiscoveredNode", b"init"), + ("MIDICISession", b"init"), + ("MIDICIResponder", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreMIDI._metadata"] diff --git a/pyobjc-framework-CoreML/Lib/CoreML/__init__.py b/pyobjc-framework-CoreML/Lib/CoreML/__init__.py index b618223c08..c59a288518 100644 --- a/pyobjc-framework-CoreML/Lib/CoreML/__init__.py +++ b/pyobjc-framework-CoreML/Lib/CoreML/__init__.py @@ -52,6 +52,67 @@ def _setup(): except objc.error: pass + for cls, sel in ( + ("MLMetricKey", b"init"), + ("MLMetricKey", b"new"), + ("MLModelStructureProgramValue", b"init"), + ("MLModelStructureProgramValue", b"new"), + ("MLGPUComputeDevice", b"init"), + ("MLGPUComputeDevice", b"new"), + ("MLComputePlanDeviceUsage", b"init"), + ("MLComputePlanDeviceUsage", b"new"), + ("MLCPUComputeDevice", b"init"), + ("MLCPUComputeDevice", b"new"), + ("MLModelStructure", b"init"), + ("MLModelStructure", b"new"), + ("MLUpdateProgressHandlers", b"init"), + ("MLUpdateProgressHandlers", b"new"), + ("MLModelCollection", b"init"), + ("MLModelCollection", b"new"), + ("MLModelStructureProgramNamedValueType", b"init"), + ("MLModelStructureProgramNamedValueType", b"new"), + ("MLUpdateTask", b"init"), + ("MLUpdateTask", b"new"), + ("MLModelCollectionEntry", b"init"), + ("MLModelCollectionEntry", b"new"), + ("MLModelStructureProgramFunction", b"init"), + ("MLModelStructureProgramFunction", b"new"), + ("MLModelStructureProgram", b"init"), + ("MLModelStructureProgram", b"new"), + ("MLComputePlan", b"init"), + ("MLComputePlan", b"new"), + ("MLParameterKey", b"init"), + ("MLParameterKey", b"new"), + ("MLModelStructureProgramBinding", b"init"), + ("MLModelStructureProgramBinding", b"new"), + ("MLModelAsset", b"init"), + ("MLModelAsset", b"new"), + ("MLModelStructureProgramArgument", b"init"), + ("MLModelStructureProgramArgument", b"new"), + ("MLModelStructureProgramOperation", b"init"), + ("MLModelStructureProgramOperation", b"new"), + ("MLComputePlanCost", b"init"), + ("MLComputePlanCost", b"new"), + ("MLModelStructureNeuralNetwork", b"init"), + ("MLModelStructureNeuralNetwork", b"new"), + ("MLNeuralEngineComputeDevice", b"init"), + ("MLNeuralEngineComputeDevice", b"new"), + ("MLTask", b"init"), + ("MLTask", b"new"), + ("MLModelStructureNeuralNetworkLayer", b"init"), + ("MLModelStructureNeuralNetworkLayer", b"new"), + ("MLKey", b"init"), + ("MLKey", b"new"), + ("MLModelStructureProgramBlock", b"init"), + ("MLModelStructureProgramBlock", b"new"), + ("MLImageConstraint", b"init"), + ("MLModelStructurePipeline", b"init"), + ("MLModelStructurePipeline", b"new"), + ("MLModelStructureProgramValueType", b"init"), + ("MLModelStructureProgramValueType", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreML._metadata"] diff --git a/pyobjc-framework-CoreMediaIO/Lib/CoreMediaIO/__init__.py b/pyobjc-framework-CoreMediaIO/Lib/CoreMediaIO/__init__.py index d89fc242fb..1e5d395203 100644 --- a/pyobjc-framework-CoreMediaIO/Lib/CoreMediaIO/__init__.py +++ b/pyobjc-framework-CoreMediaIO/Lib/CoreMediaIO/__init__.py @@ -31,6 +31,34 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CMIOExtensionStreamProperties", b"init"), + ("CMIOExtensionStreamProperties", b"new"), + ("CMIOExtensionStream", b"init"), + ("CMIOExtensionStream", b"new"), + ("CMIOExtensionPropertyAttributes", b"init"), + ("CMIOExtensionPropertyAttributes", b"new"), + ("CMIOExtensionPropertyState", b"init"), + ("CMIOExtensionPropertyState", b"new"), + ("CMIOExtensionStreamCustomClockConfiguration", b"init"), + ("CMIOExtensionStreamCustomClockConfiguration", b"new"), + ("CMIOExtensionStreamFormat", b"init"), + ("CMIOExtensionStreamFormat", b"new"), + ("CMIOExtensionScheduledOutput", b"init"), + ("CMIOExtensionScheduledOutput", b"new"), + ("CMIOExtensionClient", b"init"), + ("CMIOExtensionClient", b"new"), + ("CMIOExtensionDeviceProperties", b"init"), + ("CMIOExtensionDeviceProperties", b"new"), + ("CMIOExtensionDevice", b"init"), + ("CMIOExtensionDevice", b"new"), + ("CMIOExtensionProviderProperties", b"init"), + ("CMIOExtensionProviderProperties", b"new"), + ("CMIOExtensionProvider", b"init"), + ("CMIOExtensionProvider", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreMediaIO._metadata"] diff --git a/pyobjc-framework-CoreMotion/Lib/CoreMotion/__init__.py b/pyobjc-framework-CoreMotion/Lib/CoreMotion/__init__.py index 45ba19edd7..b1436e1f82 100644 --- a/pyobjc-framework-CoreMotion/Lib/CoreMotion/__init__.py +++ b/pyobjc-framework-CoreMotion/Lib/CoreMotion/__init__.py @@ -31,6 +31,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("CMFallDetectionEvent", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreMotion._metadata"] diff --git a/pyobjc-framework-CoreSpotlight/Lib/CoreSpotlight/__init__.py b/pyobjc-framework-CoreSpotlight/Lib/CoreSpotlight/__init__.py index fcbe733a3c..0a5781d10c 100644 --- a/pyobjc-framework-CoreSpotlight/Lib/CoreSpotlight/__init__.py +++ b/pyobjc-framework-CoreSpotlight/Lib/CoreSpotlight/__init__.py @@ -31,6 +31,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("CSSearchQuery", b"init"), + ("CSCustomAttributeKey", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CoreSpotlight._metadata"] diff --git a/pyobjc-framework-CryptoTokenKit/Lib/CryptoTokenKit/__init__.py b/pyobjc-framework-CryptoTokenKit/Lib/CryptoTokenKit/__init__.py index 7a6efc06eb..b19791af6f 100644 --- a/pyobjc-framework-CryptoTokenKit/Lib/CryptoTokenKit/__init__.py +++ b/pyobjc-framework-CryptoTokenKit/Lib/CryptoTokenKit/__init__.py @@ -31,6 +31,25 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("TKSmartCardToken", b"initWithTokenDriver:instanceID:"), + ("TKTokenWatcherTokenInfo", b"init"), + ("TKTokenWatcherTokenInfo", b"new"), + ("TKTokenKeychainItem", b"init"), + ("TKTokenKeychainCertificate", b"initWithTokenDriver:instanceID:"), + ("TKTokenKeychainKey", b"initWithTokenDriver:instanceID:"), + ("TKTokenKeychainContents", b"init"), + ("TKTokenDriverConfiguration", b"init"), + ("TKTokenDriverConfiguration", b"new"), + ("TKTokenConfiguration", b"init"), + ("TKTokenConfiguration", b"new"), + ("TKTokenKeyAlgorithm", b"init"), + ("TKTokenSession", b"init"), + ("TKToken", b"init"), + ("TKTLVRecord", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["CryptoTokenKit._metadata"] diff --git a/pyobjc-framework-DataDetection/Lib/DataDetection/__init__.py b/pyobjc-framework-DataDetection/Lib/DataDetection/__init__.py index 5d86256144..28ba2f4761 100644 --- a/pyobjc-framework-DataDetection/Lib/DataDetection/__init__.py +++ b/pyobjc-framework-DataDetection/Lib/DataDetection/__init__.py @@ -28,6 +28,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("DDMatch", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["DataDetection._metadata"] diff --git a/pyobjc-framework-EventKit/Lib/EventKit/__init__.py b/pyobjc-framework-EventKit/Lib/EventKit/__init__.py index 8c3e39742d..f1c241950f 100644 --- a/pyobjc-framework-EventKit/Lib/EventKit/__init__.py +++ b/pyobjc-framework-EventKit/Lib/EventKit/__init__.py @@ -33,6 +33,16 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("EKVirtualConferenceRoomTypeDescriptor", b"init"), + ("EKVirtualConferenceRoomTypeDescriptor", b"new"), + ("EKVirtualConferenceURLDescriptor", b"init"), + ("EKVirtualConferenceURLDescriptor", b"new"), + ("EKVirtualConferenceDescriptor", b"init"), + ("EKVirtualConferenceDescriptor", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["EventKit._metadata"] diff --git a/pyobjc-framework-FileProvider/Lib/FileProvider/__init__.py b/pyobjc-framework-FileProvider/Lib/FileProvider/__init__.py index fabcdbca11..c0988fbd30 100644 --- a/pyobjc-framework-FileProvider/Lib/FileProvider/__init__.py +++ b/pyobjc-framework-FileProvider/Lib/FileProvider/__init__.py @@ -31,6 +31,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("NSFileProviderManager", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["FileProvider._metadata"] diff --git a/pyobjc-framework-FileProviderUI/Lib/FileProviderUI/__init__.py b/pyobjc-framework-FileProviderUI/Lib/FileProviderUI/__init__.py index 6c00fe174c..2ec7c41cfb 100644 --- a/pyobjc-framework-FileProviderUI/Lib/FileProviderUI/__init__.py +++ b/pyobjc-framework-FileProviderUI/Lib/FileProviderUI/__init__.py @@ -28,6 +28,14 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ( + "FPUIActionExtensionContext", + b"completeRequestReturningItems:completionHandler:", + ), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["FileProviderUI._metadata"] diff --git a/pyobjc-framework-GameController/Lib/GameController/__init__.py b/pyobjc-framework-GameController/Lib/GameController/__init__.py index 78880f30f8..88ed0d8199 100644 --- a/pyobjc-framework-GameController/Lib/GameController/__init__.py +++ b/pyobjc-framework-GameController/Lib/GameController/__init__.py @@ -31,6 +31,18 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("GCSteeringWheelElement", b"init"), + ("GCDeviceHaptics", b"init"), + ("GCPhysicalInputElementCollection", b"init"), + ("GCPhysicalInputElementCollection", b"new"), + ("GCDeviceBattery", b"init"), + ("GCDeviceLight", b"init"), + ("GCRacingWheel", b"init"), + ("GCColor", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["GameController._metadata"] diff --git a/pyobjc-framework-GameKit/Lib/GameKit/__init__.py b/pyobjc-framework-GameKit/Lib/GameKit/__init__.py index 4585653751..ee40439909 100644 --- a/pyobjc-framework-GameKit/Lib/GameKit/__init__.py +++ b/pyobjc-framework-GameKit/Lib/GameKit/__init__.py @@ -31,6 +31,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("GKLeaderboardEntry", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["GameKit._metadata"] diff --git a/pyobjc-framework-HealthKit/Lib/HealthKit/__init__.py b/pyobjc-framework-HealthKit/Lib/HealthKit/__init__.py index 430495fe70..05945b6ef0 100644 --- a/pyobjc-framework-HealthKit/Lib/HealthKit/__init__.py +++ b/pyobjc-framework-HealthKit/Lib/HealthKit/__init__.py @@ -31,6 +31,69 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("HKQuantity", b"init"), + ("HKAttachment", b"init"), + ("HKAttachment", b"new"), + ("HKVerifiableClinicalRecord", b"init"), + ("HKVerifiableClinicalRecord", b"new"), + ("HKFHIRVersion", b"init"), + ("HKSeriesBuilder", b"init"), + ("HKObject", b"init"), + ("HKUnit", b"init"), + ("HKQueryAnchor", b"init"), + ("HKAudiogramSensitivityPoint", b"init"), + ("HKSourceRevision", b"init"), + ("HKQuery", b"init"), + ("HKVisionPrescription", b"init"), + ("HKVisionPrescription", b"new"), + ("HKClinicalRecord", b"init"), + ("HKClinicalRecord", b"new"), + ("HKCategorySample", b"init"), + ("HKLiveWorkoutDataSource", b"init"), + ("HKVerifiableClinicalRecordSubject", b"init"), + ("HKVerifiableClinicalRecordSubject", b"new"), + ("HKLiveWorkoutBuilder", b"initWithHealthStore:configuration:device:"), + ("HKWorkoutBuilder", b"init"), + ("HKGlassesPrescription", b"init"), + ("HKGlassesPrescription", b"new"), + ( + "HKGlassesPrescription", + b"prescriptionWithType:dateIssued:expirationDate:device:metadata:", + ), + ("HKWorkoutActivity", b"init"), + ("HKWorkoutActivity", b"new"), + ("HKDevice", b"init"), + ("HKWorkoutSession", b"init"), + ("HKQueryDescriptor", b"init"), + ("HKQueryDescriptor", b"new"), + ("HKContactsPrescription", b"init"), + ("HKContactsPrescription", b"new"), + ( + "HKContactsPrescription", + b"prescriptionWithType:dateIssued:expirationDate:device:metadata:", + ), + ("HKContactsLensSpecification", b"init"), + ("HKContactsLensSpecification", b"new"), + ("HKQuantitySeriesSampleBuilder", b"init"), + ("HKVerifiableClinicalRecordQuery", b"init"), + ("HKVerifiableClinicalRecordQuery", b"new"), + ("HKLensSpecification", b"init"), + ("HKLensSpecification", b"new"), + ("HKFHIRResource", b"init"), + ("HKDeletedObject", b"init"), + ("HKStatistics", b"init"), + ("HKVisionPrism", b"init"), + ("HKVisionPrism", b"new"), + ("HKSource", b"init"), + ("HKObjectType", b"init"), + ("HKWorkoutEvent", b"init"), + ("HKStatisticsCollection", b"init"), + ("HKGlassesLensSpecification", b"init"), + ("HKGlassesLensSpecification", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["HealthKit._metadata"] diff --git a/pyobjc-framework-Intents/Lib/Intents/__init__.py b/pyobjc-framework-Intents/Lib/Intents/__init__.py index 4ba4e45b71..cc5889a43f 100644 --- a/pyobjc-framework-Intents/Lib/Intents/__init__.py +++ b/pyobjc-framework-Intents/Lib/Intents/__init__.py @@ -31,6 +31,52 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("INFocusStatus", b"init"), + ("INTicketedEvent", b"init"), + ("INCallRecordFilter", b"init"), + ("INPaymentMethod", b"init"), + ("INShortcut", b"init"), + ("INShortcut", b"new"), + ("INVoiceShortcut", b"init"), + ("INVoiceShortcut", b"new"), + ("INCallRecord", b"init"), + ("INTrainTrip", b"init"), + ("INIntentDonationMetadata", b"init"), + ("INAirport", b"init"), + ("INGetReservationDetailsIntentResponse", b"init"), + ("INPersonHandle", b"init"), + ("INRentalCar", b"init"), + ("INUnsendMessagesIntentResponse", b"init"), + ("INShareFocusStatusIntentResponse", b"init"), + ("INEditMessageIntentResponse", b"init"), + ("INBoatReservation", b"init"), + ("INBoatTrip", b"init"), + ("INPerson", b"init"), + ("INDateComponentsRange", b"init"), + ("INReservation", b"init"), + ("INObjectCollection", b"init"), + ("INBusTrip", b"init"), + ("INBusReservation", b"init"), + ("INAirportGate", b"init"), + ("INSendMessageIntentResponse", b"init"), + ("INObjectSection", b"init"), + ("INCurrencyAmount", b"init"), + ("INSpeakableString", b"init"), + ("INIntentResolutionResult", b"init"), + ("INAirline", b"init"), + ("INObject", b"init"), + ("INHangUpCallIntentResponse", b"init"), + ("INCallGroup", b"init"), + ("INSeat", b"init"), + ("INAnswerCallIntentResponse", b"init"), + ("INInteraction", b"init"), + ("INReservationAction", b"init"), + ("INVoiceShortcutCenter", b"init"), + ("INVoiceShortcutCenter", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Intents._metadata"] diff --git a/pyobjc-framework-IntentsUI/Lib/IntentsUI/__init__.py b/pyobjc-framework-IntentsUI/Lib/IntentsUI/__init__.py index 14df782e5c..ec74a96261 100644 --- a/pyobjc-framework-IntentsUI/Lib/IntentsUI/__init__.py +++ b/pyobjc-framework-IntentsUI/Lib/IntentsUI/__init__.py @@ -31,6 +31,16 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("INUIAddVoiceShortcutViewController", b"init"), + ("INUIAddVoiceShortcutViewController", b"initWithNibName:bundle:"), + ("INUIEditVoiceShortcutViewController", b"init"), + ("INUIEditVoiceShortcutViewController", b"initWithNibName:bundle:"), + ("INUIAddVoiceShortcutButton", b"init"), + ("INUIAddVoiceShortcutButton", b"initWithFrame:"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["IntentsUI._metadata"] diff --git a/pyobjc-framework-LinkPresentation/Lib/LinkPresentation/__init__.py b/pyobjc-framework-LinkPresentation/Lib/LinkPresentation/__init__.py index 1c6ba94cf9..a992f731f6 100644 --- a/pyobjc-framework-LinkPresentation/Lib/LinkPresentation/__init__.py +++ b/pyobjc-framework-LinkPresentation/Lib/LinkPresentation/__init__.py @@ -28,6 +28,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("LPLinkView", b"initWithCoder:"), + ("LPLinkView", b"encodeWithCoder:"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["LinkPresentation._metadata"] diff --git a/pyobjc-framework-LocalAuthentication/Lib/LocalAuthentication/__init__.py b/pyobjc-framework-LocalAuthentication/Lib/LocalAuthentication/__init__.py index 6a80010e45..e1225284f9 100644 --- a/pyobjc-framework-LocalAuthentication/Lib/LocalAuthentication/__init__.py +++ b/pyobjc-framework-LocalAuthentication/Lib/LocalAuthentication/__init__.py @@ -28,6 +28,20 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("LARightStore", b"init"), + ("LARightStore", b"new"), + ("LAPrivateKey", b"init"), + ("LAPrivateKey", b"new"), + ("LAPublicKey", b"init"), + ("LAPublicKey", b"new"), + ("LASecret", b"init"), + ("LASecret", b"new"), + ("LAPersistedRight", b"init"), + ("LAPersistedRight", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["LocalAuthentication._metadata"] diff --git a/pyobjc-framework-LocalAuthenticationEmbeddedUI/Lib/LocalAuthenticationEmbeddedUI/__init__.py b/pyobjc-framework-LocalAuthenticationEmbeddedUI/Lib/LocalAuthenticationEmbeddedUI/__init__.py index d0eae7e48c..f7cc7db651 100644 --- a/pyobjc-framework-LocalAuthenticationEmbeddedUI/Lib/LocalAuthenticationEmbeddedUI/__init__.py +++ b/pyobjc-framework-LocalAuthenticationEmbeddedUI/Lib/LocalAuthenticationEmbeddedUI/__init__.py @@ -32,6 +32,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("LAAuthenticationView", b"initWithFrame:"), + ("LAAuthenticationView", b"initWithCoder:"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["LocalAuthenticationEmbeddedUI._metadata"] diff --git a/pyobjc-framework-MLCompute/Lib/MLCompute/__init__.py b/pyobjc-framework-MLCompute/Lib/MLCompute/__init__.py index a501dee5b9..a980b8f2be 100644 --- a/pyobjc-framework-MLCompute/Lib/MLCompute/__init__.py +++ b/pyobjc-framework-MLCompute/Lib/MLCompute/__init__.py @@ -28,6 +28,42 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("MLCTensorParameter", b"init"), + ("MLCTensorParameter", b"new"), + ("MLCTensorOptimizerDeviceData", b"init"), + ("MLCTensorOptimizerDeviceData", b"new"), + ("MLCTensor", b"init"), + ("MLCTensor", b"new"), + ("MLCLSTMDescriptor", b"init"), + ("MLCLSTMDescriptor", b"new"), + ("MLCActivationDescriptor", b"init"), + ("MLCActivationDescriptor", b"new"), + ("MLCMatMulDescriptor", b"init"), + ("MLCMatMulDescriptor", b"new"), + ("MLCEmbeddingDescriptor", b"init"), + ("MLCEmbeddingDescriptor", b"new"), + ("MLCInferenceGraph", b"init"), + ("MLCInferenceGraph", b"new"), + ("MLCLayer", b"init"), + ("MLCLayer", b"new"), + ("MLCTensorDescriptor", b"init"), + ("MLCTensorDescriptor", b"new"), + ("MLCYOLOLossDescriptor", b"init"), + ("MLCYOLOLossDescriptor", b"new"), + ("MLCTensorData", b"init"), + ("MLCTensorData", b"new"), + ("MLCPoolingDescriptor", b"init"), + ("MLCPoolingDescriptor", b"new"), + ("MLCOptimizer", b"init"), + ("MLCOptimizer", b"new"), + ("MLCLossDescriptor", b"init"), + ("MLCLossDescriptor", b"new"), + ("MLCMultiheadAttentionDescriptor", b"init"), + ("MLCMultiheadAttentionDescriptor", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["MLCompute._metadata"] diff --git a/pyobjc-framework-MailKit/Lib/MailKit/__init__.py b/pyobjc-framework-MailKit/Lib/MailKit/__init__.py index a50f4598ca..90fd4878f5 100644 --- a/pyobjc-framework-MailKit/Lib/MailKit/__init__.py +++ b/pyobjc-framework-MailKit/Lib/MailKit/__init__.py @@ -28,6 +28,36 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("MEComposeSession", b"init"), + ("MEComposeSession", b"new"), + ("MEDecodedMessage", b"init"), + ("MEDecodedMessage", b"new"), + ("MEMessageAction", b"init"), + ("MEMessageAction", b"new"), + ("MEMessageActionDecision", b"init"), + ("MEMessageActionDecision", b"new"), + ("MEExtensionManager", b"init"), + ("MEExtensionManager", b"new"), + ("MEMessage", b"init"), + ("MEMessage", b"new"), + ("MEMessageSecurityInformation", b"init"), + ("MEMessageSecurityInformation", b"new"), + ("MEMessageSigner", b"init"), + ("MEMessageSigner", b"new"), + ("MEEmailAddress", b"init"), + ("MEEmailAddress", b"new"), + ("MEMessageEncodingResult", b"init"), + ("MEMessageEncodingResult", b"new"), + ("MEOutgoingMessageEncodingStatus", b"init"), + ("MEOutgoingMessageEncodingStatus", b"new"), + ("MEAddressAnnotation", b"init"), + ("MEAddressAnnotation", b"new"), + ("MEDecodedMessageBanner", b"init"), + ("MEDecodedMessageBanner", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["MailKit._metadata"] diff --git a/pyobjc-framework-MapKit/Lib/MapKit/__init__.py b/pyobjc-framework-MapKit/Lib/MapKit/__init__.py index a17358ac53..07548d4258 100644 --- a/pyobjc-framework-MapKit/Lib/MapKit/__init__.py +++ b/pyobjc-framework-MapKit/Lib/MapKit/__init__.py @@ -36,6 +36,22 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("MKMapConfiguration", b"init"), + ("MKMapConfiguration", b"new"), + ("MKLocalPointsOfInterestRequest", b"init"), + ("MKLocalPointsOfInterestRequest", b"new"), + ("MKLookAroundSnapshotter", b"init"), + ("MKLookAroundSnapshotter", b"new"), + ("MKLookAroundSceneRequest", b"init"), + ("MKLookAroundSceneRequest", b"new"), + ("MKLookAroundScene", b"init"), + ("MKLookAroundScene", b"new"), + ("MKClusterAnnotation", b"init"), + ("MKClusterAnnotation", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["MapKit._metadata"] diff --git a/pyobjc-framework-MediaPlayer/Lib/MediaPlayer/__init__.py b/pyobjc-framework-MediaPlayer/Lib/MediaPlayer/__init__.py index a3fca99c22..89c8810065 100644 --- a/pyobjc-framework-MediaPlayer/Lib/MediaPlayer/__init__.py +++ b/pyobjc-framework-MediaPlayer/Lib/MediaPlayer/__init__.py @@ -28,6 +28,30 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("MPMusicPlayerQueueDescriptor", b"init"), + ("MPMusicPlayerQueueDescriptor", b"new"), + ("MPRemoteCommand", b"init"), + ("MPRemoteCommand", b"new"), + ("MPAdTimeRange", b"init"), + ("MPAdTimeRange", b"new"), + ("MPNowPlayingSession", b"init"), + ("MPNowPlayingSession", b"new"), + ("MPMusicPlayerControllerQueue", b"init"), + ("MPMusicPlayerControllerQueue", b"new"), + ("MPMusicPlayerController", b"init"), + ("MPMusicPlayerController", b"new"), + ("MPMediaPlaylistCreationMetadata", b"init"), + ("MPMediaPlaylistCreationMetadata", b"new"), + ("MPRemoteCommandCenter", b"init"), + ("MPRemoteCommandCenter", b"new"), + ("MPNowPlayingInfoCenter", b"init"), + ("MPNowPlayingInfoCenter", b"new"), + ("MPMediaItemArtwork", b"init"), + ("MPMediaItemArtwork", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["MediaPlayer._metadata"] diff --git a/pyobjc-framework-MetalKit/Lib/MetalKit/__init__.py b/pyobjc-framework-MetalKit/Lib/MetalKit/__init__.py index a174ee3672..c9c0890290 100644 --- a/pyobjc-framework-MetalKit/Lib/MetalKit/__init__.py +++ b/pyobjc-framework-MetalKit/Lib/MetalKit/__init__.py @@ -33,6 +33,15 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("MTKMeshBufferAllocator", b"init"), + ("MTKMeshBuffer", b"init"), + ("MTKSubmesh", b"init"), + ("MTKMesh", b"init"), + ("MTKTextureLoader", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["MetalKit._metadata"] diff --git a/pyobjc-framework-MetalPerformanceShaders/Lib/MetalPerformanceShaders/__init__.py b/pyobjc-framework-MetalPerformanceShaders/Lib/MetalPerformanceShaders/__init__.py index 1cc1bb8bbf..7d5c1eac19 100644 --- a/pyobjc-framework-MetalPerformanceShaders/Lib/MetalPerformanceShaders/__init__.py +++ b/pyobjc-framework-MetalPerformanceShaders/Lib/MetalPerformanceShaders/__init__.py @@ -32,6 +32,245 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("MMPSAccelerationStructureGroupTKMeshBufferAllocator", b"init"), + ("MPSAccelerationStructure", b"init"), + ("MPSRayIntersector", b"init"), + ("MPSCNNMultiaryKernel", b"initWithDevice:"), + ("MPSMatrixSum", b"initWithDevice:"), + ("MPSNNGraph", b"initWithDevice:"), + ("MPSNNImageNode", b"init"), + ("MPSNNStateNode", b"init"), + ("MPSNNFilterNode", b"init"), + ("MPSNNGradientFilterNode", b"gradientFilterWithSources:"), + ("MPSNNGradientFilterNode", b"gradientFiltersWithSources:"), + ("MPSNNGradientFilterNode", b"gradientFilterWithSource:"), + ("MPSNNGradientFilterNode", b"gradientFiltersWithSource:"), + ("MPSCNNBinaryConvolutionNode", b"convolutionGradientState"), + ("MPSCNNConvolutionTransposeNode", b"convolutionGradientState"), + ("MPSCNNNeuronNode", b"init"), + ("MPSCNNNeuronPReLUNode", b"initWithSource:"), + ("MPSCNNNeuronPReLUNode", b"nodeWithSource:"), + ("MPSCNNNeuronGradientNode", b"init"), + ("MPSNNBinaryArithmeticNode", b"gradientFilterWithSources:"), + ("MPSCNNLossNode", b"gradientFilterWithSources:"), + ("MPSCNNYOLOLossNode", b"gradientFilterWithSources:"), + ("MPSNNConcatenationNode", b"gradientFilterWithSources:"), + ("MPSNNLossGradientNode", b"gradientFilterWithSources:"), + ("MPSNNInitialGradientNode", b"gradientFilterWithSources:"), + ("MPSCNNArithmeticGradientState", b"init"), + ("MPSCNNArithmetic", b"initWithDevice:"), + ("MPSCNNArithmeticGradient", b"initWithDevice:"), + ("MPSCNNArithmeticGradient", b"initWithDevice:isSecondarySourceFilter:"), + ("MPSCNNUpsampling", b"initWithDevice:"), + ("MPSCNNConvolution", b"initWithDevice:"), + ("MPSCNNConvolutionGradient", b"initWithDevice:"), + ("MPSCNNFullyConnected", b"initWithDevice:"), + ("MPSCNNFullyConnectedGradient", b"initWithDevice:"), + ("MPSCNNConvolutionTranspose", b"initWithDevice:"), + ("MPSCNNConvolutionTransposeGradient", b"initWithDevice:"), + ("MPSCNNBinaryConvolution", b"initWithDevice:"), + ("MPSCNNBinaryFullyConnected", b"initWithDevice:"), + ("MPSNNResizeBilinear", b"initWithDevice:"), + ("MPSNNCropAndResizeBilinear", b"initWithDevice:"), + ("MPSCNNBatchNormalizationState", b"initWithResource:"), + ( + "MPSCNNBatchNormalizationState", + b"temporaryStateWithCommandBuffer:bufferSize:", + ), + ( + "MPSCNNBatchNormalizationState", + b"temporaryStateWithCommandBuffer:textureDescriptor:", + ), + ("MPSCNNBatchNormalization", b"initWithDevice:"), + ( + "MPSCNNBatchNormalization", + b"encodeToCommandBuffer:sourceImage:destinationState:destinationImage:", + ), + ( + "MPSCNNBatchNormalization", + b"encodeToCommandBuffer:sourceImage:destinationState:destinationStateIsTemporary:", + ), + ( + "MPSCNNBatchNormalization", + b"encodeToCommandBuffer:sourceImage:destinationStates:destinationImages:", + ), + ( + "MPSCNNBatchNormalization", + b"encodeToCommandBuffer:sourceImage:destinationStates:destinationStateIsTemporary:", + ), + ( + "MPSCNNBatchNormalizationStatistics", + b"encodeToCommandBuffer:sourceImage:destinationImages:", + ), + ( + "MPSCNNBatchNormalizationStatistics", + b"encodeToCommandBuffer:sourceImage:destinationImage:", + ), + ("MPSCNNBatchNormalizationStatistics", b"encodeToCommandBuffer:sourceImage:"), + ("MPSCNNBatchNormalizationStatistics", b"encodeToCommandBuffer:sourceImages:"), + ("MPSCNNBatchNormalizationState", b"initWithResource:"), + ( + "MPSCNNBatchNormalizationGradient", + b"encodeToCommandBuffer:primaryImage:secondaryImage:destinationImage:", + ), + ( + "MPSCNNBatchNormalizationGradient", + b"encodeToCommandBuffer:primaryImages:secondaryImages:destinationImages:", + ), + ( + "MPSCNNBatchNormalizationGradient", + b"encodeToCommandBuffer:primaryImage:secondaryImage:", + ), + ( + "MPSCNNBatchNormalizationGradient", + b"encodeToCommandBuffer:primaryImages:secondaryImages:", + ), + ( + "MPSCNNBatchNormalizationStatisticsGradient", + b"encodeToCommandBuffer:sourceGradient:sourceImage:gradientState:", + ), + ( + "MPSCNNBatchNormalizationStatisticsGradient", + b"encodeToCommandBuffer:sourceGradient:sourceImage:gradientState:destinationGradient:", + ), + ( + "MPSCNNBatchNormalizationStatisticsGradient", + b"encodeToCommandBuffer:sourceGradients:sourceImages:gradientStates:destinationGradients:", + ), + ("MPSCNNLossDataDescriptor", b"init"), + ("MPSCNNLossLabels", b"init"), + ("MPSCNNLossDescriptor", b"init"), + ("MPSCNNLoss", b"initWithDevice:"), + ("MPSCNNYOLOLossDescriptor", b"init"), + ("MPSCNNYOLOLoss", b"initWithDevice:"), + ("MPSNNForwardLoss", b"initWithDevice:"), + ("MPSNNLossGradient", b"initWithDevice:"), + ("MPSRNNImageInferenceLayer", b"initWithDevice:"), + ("MPSRNNMatrixInferenceLayer", b"initWithDevice:"), + ("MPSRNNMatrixTrainingLayer", b"initWithDevice:"), + ("MPSNNReduceUnary", b"initWithDevice:"), + ("MPSNNReduceBinary", b"initWithDevice:"), + ("MPSNNNeuronDescriptor", b"init"), + ("MPSCNNNeuron", b"initWithDevice:"), + ("MPSCNNNeuronGradient", b"initWithDevice:"), + ("MPSCNNNeuronLinear", b"initWithDevice:"), + ("MPSCNNNeuronReLU", b"initWithDevice:"), + ("MPSCNNNeuronPReLU", b"initWithDevice:"), + ("MPSCNNNeuronHardSigmoid", b"initWithDevice:"), + ("MPSCNNNeuronTanH", b"initWithDevice:"), + ("MPSCNNNeuronSoftPlus", b"initWithDevice:"), + ("MPSCNNNeuronELU", b"initWithDevice:"), + ("MPSCNNNeuronReLUN", b"initWithDevice:"), + ("MPSCNNNeuronPower", b"initWithDevice:"), + ("MPSCNNNeuronExponential", b"initWithDevice:"), + ("MPSCNNNeuronLogarithm", b"initWithDevice:"), + ("MPSNNOptimizer", b"initWithDevice:"), + ("MPSNNOptimizerStochasticGradientDescent", b"initWithDevice:"), + ("MPSNNOptimizerRMSProp", b"initWithDevice:"), + ("MPSNNOptimizerAdam", b"initWithDevice:"), + ("MPSCNNPooling", b"initWithDevice:"), + ("MPSCNNPoolingGradient", b"initWithDevice:"), + ( + "MPSCNNDilatedPoolingMaxGradient", + b"initWithDevice:kernelWidth:kernelHeight:strideInPixelsX:strideInPixelsY:", + ), + ( + "MPSCNNInstanceNormalizationGradientState", + b"temporaryStateWithCommandBuffer:textureDescriptor:", + ), + ( + "MPSCNNInstanceNormalizationGradientState", + b"temporaryStateWithCommandBuffer:", + ), + ( + "MPSCNNInstanceNormalizationGradientState", + b"temporaryStateWithCommandBuffer:bufferSize:", + ), + ( + "MPSCNNInstanceNormalizationGradientState", + b"initWithDevice:textureDescriptor:", + ), + ("MPSCNNInstanceNormalizationGradientState", b"initWithResource:"), + ("MPSCNNInstanceNormalizationGradientState", b"initWithDevice::bufferSize:"), + ("MPSCNNInstanceNormalization", b"initWithDevice:"), + ("MPSCNNSpatialNormalization", b"initWithDevice:"), + ("MPSCNNLocalContrastNormalization", b"initWithDevice:"), + ("MPSCNNCrossChannelNormalization", b"initWithDevice:"), + ("MPSCNNDropoutGradientState", b"init"), + ("MPSCNNDropout", b"initWithDevice:"), + ("MPSCNNDropoutGradient", b"initWithDevice:"), + ( + "MPSCNNGroupNormalizationGradientState", + b"temporaryStateWithCommandBuffer:textureDescriptor:", + ), + ("MPSCNNGroupNormalizationGradientState", b"temporaryStateWithCommandBuffer:"), + ( + "MPSCNNGroupNormalizationGradientState", + b"temporaryStateWithCommandBuffer:bufferSize:", + ), + ("MPSCNNGroupNormalizationGradientState", b"initWithDevice:textureDescriptor:"), + ("MPSCNNGroupNormalizationGradientState", b"initWithResource:"), + ("MPSCNNGroupNormalizationGradientState", b"initWithDevice::bufferSize:"), + ("MPSCNNGroupNormalization", b"initWithDevice:"), + ("MPSNDArrayMultiaryBase", b"initWithDevice:"), + ("MPSNDArrayMultiaryGradientKernel", b"initWithDevice:sourceCount:"), + ("MPSNDArrayUnaryKernel", b"initWithDevice:sourceCount:"), + ( + "MPSNDArrayUnaryGradientKernel", + b"initWithDevice:sourceCount:sourceGradientIndex:", + ), + ("MPSNDArrayBinaryKernel", b"initWithDevice:sourceCount:"), + ( + "MPSNDArrayBinaryPrimaryGradientKernel", + b"initWithDevice:sourceCount:sourceGradientIndex:", + ), + ( + "MPSNDArrayBinarySecondaryGradientKernel", + b"initWithDevice:sourceCount:sourceGradientIndex:", + ), + ("MPSCommandBuffer", b"init"), + ("MPSKeyedUnarchiver", b"unarchivedObjectOfClasses:fromData:error:"), + ("MPSKeyedUnarchiver", b"unarchivedObjectOfClass:fromData:error:"), + ("MPSKeyedUnarchiver", b"init"), + ("MPSKeyedUnarchiver", b"initForReadingFromData:error:"), + ("MPSKeyedUnarchiver", b"unarchiveObjectWithData:"), + ("MPSKeyedUnarchiver", b"unarchiveTopLevelObjectWithData:error:"), + ("MPSKeyedUnarchiver", b"unarchiveObjectWithFile:"), + ("MPSKeyedUnarchiver", b"initForReadingWithData:"), + ("MPSNDArrayDescriptor", b"init"), + ("MPSNDArray", b"init"), + ("MPSTemporaryNDArray", b"initWithDevice:descriptor:"), + ("MPSState", b"init"), + ("MPSImage", b"init"), + ("MPSTemporaryImage", b"initWithDevice:imageDescriptor:"), + ("MPSMatrix", b"init"), + ("MPSVector", b"init"), + ("MPSTemporaryMatrix", b"initWithBuffer:descriptor:"), + ("MPSTemporaryVector", b"initWithBuffer:descriptor:"), + ("MPSImageThresholdBinary", b"initWithDevice:"), + ("MPSImageThresholdBinaryInverse", b"initWithDevice:"), + ("MPSImageThresholdTruncate", b"initWithDevice:"), + ("MPSImageThresholdToZero", b"initWithDevice:"), + ("MPSImageThresholdToZeroInverse", b"initWithDevice:"), + ("MPSImageArithmetic", b"initWithDevice:"), + ("MPSImageReduceUnary", b"initWithDevice:"), + ("MPSImageMedian", b"initWithDevice:"), + ("MPSImageAreaMax", b"initWithDevice:"), + ("MPSImageDilate", b"initWithDevice:"), + ("MPSImageBox", b"initWithDevice:"), + ("MPSImageGaussianBlur", b"initWithDevice:"), + ("MPSImageGuidedFilter", b"initWithDevice:"), + ("MPSImageFindKeypoints", b"initWithDevice:"), + ("MPSMatrixFindTopK", b"initWithDevice:"), + ("MPSMatrixRandom", b"initWithDevice:"), + ("MPSMatrixMultiplication", b"initWithDevice:"), + ("MPSMatrixVectorMultiplication", b"initWithDevice:"), + ("MPSMatrixCopyDescriptor", b"init"), + ("MPSMatrixCopy", b"initWithDevice:"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["MetalPerformanceShaders._metadata"] diff --git a/pyobjc-framework-ModelIO/Lib/ModelIO/__init__.py b/pyobjc-framework-ModelIO/Lib/ModelIO/__init__.py index b83bd607a7..876b812723 100644 --- a/pyobjc-framework-ModelIO/Lib/ModelIO/__init__.py +++ b/pyobjc-framework-ModelIO/Lib/ModelIO/__init__.py @@ -33,6 +33,14 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("MDLMaterialProperty", b"init"), + ("MDLMaterialPropertyConnection", b"init"), + ("MDLMaterialPropertyNode", b"init"), + ("MDLMaterialPropertyNode", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["ModelIO._metadata"] diff --git a/pyobjc-framework-NaturalLanguage/Lib/NaturalLanguage/__init__.py b/pyobjc-framework-NaturalLanguage/Lib/NaturalLanguage/__init__.py index e7d877b31c..ffd055457c 100644 --- a/pyobjc-framework-NaturalLanguage/Lib/NaturalLanguage/__init__.py +++ b/pyobjc-framework-NaturalLanguage/Lib/NaturalLanguage/__init__.py @@ -28,6 +28,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("NLContextualEmbedding", b"init"), + ("NLContextualEmbeddingResult", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["NaturalLanguage._metadata"] diff --git a/pyobjc-framework-OSLog/Lib/OSLog/__init__.py b/pyobjc-framework-OSLog/Lib/OSLog/__init__.py index e621b83a9f..8478d8987b 100644 --- a/pyobjc-framework-OSLog/Lib/OSLog/__init__.py +++ b/pyobjc-framework-OSLog/Lib/OSLog/__init__.py @@ -31,6 +31,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("OSLogPosition", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["OSLog._metadata"] diff --git a/pyobjc-framework-PHASE/Lib/PHASE/__init__.py b/pyobjc-framework-PHASE/Lib/PHASE/__init__.py index 716db1d8a5..0b95abc140 100644 --- a/pyobjc-framework-PHASE/Lib/PHASE/__init__.py +++ b/pyobjc-framework-PHASE/Lib/PHASE/__init__.py @@ -28,6 +28,109 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("PHASESource", b"init"), + ("PHASESource", b"new"), + ("PHASEDistanceModelFadeOutParameters", b"init"), + ("PHASEDistanceModelFadeOutParameters", b"new"), + ("PHASEDistanceModelParameters", b"init"), + ("PHASEDistanceModelParameters", b"new"), + ("PHASEEnvelopeDistanceModelParameters", b"init"), + ("PHASEEnvelopeDistanceModelParameters", b"new"), + ("PHASEMetaParameterDefinition", b"init"), + ("PHASEMetaParameterDefinition", b"new"), + ("PHASENumberMetaParameterDefinition", b"init"), + ("PHASENumberMetaParameterDefinition", b"new"), + ("PHASEStringMetaParameterDefinition", b"init"), + ("PHASEStringMetaParameterDefinition", b"new"), + ("PHASEMappedMetaParameterDefinition", b"init"), + ("PHASEMappedMetaParameterDefinition", b"new"), + ("PHASEMappedMetaParameterDefinition", b"initWithValue:identifier:"), + ("PHASEMappedMetaParameterDefinition", b"initWithValue:"), + ( + "PHASEMappedMetaParameterDefinition", + b"initWithValue:minimum:maximum:identifier:", + ), + ("PHASEMappedMetaParameterDefinition", b"initWithValue:minimum:maximum:"), + ("PHASEMappedMetaParameterDefinition", b"minimum"), + ("PHASEMappedMetaParameterDefinition", b"maximum"), + ("PHASEMetaParameter", b"init"), + ("PHASEMetaParameter", b"new"), + ("PHASENumberMetaParameter", b"init"), + ("PHASENumberMetaParameter", b"new"), + ("PHASEStringMetaParameter", b"init"), + ("PHASEStringMetaParameter", b"new"), + ("PHASEEnvelope", b"init"), + ("PHASEEnvelope", b"new"), + ("PHASEMedium", b"init"), + ("PHASEMedium", b"new"), + ("PHASEEngine", b"init"), + ("PHASEEngine", b"new"), + ("PHASEShapeElement", b"init"), + ("PHASEShapeElement", b"new"), + ("PHASEShape", b"init"), + ("PHASEShape", b"new"), + ("PHASEOccluder", b"init"), + ("PHASEOccluder", b"initWithEngine:"), + ("PHASEOccluder", b"new"), + ("PHASEGroupPresetSetting", b"init"), + ("PHASEGroupPresetSetting", b"new"), + ("PHASEGroupPreset", b"init"), + ("PHASEGroupPreset", b"new"), + ("PHASEMixerDefinition", b"init"), + ("PHASEMixerDefinition", b"new"), + ("PHASESpatialMixerDefinition", b"init"), + ("PHASESpatialMixerDefinition", b"new"), + ("PHASEAmbientMixerDefinition", b"init"), + ("PHASEAmbientMixerDefinition", b"new"), + ("PHASEChannelMixerDefinition", b"init"), + ("PHASEChannelMixerDefinition", b"new"), + ("PHASEMixer", b"init"), + ("PHASEMixer", b"new"), + ("PHASEMaterial", b"init"), + ("PHASEMaterial", b"new"), + ("PHASEDirectivityModelParameters", b"init"), + ("PHASEDirectivityModelParameters", b"new"), + ("PHASEGroup", b"init"), + ("PHASEGroup", b"new"), + ("PHASEListener", b"init"), + ("PHASEListener", b"new"), + ("PHASEDefinition", b"init"), + ("PHASEDefinition", b"new"), + ("PHASEDucker", b"init"), + ("PHASEDucker", b"new"), + ("PHASESpatialPipeline", b"init"), + ("PHASESpatialPipeline", b"new"), + ("PHASESoundEventNodeDefinition", b"init"), + ("PHASESoundEventNodeDefinition", b"new"), + ("PHASEGeneratorNodeDefinition", b"init"), + ("PHASEGeneratorNodeDefinition", b"new"), + ("PHASESamplerNodeDefinition", b"init"), + ("PHASESamplerNodeDefinition", b"new"), + ("PHASEBlendNodeDefinition", b"init"), + ("PHASEBlendNodeDefinition", b"new"), + ("PHASESwitchNodeDefinition", b"init"), + ("PHASESwitchNodeDefinition", b"new"), + ("PHASEPushStreamNodeDefinition", b"init"), + ("PHASEPushStreamNodeDefinition", b"new"), + ("PHASEPushStreamNode", b"init"), + ("PHASEPushStreamNode", b"new"), + ("PHASEObject", b"init"), + ("PHASEObject", b"new"), + ("PHASEAsset", b"init"), + ("PHASEAsset", b"new"), + ("PHASESoundAsset", b"init"), + ("PHASESoundAsset", b"new"), + ("PHASESoundEventNodeAsset", b"init"), + ("PHASESoundEventNodeAsset", b"new"), + ("PHASEGlobalMetaParameterAsset", b"init"), + ("PHASEGlobalMetaParameterAsset", b"new"), + ("PHASEAssetRegistry", b"init"), + ("PHASEAssetRegistry", b"new"), + ("PHASESoundEvent", b"init"), + ("PHASESoundEvent", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) del sys.modules["PHASE._metadata"] diff --git a/pyobjc-framework-PassKit/Lib/PassKit/__init__.py b/pyobjc-framework-PassKit/Lib/PassKit/__init__.py index 10d98c3682..6e93ca1b24 100644 --- a/pyobjc-framework-PassKit/Lib/PassKit/__init__.py +++ b/pyobjc-framework-PassKit/Lib/PassKit/__init__.py @@ -31,6 +31,39 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("PKIssuerProvisioningExtensionPassEntry", b"init"), + ("PKPaymentOrderDetails", b"init"), + ("PKPaymentOrderDetails", b"new"), + ("PKPaymentTokenContext", b"init"), + ("PKDeferredPaymentRequest", b"init"), + ("PKPayLaterView", b"init"), + ("PKPayLaterView", b"new"), + ("PKPayLaterView", b"initWithFrame:"), + ("PKPayLaterView", b"initWithCoder:"), + ("PKIdentityButton", b"initWithFrame:"), + ("PKIdentityButton", b"initWithFrame:primaryAction:"), + ("PKIdentityElement", b"init"), + ("PKIdentityElement", b"new"), + ("PKAddSecureElementPassConfiguration", b"init"), + ("PKAddSecureElementPassConfiguration", b"new"), + ("PKDateComponentsRange", b"init"), + ("PKStoredValuePassBalance", b"init"), + ("PKStoredValuePassBalance", b"new"), + ("PKIdentityDocument", b"init"), + ("PKIdentityDocument", b"new"), + ("PKIdentityIntentToStore", b"init"), + ("PKIdentityIntentToStore", b"new"), + ("PKAutomaticReloadPaymentRequest", b"init"), + ("PKShareSecureElementPassViewController", b"init"), + ("PKVehicleConnectionSession", b"init"), + ("PKVehicleConnectionSession", b"new"), + ("PKRecurringPaymentRequest", b"init"), + ("PKShareablePassMetadataPreview", b"init"), + ("PKShareablePassMetadataPreview", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["PassKit._metadata"] diff --git a/pyobjc-framework-PencilKit/Lib/PencilKit/__init__.py b/pyobjc-framework-PencilKit/Lib/PencilKit/__init__.py index 53d5e166c6..3087873ff9 100644 --- a/pyobjc-framework-PencilKit/Lib/PencilKit/__init__.py +++ b/pyobjc-framework-PencilKit/Lib/PencilKit/__init__.py @@ -28,6 +28,13 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("PKStrokePoint", b"init"), + ("PKTool", b"init"), + ("PKTool", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["PencilKit._metadata"] diff --git a/pyobjc-framework-Photos/Lib/Photos/__init__.py b/pyobjc-framework-Photos/Lib/Photos/__init__.py index 36f2afb00b..b39c2fdf7f 100644 --- a/pyobjc-framework-Photos/Lib/Photos/__init__.py +++ b/pyobjc-framework-Photos/Lib/Photos/__init__.py @@ -36,6 +36,20 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("PHPersistentChangeToken", b"init"), + ("PHPersistentChangeToken", b"new"), + ("PHLivePhoto", b"init"), + ("PHPersistentObjectChangeDetails", b"init"), + ("PHPersistentObjectChangeDetails", b"new"), + ("PHLivePhotoEditingContext", b"init"), + ("PHPersistentChangeFetchResult", b"init"), + ("PHPersistentChangeFetchResult", b"new"), + ("PHPersistentChange", b"init"), + ("PHPersistentChange", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Photos._metadata"] diff --git a/pyobjc-framework-PhotosUI/Lib/PhotosUI/__init__.py b/pyobjc-framework-PhotosUI/Lib/PhotosUI/__init__.py index 1baf1525b8..bf4764bc33 100644 --- a/pyobjc-framework-PhotosUI/Lib/PhotosUI/__init__.py +++ b/pyobjc-framework-PhotosUI/Lib/PhotosUI/__init__.py @@ -31,6 +31,30 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("PHProjectInfo", b"init"), + ("PHProjectInfo", b"new"), + ("PHProjectSection", b"init"), + ("PHProjectSection", b"new"), + ("PHProjectSectionContent", b"init"), + ("PHProjectSectionContent", b"new"), + ("PHProjectElement", b"init"), + ("PHProjectElement", b"new"), + ("PHProjectRegionOfInterest", b"init"), + ("PHProjectRegionOfInterest", b"new"), + ("PHPickerFilter", b"init"), + ("PHPickerFilter", b"new"), + ("PHPickerResult", b"init"), + ("PHPickerResult", b"new"), + ("PHPickerViewController", b"init"), + ("PHPickerViewController", b"initWithNibName:bundle:"), + ("PHPickerViewController", b"initWithCoder:"), + ("PHPickerViewController", b"new"), + ("PHProjectTypeDescription", b"init"), + ("PHProjectTypeDescription", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["PhotosUI._metadata"] for cls_name in ( diff --git a/pyobjc-framework-PushKit/Lib/PushKit/__init__.py b/pyobjc-framework-PushKit/Lib/PushKit/__init__.py index b3178ce198..39bc2e3f75 100644 --- a/pyobjc-framework-PushKit/Lib/PushKit/__init__.py +++ b/pyobjc-framework-PushKit/Lib/PushKit/__init__.py @@ -31,6 +31,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("PKPushRegistry", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["PushKit._metadata"] diff --git a/pyobjc-framework-Quartz/Lib/Quartz/QuartzCore/__init__.py b/pyobjc-framework-Quartz/Lib/Quartz/QuartzCore/__init__.py index ad9bc42708..82e05a5db9 100644 --- a/pyobjc-framework-Quartz/Lib/Quartz/QuartzCore/__init__.py +++ b/pyobjc-framework-Quartz/Lib/Quartz/QuartzCore/__init__.py @@ -31,6 +31,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("CAEDRMetadata", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Quartz.QuartzCore._metadata"] def CIVector__getitem__(self, idx): diff --git a/pyobjc-framework-QuickLookThumbnailing/Lib/QuickLookThumbnailing/__init__.py b/pyobjc-framework-QuickLookThumbnailing/Lib/QuickLookThumbnailing/__init__.py index 697474835a..5ba7e97c82 100644 --- a/pyobjc-framework-QuickLookThumbnailing/Lib/QuickLookThumbnailing/__init__.py +++ b/pyobjc-framework-QuickLookThumbnailing/Lib/QuickLookThumbnailing/__init__.py @@ -28,6 +28,13 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("QLThumbnailGenerationRequest", b"init"), + ("QLThumbnailGenerationRequest", b"new"), + ("QLThumbnailReply", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["QuickLookThumbnailing._metadata"] diff --git a/pyobjc-framework-SafariServices/Lib/SafariServices/__init__.py b/pyobjc-framework-SafariServices/Lib/SafariServices/__init__.py index b47a1ec0a1..e098668df4 100644 --- a/pyobjc-framework-SafariServices/Lib/SafariServices/__init__.py +++ b/pyobjc-framework-SafariServices/Lib/SafariServices/__init__.py @@ -31,6 +31,24 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("SFSafariToolbarItem", b"init"), + ("SFSafariToolbarItem", b"new"), + ("SFSafariExtension", b"init"), + ("SFSafariExtension", b"new"), + ("SFUniversalLink", b"init"), + ("SFUniversalLink", b"new"), + ("SFSafariApplication", b"init"), + ("SFSafariApplication", b"new"), + ("SFSafariPage", b"init"), + ("SFSafariPage", b"new"), + ("SFSafariTab", b"init"), + ("SFSafariTab", b"new"), + ("SFSafariWindow", b"init"), + ("SFSafariWindow", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["SafariServices._metadata"] diff --git a/pyobjc-framework-SafetyKit/Lib/SafetyKit/__init__.py b/pyobjc-framework-SafetyKit/Lib/SafetyKit/__init__.py index 08a5369f67..1d31d4534b 100644 --- a/pyobjc-framework-SafetyKit/Lib/SafetyKit/__init__.py +++ b/pyobjc-framework-SafetyKit/Lib/SafetyKit/__init__.py @@ -31,6 +31,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("SACrashDetectionEvent", b"init"), + ("SACrashDetectionEvent", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["SafetyKit._metadata"] diff --git a/pyobjc-framework-SceneKit/Lib/SceneKit/__init__.py b/pyobjc-framework-SceneKit/Lib/SceneKit/__init__.py index c5a737d0d3..1c6106b3ee 100644 --- a/pyobjc-framework-SceneKit/Lib/SceneKit/__init__.py +++ b/pyobjc-framework-SceneKit/Lib/SceneKit/__init__.py @@ -34,6 +34,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("SCNAudioPlayer", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["SceneKit._metadata"] import SceneKit as mod # isort:skip diff --git a/pyobjc-framework-ScreenCaptureKit/Lib/ScreenCaptureKit/__init__.py b/pyobjc-framework-ScreenCaptureKit/Lib/ScreenCaptureKit/__init__.py index f5d08721da..f311127c10 100644 --- a/pyobjc-framework-ScreenCaptureKit/Lib/ScreenCaptureKit/__init__.py +++ b/pyobjc-framework-ScreenCaptureKit/Lib/ScreenCaptureKit/__init__.py @@ -31,6 +31,22 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("SCStream", b"init"), + ("SCStream", b"new"), + ("SCRunningApplication", b"init"), + ("SCRunningApplication", b"new"), + ("SCWindow", b"init"), + ("SCWindow", b"new"), + ("SCDisplay", b"init"), + ("SCDisplay", b"new"), + ("SCShareableContent", b"init"), + ("SCShareableContent", b"new"), + ("SCContentSharingPicker", b"init"), + ("SCContentSharingPicker", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["ScreenCaptureKit._metadata"] diff --git a/pyobjc-framework-ScreenTime/Lib/ScreenTime/__init__.py b/pyobjc-framework-ScreenTime/Lib/ScreenTime/__init__.py index 5e4524bbe2..c418bdcd15 100644 --- a/pyobjc-framework-ScreenTime/Lib/ScreenTime/__init__.py +++ b/pyobjc-framework-ScreenTime/Lib/ScreenTime/__init__.py @@ -28,6 +28,16 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("STWebpageController", b"initWithNibName:bundle:"), + ("STWebpageController", b"initWithCoder:"), + ("STScreenTimeConfiguration", b"init"), + ("STScreenTimeConfiguration", b"new"), + ("STScreenTimeConfigurationObserver", b"init"), + ("STScreenTimeConfigurationObserver", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["ScreenTime._metadata"] diff --git a/pyobjc-framework-SharedWithYou/Lib/SharedWithYou/__init__.py b/pyobjc-framework-SharedWithYou/Lib/SharedWithYou/__init__.py index 8497288acc..eca12ddaee 100644 --- a/pyobjc-framework-SharedWithYou/Lib/SharedWithYou/__init__.py +++ b/pyobjc-framework-SharedWithYou/Lib/SharedWithYou/__init__.py @@ -31,6 +31,20 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("SWHighlightMembershipEvent", b"init"), + ("SWHighlightMembershipEvent", b"new"), + ("SWHighlightPersistenceEvent", b"init"), + ("SWHighlightPersistenceEvent", b"new"), + ("SWHighlightMentionEvent", b"init"), + ("SWHighlightMentionEvent", b"new"), + ("SWHighlightChangeEvent", b"init"), + ("SWHighlightChangeEvent", b"new"), + ("SWHighlight", b"init"), + ("SWHighlight", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["SharedWithYou._metadata"] diff --git a/pyobjc-framework-SharedWithYouCore/Lib/SharedWithYouCore/__init__.py b/pyobjc-framework-SharedWithYouCore/Lib/SharedWithYouCore/__init__.py index f0e404d09d..5a5add90ca 100644 --- a/pyobjc-framework-SharedWithYouCore/Lib/SharedWithYouCore/__init__.py +++ b/pyobjc-framework-SharedWithYouCore/Lib/SharedWithYouCore/__init__.py @@ -31,6 +31,28 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("SWUpdateCollaborationParticipantsAction", b"init"), + ("SWUpdateCollaborationParticipantsAction", b"new"), + ("SWPersonIdentity", b"init"), + ("SWPersonIdentity", b"new"), + ("SWPerson", b"init"), + ("SWPerson", b"new"), + ("SWPersonIdentityProof", b"init"), + ("SWPersonIdentityProof", b"new"), + ("SWCollaborationMetadata", b"init"), + ("SWCollaborationMetadata", b"new"), + ("SWCollaborationOption", b"init"), + ("SWCollaborationOption", b"new"), + ("SWStartCollaborationAction", b"init"), + ("SWStartCollaborationAction", b"new"), + ("SWCollaborationOptionsGroup", b"init"), + ("SWCollaborationOptionsGroup", b"new"), + ("SWCollaborationShareOptions", b"init"), + ("SWCollaborationShareOptions", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["SharedWithYouCore._metadata"] diff --git a/pyobjc-framework-ShazamKit/Lib/ShazamKit/__init__.py b/pyobjc-framework-ShazamKit/Lib/ShazamKit/__init__.py index 1a3ab1168b..45fe85aa4a 100644 --- a/pyobjc-framework-ShazamKit/Lib/ShazamKit/__init__.py +++ b/pyobjc-framework-ShazamKit/Lib/ShazamKit/__init__.py @@ -31,6 +31,20 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("SHMediaLibrary", b"init"), + ("SHMediaLibrary", b"new"), + ("SHRange", b"init"), + ("SHRange", b"new"), + ("SHMediaItem", b"init"), + ("SHMediaItem", b"new"), + ("SHCatalog", b"init"), + ("SHCatalog", b"new"), + ("SHMatch", b"init"), + ("SHMatch", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["ShazamKit._metadata"] diff --git a/pyobjc-framework-SoundAnalysis/Lib/SoundAnalysis/__init__.py b/pyobjc-framework-SoundAnalysis/Lib/SoundAnalysis/__init__.py index 55fea0720a..30482ceaaa 100644 --- a/pyobjc-framework-SoundAnalysis/Lib/SoundAnalysis/__init__.py +++ b/pyobjc-framework-SoundAnalysis/Lib/SoundAnalysis/__init__.py @@ -28,6 +28,22 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("SNTimeDurationConstraint", b"init"), + ("SNTimeDurationConstraint", b"new"), + ("SNClassification", b"init"), + ("SNClassification", b"new"), + ("SNClassificationResult", b"init"), + ("SNClassificationResult", b"new"), + ("SNClassifySoundRequest", b"init"), + ("SNClassifySoundRequest", b"new"), + ("SNAudioStreamAnalyzer", b"init"), + ("SNAudioFileAnalyzer", b"init"), + ("SNAudioStreamAnalyzer", b"init"), + ("SNAudioFileAnalyzer", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["SoundAnalysis._metadata"] diff --git a/pyobjc-framework-Speech/Lib/Speech/__init__.py b/pyobjc-framework-Speech/Lib/Speech/__init__.py index 24209b253a..fcc57d7d99 100644 --- a/pyobjc-framework-Speech/Lib/Speech/__init__.py +++ b/pyobjc-framework-Speech/Lib/Speech/__init__.py @@ -31,6 +31,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("SFSpeechURLRecognitionRequest", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Speech._metadata"] diff --git a/pyobjc-framework-StoreKit/Lib/StoreKit/__init__.py b/pyobjc-framework-StoreKit/Lib/StoreKit/__init__.py index 16915e239a..54f55a7831 100644 --- a/pyobjc-framework-StoreKit/Lib/StoreKit/__init__.py +++ b/pyobjc-framework-StoreKit/Lib/StoreKit/__init__.py @@ -31,6 +31,20 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("SKOverlayConfiguration", b"init"), + ("SKOverlayConfiguration", b"new"), + ("SKOverlayAppConfiguration", b"init"), + ("SKOverlayAppConfiguration", b"new"), + ("SKOverlayAppClipConfiguration", b"init"), + ("SKOverlayAppClipConfiguration", b"new"), + ("SKOverlayTransitionContext", b"init"), + ("SKOverlayTransitionContext", b"new"), + ("SKOverlay", b"init"), + ("SKOverlay", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["StoreKit._metadata"] diff --git a/pyobjc-framework-Symbols/Lib/Symbols/__init__.py b/pyobjc-framework-Symbols/Lib/Symbols/__init__.py index e78c328e2a..343a68c2d3 100644 --- a/pyobjc-framework-Symbols/Lib/Symbols/__init__.py +++ b/pyobjc-framework-Symbols/Lib/Symbols/__init__.py @@ -28,6 +28,16 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("NSSymbolEffectOptions", b"init"), + ("NSSymbolEffectOptions", b"new"), + ("NSSymbolEffect", b"init"), + ("NSSymbolEffect", b"new"), + ("NSSymbolContentTransition", b"init"), + ("NSSymbolContentTransition", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Symbols._metadata"] diff --git a/pyobjc-framework-SystemExtensions/Lib/SystemExtensions/__init__.py b/pyobjc-framework-SystemExtensions/Lib/SystemExtensions/__init__.py index 31d8281ddb..31ea331892 100644 --- a/pyobjc-framework-SystemExtensions/Lib/SystemExtensions/__init__.py +++ b/pyobjc-framework-SystemExtensions/Lib/SystemExtensions/__init__.py @@ -31,6 +31,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("OSSystemExtensionManager", b"init"), + ("OSSystemExtensionManager", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["SystemExtensions._metadata"] diff --git a/pyobjc-framework-ThreadNetwork/Lib/ThreadNetwork/__init__.py b/pyobjc-framework-ThreadNetwork/Lib/ThreadNetwork/__init__.py index 4ba1d303ee..494a3f24fd 100644 --- a/pyobjc-framework-ThreadNetwork/Lib/ThreadNetwork/__init__.py +++ b/pyobjc-framework-ThreadNetwork/Lib/ThreadNetwork/__init__.py @@ -28,6 +28,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("THCredentials", b"init"), + ("THCredentials", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["ThreadNetwork._metadata"] diff --git a/pyobjc-framework-UniformTypeIdentifiers/Lib/UniformTypeIdentifiers/__init__.py b/pyobjc-framework-UniformTypeIdentifiers/Lib/UniformTypeIdentifiers/__init__.py index 9d42e35f7c..04003552fd 100644 --- a/pyobjc-framework-UniformTypeIdentifiers/Lib/UniformTypeIdentifiers/__init__.py +++ b/pyobjc-framework-UniformTypeIdentifiers/Lib/UniformTypeIdentifiers/__init__.py @@ -28,6 +28,12 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("UTType", b"init"), + ("UTType", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["UniformTypeIdentifiers._metadata"] diff --git a/pyobjc-framework-UserNotifications/Lib/UserNotifications/__init__.py b/pyobjc-framework-UserNotifications/Lib/UserNotifications/__init__.py index 9ea443a87d..2cb956be29 100644 --- a/pyobjc-framework-UserNotifications/Lib/UserNotifications/__init__.py +++ b/pyobjc-framework-UserNotifications/Lib/UserNotifications/__init__.py @@ -31,6 +31,20 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("UNNotificationActionIcon", b"init"), + ("UNUserNotificationCenter", b"init"), + ("UNNotificationCategory", b"init"), + ("UNNotificationRequest", b"init"), + ("UNNotificationTrigger", b"init"), + ("UNNotificationAttachment", b"init"), + ("UNNotificationAction", b"init"), + ("UNNotificationSound", b"init"), + ("UNNotificationResponse", b"init"), + ("UNNotificationSettings", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["UserNotifications._metadata"] diff --git a/pyobjc-framework-VideoSubscriberAccount/Lib/VideoSubscriberAccount/__init__.py b/pyobjc-framework-VideoSubscriberAccount/Lib/VideoSubscriberAccount/__init__.py index d9ec0d22c9..7385c02a77 100644 --- a/pyobjc-framework-VideoSubscriberAccount/Lib/VideoSubscriberAccount/__init__.py +++ b/pyobjc-framework-VideoSubscriberAccount/Lib/VideoSubscriberAccount/__init__.py @@ -28,6 +28,18 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("VSAccountApplicationProvider", b"init"), + ("VSAccountApplicationProvider", b"new"), + ("VSAppleSubscription", b"init"), + ("VSAppleSubscription", b"new"), + ("VSAccountManagerResult", b"init"), + ("VSAccountManagerResult", b"new"), + ("VSUserAccount", b"init"), + ("VSUserAccount", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["VideoSubscriberAccount._metadata"] diff --git a/pyobjc-framework-Virtualization/Lib/Virtualization/__init__.py b/pyobjc-framework-Virtualization/Lib/Virtualization/__init__.py index 1312ac820b..7749d0cb66 100644 --- a/pyobjc-framework-Virtualization/Lib/Virtualization/__init__.py +++ b/pyobjc-framework-Virtualization/Lib/Virtualization/__init__.py @@ -31,6 +31,110 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("VZDirectoryShare", b"init"), + ("VZDirectoryShare", b"new"), + ("VZVirtioSoundDeviceStreamConfiguration", b"init"), + ("VZVirtioSoundDeviceStreamConfiguration", b"new"), + ("VZVirtioConsoleDevice", b"init"), + ("VZVirtioConsoleDevice", b"new"), + ("VZSharedDirectory", b"init"), + ("VZSharedDirectory", b"new"), + ("VZBootLoader", b"init"), + ("VZBootLoader", b"new"), + ("VZKeyboardConfiguration", b"init"), + ("VZKeyboardConfiguration", b"new"), + ("VZGraphicsDevice", b"init"), + ("VZGraphicsDevice", b"new"), + ("VZVirtioSocketDevice", b"init"), + ("VZVirtioSocketDevice", b"new"), + ("VZAudioDeviceConfiguration", b"init"), + ("VZAudioDeviceConfiguration", b"new"), + ("VZEntropyDeviceConfiguration", b"init"), + ("VZEntropyDeviceConfiguration", b"new"), + ("VZGraphicsDisplayConfiguration", b"init"), + ("VZGraphicsDisplayConfiguration", b"new"), + ("VZMacOSRestoreImage", b"init"), + ("VZMacOSRestoreImage", b"new"), + ("VZSerialPortAttachment", b"init"), + ("VZSerialPortAttachment", b"new"), + ("VZVirtioSocketConnection", b"init"), + ("VZVirtioSocketConnection", b"new"), + ("VZVirtioConsolePortConfigurationArray", b"init"), + ("VZVirtioConsolePortConfigurationArray", b"new"), + ("VZDirectorySharingDevice", b"init"), + ("VZDirectorySharingDevice", b"new"), + ("VZAudioInputStreamSource", b"init"), + ("VZAudioInputStreamSource", b"new"), + ("VZStorageDeviceAttachment", b"init"), + ("VZStorageDeviceAttachment", b"new"), + ("VZFileHandleSerialPortAttachment", b"init"), + ("VZFileHandleSerialPortAttachment", b"new"), + ("VZGraphicsDisplay", b"init"), + ("VZGraphicsDisplay", b"new"), + ("VZGraphicsDeviceConfiguration", b"init"), + ("VZGraphicsDeviceConfiguration", b"new"), + ("VZVirtioConsolePort", b"init"), + ("VZVirtioConsolePort", b"new"), + ("VZFileSerialPortAttachment", b"init"), + ("VZFileSerialPortAttachment", b"new"), + ("VZSocketDeviceConfiguration", b"init"), + ("VZSocketDeviceConfiguration", b"new"), + ("VZEFIVariableStore", b"init"), + ("VZEFIVariableStore", b"new"), + ("VZNetworkDevice", b"init"), + ("VZNetworkDevice", b"new"), + ("VZLinuxRosettaCachingOptions", b"init"), + ("VZLinuxRosettaCachingOptions", b"new"), + ("VZConsoleDeviceConfiguration", b"init"), + ("VZConsoleDeviceConfiguration", b"new"), + ("VZMacOSInstaller", b"init"), + ("VZMacOSInstaller", b"new"), + ("VZMacOSConfigurationRequirements", b"init"), + ("VZMacOSConfigurationRequirements", b"new"), + ("VZVirtioTraditionalMemoryBalloonDevice", b"init"), + ("VZVirtioTraditionalMemoryBalloonDevice", b"new"), + ("VZMacAuxiliaryStorage", b"init"), + ("VZMacAuxiliaryStorage", b"new"), + ("VZConsoleDevice", b"init"), + ("VZConsoleDevice", b"new"), + ("VZBridgedNetworkInterface", b"init"), + ("VZBridgedNetworkInterface", b"new"), + ("VZSerialPortConfiguration", b"init"), + ("VZSerialPortConfiguration", b"new"), + ("VZMemoryBalloonDevice", b"init"), + ("VZMemoryBalloonDevice", b"new"), + ("VZVirtualMachine", b"init"), + ("VZVirtualMachine", b"new"), + ("VZAudioOutputStreamSink", b"init"), + ("VZAudioOutputStreamSink", b"new"), + ("VZMacHardwareModel", b"init"), + ("VZMacHardwareModel", b"new"), + ("VZNetworkDeviceConfiguration", b"init"), + ("VZNetworkDeviceConfiguration", b"new"), + ("VZDirectorySharingDeviceConfiguration", b"init"), + ("VZDirectorySharingDeviceConfiguration", b"new"), + ("VZSocketDevice", b"init"), + ("VZSocketDevice", b"new"), + ("VZMemoryBalloonDeviceConfiguration", b"init"), + ("VZMemoryBalloonDeviceConfiguration", b"new"), + ("VZStorageDeviceConfiguration", b"init"), + ("VZStorageDeviceConfiguration", b"new"), + ("VZVirtioConsolePortArray", b"init"), + ("VZVirtioConsolePortArray", b"new"), + ("VZPlatformConfiguration", b"init"), + ("VZPlatformConfiguration", b"new"), + ("VZNetworkDeviceAttachment", b"init"), + ("VZNetworkDeviceAttachment", b"new"), + ("VZPointingDeviceConfiguration", b"init"), + ("VZPointingDeviceConfiguration", b"new"), + ("VZMACAddress", b"init"), + ("VZMACAddress", b"new"), + ("VZConsolePortConfiguration", b"init"), + ("VZConsolePortConfiguration", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Virtualization._metadata"] diff --git a/pyobjc-framework-Vision/Lib/Vision/__init__.py b/pyobjc-framework-Vision/Lib/Vision/__init__.py index 2845fc6943..ee7fcc56a8 100644 --- a/pyobjc-framework-Vision/Lib/Vision/__init__.py +++ b/pyobjc-framework-Vision/Lib/Vision/__init__.py @@ -35,6 +35,54 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("VNVideoProcessorFrameRateCadence", b"init"), + ("VNVideoProcessorTimeIntervalCadence", b"init"), + ("VNVideoProcessor", b"init"), + ( + "VNGeneratePersonSegmentationRequest", + b"initWithFrameAnalysisSpacing:completionHandler:", + ), + ("VNDetectedPoint", b"init"), + ("VNDetectedPoint", b"new"), + ("VNDetectedPoint", b"initWithX:y:"), + ("VNDetectedPoint", b"initWithLocation:"), + ("VNFaceLandmarkRegion", b"init"), + ("VNFaceLandmarkRegion", b"new"), + ("VNFaceLandmarks", b"init"), + ("VNCoreMLModel", b"init"), + ("VNCoreMLRequest", b"init"), + ("VNCoreMLRequest", b"initWithCompletionHandler:"), + ("VNTrackingRequest", b"init"), + ("VNTrackingRequest", b"initWithCompletionHandler:"), + ("VNHumanBodyRecognizedPoint3D", b"init"), + ("VNHumanBodyRecognizedPoint3D", b"new"), + ("VNImageRequestHandler", b"init"), + ("VNPoint3D", b"init"), + ("VNContour", b"init"), + ("VNContour", b"new"), + ("VNRecognizedPointsObservation", b"init"), + ("VNRecognizedPointsObservation", b"new"), + ("VNRecognizedPoints3DObservation", b"init"), + ("VNRecognizedPoints3DObservation", b"new"), + ("VNTrackObjectRequest", b"init"), + ("VNTrackObjectRequest", b"initWithCompletionHandler:"), + ("VNTargetedImageRequest", b"init"), + ("VNTargetedImageRequest", b"initWithCompletionHandler:"), + ( + "VNDetectTrajectoriesRequest", + b"initWithFrameAnalysisSpacing:completionHandler:", + ), + ("VNTrackRectangleRequest", b"init"), + ("VNTrackRectangleRequest", b"initWithCompletionHandler:"), + ("VNStatefulRequest", b"init"), + ("VNStatefulRequest", b"initwithcompletionhandler:"), + ("VNStatefulRequest", b"new"), + ("VNRecognizedPoint3D", b"init"), + ("VNRecognizedPoint3D", b"new"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["Vision._metadata"] diff --git a/pyobjc-framework-WebKit/Lib/WebKit/__init__.py b/pyobjc-framework-WebKit/Lib/WebKit/__init__.py index d96b1ea4de..7c1636f4b2 100644 --- a/pyobjc-framework-WebKit/Lib/WebKit/__init__.py +++ b/pyobjc-framework-WebKit/Lib/WebKit/__init__.py @@ -31,6 +31,20 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in ( + ("WKContentWorld", b"init"), + ("WKContentWorld", b"new"), + ("WKHTTPCookieStore", b"init"), + ("WKSecurityOrigin", b"init"), + ("WKFindResult", b"init"), + ("WKBackForwardListItem", b"init"), + ("WKWebsiteDataStore", b"init"), + ("WKWebsiteDataStore", b"new"), + ("DOMObject", b"init"), + ("WKContextMenuElementInfo", b"init"), + ): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["WebKit._metadata"] objc.addConvenienceForBasicSequence("WebScriptObject", True) diff --git a/pyobjc-framework-iTunesLibrary/Lib/iTunesLibrary/__init__.py b/pyobjc-framework-iTunesLibrary/Lib/iTunesLibrary/__init__.py index cbf3d2d403..60428b3a29 100644 --- a/pyobjc-framework-iTunesLibrary/Lib/iTunesLibrary/__init__.py +++ b/pyobjc-framework-iTunesLibrary/Lib/iTunesLibrary/__init__.py @@ -32,6 +32,9 @@ def _setup(): globals()["__dir__"] = dir_func globals()["__getattr__"] = getattr_func + for cls, sel in (("ITLibrary", b"init"),): + objc.registerUnavailableMethod(cls, sel) + del sys.modules["iTunesLibrary._metadata"] From 004d8e32c91826114af2bfc3b6ef64f25bed3593 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 2 May 2024 22:38:34 +0200 Subject: [PATCH 11/23] Implement NS_UNAVAILABLE support through the metadata system There's still an API to support __new__ keyword support, but actually marking the selector unavailable is done through the metadata system. Also add tests for the NS_UNAVAILABLE support code. A minor disadvantage of this is that subclasses cannot mark a method as available again, but AFAIK that's not used in Apple's SDKs and can be added later. --- pyobjc-core/Lib/objc/_convenience.py | 7 +- pyobjc-core/Lib/objc/_new.py | 5 ++ pyobjc-core/Modules/objc/test/unavailable.m | 81 ++++++++++++++++++++ pyobjc-core/PyObjCTest/test_nsunavailable.py | 63 +++++++++++++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 pyobjc-core/Modules/objc/test/unavailable.m create mode 100644 pyobjc-core/PyObjCTest/test_nsunavailable.py diff --git a/pyobjc-core/Lib/objc/_convenience.py b/pyobjc-core/Lib/objc/_convenience.py index f20def62f3..5d53cf38f6 100644 --- a/pyobjc-core/Lib/objc/_convenience.py +++ b/pyobjc-core/Lib/objc/_convenience.py @@ -106,7 +106,12 @@ def registerUnavailableMethod(classname, selector): # registering metadata because NS_UNAVAILABLE is # used to mark abstract base classes with concrete # public subclasses. - addConvenienceForClass(classname, ((selname.replace(":", "_"), None),)) + # addConvenienceForClass(classname, ((selname.replace(":", "_"), None),)) + registerMetaDataForSelector( + classname.encode(), + selector, + {"suggestion": f"{selector.decode()!r} is NS_UNAVAILABLE"}, + ) if selname.startswith("init"): kw = _selectorToKeywords(selname) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 7459af9597..8a9129ee2d 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -16,6 +16,8 @@ # TODO: # - Calculate __new__.__doc__ statically for Python subclasses +# - Likewise for ObjC classes (should be possible by updating +# doc strings when new keywords are registered) # - Make sure __init__ is never invoked implicitly (it # currently is when __new__ is invoked). There is a slight # risks this breaks code that implements a custom __new__ @@ -38,6 +40,9 @@ # invoked by the interpreter when __new__ is called, unless # __new__ returns more than one value (e.g. has some output # arguments, such as -[FooClass initWithValue:(int)value error:(NSError**)error] +# +# FIXME: 'unavailable' annations vs. calls methods +# (fairly sure those don't work properly yet with current setup) __all__ = () diff --git a/pyobjc-core/Modules/objc/test/unavailable.m b/pyobjc-core/Modules/objc/test/unavailable.m new file mode 100644 index 0000000000..601d869288 --- /dev/null +++ b/pyobjc-core/Modules/objc/test/unavailable.m @@ -0,0 +1,81 @@ +#include "Python.h" +#include "pyobjc-api.h" +#include + +#import + +@interface OC_NSUnavailable : NSObject { +} +@end + +@interface OC_NSUnavailableChild : OC_NSUnavailable { +} +@end + +@implementation OC_NSUnavailable +- (id)instmeth1 +{ + return @"objc-inst"; +} + ++ (id)clsmeth1 +{ + return @"objc-cls"; +} + + ++(id)invokeInst:(OC_NSUnavailable*)inst +{ + return [inst instmeth1]; +} + ++(id)invokeCls +{ + return [self clsmeth1]; +} + +@end + +@implementation OC_NSUnavailableChild +- (id)instmeth1 +{ + return @"objc-inst child"; +} + ++ (id)clsmeth1 +{ + return @"objc-cls child"; +} +@end + + +static PyMethodDef mod_methods[] = {{0, 0, 0, 0}}; + +static struct PyModuleDef mod_module = { + PyModuleDef_HEAD_INIT, "unavailable", NULL, 0, mod_methods, NULL, NULL, NULL, NULL}; + +PyObject* PyInit_unavailable(void); + +PyObject* __attribute__((__visibility__("default"))) PyInit_unavailable(void) +{ + PyObject* m; + + m = PyModule_Create(&mod_module); + if (!m) { + return NULL; + } + + PyObjC_ImportAPI(m); + + if (PyModule_AddObject(m, "OC_NSUnavailable", PyObjC_IdToPython([OC_NSUnavailable class])) + < 0) { + return NULL; + } + + if (PyModule_AddObject(m, "OC_NSUnavailableChild", PyObjC_IdToPython([OC_NSUnavailableChild class])) + < 0) { + return NULL; + } + + return m; +} diff --git a/pyobjc-core/PyObjCTest/test_nsunavailable.py b/pyobjc-core/PyObjCTest/test_nsunavailable.py new file mode 100644 index 0000000000..7ebd608355 --- /dev/null +++ b/pyobjc-core/PyObjCTest/test_nsunavailable.py @@ -0,0 +1,63 @@ +import objc +from .unavailable import OC_NSUnavailable, OC_NSUnavailableChild +from PyObjCTools.TestSupport import TestCase + +objc.registerUnavailableMethod("OC_NSUnavailable", b"instmeth1") +objc.registerUnavailableMethod("OC_NSUnavailable", b"clsmeth1") + + +class OC_PyUnavailable(OC_NSUnavailable): + def instmeth1(self): + return "py-inst" + + @classmethod + def clsmeth1(self): + return "py-cls" + + +class TestUnavailable(TestCase): + def test_method_unavailable(self): + v = OC_NSUnavailable.alloc().init() + with self.assertRaisesRegex(TypeError, "'instmeth1' is NS_UNAVAILABLE"): + v.instmeth1() + + with self.assertRaisesRegex(TypeError, "'clsmeth1' is NS_UNAVAILABLE"): + OC_NSUnavailable.clsmeth1() + + with self.assertRaisesRegex(AttributeError, "has no attribute 'clsmeth1'"): + v.clsmeth1() + + def test_method_unavailable_in_subclass(self): + # Same as test_method_unavailable but with + # OC_NSUnavailbleChild. + v = OC_NSUnavailableChild.alloc().init() + with self.assertRaisesRegex(TypeError, "'instmeth1' is NS_UNAVAILABLE"): + v.instmeth1() + + with self.assertRaisesRegex(TypeError, "'clsmeth1' is NS_UNAVAILABLE"): + OC_NSUnavailableChild.clsmeth1() + + with self.assertRaisesRegex(AttributeError, "has no attribute 'clsmeth1'"): + v.clsmeth1() + + # XXX: Add this (and corresponding implementation) when + # there are instances where a Cocoa class uses + # NS_UNAVAILABLE and a Cocoa subclass makes it available + # again ('Cocoa subclass' being 'in Apple's system headers') + # + # def test_method_availble_in_subclass(self): + # self.fail() + # + + def test_instance_method_defined_in_python(self): + # Subclass class from `test_instance_method_unavailable` and + # define the unavailable method. Check that method then works + # on the subclass (and still doesn't work on parent class) + + v = OC_PyUnavailable.alloc().init() + self.assertEqual(v.instmeth1(), "py-inst") + self.assertEqual(OC_PyUnavailable.clsmeth1(), "py-cls") + + # Also test by invoking the selector through ObjC + self.assertEqual(OC_PyUnavailable.invokeInst_(v), "py-inst") + self.assertEqual(OC_PyUnavailable.invokeCls(), "py-cls") From 2a490ec1748add2594bbcefafb12d1cc638e121a Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Fri, 3 May 2024 20:40:35 +0200 Subject: [PATCH 12/23] Fix docstrings for the __new__ method --- pyobjc-core/Lib/objc/_new.py | 58 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 8a9129ee2d..2625294847 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -15,9 +15,6 @@ import objc # TODO: -# - Calculate __new__.__doc__ statically for Python subclasses -# - Likewise for ObjC classes (should be possible by updating -# doc strings when new keywords are registered) # - Make sure __init__ is never invoked implicitly (it # currently is when __new__ is invoked). There is a slight # risks this breaks code that implements a custom __new__ @@ -27,10 +24,6 @@ # also support the generic __new__ interface. # - Document the feature # - Add tests [in progress] -# - Maybe: somehow add __doc__ to classes that reflect the -# __new__ API. -# - Maybe: In 3.13 switch to MultiSignature instead of -# __doc__ (assuming #117671 is merged) # # - Later: generate class/module documentation for framework # bindings, including the generated __new__ signatures. @@ -41,9 +34,6 @@ # __new__ returns more than one value (e.g. has some output # arguments, such as -[FooClass initWithValue:(int)value error:(NSError**)error] # -# FIXME: 'unavailable' annations vs. calls methods -# (fairly sure those don't work properly yet with current setup) - __all__ = () # Mapping: class name -> { kwds: selector_name } @@ -68,6 +58,34 @@ DOC_SUFFIX = "The order of keyword arguments is significant\n" +def calculate_new_doc(cls): + """ + Calculate the docstring for the __new__ + for *cls* + """ + result = {} + for c in reversed(cls.__mro__): + new_map = NEW_MAP.get(c.__name__, UNSET) + if new_map is UNSET: + continue + + for kwds, selector in new_map.items(): + if selector is None: + result.pop(kwds, None) + + if not kwds: + result[kwds] = f"{cls.__name__}(): " + else: + result[kwds] = f"{cls.__name__}(*, " + ", ".join(kwds) + "): " + if selector.startswith("init"): + result[ + kwds + ] += f"\n returns cls.alloc().{selector}({', '.join(kwds)})\n\n" + else: + result[kwds] += f"\n returns cls.{selector}({', '.join(kwds)})\n\n" + return "".join(sorted(result.values())) + DOC_SUFFIX + + class _function: """ Wrapper for the __new__ function to generate the @@ -86,25 +104,7 @@ def __class__(self): @property def __doc__(self): - result = {} - for c in reversed(self._cls.__mro__): - new_map = NEW_MAP.get(c, UNSET) - if new_map is UNSET: - continue - - for kwds, selector in new_map.items(): - if selector is None: - result.pop(kwds, None) - - if not kwds: - result[kwds] = f"{self._cls.__name__}(): " - else: - result[kwds] = f"{self._cls.__name__}(*, " + ", ".join(kwds) + "): " - if selector.startswith("init"): - result[kwds] += f" returns cls.alloc().{selector}()\n\n" - else: - result[kwds] += f" returns cls.{selector}()\n\n" - return "".join(sorted(result.values())) + DOC_SUFFIX + return calculate_new_doc(self._cls) def __getattr__(self, name): return getattr(self._function, name) From 8ee9abf2143c747e43e61d8964467bcda79286f2 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Fri, 3 May 2024 21:03:56 +0200 Subject: [PATCH 13/23] Don't call NSObject.__init__ after __new__ This changeset implements ``objc.objc_class.__call__`` to make sure that calling a class to invoke the ``__new__`` slot will never call ``__init__``. This can break code that explicitly implements ``__new__`` and ``__init__``, but is needed to get consistent behaviour for the new generic ``__new__`` method. User code should always follow the ObjC convention for initializing instances by implementing one or more 'init' methods. --- pyobjc-core/Lib/objc/_new.py | 11 ----------- pyobjc-core/Modules/objc/objc-class.m | 16 ++++++++++++++++ pyobjc-core/PyObjCTest/test_generic_new.py | 11 +++++------ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 2625294847..3f6d11e5ad 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -15,11 +15,6 @@ import objc # TODO: -# - Make sure __init__ is never invoked implicitly (it -# currently is when __new__ is invoked). There is a slight -# risks this breaks code that implements a custom __new__ -# and relies on the invocation of __init__ -# (Implement by overriding tp_call in objc-class) # - Update the __new__ implementation for _convenience* to # also support the generic __new__ interface. # - Document the feature @@ -28,12 +23,6 @@ # - Later: generate class/module documentation for framework # bindings, including the generated __new__ signatures. # -# FIXME: __init__ invocation is a mess, consider trying -# to suppress its invocation. Currently: __init__ is -# invoked by the interpreter when __new__ is called, unless -# __new__ returns more than one value (e.g. has some output -# arguments, such as -[FooClass initWithValue:(int)value error:(NSError**)error] -# __all__ = () # Mapping: class name -> { kwds: selector_name } diff --git a/pyobjc-core/Modules/objc/objc-class.m b/pyobjc-core/Modules/objc/objc-class.m index 72bdcdaf65..dc880be3eb 100644 --- a/pyobjc-core/Modules/objc/objc-class.m +++ b/pyobjc-core/Modules/objc/objc-class.m @@ -345,6 +345,20 @@ static Class _Nullable objc_metaclass_locate(PyObject* meta_class) * Note: This function creates new _classes_ */ +static PyObject* _Nullable class_call(PyObject* self, PyObject* _Nullable args, PyObject* _Nullable kwds) +{ + PyTypeObject* type = (PyTypeObject*)self; + + if (type->tp_new == NULL) { + PyErr_Format( PyExc_TypeError, + "cannot create '%s' instances", type->tp_name); + return NULL; + } + + return type->tp_new(type, args, kwds); +} + + static int class_init(PyObject* cls, PyObject* args, PyObject* kwds) { @@ -365,6 +379,7 @@ static Class _Nullable objc_metaclass_locate(PyObject* meta_class) return PyType_Type.tp_init(cls, args, kwds); } + static PyObject* _Nullable class_new(PyTypeObject* type __attribute__((__unused__)), PyObject* _Nullable args, PyObject* _Nullable kwds) { @@ -2424,6 +2439,7 @@ static Class _Nullable objc_metaclass_locate(PyObject* meta_class) .tp_base = &PyObjCMetaClass_Type, .tp_init = class_init, .tp_new = class_new, + .tp_call = class_call, }; /* diff --git a/pyobjc-core/PyObjCTest/test_generic_new.py b/pyobjc-core/PyObjCTest/test_generic_new.py index 75ede66dc2..cd68aff978 100644 --- a/pyobjc-core/PyObjCTest/test_generic_new.py +++ b/pyobjc-core/PyObjCTest/test_generic_new.py @@ -83,16 +83,15 @@ def initWithValue_(self, v): return self def __init__(self, **kwds): - # __init__ will be called when __new__ - # is invoked, but not when the instance - # is created regularly. + # __init__ is never called automaticly for + # Cocoa classes. self.value += 1 v = OCPyNew3.alloc().initWithValue_(3) self.assertEqual(v.value, 3) v = OCPyNew3(value=4) - self.assertEqual(v.value, 5) + self.assertEqual(v.value, 4) def test_dunder_init_with_error(self): class OCPyNew4(NSObject): @@ -102,8 +101,8 @@ def initWithValue_error_(self, v, error): return self, None def __init__(self, **kwds): - # __init__ will not be called when the - # init method returns 2 values. + # __init__ is never called automaticly for + # Cocoa classes. self.value += 1 v, e = OCPyNew4.alloc().initWithValue_error_(3, None) From e28c55b0f3e4827286b81216dad95ca7b8d26f9c Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Fri, 3 May 2024 21:27:24 +0200 Subject: [PATCH 14/23] Add documentation on using the generic __new__ functionality --- docs/_templates/index.html | 1 + docs/index.rst | 1 + docs/notes/instantiating.rst | 57 ++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 docs/notes/instantiating.rst diff --git a/docs/_templates/index.html b/docs/_templates/index.html index 5a2c17d742..e63450941e 100644 --- a/docs/_templates/index.html +++ b/docs/_templates/index.html @@ -55,6 +55,7 @@

General documentation

Various notes
    +
  • Instantiation Objective-C objects
  • Using Objective-C protocols
  • Using Objective-C blocks
  • Using Objective-C SIMD types diff --git a/docs/index.rst b/docs/index.rst index ed79d772ca..acb1062656 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -56,6 +56,7 @@ General documentation metadata/index tutorials/index notes/exceptions + notes/instantiation notes/quartz-vs-coregraphics notes/using-nsxpcinterface notes/ctypes diff --git a/docs/notes/instantiating.rst b/docs/notes/instantiating.rst new file mode 100644 index 0000000000..bfe8345352 --- /dev/null +++ b/docs/notes/instantiating.rst @@ -0,0 +1,57 @@ +Instantiating Objective-C objects +================================= + + +.. versionchanged:: 10.4 + + The Pythonic interface for instantiation classes + was added. + +Objective-C uses a two step object instantatin +process, similar to Python's ``__new__`` and +``__init__`` methods, but with explicit invocation +of the methods ``alloc`` and ``init``. By default +this is mirrored in the Python proxies: + +.. sourcecode:: python + + some_value = NSObject.alloc().init() + + some_button = NSButton.alloc().initWithFrame_(some_frame) + + +This looks very foreign in Python, therefore PyObjC +also supports a condensed version of this by directly +calling the class:: + +.. sourcecode:: python + + some_value = NSObject() + + some_button = NSButton(frame=some_frame) + +The generic rules for instantiation objects through calling +the class are: + +* Calling the class without arguments in supported unless + the ``init`` method has been marked with ``NS_UNAVAILABLE`` + in Apple's SDK. + +* Every instance selector of the Objective-C with a name starting + with ``init`` adds a possible set of keyword arguments using + the following algorithm: + + 1. Strip ``initWith`` or ``init`` from the start of the selector; + + 2. Lowercase the first character of the result + + 3. All segments are now keyword only arguments, in that order. + + For example given, ``-[SomeClass initWithX:y:z]`` the + following invocation is valid: ``SomeClass(x=1, y=2, z=3)``. + Using the keywords in a different order is not valid. + +* Some classes may have additional sets of keyword arguments, + whose will be documented in the framework notes. In general + those will be based on factory class methods for which there + are no equivalent using the ``alloc().init...(...)`` pattern. From aaec9045bc85b8006789457f0db262985690f588 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Fri, 3 May 2024 21:51:39 +0200 Subject: [PATCH 15/23] Some code and cleanups and more documentation --- docs/notes/instantiating.rst | 25 +++++++++++++++++++++++++ pyobjc-core/Lib/objc/_convenience.py | 4 ++-- pyobjc-core/Lib/objc/_new.py | 7 +++---- pyobjc-core/Lib/objc/_transform.py | 2 +- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/docs/notes/instantiating.rst b/docs/notes/instantiating.rst index bfe8345352..92ed1fd234 100644 --- a/docs/notes/instantiating.rst +++ b/docs/notes/instantiating.rst @@ -55,3 +55,28 @@ the class are: whose will be documented in the framework notes. In general those will be based on factory class methods for which there are no equivalent using the ``alloc().init...(...)`` pattern. + +For classes in system frameworks the possibly init method are +registered using frmaework data. + +For classes implemented in Python the possible init methods +are detected automatically, just implement one or more Objective-C +style init methods to add sets of keyword arguments for ``__new__`` +(and don't implement ``__new__`` or ``__init__`` in the Python +class). + +Set ``init`` to ``None`` to require using one or more keyword +arguments, that is: + +.. sourcecode:: python + + class MyObject(NSObject): + init = None # Calling MyOjbect() is not allowed + + def initWithX_y_(self, x_value, y_value): + self = super.init() + self.x = x_value + self.y = y_value + return self + + value = MyValue(x=42, y=24) diff --git a/pyobjc-core/Lib/objc/_convenience.py b/pyobjc-core/Lib/objc/_convenience.py index 5d53cf38f6..45e82b619f 100644 --- a/pyobjc-core/Lib/objc/_convenience.py +++ b/pyobjc-core/Lib/objc/_convenience.py @@ -13,7 +13,7 @@ selector, ) import PyObjCTools.KeyValueCoding as kvc -from objc._new import _make_new, NEW_MAP +from objc._new import make_generic_new, NEW_MAP from objc._transform import _selectorToKeywords __all__ = ( @@ -69,7 +69,7 @@ class name to a list of Python method names and implementation. if not cls.__has_python_implementation__ and type( # noqa: E721 cls.__mro__[1].__new__ ) != type(lambda: None): - type_dict["__new__"] = _make_new(cls) + type_dict["__new__"] = make_generic_new(cls) for nm, value in CLASS_METHODS.get(cls.__name__, ()): type_dict[nm] = value diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 3f6d11e5ad..934cf934c0 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -17,7 +17,6 @@ # TODO: # - Update the __new__ implementation for _convenience* to # also support the generic __new__ interface. -# - Document the feature # - Add tests [in progress] # # - Later: generate class/module documentation for framework @@ -75,7 +74,7 @@ def calculate_new_doc(cls): return "".join(sorted(result.values())) + DOC_SUFFIX -class _function: +class function_wrapper: """ Wrapper for the __new__ function to generate the docstring dynamically. @@ -107,7 +106,7 @@ def __call__(self, *args, **kwds): return self._function(*args, **kwds) -def _make_new(cls): +def make_generic_new(cls): def __new__(cls, **kwds): """ Generic implementation for Objective-C `__new__`. @@ -156,4 +155,4 @@ def __new__(cls, **kwds): __new__.__name__ = cls.__name__ + ".__new__" __new__.__qualname__ = cls.__name__ + ".__new__" __new__.__module__ = cls.__module__ - return _function(__new__, cls) + return function_wrapper(__new__, cls) diff --git a/pyobjc-core/Lib/objc/_transform.py b/pyobjc-core/Lib/objc/_transform.py index 281ae1cab3..123e70332b 100644 --- a/pyobjc-core/Lib/objc/_transform.py +++ b/pyobjc-core/Lib/objc/_transform.py @@ -48,7 +48,7 @@ def _selectorToKeywords(selector): def setDunderNew( class_object, ): - class_object.__new__ = _new._make_new(class_object) + class_object.__new__ = _new.make_generic_new(class_object) def processClassDict( From 6e1e41c8454f0e3aa471f4f8d6fdbb4c795a36ad Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 5 May 2024 09:49:10 +0200 Subject: [PATCH 16/23] Improve testing for the generic new feature --- pyobjc-core/Lib/objc/_convenience.py | 8 +- pyobjc-core/Lib/objc/_new.py | 1 - pyobjc-core/Lib/objc/_transform.py | 5 +- pyobjc-core/Modules/objc/test/genericnew.m | 108 +++++++++++++++++++++ pyobjc-core/PyObjCTest/test_convenience.py | 78 +++++++++++++++ pyobjc-core/PyObjCTest/test_generic_new.py | 64 +++++++++++- 6 files changed, 258 insertions(+), 6 deletions(-) create mode 100644 pyobjc-core/Modules/objc/test/genericnew.m diff --git a/pyobjc-core/Lib/objc/_convenience.py b/pyobjc-core/Lib/objc/_convenience.py index 45e82b619f..cfee471a31 100644 --- a/pyobjc-core/Lib/objc/_convenience.py +++ b/pyobjc-core/Lib/objc/_convenience.py @@ -100,6 +100,8 @@ def registerUnavailableMethod(classname, selector): """ Mark *selector* as unavailable for *classname*. """ + if not isinstance(selector, bytes): + raise TypeError("selector should by a bytes object") selname = selector.decode() # This adds None as a replacement value instead of @@ -124,6 +126,8 @@ def registerNewKeywordsFromSelector(classname, selector): keyword arguments for __new__ for the given class. The selector should be an 'init' method. """ + if not isinstance(selector, bytes): + raise TypeError("selector should by a bytes object") selname = selector.decode() kw = _selectorToKeywords(selname) NEW_MAP.setdefault(classname, {})[kw] = selname.replace(":", "_") @@ -137,7 +141,9 @@ def registerNewKeywords(classname, keywords, methodname): Method should be either an init method or a class method. """ - NEW_MAP.setdefault(classname, {})[keywords] = method + if not isinstance(keywords, tuple) or not all(isinstance(x, str) for x in keywords): + raise TypeError("keywords must be tuple of strings") + NEW_MAP.setdefault(classname, {})[keywords] = methodname def registerABCForClass(classname, *abc_class): diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 934cf934c0..2248b7713f 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -17,7 +17,6 @@ # TODO: # - Update the __new__ implementation for _convenience* to # also support the generic __new__ interface. -# - Add tests [in progress] # # - Later: generate class/module documentation for framework # bindings, including the generated __new__ signatures. diff --git a/pyobjc-core/Lib/objc/_transform.py b/pyobjc-core/Lib/objc/_transform.py index 123e70332b..0d83b5c99d 100644 --- a/pyobjc-core/Lib/objc/_transform.py +++ b/pyobjc-core/Lib/objc/_transform.py @@ -32,7 +32,10 @@ def _isSelectorPrefix(name, prefix): def _selectorToKeywords(selector): - assert selector.startswith("init") + if not selector.startswith("init"): + raise ValueError("selector is not a valid init selector") + if len(selector) > 4 and not selector[4].isupper(): + raise ValueError("selector is a valid init selector") selector = selector[4:] if not selector: return () diff --git a/pyobjc-core/Modules/objc/test/genericnew.m b/pyobjc-core/Modules/objc/test/genericnew.m new file mode 100644 index 0000000000..b7c39a916e --- /dev/null +++ b/pyobjc-core/Modules/objc/test/genericnew.m @@ -0,0 +1,108 @@ +#include "Python.h" +#include "pyobjc-api.h" +#include + +#import + +@interface OC_GenericNew : NSObject { + NSObject* value; +} +@end +@interface OC_GenericNewChild : OC_GenericNew { +} +@end +@interface OC_GenericNewChild2 : OC_GenericNewChild { +} +@end + +@implementation OC_GenericNew +-(NSObject*)value +{ + return value; +} + +-(instancetype)init +{ + self = [super init]; + if (!self) return nil; + + value = nil; + return self; +} + +-(instancetype)initWithValue:(NSObject*)v +{ + self = [super init]; + if (!self) return nil; + + value = [v retain]; + return self; +} + +-(instancetype)initWithFirst:(NSObject*)first second:(NSObject*)second +{ + self = [super init]; + if (!self) return nil; + + value = [[NSArray alloc] initWithObjects:@"first-second", first,second,nil]; + return self; +} +@end + +@implementation OC_GenericNewChild + +-(instancetype)initWithX:(NSObject*)x y:(NSObject*)y +{ + self = [super init]; + if (!self) return nil; + + value = [[NSArray alloc] initWithObjects:@"x-y", x,y,nil]; + return self; +} +@end + +@implementation OC_GenericNewChild2 + +-(instancetype)initWithX:(NSObject*)x y:(NSObject*)y z:(NSObject*)z +{ + self = [super init]; + if (!self) return nil; + + value = [[NSArray alloc] initWithObjects:@"x-y-z", x,y,z,nil]; + return self; +} +@end + +static PyMethodDef mod_methods[] = {{0, 0, 0, 0}}; + +static struct PyModuleDef mod_module = { + PyModuleDef_HEAD_INIT, "genericnew", NULL, 0, mod_methods, NULL, NULL, NULL, NULL}; + +PyObject* PyInit_genericnew(void); + +PyObject* __attribute__((__visibility__("default"))) PyInit_genericnew(void) +{ + PyObject* m; + + m = PyModule_Create(&mod_module); + if (!m) { + return NULL; + } + + PyObjC_ImportAPI(m); + + if (PyModule_AddObject(m, "OC_GenericNew", PyObjC_IdToPython([OC_GenericNew class])) + < 0) { + return NULL; + } + if (PyModule_AddObject(m, "OC_GenericNewChild", PyObjC_IdToPython([OC_GenericNewChild class])) + < 0) { + return NULL; + } + if (PyModule_AddObject(m, "OC_GenericNewChild2", PyObjC_IdToPython([OC_GenericNewChild2 class])) + < 0) { + return NULL; + } + + return m; +} diff --git a/pyobjc-core/PyObjCTest/test_convenience.py b/pyobjc-core/PyObjCTest/test_convenience.py index 1985555ac4..374da1eb62 100644 --- a/pyobjc-core/PyObjCTest/test_convenience.py +++ b/pyobjc-core/PyObjCTest/test_convenience.py @@ -7,6 +7,9 @@ from PyObjCTest.sequence import OC_TestSequence, OC_TestMutableSequence from PyObjCTools.TestSupport import TestCase +from objc._new import NEW_MAP +from unittest import mock + objc.addConvenienceForBasicSequence("OC_TestSequence", False) objc.addConvenienceForBasicSequence("OC_TestMutableSequence", True) @@ -599,3 +602,78 @@ class FakeSequence2(objc.lookUpClass("NSObject")): pass self.assertTrue(issubclass(FakeSequence2, collections.abc.Sequence)) + + +class TestRegisterKeywords(TestCase): + def test_init_registration(self): + self.assertNotIn("OC_Keyword1", NEW_MAP) + + objc.registerNewKeywordsFromSelector("OC_Keyword1", b"init") + self.assertIn("OC_Keyword1", NEW_MAP) + self.assertEqual(len(NEW_MAP["OC_Keyword1"]), 1) + self.assertEqual(NEW_MAP["OC_Keyword1"][()], "init") + + objc.registerNewKeywordsFromSelector("OC_Keyword1", b"initWithFoo:bar:baz:") + self.assertEqual(len(NEW_MAP["OC_Keyword1"]), 2) + self.assertEqual( + NEW_MAP["OC_Keyword1"][("foo", "bar", "baz")], "initWithFoo_bar_baz_" + ) + + objc.registerNewKeywordsFromSelector("OC_Keyword1", b"initX:") + self.assertEqual(len(NEW_MAP["OC_Keyword1"]), 3) + self.assertEqual(NEW_MAP["OC_Keyword1"][("x",)], "initX_") + + with self.assertRaises(ValueError): + objc.registerNewKeywordsFromSelector("OC_Keyword1", b"keywordWithX:y:") + + with self.assertRaises(ValueError): + objc.registerNewKeywordsFromSelector("OC_Keyword1", b"initialize") + + with self.assertRaises(TypeError): + objc.registerNewKeywordsFromSelector("OC_Keyword1", "initWithFoo:bar:") + + self.assertEqual(len(NEW_MAP["OC_Keyword1"]), 3) + + def test_other_registration(self): + self.assertNotIn("OC_Keyword2", NEW_MAP) + + objc.registerNewKeywords("OC_Keyword2", ("a", "b"), "keywordWithValue1_value2_") + self.assertIn("OC_Keyword2", NEW_MAP) + self.assertEqual(len(NEW_MAP["OC_Keyword2"]), 1) + self.assertEqual( + NEW_MAP["OC_Keyword2"][("a", "b")], "keywordWithValue1_value2_" + ) + + objc.registerNewKeywords("OC_Keyword2", (), "keyword") + self.assertEqual(len(NEW_MAP["OC_Keyword2"]), 2) + self.assertEqual(NEW_MAP["OC_Keyword2"][()], "keyword") + + with self.assertRaises(TypeError): + objc.registerNewKeywords("OC_Keyword2", [], "keywords") + + with self.assertRaises(TypeError): + objc.registerNewKeywords("OC_Keyword2", "ab", "keywords") + + with self.assertRaises(TypeError): + objc.registerNewKeywords("OC_Keyword2", ("ab", 42), "keywords") + + self.assertEqual(len(NEW_MAP["OC_Keyword2"]), 2) + + def test_unavailable_registration(self): + self.assertNotIn("OC_Keyword3", NEW_MAP) + + with mock.patch("objc._convenience.registerMetaDataForSelector") as mck: + objc.registerUnavailableMethod("OC_Keyword3", b"init") + + mck.assert_called() + self.assertEqual(len(NEW_MAP["OC_Keyword3"]), 1) + self.assertIs(NEW_MAP["OC_Keyword3"][()], None) + + with mock.patch("objc._convenience.registerMetaDataForSelector") as mck: + objc.registerUnavailableMethod("OC_Keyword3", b"doubleX:y:") + + mck.assert_called() + self.assertEqual(len(NEW_MAP["OC_Keyword3"]), 1) + + with self.assertRaises(TypeError): + objc.registerUnavailableMethod("OC_Keyword3", "init") diff --git a/pyobjc-core/PyObjCTest/test_generic_new.py b/pyobjc-core/PyObjCTest/test_generic_new.py index cd68aff978..e669973211 100644 --- a/pyobjc-core/PyObjCTest/test_generic_new.py +++ b/pyobjc-core/PyObjCTest/test_generic_new.py @@ -2,9 +2,17 @@ from PyObjCTools.TestSupport import TestCase from objc import super # noqa: A004 import objc._new as new_mod +from .genericnew import OC_GenericNew, OC_GenericNewChild, OC_GenericNewChild2 NSObject = objc.lookUpClass("NSObject") +objc.registerNewKeywordsFromSelector("OC_GenericNew", b"initWithValue:") +objc.registerNewKeywordsFromSelector("OC_GenericNew", b"initWithFirst:second:") +objc.registerNewKeywordsFromSelector("OC_GenericNewChild", b"initWithX:y:") +objc.registerNewKeywordsFromSelector("OC_GenericNewChild2", b"initWithX:y:z:") +objc.registerUnavailableMethod("OC_GenericNewChild2", b"initWithX:y:") +objc.registerUnavailableMethod("OC_GenericNewChild2", b"init") + class TestDefaultNewForPythonClass(TestCase): def test_nsobject(self): @@ -132,6 +140,56 @@ def initWithValue_(self, new_value): self.assertEqual(v.value, 3) -# TODO: TestDefaultNewForObjectiveCClass -# Need the metadata update interface before implementing this. -# Also check interaction with __init__ +class TestDefaultNewForObjectiveCClass(TestCase): + # 1. Class with init methods + # 2. Subclass with more init methods + # 3. Sublcass with unavailable init methods + def test_base(self): + v = OC_GenericNew() + self.assertEqual(v.value(), None) + + v = OC_GenericNew(value=42) + self.assertEqual(v.value(), 42) + + v = OC_GenericNew(first=1, second=2) + self.assertEqual(v.value(), ["first-second", 1, 2]) + + with self.assertRaisesRegex( + TypeError, r"OC_GenericNew\(\) does not support keyword arguments 'x', 'y'" + ): + OC_GenericNew(x=1, y=2) + + def test_extended_base(self): + v = OC_GenericNewChild() + self.assertEqual(v.value(), None) + + v = OC_GenericNewChild(value=42) + self.assertEqual(v.value(), 42) + + v = OC_GenericNewChild(first=1, second=2) + self.assertEqual(v.value(), ["first-second", 1, 2]) + + v = OC_GenericNewChild(x=1, y=2) + self.assertEqual(v.value(), ["x-y", 1, 2]) + + def test_removed_init(self): + + with self.assertRaisesRegex( + TypeError, r"OC_GenericNewChild2\(\) requires keyword arguments" + ): + v = OC_GenericNewChild2() + + v = OC_GenericNewChild2(value=42) + self.assertEqual(v.value(), 42) + + v = OC_GenericNewChild2(first=1, second=2) + self.assertEqual(v.value(), ["first-second", 1, 2]) + + with self.assertRaisesRegex( + TypeError, + r"OC_GenericNewChild2\(\) does not support keyword arguments 'x', 'y'", + ): + OC_GenericNewChild2(x=1, y=2) + + v = OC_GenericNewChild2(x=1, y=2, z=3) + self.assertEqual(v.value(), ["x-y-z", 1, 2, 3]) From dc708c44d5156cb827c65e0f6577bb4242188822 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 5 May 2024 10:04:07 +0200 Subject: [PATCH 17/23] Support generic new functionality for NSArray classes These classes already had a __new__ method, restructure the code to support both generic new feature and the older Python compatible interface. This breaks using a keyword argument named "sequence", support was dropped to get an easier to explain interface. This is compatible with the interface for list and tuple because don't accept keyword arguments at all. --- pyobjc-core/Lib/objc/_convenience_nsarray.py | 18 ++++++++++++------ pyobjc-core/Lib/objc/_new.py | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/pyobjc-core/Lib/objc/_convenience_nsarray.py b/pyobjc-core/Lib/objc/_convenience_nsarray.py index d0fcdf96fd..a8c073a399 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsarray.py +++ b/pyobjc-core/Lib/objc/_convenience_nsarray.py @@ -11,6 +11,7 @@ from objc._objc import _C_ID, _C_NSInteger from objc._objc import _NSNotFound as NSNotFound from objc._objc import lookUpClass, registerMetaDataForSelector +from ._new import NEW_MAP NSArray = lookUpClass("NSArray") NSMutableArray = lookUpClass("NSMutableArray") @@ -297,6 +298,11 @@ def nsarray_new(cls, sequence=None): return NSArray.arrayWithArray_(sequence) +for cls in ("NSArray", "__NSArrayI", "__NSArrayM", "__NSArray0"): + d = NEW_MAP.setdefault(cls, {}) + d[()] = nsarray_new + + def nsmutablearray_new(cls, sequence=None): if not sequence: return NSMutableArray.array() @@ -314,6 +320,11 @@ def nsmutablearray_new(cls, sequence=None): return NSMutableArray.arrayWithArray_(sequence) +for cls in ("NSMutableArray",): + d = NEW_MAP.setdefault(cls, {}) + d[()] = nsmutablearray_new + + def nsarray__contains__(self, elem): return bool(self.containsObject_(container_wrap(elem))) @@ -374,7 +385,6 @@ def nsarray__iter__(self): addConvenienceForClass( "NSArray", ( - ("__new__", staticmethod(nsarray_new)), ("__add__", nsarray_add), ("__radd__", nsarray_radd), ("__mul__", nsarray_mul), @@ -401,10 +411,7 @@ def nsarray__iter__(self): ): addConvenienceForClass( cls, - ( - ("__new__", staticmethod(nsarray_new)), - ("pop", nsarray_pop), - ), + (("pop", nsarray_pop),), ) @@ -415,7 +422,6 @@ def nsmutablearray__copy__(self): addConvenienceForClass( "NSMutableArray", ( - ("__new__", staticmethod(nsmutablearray_new)), ("__copy__", nsmutablearray__copy__), ("__setitem__", nsarray__setitem__), ("__delitem__", nsarray__delitem__), diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 2248b7713f..12365c3adc 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -106,11 +106,10 @@ def __call__(self, *args, **kwds): def make_generic_new(cls): - def __new__(cls, **kwds): + def __new__(cls, *args, **kwds): """ Generic implementation for Objective-C `__new__`. """ - # XXX: should this sort the keywords? key = tuple(kwds.keys()) for c in cls.__mro__: @@ -130,6 +129,18 @@ def __new__(cls, **kwds): else: raise TypeError(f"{cls.__name__}() requires keyword arguments") + if not isinstance(name, str): + # Assume that 'name' is actually a callable. + # + # This is used to implement custom signatures for a number + # of classes in the various ._convenience sibling modules. + return name(cls, *args, **kwds) + + if args: + raise TypeError( + f"{cls.__name__}() does not accept positional arguments" + ) + args = [kwds[n] for n in key] if name.startswith("init") and len(name) == 4 or name[4].isupper(): return getattr(cls.alloc(), name)(*args) From db8fc1da9d598f559ee0585e43587106de6c59c0 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 5 May 2024 20:34:06 +0200 Subject: [PATCH 18/23] Remove test_posing because it is only relevant for 32-bit code --- pyobjc-core/PyObjCTest/test_posing.py | 42 --------------------------- 1 file changed, 42 deletions(-) delete mode 100644 pyobjc-core/PyObjCTest/test_posing.py diff --git a/pyobjc-core/PyObjCTest/test_posing.py b/pyobjc-core/PyObjCTest/test_posing.py deleted file mode 100644 index cd282a14b7..0000000000 --- a/pyobjc-core/PyObjCTest/test_posing.py +++ /dev/null @@ -1,42 +0,0 @@ -import sys - -import objc -from PyObjCTools.TestSupport import TestCase - -# Most useful systems will at least have 'NSObject'. -# NSObject = objc.lookUpClass('NSObject') - -# Use a class that isn't used in the rest of the testsuite, -# should write a native class for this! -BaseName = "NSAttributedString" -BaseClass = objc.lookUpClass(BaseName) - -if sys.maxsize >= 2**32: - # -poseAsClass: is not supported in 64-bit mode (the functionality is - # not present in the 64-bit runtime and will never be because it - # conflicts with new functionality such as non-fragile class layouts) - pass - -else: - - class TestPosing(TestCase): - def testPosing(self): - class PoseClass(BaseClass): - __slots__ = () # Don't add instance variables, not even __dict__ - - def testPosingMethod(self): - return "" - - PoseClass.poseAsClass_(BaseClass) - - # BaseClass still refers to the old class, if we look it up again - # we get to see the new value. There's not much we can do about that. - obj = objc.lookUpClass(BaseName).new() - self.assertEqual(obj.testPosingMethod(), "") - - # XXX: next assertion fails because the runtime seems to copy the - # original class. - # self.assertIsInstance(obj, PoseClass) - self.assertNotEqual(BaseClass.__name__, BaseName) - self.assertEqual(PoseClass.__name__, BaseName) - del obj From 350d2d7bf51f3df8211912e5479d8808c4ebea96 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 5 May 2024 20:35:31 +0200 Subject: [PATCH 19/23] Reactivate tests These have been active for a long time --- pyobjc-core/PyObjCTest/test_varargs.py | 81 +++++++++++++------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/pyobjc-core/PyObjCTest/test_varargs.py b/pyobjc-core/PyObjCTest/test_varargs.py index 7db84d4dbb..474cd1ebc1 100644 --- a/pyobjc-core/PyObjCTest/test_varargs.py +++ b/pyobjc-core/PyObjCTest/test_varargs.py @@ -3,59 +3,58 @@ NSObject = objc.lookUpClass("NSObject") -if 0: - class VarargsMethod(TestCase): - def testVariableArgumentCount(self): - class VarArgsClass1(NSObject): - def instanceMethod1_(self, arg1, *args): - arg1.append(args) +class VarargsMethod(TestCase): + def testVariableArgumentCount(self): + class VarArgsClass1(NSObject): + def instanceMethod1_(self, arg1, *args): + arg1.append(args) - def classMethod1_(cls, arg1, *args): - arg1.append(args) + def classMethod1_(cls, arg1, *args): + arg1.append(args) - classMethod1_ = classmethod(classMethod1_) + classMethod1_ = classmethod(classMethod1_) - def instanceMethod2_(self, *args): - args[0].append(args[1:]) + def instanceMethod2_(self, *args): + args[0].append(args[1:]) - def classMethod2_(cls, *args): - args[0].append(args[1:]) + def classMethod2_(cls, *args): + args[0].append(args[1:]) - classMethod2_ = classmethod(classMethod2_) + classMethod2_ = classmethod(classMethod2_) - o = VarArgsClass1.alloc().init() - lst = [] - o.instanceMethod1_(lst, 1, 2, 3) - self.assertEqual(lst, [(1, 2, 3)]) + o = VarArgsClass1.alloc().init() + lst = [] + o.instanceMethod1_(lst, 1, 2, 3) + self.assertEqual(lst, [(1, 2, 3)]) - lst = [] - VarArgsClass1.classMethod1_(lst, 3, 4, 5) - self.assertEqual(lst, [(3, 4, 5)]) + lst = [] + VarArgsClass1.classMethod1_(lst, 3, 4, 5) + self.assertEqual(lst, [(3, 4, 5)]) - lst = [] - o.instanceMethod2_(lst, 1, 2, 3) - self.assertEqual(lst, [(1, 2, 3)]) + lst = [] + o.instanceMethod2_(lst, 1, 2, 3) + self.assertEqual(lst, [(1, 2, 3)]) - lst = [] - VarArgsClass1.classMethod2_(lst, 3, 4, 5) - self.assertEqual(lst, [(3, 4, 5)]) + lst = [] + VarArgsClass1.classMethod2_(lst, 3, 4, 5) + self.assertEqual(lst, [(3, 4, 5)]) - def testKeywordArguments(self): - class VarArgsClass2(NSObject): - def instanceMethod1_(self, arg1, **kwds): - arg1.append(kwds) + def testKeywordArguments(self): + class VarArgsClass2(NSObject): + def instanceMethod1_(self, arg1, **kwds): + arg1.append(kwds) - def classMethod1_(cls, arg1, **kwds): - arg1.append(kwds) + def classMethod1_(cls, arg1, **kwds): + arg1.append(kwds) - classMethod1_ = classmethod(classMethod1_) + classMethod1_ = classmethod(classMethod1_) - o = VarArgsClass2.alloc().init() - lst = [] - o.instanceMethod1_(lst, a=1, c=2) - self.assertEqual(lst, [{"a": 1, "c": 2}]) + o = VarArgsClass2.alloc().init() + lst = [] + o.instanceMethod1_(lst, a=1, c=2) + self.assertEqual(lst, [{"a": 1, "c": 2}]) - lst = [] - VarArgsClass2.classMethod1_(lst, foo="bar", baz="foo") - self.assertEqual(lst, [{"foo": "bar", "baz": "foo"}]) + lst = [] + VarArgsClass2.classMethod1_(lst, foo="bar", baz="foo") + self.assertEqual(lst, [{"foo": "bar", "baz": "foo"}]) From 055fb6e0de073c8803b0c652f7e361c03c9062f6 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 5 May 2024 20:39:24 +0200 Subject: [PATCH 20/23] Switch to using super to avoid test error Test fails when running `python -m unittest PyObjCTest/test_leaks.py`, but passes when run as part of complete test run. Using super is more correct here. --- pyobjc-core/PyObjCTest/test_leaks.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyobjc-core/PyObjCTest/test_leaks.py b/pyobjc-core/PyObjCTest/test_leaks.py index 850492d73a..0b04e5b153 100644 --- a/pyobjc-core/PyObjCTest/test_leaks.py +++ b/pyobjc-core/PyObjCTest/test_leaks.py @@ -7,6 +7,7 @@ import objc from PyObjCTest.fnd import NSAutoreleasePool, NSMutableArray, NSObject from PyObjCTools.TestSupport import TestCase +from objc import super # noqa: A004 LeaksDel = 0 @@ -26,14 +27,14 @@ class SlottedClass(NSObject): __slots__ = ("slot1",) def init(self): - NSObject.pyobjc_instanceMethods.init(self) + self = super().init() self.slot1 = LeaksClass.alloc().init() return self class MemberClass(NSObject): def init(self): - self = NSObject.pyobjc_instanceMethods.init(self) + self = super().init() self.slot1 = LeaksClass.alloc().init() return self From 62b5dcf1a976e86552ded322e275a2297c1207d0 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 5 May 2024 20:44:50 +0200 Subject: [PATCH 21/23] Fix running `PyObjCTest/test_keyvaluecoding.py` standalone The test imports `PyObjCTools.KeyValueCoding` before importing `objc` and that causes a problem because `KeyValueCoding` imports `objc` at the start of the module and `objc` tries to access a not yet defined attribute of the module... NOTE: This is a fairly crude fix, long term most of the KeyValueCoding module needs to be moved into 'objc' --- pyobjc-core/Lib/PyObjCTools/KeyValueCoding.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pyobjc-core/Lib/PyObjCTools/KeyValueCoding.py b/pyobjc-core/Lib/PyObjCTools/KeyValueCoding.py index b96c301dc8..b257574200 100644 --- a/pyobjc-core/Lib/PyObjCTools/KeyValueCoding.py +++ b/pyobjc-core/Lib/PyObjCTools/KeyValueCoding.py @@ -29,10 +29,8 @@ import collections.abc import types -import objc __all__ = ("getKey", "setKey", "getKeyPath", "setKeyPath") -_null = objc.lookUpClass("NSNull").null() def keyCaps(s): @@ -382,3 +380,13 @@ def __setitem__(self, item, value): if not isinstance(item, str): raise TypeError("Keys must be strings") setKeyPath(self.__pyobjc_object__, item, value) + + +# The import of 'objc' is at the end of the module +# to avoid problems when importing this module before +# importing objc due to the objc package importing bits +# of this module. + +import objc # noqa: E402 + +_null = objc.lookUpClass("NSNull").null() From 7943b870c53ed7c889ef238122b23dd19a671793 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 5 May 2024 20:50:55 +0200 Subject: [PATCH 22/23] Fix use of strtoul The contract of strtoul only says it will set errno on error, not that it won't set errno when there isn't an error. Explicitly set errno to 0. This avoids a test failure when running test_functions.py standalone. --- pyobjc-core/Modules/objc/options.m | 1 + 1 file changed, 1 insertion(+) diff --git a/pyobjc-core/Modules/objc/options.m b/pyobjc-core/Modules/objc/options.m index 041de1b778..6206b3dc15 100644 --- a/pyobjc-core/Modules/objc/options.m +++ b/pyobjc-core/Modules/objc/options.m @@ -218,6 +218,7 @@ unsigned long major = 0; unsigned long minor = 0; + errno = 0; major = strtoul(text, &text, 10); if (major >= 100 || ((major == 0 || major == ULONG_MAX) && errno != 0)) { PyErr_Format(PyExc_ValueError, From 8ed363d0cb47fb281a25ac453870ee301eeb78e3 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Sun, 5 May 2024 20:52:43 +0200 Subject: [PATCH 23/23] Update the existing __new__ implementations for the generic new All classes except NSDictionary and NSMutableDictionary now support the generic new interface as well as the older interface. The two dictionary classes cannot be converted because the python dict-like interface conflicts with generic new. --- pyobjc-core/Lib/objc/_convenience_nsarray.py | 3 +-- pyobjc-core/Lib/objc/_convenience_nsdata.py | 7 +++++-- pyobjc-core/Lib/objc/_convenience_nsdecimal.py | 4 +++- pyobjc-core/Lib/objc/_convenience_nsset.py | 6 +++--- pyobjc-core/Lib/objc/_convenience_nsstring.py | 10 ++++------ pyobjc-core/Lib/objc/_new.py | 7 ------- 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/pyobjc-core/Lib/objc/_convenience_nsarray.py b/pyobjc-core/Lib/objc/_convenience_nsarray.py index a8c073a399..b16054eda7 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsarray.py +++ b/pyobjc-core/Lib/objc/_convenience_nsarray.py @@ -299,8 +299,7 @@ def nsarray_new(cls, sequence=None): for cls in ("NSArray", "__NSArrayI", "__NSArrayM", "__NSArray0"): - d = NEW_MAP.setdefault(cls, {}) - d[()] = nsarray_new + NEW_MAP.setdefault(cls, {})[()] = nsarray_new def nsmutablearray_new(cls, sequence=None): diff --git a/pyobjc-core/Lib/objc/_convenience_nsdata.py b/pyobjc-core/Lib/objc/_convenience_nsdata.py index 60ef179e9e..4bbf3e2fdd 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsdata.py +++ b/pyobjc-core/Lib/objc/_convenience_nsdata.py @@ -8,6 +8,7 @@ from objc._convenience import addConvenienceForClass from objc._objc import registerMetaDataForSelector +from ._new import NEW_MAP import sys import operator @@ -53,6 +54,10 @@ def nsdata__new__(cls, value=None): return cls.dataWithBytes_length_(view, len(view)) +for cls in ("NSData", "NSMutableData"): + NEW_MAP.setdefault(cls, {})[()] = nsdata__new__ + + def nsdata__str__(self): if len(self) == 0: return str(b"") @@ -249,7 +254,6 @@ def nsdata_isascii(self, *args, **kwds): addConvenienceForClass( "NSData", ( - ("__new__", staticmethod(nsdata__new__)), ("__len__", lambda self: self.length()), ("__str__", nsdata__str__), ("__getitem__", nsdata__getitem__), @@ -421,7 +425,6 @@ def nsmutabledata_clear(self): addConvenienceForClass( "NSMutableData", ( - ("__new__", staticmethod(nsdata__new__)), ("__setitem__", nsmutabledata__setitem__), ("__delitem__", nsmutabledata__delitem__), ("__iadd__", nsmutabledata__iadd__), diff --git a/pyobjc-core/Lib/objc/_convenience_nsdecimal.py b/pyobjc-core/Lib/objc/_convenience_nsdecimal.py index d4bc7ccfb8..63e2b18f1f 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsdecimal.py +++ b/pyobjc-core/Lib/objc/_convenience_nsdecimal.py @@ -10,6 +10,7 @@ from objc._convenience import addConvenienceForClass from objc._objc import NSDecimal, lookUpClass +from ._new import NEW_MAP NSDecimalNumber = lookUpClass("NSDecimalNumber") @@ -39,10 +40,11 @@ def decimal_new(cls, value=None): raise TypeError("Value is not a number") +NEW_MAP.setdefault("NSDecimalNumber", {})[()] = decimal_new + addConvenienceForClass( "NSDecimalNumber", ( - ("__new__", staticmethod(decimal_new)), ( "__add__", lambda self, other: NSDecimalNumber(operator.add(NSDecimal(self), other)), diff --git a/pyobjc-core/Lib/objc/_convenience_nsset.py b/pyobjc-core/Lib/objc/_convenience_nsset.py index 091b4941fe..7b0ed1b34e 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsset.py +++ b/pyobjc-core/Lib/objc/_convenience_nsset.py @@ -8,6 +8,7 @@ from objc._convenience import addConvenienceForClass, container_unwrap, container_wrap from objc._objc import lookUpClass +from ._new import NEW_MAP NSSet = lookUpClass("NSSet") NSMutableSet = lookUpClass("NSMutableSet") @@ -342,6 +343,5 @@ def nsmutableset_new(cls, sequence=None): return value -addConvenienceForClass("NSSet", (("__new__", staticmethod(nsset_new)),)) - -addConvenienceForClass("NSMutableSet", (("__new__", staticmethod(nsmutableset_new)),)) +NEW_MAP.setdefault("NSSet", {})[()] = nsset_new +NEW_MAP.setdefault("NSMutableSet", {})[()] = nsmutableset_new diff --git a/pyobjc-core/Lib/objc/_convenience_nsstring.py b/pyobjc-core/Lib/objc/_convenience_nsstring.py index 500fbea8df..6384d2561f 100644 --- a/pyobjc-core/Lib/objc/_convenience_nsstring.py +++ b/pyobjc-core/Lib/objc/_convenience_nsstring.py @@ -3,6 +3,7 @@ """ from objc._convenience import addConvenienceForClass +from ._new import NEW_MAP __all__ = () @@ -16,17 +17,14 @@ def nsstring_new(cls, value=_no_value): return cls.alloc().initWithString_(value) +for cls in ("NSString", "NSMutableString"): + NEW_MAP.setdefault(cls, {})[()] = nsstring_new + addConvenienceForClass( "NSString", ( ("__len__", lambda self: self.length()), ("endswith", lambda self, pfx: self.hasSuffix_(pfx)), ("startswith", lambda self, pfx: self.hasPrefix_(pfx)), - ("__new__", staticmethod(nsstring_new)), ), ) - -addConvenienceForClass( - "NSMutableString", - (("__new__", staticmethod(nsstring_new)),), -) diff --git a/pyobjc-core/Lib/objc/_new.py b/pyobjc-core/Lib/objc/_new.py index 12365c3adc..327392ea8d 100644 --- a/pyobjc-core/Lib/objc/_new.py +++ b/pyobjc-core/Lib/objc/_new.py @@ -14,13 +14,6 @@ import objc -# TODO: -# - Update the __new__ implementation for _convenience* to -# also support the generic __new__ interface. -# -# - Later: generate class/module documentation for framework -# bindings, including the generated __new__ signatures. -# __all__ = () # Mapping: class name -> { kwds: selector_name }