Home
Overview
Fundamentals
Glossary
Cheatsheet
API Reference
Quick Recipes
Deep Dive
Common Pitfalls and Gotchas
Persistent Storage
Extension type operators.
kd.extension_types.NullableMixin()Mixin class that adds nullability methods to the extension type.
Adds two methods:
* `get_null` - Class method that returns a null instance of the extension
type. Wrapper around `kd.extension_types.make_null`.
* `is_null` - Returns present iff the object is null. Wrapper around
`kd.extension_types.is_null`.
A null instance of an extension type has no attributes and calling `getattr`
or `with_attrs` on it will raise an error.
Example:
@kd.extension_type()
class A(kd.extension_types.NullableMixin):
x: kd.INT32
# Normal usage.
a = A(1)
a.x # -> 1.
a.is_null() # kd.missing
# Null usage.
a_null = A.get_null()
a_null.x # ERROR
a_null.is_null() # kd.present
kd.extension_types.dynamic_cast(value: Any, qtype: QType) -> AnyUp-, down-, and side-casts `value` to `qtype`.
kd.extension_types.extension_type(unsafe_override=False) -> Callable[[type[Any]], type[Any]]Aliases:
Creates a Koda extension type from the given original class.
This function is intended to be used as a class decorator. The decorated class
serves as a schema for the new extension type.
Internally, this function creates the following:
- A new `QType` for the extension type, which is a labeled `QType` on top of
an arolla::Object.
- A `QValue` class for representing evaluated instances of the extension type.
- An `ExprView` class for representing expressions that will evaluate to the
extension type.
It replaces the decorated class with a new class that acts as a factory. This
factory's `__new__` method dispatches to either create an `Expr` or a `QValue`
instance, depending on the types of the arguments provided.
The fields of the dataclass are exposed as properties on both the `QValue` and
`ExprView` classes. Any methods defined on the dataclass are also carried
over.
Note:
- The decorated class must not have its own `__new__` method - it will be
ignored.
- The decorated class must not have its own `__init__` method - it will be
ignored.
- The type annotations on the fields of the dataclass are used to determine
the schema of the underlying `DataSlice` (if relevant).
- All fields must have type annotations.
- Supported annotations include `SchemaItem`, `DataSlice`, `DataBag`,
`JaggedShape`, and other extension types. Additionally, any QType can be
used as an annotation.
- The `with_attrs` method is automatically added if not already present,
allowing for attributes to be dynamically updated.
- If the class implements the `_extension_arg_boxing(self, value, annotation)`
classmethod, it will be called on all input arguments (including defaults)
passed to `MyExtension(...)`. The classmethod should return an arolla QValue
or an Expression. If the class does not implement such a method, a default
method will be used.
- If the class implements the `_extension_post_init(self)` method, it will be
called as the final step of instantiating the extension through
`MyExtension(...)`. The method should take `self`, do the necessary post
processing, and then return the (potentially modified) `self`. As with other
methods, it's required to be traceable in order to function in a tracing
context.
Example:
@extension_type()
class MyPoint:
x: kd.FLOAT32
y: kd.FLOAT32
def norm(self):
return (self.x**2 + self.y**2)**0.5
# Creates a QValue instance of MyPoint.
p1 = MyPoint(x=1.0, y=2.0)
Extension type inheritance is supported through Python inheritance. Passing an
extension type argument to a functor will automatically upcast / downcast the
argument to the correct extension type based on the argument annotation. To
support calling a child class's methods after upcasting, the parent method
must be annotated with @kd.extension_types.virtual() and the child method
must be annotated with @kd.extension_types.override(). Internally, this traces
the methods into Functors. Virtual methods _require_ proper return
annotations (and if relevant, input argument annotations).
Example:
@kd.extension_type(unsafe_override=True)
class A:
x: kd.INT32
def fn(self, y): # Normal method.
return self.x + y
@kd.extension_types.virtual()
def virt_fn(self, y): # Virtual method.
return self.x * y
@kd.extension_type(unsafe_override=True)
class B(A): # Inherits from A.
y: kd.FLOAT32
def fn(self, y):
return self.x + self.y + y
@kd.extension_types.override()
def virt_fn(self, y):
return self.x * self.y * y
@kd.fn
def call_a_fn(a: A): # Automatically casts to A.
return a.fn(4) # Calls non-virtual method.
@kd.fn
def call_a_virt_fn(a: A): # Automatically casts to A.
return a.virt_fn(4) # Calls virtual method.
b = B(2, 3)
# -> 6. `fn` is _not_ marked as virtual, so the parent method is invoked.
call_a_fn(b)
# -> 24.0. `virt_fn` is marked as virtual, so the child method is invoked.
call_a_virt_fn(b)
Args:
unsafe_override: Overrides existing registered extension types.
Returns:
A new class that serves as a factory for the extension type.
kd.extension_types.get_annotations(cls: type[Any]) -> dict[str, Any]Returns the annotations for the provided extension type class.
kd.extension_types.get_attr(ext: Any, attr: str | QValue, qtype: QType) -> AnyReturns the attribute of `ext` with name `attr` and type `qtype`.
kd.extension_types.get_attr_qtype(ext, attr)Returns the qtype of the `attr`, or NOTHING if the `attr` is missing.
kd.extension_types.get_extension_cls(qtype: QType) -> type[Any]Returns the extension type class for the given QType.
kd.extension_types.get_extension_qtype(cls: type[Any]) -> QTypeReturns the QType for the given extension type class.
kd.extension_types.has_attr(ext, attr)Returns present iff `attr` is an attribute of `ext`.
kd.extension_types.is_koda_extension(x: Any) -> boolReturns True iff the given object is an instance of a Koda extension type.
kd.extension_types.is_koda_extension_type(cls: type[Any]) -> boolReturns True iff the given type is a registered Koda extension type.
kd.extension_types.is_null(ext)Returns present iff `ext` is null.
kd.extension_types.make(qtype: QType, prototype: Object | None = None, /, **attrs: Any)Returns an extension type of the given `qtype` with the given `attrs`.
Args:
qtype: the output qtype of the extension type.
prototype: parent object (arolla.Object).
**attrs: attributes of the extension type.
kd.extension_types.make_null(qtype: QType) -> AnyReturns a null instance of an extension type.
kd.extension_types.override()Marks the method as overriding a virtual method.
kd.extension_types.unwrap(ext)Unwraps the extension type `ext` into an arolla::Object.
kd.extension_types.virtual()Marks the method as virtual, allowing it to be overridden.
kd.extension_types.with_attrs(ext, /, **attrs)Returns `ext` containing the given `attrs`.
kd.extension_types.wrap(x: Any, qtype: QType) -> AnyWraps `x` into an instance of the given extension type.