blob: e5900fb67fa8357187f7e8e04ccc229d3fde301a [file] [log] [blame]
import torch._C
class _OpNamespace(object):
"""
An op namespace to dynamically bind Operators into Python.
Say a user has created a custom Operator called "my_namespace::my_op". To
call this op, the user will write torch.ops.my_namespace.my_op(...).
At startup, this operation will not yet be bound into Python. Instead, the
following sequence of magic tricks will occur:
1. `torch.ops.my_namespace` will invoke the `__getattr__` magic method
on the `torch.ops` object, which will create a new `_OpNamespace`
object called `my_namespace` and set it as an attribute on the `ops`
object.
2. `torch.ops.my_namespace.my_op` will then invoke `__getattr__` on
the `my_namespace` object, which will retrieve the operation via
`torch.get_operation`, a function bound from C++, and then in a similar
fashion bind this new object onto the `my_namespace` object.
3. `torch.ops.my_namespace.my_op(...)` then calls this new operation
and subsequent accesses will incur no further lookup (the namespace and
operation will already exist).
"""
def __init__(self, name):
self.name = name
def __getattr__(self, op_name):
# Get the op `my_namespace::my_op` if available. This will also check
# for overloads and raise an exception if there are more than one.
op = torch._C._jit_get_operation('{}::{}'.format(self.name, op_name))
setattr(self, op_name, op)
return op
class _Ops(object):
def __getattr__(self, name):
# Here we are creating `torch.ops.my_namespace`
namespace = _OpNamespace(name)
setattr(self, name, namespace)
return namespace
# The ops "namespace"
ops = _Ops()