Skip to content

Commit

Permalink
First stab at adding a generic __new__
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ronaldoussoren committed Apr 14, 2024
1 parent 04a7a59 commit 334a7a6
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
6 changes: 6 additions & 0 deletions pyobjc-core/Lib/objc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
}
4 changes: 4 additions & 0 deletions pyobjc-core/Lib/objc/_convenience.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
selector,
)
import PyObjCTools.KeyValueCoding as kvc
from objc._new import _make_new

__all__ = ("addConvenienceForClass", "registerABCForClass")

Expand Down Expand Up @@ -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

Expand Down
54 changes: 54 additions & 0 deletions pyobjc-core/Lib/objc/_new.py
Original file line number Diff line number Diff line change
@@ -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__

0 comments on commit 334a7a6

Please sign in to comment.