tqchen commented on code in PR #8: URL: https://github.com/apache/tvm-ffi/pull/8#discussion_r2364650435
########## python/tvm_ffi/dataclasses/c_class.py: ########## @@ -0,0 +1,167 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Helpers for mirroring registered C++ FFI types with Python dataclass syntax. + +The :func:`c_class` decorator is the primary entry point. It inspects the +reflection metadata that the C++ runtime exposes via the TVM FFI registry and +turns it into Python ``dataclass``-style descriptors: annotated attributes become +properties that forward to the underlying C++ object, while an ``__init__`` +method is synthesized to call the FFI constructor when requested. +""" + +from collections.abc import Callable +from dataclasses import InitVar +from typing import ClassVar, TypeVar, get_origin, get_type_hints + +from ..core import TypeField, TypeInfo +from . import _utils, field + +try: + from typing import dataclass_transform +except ImportError: + from typing_extensions import dataclass_transform + + +_InputClsType = TypeVar("_InputClsType") + + +@dataclass_transform(field_specifiers=(field.field, field.Field)) +def c_class( + type_key: str, init: bool = True +) -> Callable[[type[_InputClsType]], type[_InputClsType]]: + """(Experimental) Create a dataclass-like proxy for a C++ class registered with TVM FFI. + + The decorator reads the reflection metadata that was registered on the C++ + side using ``tvm::ffi::reflection::ObjectDef`` and binds it to the annotated + attributes in the decorated Python class. Each field defined in C++ becomes + a property on the Python class, and optional default values can be provided + with :func:`tvm_ffi.dataclasses.field` in the same way as Python's native + ``dataclasses.field``. + + The intent is to offer a familiar dataclass authoring experience while still + exposing the underlying C++ object. The ``type_key`` of the C++ class must + match the string passed to :func:`c_class`, and inheritance relationships are + preserved—subclasses registered in C++ can subclass the Python proxy defined + for their parent. + + Parameters + ---------- + type_key : str + The reflection key that identifies the C++ type in the FFI registry, + e.g. ``"testing.MyClass"`` as registered in + ``src/ffi/extra/testing.cc``. + + init : bool, default True + If ``True`` and the Python class does not define ``__init__``, an + initializer is auto-generated that mirrors the reflected constructor + signature. The generated initializer calls the C++ ``__init__`` + function registered with ``ObjectDef`` and invokes ``__post_init__`` if + it exists on the Python class. + + Returns + ------- + Callable[[type], type] + A class decorator that materializes the final proxy class. + + Examples + -------- + Register the C++ type and its fields with TVM FFI:: + + TVM_FFI_STATIC_INIT_BLOCK() { + namespace refl = tvm::ffi::reflection; + refl::ObjectDef<MyClass>() + .def_static("__init__", [](int64_t v_i64, int32_t v_i32, + double v_f64, float v_f32) -> Any { + return ObjectRef(ffi::make_object<MyClass>( + v_i64, v_i32, v_f64, v_f32)); + }) + .def_rw("v_i64", &MyClass::v_i64) + .def_rw("v_i32", &MyClass::v_i32) + .def_rw("v_f64", &MyClass::v_f64) + .def_rw("v_f32", &MyClass::v_f32); + } + + Mirror the same structure in Python using dataclass-style annotations:: + + from tvm_ffi.dataclasses import c_class, field Review Comment: Use rst style block .. code:: python ########## python/tvm_ffi/dataclasses/c_class.py: ########## @@ -0,0 +1,167 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Helpers for mirroring registered C++ FFI types with Python dataclass syntax. + +The :func:`c_class` decorator is the primary entry point. It inspects the +reflection metadata that the C++ runtime exposes via the TVM FFI registry and +turns it into Python ``dataclass``-style descriptors: annotated attributes become +properties that forward to the underlying C++ object, while an ``__init__`` +method is synthesized to call the FFI constructor when requested. +""" + +from collections.abc import Callable +from dataclasses import InitVar +from typing import ClassVar, TypeVar, get_origin, get_type_hints + +from ..core import TypeField, TypeInfo +from . import _utils, field + +try: + from typing import dataclass_transform +except ImportError: + from typing_extensions import dataclass_transform + + +_InputClsType = TypeVar("_InputClsType") + + +@dataclass_transform(field_specifiers=(field.field, field.Field)) +def c_class( + type_key: str, init: bool = True +) -> Callable[[type[_InputClsType]], type[_InputClsType]]: + """(Experimental) Create a dataclass-like proxy for a C++ class registered with TVM FFI. + + The decorator reads the reflection metadata that was registered on the C++ + side using ``tvm::ffi::reflection::ObjectDef`` and binds it to the annotated + attributes in the decorated Python class. Each field defined in C++ becomes + a property on the Python class, and optional default values can be provided + with :func:`tvm_ffi.dataclasses.field` in the same way as Python's native + ``dataclasses.field``. + + The intent is to offer a familiar dataclass authoring experience while still + exposing the underlying C++ object. The ``type_key`` of the C++ class must + match the string passed to :func:`c_class`, and inheritance relationships are + preserved—subclasses registered in C++ can subclass the Python proxy defined + for their parent. + + Parameters + ---------- + type_key : str + The reflection key that identifies the C++ type in the FFI registry, + e.g. ``"testing.MyClass"`` as registered in + ``src/ffi/extra/testing.cc``. + + init : bool, default True + If ``True`` and the Python class does not define ``__init__``, an + initializer is auto-generated that mirrors the reflected constructor + signature. The generated initializer calls the C++ ``__init__`` + function registered with ``ObjectDef`` and invokes ``__post_init__`` if + it exists on the Python class. + + Returns + ------- + Callable[[type], type] + A class decorator that materializes the final proxy class. + + Examples + -------- + Register the C++ type and its fields with TVM FFI:: + + TVM_FFI_STATIC_INIT_BLOCK() { Review Comment: .. code:: c++ ########## python/tvm_ffi/dataclasses/field.py: ########## @@ -0,0 +1,95 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""Public helpers for describing dataclass-style defaults on FFI proxies.""" + +from __future__ import annotations + +from dataclasses import MISSING, dataclass +from typing import Any, Callable + + +@dataclass(kw_only=True) +class Field: + """(Experimental) Descriptor placeholder returned by :func:`tvm_ffi.dataclasses.field`. Review Comment: I think we only need to put experimental at the docstring for dataclasses `__init__.py` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
