API Stability#
This document defines which flydsl APIs you can rely on across releases and
the compatibility commitments that apply when they change. Its scope is limited
to python/flydsl/. Below, fx refers to flydsl.expr, and flyc refers to
flydsl.compiler.
A release means a minor-version increment (for example, 0.3 → 0.4). A patch
release must not break a stable API.
These compatibility guarantees apply only between released versions. APIs on the main development branch may undergo semantic adjustments during development; intermediate commits do not carry the same stability guarantee.
1. Summary and general rules#
stable: backward compatible across minor releases. Previously valid call paths, signatures, and semantics must continue to work.
unstable: everything else. These APIs may change or be removed in any minor release without notice.
deprecated is not a third stability level. It is a lifecycle marker for a
stable API: during its deprecation window, it remains stable and protected by
this document’s compatibility rules; it may be removed only after that window
ends.
Returned-object rule#
An object returned by a stable API has a stable public result interface: its non-underscore members and Python special methods are stable when reached through that result. This rule applies recursively to objects returned by those members.
This rule does not promise the concrete implementation class, its constructor,
or its import path. They may change if the replacement preserves the result
interface’s public members, signatures, and semantics. For example,
flyc.from_torch_tensor(x).mark_shape_dynamic(0) is stable, while
flyc.from_torch_tensor(x)._ensure_spec() is unstable.
Determine stability by the mechanical process below. A public export from an
expr direct-child module has several equivalent access forms: fx.<name>,
fx.<module>.<name>, and from flydsl.expr.<module> import <name> have the
same stability. Otherwise, classify the path that a caller actually uses, not
the object’s identity.
2. Determining stability#
Apply the following branches by path prefix:
Any path whose module path contains a segment named
experimentalis unstable, at any depth, regardless of export manifests or explicit stable listings. A module-global name or namespace segment beginning with_is also unstable. On stable types and returned objects, only__...__Python special methods may begin with_; all other underscore-prefixed members are unstable.A path under
flydsl.expr: classify it only under §2.1; it is unstable if it does not qualify.A path under
flydsl.compiler: direct members incompiler.__all__, and members incompiler.protocol.__all__, are stable. Other deep paths are stable only when listed exactly in §2.4.A path under
flydsl.extension: classify it only under §2.3; it is unstable if it does not qualify.Every other path is stable only when listed exactly in §2.4.
For a member reached through a returned object, first classify its producing API under these branches, then apply the returned-object rule in §1.
2.1 flydsl.expr#
expr/__init__.py is the sole top-level aggregation manifest. It has no
__all__ of its own; stability is determined exclusively by the following three
export chains.
Symbols exported from direct-child modules#
Subject to the first branch above, <name> in a direct-child module <module>
is stable if and only if:
expr/__init__.pyaggregates that direct-child module throughfrom .<module> import *;<name>is in that child module’s__all__.
Names satisfying these conditions have identical stability when accessed via
fx.<name>, fx.<module>.<name>, or a direct import. Those direct-child
modules and their public export paths are part of the compatibility commitment.
Therefore, both fx.Int32 and fx.numeric.Int32 are stable. Members omitted
from __all__ remain unstable; fx.arith._to_raw is unstable under the first
branch even if it was listed in a historical __all__.
Backend entry points and recursive child namespaces#
Subject to the first branch above, fx.<backend>...<name> is stable if and only
if:
the first-level
<backend>appears in_BACKEND_MODULESinexpr/__init__.py;every following child namespace appears in the
__all__of its direct parent package; andthe final
<name>appears in the__all__of its owning module or package.
The first-level backend entry point, and intermediate child namespaces that satisfy condition 2, are stable namespaces as well. This rule applies recursively and has no path-depth limit.
For example, fx.rocdl.cdna3.s_waitcnt satisfies the complete export chain and
is stable, while fx.rocdl.cluster.* is unstable when cluster is not listed
in rocdl.__all__. An upstream-MLIR ODS builder that is re-exported but omitted
from the final __all__ is unstable as well.
__all__ is not access control: an attribute may exist and be callable while
still failing the stability test above.
Extension aliases#
Entries in _EXTENSION_MODULES expose extension libraries as fx.<extension>.
These aliases and their descendants follow §2.3 and have the same stability as
the corresponding flydsl.extension paths.
2.2 flydsl.compiler#
Only direct members of flydsl.compiler.__all__ are stable. For example, if
jit is in that manifest, flydsl.compiler.jit is stable.
flydsl.compiler.protocol is an exception: every non-underscore
flydsl.compiler.protocol.<name> in its __all__ is stable. It is the public
extension namespace for user implementations of JIT / DSL-value protocols.
This rule is otherwise not recursive: flydsl.compiler.<submodule>.<name> does
not become stable merely because <submodule> is importable; it must be listed
explicitly in §2.4.
2.3 flydsl.extension#
Extension libraries follow the same recursive export-chain rule as backend namespaces. Subject to the first branch in §2, an extension API is stable if and only if:
its extension entry point is a target of
_EXTENSION_MODULESinexpr/__init__.py;every following child namespace appears in the
__all__of its direct parent package; andthe final name appears in the
__all__of its owning module or package.
flydsl.extension, registered extension entry points, and intermediate child
namespaces satisfying condition 2 are stable namespaces. The rule has no
path-depth limit. An extension alias fx.<extension> and its descendants have
the same stability as the corresponding canonical paths under
flydsl.extension.
2.4 Other explicitly stable APIs#
Subject to the first branch in §2, the following full paths are stable. This table is the only exception list; a new commitment must add an explicit row.
API |
Description |
|---|---|
|
Query the target ROCm architecture |
|
Choose between CDNA and RDNA paths |
2.5 All other APIs#
Every API that does not satisfy §2.1, §2.2, or §2.3, and is not listed exactly
in §2.4, is unstable. This includes undeclared flydsl.* submodules,
flydsl._mlir.*, every underscore-prefixed name, and any path with an
experimental module segment.
Direct invocation of an upstream MLIR dialect op is allowed but unstable: its name, arguments, and semantics are controlled by upstream MLIR, and FlyDSL provides no compatibility commitment for it.
Stable API catalog#
Generate the complete non-deprecated stable API catalog from the checked-out source:
python3 scripts/list_stable_apis.py
python3 scripts/list_stable_apis.py --format json
The script reads export manifests without importing FlyDSL. It lists canonical
module paths, using flydsl.extension paths for extension libraries and
omitting equivalent flydsl.expr aliases. Deprecated APIs remain compatible but
are intentionally excluded from the default catalog. Use --repo-root to select
another source tree. For release review, add --include-deprecated and also
review the §3 table and the member and semantic contracts that a path list
cannot capture.
3. Stable but deprecated#
The APIs in the table below satisfy the stable rules in §2 but are marked as deprecated. They remain stable during the §5 window; new code must not use them, and you must provide a replacement before removal.
For direct-child module exports under §2.1, the deprecated status in this table
also applies to fx.<name>, fx.<module>.<name>, and direct-import forms. For
extension libraries, it applies to both canonical paths and their §2.3 aliases.
FlyDSL maintains this table separately as the compatibility-debt list and
excludes it from the catalog above.
API |
Replacement or required work before removal |
Declared removal release |
|---|---|---|
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
|
|
v0.4 |
4. What counts as a breaking change#
For a stable API, each of the following is a breaking change:
removing a stable API or breaking its export chain: removing an entry from a direct-child module’s
__all__,flydsl.compiler.__all__, orflydsl.compiler.protocol.__all__; removing a backend or extension entry point from_BACKEND_MODULESor_EXTENSION_MODULES, or an entry from any__all__in their recursive export chains; or removing a §2.4 entry without a new rule that covers it;removing an argument, renaming an argument that may be passed by keyword, reordering positional arguments, removing a default, or changing a default;
narrowing accepted types, architectures, or value ranges;
changing a returned scalar or value type, tuple arity, or a returned object’s stable public result interface (including non-private members and
__...__Python special methods), or the numerical, layout, or emitted-op semantics for previously valid input.
The following are not breaking changes:
adding an API, or adding an optional keyword argument whose default preserves existing behavior;
widening accepted input;
improving an error message, converting undefined behavior into a clear error, or changing the exception type on failure;
replacing a returned object’s concrete implementation class while preserving its stable public result interface;
changing only unstable APIs.
5. Changing or retiring a stable API#
Provide a replacement first, normally exposing it from an appropriate stable path.
Mark the original API as deprecated at its definition or export declaration, and add the API and replacement to §3.
Retain the old API in the release where it is marked,
N, and in the next minor release,N+1.Remove the old API no earlier than
N+2, and remove its corresponding §3 entry at the same time.