edutap.data_models
Shared contracts of the eduTAP packages: controlled vocabularies, the Kafka message contract, and settings building blocks whose field names are meant to be identical in every container.
Why this exists
Three duplicates, all of them found in the field.
Vocabularies in three diverging copies. PassLifecycleState existed with eight
values in lmu_edutap_common and with six in both lmu_edutap_full_view and
edutap.data_provider. WalletType existed in four spellings.
The message contract. Header block, key rule and dead letter envelope have to be identical in six packages. Six copies diverge, and the divergence is invisible until a consumer quietly stops recognising a message.
Settings that should mean the same thing everywhere. environment is the clearest
case: the same field name in every container, populated per service by the Swarm
compose file, and read by the error tracker and the trace exporter alike.
What belongs here
| Module | Contents |
|---|---|
vocabulary |
WalletType, IssuanceState, HolderState, InstanceState, FieldKind, Provider |
messaging |
header names and construction, logical topic names, DLQ naming |
settings |
ServiceSettings, KafkaSettings — mixins, not a finished class |
runtime |
the shared Kafka runtime: consume(), Unprocessable, DeadLetterQueue, serve() |
The runtime package is the odd one out and says so. It is behaviour rather than a
contract in the way a vocabulary is, and it is here because the behaviour is what
several services have to agree on: the commit order, the dead letter naming, what a
stop signal does. It is written against protocols, so the Kafka driver is not a
dependency of this package — build_consumer() and build_dead_letter_producer()
stay in the service, with its settings class. See the design record of 2026-08-11.
The pass lifecycle is spelled on three axes. IssuanceState is what the issuer
did or wants and exists with no exemplar at all; InstanceState is what one exemplar
at the holder is doing; HolderState is the summary of the second and is derived,
never set. PassLifecycleState conflated the first two and is superseded — it is
still reachable under edutap.data_models.vocabulary and warns when used.
Error tracking and trace export live in edutap.observability_settings, not here.
The options that decide what may leave a process were chosen against measurements
and are worth nothing apart from the sentry_sdk.init() call that applies them.
What does not
Table definitions of individual packages. edutap.db_definitions collects those
through entry points, and that collection is what makes one package answerable for
one schema. Move them here and nobody owns a schema any more.
Anything LMU-specific. lmu_edutap_common stays what it is; the edutap.* packages
must not depend on it.
Dependency direction
This package depends on nothing from the eduTAP estate — only on pydantic,
pydantic-settings and structlog. Everything else may depend on it. A library that
knows about services is not a library.
structlog is the third and had to be argued for: the runtime loop's log records are
structured — topic, partition, offset, reason — and that structure is their
entire value in operation. Every consumer already uses it.
Usage
from edutap.data_models import WalletType
from edutap.data_models.messaging import TOPIC_PASS_STATE, build_headers
from edutap.data_models.settings import KafkaSettings
class MySettings(KafkaSettings):
model_config = {"env_prefix": "EDUTAP_MY_SERVICE_"}
settings = MySettings() # aborts without EDUTAP_MY_SERVICE_TOPIC_PREFIX
topic = settings.topic(TOPIC_PASS_STATE) # edutap.production.pass.state
Reaching a broker that requires mTLS is the same three settings fields everywhere —
ca_file, cert_file, key_file, plus password for an encrypted key — and one
function that turns them into driver options:
from edutap.data_models.runtime import transport_options
AIOKafkaConsumer(topic, bootstrap_servers=..., **transport_options(settings))
It returns {} when nothing is configured, which is the development case against a
broker without TLS. Configuring only some of the three raises instead of falling
back: against an SSL-only broker a silent fallback does not produce an unencrypted
connection, it produces one that fails during the handshake — and that error names
the broker rather than the secret nobody mounted.
The context is built from the standard library, so the Kafka driver stays out of this package's dependencies.
Development
make venv
make lint
make test-local
tox runs the suite across every supported Python version.
Design records
The design is written down under docs/superpowers/specs/.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file edutap_data_models-0.2.2.tar.gz.
File metadata
- Download URL: edutap_data_models-0.2.2.tar.gz
- Upload date:
- Size: 40.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5d8169b7ed1efb3eaed25c580c9164e81a43be317c8837153a717eac1372828
|
|
| MD5 |
f05780e76a2ae7df1cea4834a371ab86
|
|
| BLAKE2b-256 |
97ab8378eea9af0d14f10f4515e456146ce2c004093edabab46a05f6fb35c84c
|
Provenance
The following attestation bundles were made for edutap_data_models-0.2.2.tar.gz:
Publisher:
release.yaml on edutap-collective/edutap.data_models
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
edutap_data_models-0.2.2.tar.gz -
Subject digest:
c5d8169b7ed1efb3eaed25c580c9164e81a43be317c8837153a717eac1372828 - Sigstore transparency entry: 2436522609
- Sigstore integration time:
-
Permalink:
edutap-collective/edutap.data_models@4dea4dffc8d867e9210bf3764d5ded6e457b260a -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/edutap-collective
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@4dea4dffc8d867e9210bf3764d5ded6e457b260a -
Trigger Event:
release
-
Statement type:
File details
Details for the file edutap_data_models-0.2.2-py3-none-any.whl.
File metadata
- Download URL: edutap_data_models-0.2.2-py3-none-any.whl
- Upload date:
- Size: 23.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4bf3f86d65551c6202619ce605694f8920020f210c7a9ab5d63a954b0805684
|
|
| MD5 |
23c538df84567e37899751e0da49c54c
|
|
| BLAKE2b-256 |
ff9a8d9b0904279f140e9f0c3ebc83b389cc1ef54c55f529d67e1e86c60b524f
|
Provenance
The following attestation bundles were made for edutap_data_models-0.2.2-py3-none-any.whl:
Publisher:
release.yaml on edutap-collective/edutap.data_models
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
edutap_data_models-0.2.2-py3-none-any.whl -
Subject digest:
e4bf3f86d65551c6202619ce605694f8920020f210c7a9ab5d63a954b0805684 - Sigstore transparency entry: 2436523038
- Sigstore integration time:
-
Permalink:
edutap-collective/edutap.data_models@4dea4dffc8d867e9210bf3764d5ded6e457b260a -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/edutap-collective
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@4dea4dffc8d867e9210bf3764d5ded6e457b260a -
Trigger Event:
release
-
Statement type: