Stable surface
The versioning policy makes one promise:
Code that runs warning-free on 1.N runs unmodified on 1.N+1.
This page says what that promise applies to.
The surface is defined here rather than implied by what happens to be importable. How precisely depends on the area:
- The Python import surface is enumerated name by name. Every export of
protean,protean.fields, andprotean.exceptionsappears in the export index with its tier, and a test keeps that table in step with the shipped__all__. For these three modules, a name absent from the index is not exported at all. - The rest is defined by tier, and enumerated by its own reference page.
Documented
domain.tomlkeys, documented CLI commands and exit codes, the publicprotean.testingDSL, and the publicprotean.integrations.*names are Stable, but the authoritative list of each lives with its own documentation, not here. "Documented" is the test: a config key or CLI flag with a reference page is covered; one you found by reading the source is not.
So absence from the export index means "internal" only for the three modules it covers. Everywhere else, the tier definitions below are what to reason with.
The three tiers
Stable. The compatibility contract applies. These names, their signatures,
and their documented behaviour only change through the deprecation process: a
DeprecationWarning naming the version it will be removed in, and a
protean check rule, in a release before the one that removes it. A minor may
remove a Stable name that has been through that; it may not break code that was
running warning-free.
Provisional. Usable, documented, and supported, but may change in a minor release with a changelog notice and no deprecation period. These are extension points whose shape is still settling, mostly because the people using them (adapter authors, custom field authors) are few enough to coordinate with directly. A provisional name graduates to Stable once its contract has held across real third-party use.
Internal. No contract at all. May change or disappear in any release,
including a patch. Reaching for these is not forbidden, but it is not
supported, and protean check will not warn you before they move.
| Tier | May change in a patch | May change in a minor | Warned first |
|---|---|---|---|
| Stable | No | Only through deprecation | Yes, in an earlier release, naming the removal version |
| Provisional | No | Yes, with a changelog notice | Not guaranteed |
| Internal | Yes | Yes | No |
What is Stable
- Top-level
proteanexports. Everything inprotean.__all__, listed in the index below. - The element decorators and their options.
@domain.aggregate,@domain.entity,@domain.event,@domain.command, and the rest, together with the documented options each accepts. protean.fields. The field factories, the association fields, and thevalidatorsmodule. Not every name inprotean.fields.__all__is Stable: see the index.protean.exceptions. Every exception and warning class.protean.testing. The public testing DSL.protean.integrations.*public names, including the FastAPI helpers and the pytest plugin's documented fixtures and options.- Documented
domain.tomlkeys. A key that appears in the configuration reference. - Documented CLI commands and their exit codes. Scripts may depend on the
exit code of
protean checkand friends. - The IR schema, versioned independently by its own
ir_version. The schema evolves under that version, not under Protean's.
What is Provisional
- The port ABCs (
BaseProvider,BaseBroker,BaseEventStore,BaseCache) for third-party adapter authors. These stay provisional until the adapter conformance suite ships publicly and has been exercised by an adapter Protean does not maintain. Fieldas the base class for custom field types.FieldBase, the common ancestor of the field hierarchy.ResolvedField, the field-reflection API adapter authors read.- The broker partitioning contract in
protean.port.broker: the partition discovery, fenced-lease andtrimmethods an adapter implements to supportsequential_by, plus theLeaseLostErrorthey raise. Enumerated in Broker partitioning. It lives outside the three modules the export index covers, so the index test does not police it. - Observatory HTTP and JSON endpoints. Useful for tooling, but the dashboard's payloads are shaped for the dashboard.
protean.serverinternals reached by operations tooling, such as the health server's response bodies.
What is Internal
- Any underscore-prefixed name, at any depth.
protean.core.*internals that are not re-exported at the top level.- Adapter implementation modules under
protean.adapters.*. Configure adapters throughdomain.toml; do not import them. Domainplumbing accessors:registry,factory_for,fetch_element_cls_from_registry, and the observability accessors. These exist for the framework's own wiring.- Direct
FieldSpecinstantiation.FieldSpecis the declaration carrier the decorators build for you. ValueObjectList, an internal helper for value-object collections.
Ratified conventions
These are settled decisions about the shape of the surface, recorded here so they are not mistaken for oversights.
Element base classes are deliberately not re-exported at the top level.
protean exports Domain but not BaseAggregate; you reach elements through
decorators (@domain.aggregate), not by subclassing an imported base. The
asymmetry is intentional. Fields and exceptions are imported directly,
because you name them in your own code; element base classes are not, because
the decorator is the supported way to declare an element.
Boolean element options are bare predicates. An option that answers yes or
no is named as the predicate itself (abstract, auto_add_id_field), not
is_* or has_*.
All three field declaration styles are supported. The annotation style is the documented default:
@domain.aggregate
class Order:
placed_at: DateTime(required=True)
The annotation style is not compatible with PEP 563 (from __future__ import
annotations). Under PEP 563 every annotation becomes a string and the field
object is never constructed. A module that needs postponed annotations must use
the assignment style instead. This is a property of the language feature, not a
gap Protean intends to close.
Export index
The normative list for the Python import surface. Every name exported by
protean, protean.fields, and protean.exceptions, with its tier. A test
asserts this table matches the shipped __all__ declarations exactly, in both
directions, so a new export cannot ship without being classified here and a row
cannot outlive the export it describes.
This index does not cover domain.toml keys, CLI commands, protean.testing,
or protean.integrations.*; see their own reference pages for those.
| Export | Module | Tier |
|---|---|---|
Domain |
protean |
Stable |
Engine |
protean |
Stable |
F |
protean |
Stable |
Index |
protean |
Stable |
Priority |
protean |
Stable |
Q |
protean |
Stable |
QuerySet |
protean |
Stable |
ReadOnlyQuerySet |
protean |
Stable |
ReadView |
protean |
Stable |
Record |
protean |
Stable |
UnitOfWork |
protean |
Stable |
apply |
protean |
Stable |
atomic_change |
protean |
Stable |
current_domain |
protean |
Stable |
current_priority |
protean |
Stable |
current_uow |
protean |
Stable |
g |
protean |
Stable |
get_version |
protean |
Stable |
handle |
protean |
Stable |
invariant |
protean |
Stable |
processing_priority |
protean |
Stable |
read |
protean |
Stable |
use_case |
protean |
Stable |
value_object_from_entity |
protean |
Stable |
Auto |
protean.fields |
Stable |
Boolean |
protean.fields |
Stable |
Date |
protean.fields |
Stable |
DateTime |
protean.fields |
Stable |
Decimal |
protean.fields |
Stable |
Dict |
protean.fields |
Stable |
Field |
protean.fields |
Provisional |
FieldBase |
protean.fields |
Provisional |
FieldSpec |
protean.fields |
Internal |
Float |
protean.fields |
Stable |
HasMany |
protean.fields |
Stable |
HasOne |
protean.fields |
Stable |
Identifier |
protean.fields |
Stable |
Integer |
protean.fields |
Stable |
List |
protean.fields |
Stable |
Method |
protean.fields |
Stable |
Nested |
protean.fields |
Stable |
Reference |
protean.fields |
Stable |
ResolvedField |
protean.fields |
Provisional |
Status |
protean.fields |
Stable |
String |
protean.fields |
Stable |
Text |
protean.fields |
Stable |
ValueObject |
protean.fields |
Stable |
ValueObjectFromEntity |
protean.fields |
Stable |
ValueObjectList |
protean.fields |
Internal |
validators |
protean.fields |
Stable |
CommandExpiredError |
protean.exceptions |
Stable |
ConfigurationError |
protean.exceptions |
Stable |
DatabaseError |
protean.exceptions |
Stable |
DeserializationError |
protean.exceptions |
Stable |
DuplicateCommandError |
protean.exceptions |
Stable |
ExpectedVersionError |
protean.exceptions |
Stable |
IncorrectUsageError |
protean.exceptions |
Stable |
InsufficientDataError |
protean.exceptions |
Stable |
InvalidDataError |
protean.exceptions |
Stable |
InvalidOperationError |
protean.exceptions |
Stable |
InvalidStateError |
protean.exceptions |
Stable |
NoDomainException |
protean.exceptions |
Stable |
NotSupportedError |
protean.exceptions |
Stable |
ObjectNotFoundError |
protean.exceptions |
Stable |
ProteanDeprecationWarning |
protean.exceptions |
Stable |
ProteanException |
protean.exceptions |
Stable |
ProteanExceptionWithMessage |
protean.exceptions |
Stable |
SendError |
protean.exceptions |
Stable |
TooManyObjectsError |
protean.exceptions |
Stable |
TransactionError |
protean.exceptions |
Stable |
ValidationError |
protean.exceptions |
Stable |
Related reading
- Versioning policy: what the tiers promise, and how to enforce it in CI.
- Consistency & delivery guarantees: the behavioural contract, which is itself part of the Stable surface.
- Configuration: the documented
domain.tomlkeys.