"""Object namespace""" # pylint: disable=unused-import from __future__ import absolute_import import ctypes import sys from .. import _api_internal from .base import _FFI_MODE, _LIB, c_str, check_call, py_str from .object_generic import convert_to_object, ObjectGeneric # pylint: disable=invalid-name IMPORT_EXCEPT = RuntimeError if _FFI_MODE == "cython" else ImportError try: # pylint: disable=wrong-import-position if _FFI_MODE == "ctypes": raise ImportError() if sys.version_info >= (3, 0): from ._cy3.core import _register_object, ObjectBase as _ObjectBase else: from ._cy2.core import _register_object, ObjectBase as _ObjectBase except IMPORT_EXCEPT: # pylint: disable=wrong-import-position from ._ctypes.object import _register_object, ObjectBase as _ObjectBase def _new_object(cls): """Helper function for pickle""" return cls.__new__(cls) class ObjectBase(_ObjectBase): """ObjectBase is the base class of all DGL CAPI object. The core attribute is ``handle``, which is a C raw pointer. It must be initialized via ``__init_handle_by_constructor__``. Note that the same handle **CANNOT** be shared across multiple ObjectBase instances. """ def __dir__(self): plist = ctypes.POINTER(ctypes.c_char_p)() size = ctypes.c_uint() check_call( _LIB.DGLObjectListAttrNames( self.handle, ctypes.byref(size), ctypes.byref(plist) ) ) names = [] for i in range(size.value): names.append(py_str(plist[i])) return names def __hash__(self): return _api_internal._raw_ptr(self) def __eq__(self, other): return self.same_as(other) def __ne__(self, other): return not self.__eq__(other) def __reduce__(self): cls = type(self) return (_new_object, (cls,), self.__getstate__()) def __getstate__(self): # TODO(minjie): TVM assumes that a Node (Object in DGL) can be serialized # to json. However, this is not true in DGL because DGL Object is meant # for runtime API, so it could contain binary data such as NDArray. # If this feature is required, please raise a RFC to DGL issue. raise RuntimeError("__getstate__ is not supported for object type") def __setstate__(self, state): # pylint: disable=assigning-non-slot # TODO(minjie): TVM assumes that a Node (Object in DGL) can be serialized # to json. However, this is not true in DGL because DGL Object is meant # for runtime API, so it could contain binary data such as NDArray. # If this feature is required, please raise a RFC to DGL issue. raise RuntimeError("__setstate__ is not supported for object type") def same_as(self, other): """check object identity equality""" if not isinstance(other, ObjectBase): return False return self.__hash__() == other.__hash__() def register_object(type_key=None): """Decorator used to register object type Examples -------- >>> @register_object >>> class MyObject: >>> ... pass Parameters ---------- type_key : str or cls The type key of the object """ object_name = type_key if isinstance(type_key, str) else type_key.__name__ def register(cls): """internal register function""" tindex = ctypes.c_int() ret = _LIB.DGLObjectTypeKey2Index( c_str(object_name), ctypes.byref(tindex) ) if ret == 0: _register_object(tindex.value, cls) return cls if isinstance(type_key, str): return register return register(type_key)