Files
Tianqi Chen 96cba60464 [PYTHON] Autoload backends; simplify library loading; remove TVMError for native errors (#19727)
This PR adds an autoload mechanism for out-of-tree backends, simplifies
TVM's Python library loading, and removes `TVMError` in favor of native
Python errors.

## Autoload out-of-tree backends

Out-of-tree packages can register an autoload callable under the
`tvm.backends` entry-point group (mirroring torch's device-backend
autoload). At `import tvm` startup each entry point is discovered and
its callable invoked once, after the core runtime and the `tvm`
namespace are fully initialized, so an extension can register
ops/targets/funcs or load extra libraries.

```toml
[project.entry-points."tvm.backends"]
tvm_foo = "tvm_foo:_autoload"
```

A failing extension is caught and surfaced via `warnings.warn` so it
cannot break `import tvm`. Autoload can be disabled with
`TVM_DEVICE_BACKEND_AUTOLOAD=0`.

## Simplify library loading

The library-loading path in `base.py` is consolidated around a single
`_LOADED_LIBS` dict (basename to ctypes handle) so downstream and
autoloaded extensions can skip already-loaded libraries; the per-backend
runtime DSO list is folded into `load_backend_libs`. Accumulated cruft
is removed: the Python-3.9 check, the readline shim, the `_FFI_MODE`
ctypes check, the `base.__version__` re-export, and `py_str` (call sites
inline `.decode("utf-8")`).

## Remove TVMError in favor of native Python errors

`TVMError` added a layer atop `RuntimeError` that downstream code had to
import and learn. It is removed; the registered FFI error kinds
(`InternalError`, `RPCError`, `OpError`, `DiagnosticError`,
`ScheduleError`) now subclass `RuntimeError` directly while staying
registered, so the FFI keeps throwing the right kinds. All `TVMError`
imports, `except`/`raise`/`isinstance` uses, and
`pytest.raises(tvm.TVMError)` sites move to the `RuntimeError` builtin.
2026-06-11 13:50:38 -04:00

127 lines
3.3 KiB
Python

# 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.
"""Structured error classes in TVM.
Each error class takes an error message as its input.
See the example sections for suggested message conventions.
To make the code more readable, we recommended developers to
copy the examples and raise errors with the same message convention.
.. note::
Please also refer to :ref:`error-handling-guide`.
"""
from tvm_ffi import register_error
@register_error
class InternalError(RuntimeError):
"""Internal error in the system.
Examples
--------
.. code :: c++
// Example code C++
LOG(FATAL) << "InternalError: internal error detail.";
.. code :: python
# Example code in python
raise InternalError("internal error detail")
"""
@register_error
class RPCError(RuntimeError):
"""Error thrown by the remote server handling the RPC call."""
@register_error
class RPCSessionTimeoutError(RPCError, TimeoutError):
"""Error thrown by the remote server when the RPC session has expired."""
@register_error
class OpError(RuntimeError):
"""Base class of all operator errors in frontends."""
@register_error
class OpNotImplemented(OpError, NotImplementedError):
"""Operator is not implemented.
Example
-------
.. code:: python
raise OpNotImplemented(
"Operator {} is not supported in {} frontend".format(
missing_op, frontend_name))
"""
@register_error
class OpAttributeRequired(OpError, AttributeError):
"""Required attribute is not found.
Example
-------
.. code:: python
raise OpAttributeRequired(
"Required attribute {} not found in operator {}".format(
attr_name, op_name))
"""
@register_error
class OpAttributeInvalid(OpError, AttributeError):
"""Attribute value is invalid when taking in a frontend operator.
Example
-------
.. code:: python
raise OpAttributeInvalid(
"Value {} in attribute {} of operator {} is not valid".format(
value, attr_name, op_name))
"""
@register_error
class OpAttributeUnImplemented(OpError, NotImplementedError):
"""Attribute is not supported in a certain frontend.
Example
-------
.. code:: python
raise OpAttributeUnImplemented(
"Attribute {} is not supported in operator {}".format(
attr_name, op_name))
"""
@register_error
class DiagnosticError(RuntimeError):
"""Error diagnostics were reported during the execution of a pass.
See the configured diagnostic renderer for detailed error information.
"""