Formspec Python package — server-side FEL evaluation, validation, linting, and mapping
Project description
formspec (Python)
src/formspec/ — Python tooling backend. Uses the Rust/PyO3 runtime for FEL parsing, evaluation, and dependency extraction, plus Python-side lint orchestration, adapters, mapping helpers, changelog generation, and registry access.
Entry point: src/formspec/ (namespace package; import from subpackages directly)
No re-exports from __init__.py — use from formspec.fel import ..., from formspec.validator import ..., etc.
FEL — src/formspec/fel/
Rust-backed FEL runtime contract for Python. The legacy pure-Python parser/evaluator stack has been removed.
Quick Start
from formspec.fel import evaluate, parse, extract_dependencies, to_python
parsed = parse("$price * $quantity") # syntax validation + opaque handle
result = evaluate("$price * $quantity", {"price": 10, "quantity": 3})
print(to_python(result.value)) # Decimal('30')
print(result.diagnostics) # []
deps = extract_dependencies("sum($items[*].cost) + $base")
print(deps.fields) # {'items.cost', 'base'}
print(deps.has_wildcard) # True
Public API (fel/__init__.py)
evaluate(source: str, data: dict | None = None, *,
instances: dict[str, dict] | None = None,
mip_states: dict[str, object] | None = None,
extensions: dict[str, object] | None = None,
variables: dict[str, FelValue] | None = None) -> EvalResult
extract_dependencies(source: str) -> DependencySet
parse(source: str) -> ParsedExpression # opaque handle; raises FelSyntaxError
default_fel_runtime() -> RustFelRuntime
builtin_function_catalog() -> list[dict[str, str]]
BUILTIN_NAMES: frozenset[str]
RESERVED_WORDS: frozenset[str]
FelNull, FelTrue, FelFalse
FelNumber(value: Decimal)
FelString(value: str)
FelBoolean(value: bool)
FelDate(value: date | datetime)
FelArray(elements: tuple)
FelMoney(amount: Decimal, currency: str)
FelObject(fields: dict)
FelValue
fel_bool(v) -> FelBoolean
from_python(val) -> FelValue
to_python(val: FelValue)
typeof(val: FelValue) -> str
is_null(val) -> bool
FelError, FelSyntaxError, FelDefinitionError, FelEvaluationError
Diagnostic(message: str, pos: SourcePos | None, severity: Severity)
SourcePos(offset: int, line: int, col: int)
Severity.ERROR, Severity.WARNING
Runtime Contract
parse()performs syntax validation and returnsParsedExpression(source=...). Python does not receive a public AST anymore.evaluate()andextract_dependencies()call the mandatoryformspec_rustPyO3 module.builtin_function_catalog()andBUILTIN_NAMESare exported from Rust metadata.- Dynamic Python FEL extensions are no longer supported.
register_extension(...)remains only to reject the removed contract explicitly.
Type System (fel/types.py)
Every FEL value remains a frozen Python dataclass wrapper. from_python() and to_python() still convert between Python-native values and the public FEL value types, including {amount, currency} money objects.
Dependency Extraction
@dataclass
class DependencySet:
fields: set[str]
instance_refs: set[str]
context_refs: set[str]
mip_deps: set[str]
has_self_ref: bool
has_wildcard: bool
uses_prev_next: bool
extract_dependencies() returns the Rust-generated static dependency set used by the validator and evaluator.
Validator / Static Linter — src/formspec/validator/
Quick Start
# One-shot
from formspec.validator import lint
diagnostics = lint(document, mode="strict")
# Full linter instance
from formspec.validator import FormspecLinter, make_policy
linter = FormspecLinter(policy=make_policy("strict"))
diagnostics = linter.lint(doc, component_definition=def_doc)
CLI
# Authoring mode (default), text output
python -m formspec.validator definition.json
# Strict CI mode, JSON output
python -m formspec.validator --mode strict --format json definition.json
# Schema-only validation
python -m formspec.validator --schema-only definition.json
# Skip FEL checks
python -m formspec.validator --no-fel definition.json
# Lint component document with definition cross-reference
python -m formspec.validator --definition def.json component.json
# GitHub Actions annotation format
python -m formspec.validator --format github definition.json
Exit code: 1 if errors, 0 if clean, 2 for input file issues.
Diagnostic Type
@dataclass(frozen=True, slots=True)
class LintDiagnostic:
severity: Literal["error", "warning", "info"]
code: str
message: str
path: str # JSON-path-like location (e.g., "$.items[0].binds[1]")
category: Literal["schema", "reference", "expression", "dependency", "tree", "theme", "component"]
detail: str | None = None
Lint Modes
authoring— passes diagnostics through unchanged; lenient for interactive editing.strict— escalates specific warnings to errors for CI:W800(unresolved bind refs),W802(compatibility fallback),W803(duplicate editable bindings),W804(summary/datatable bind issues).
Pipeline Passes
- Schema validation (always) —
jsonschemaDraft202012Validatoragainst the appropriate schema. 10 supported document types:definition,response,validation_report,validation_result,mapping,registry,theme,component,changelog,fel_functions. - Document type detection — sentinel keys:
$formspec→ definition,$formspecTheme→ theme,$formspecComponent→ component,$formspecRegistry→ registry; structural key sets detectvalidation_result(path,severity,constraintKind,message) andfel_functions(version,functions). - Structural error gate — structural schema errors halt further passes.
- For
definitiondocuments:- Tree indexing (item key/path index, duplicate detection)
- Reference integrity (bind paths, shape targets, optionSet refs)
- FEL expression compilation (parse all FEL in binds/shapes/screener)
- Dependency analysis (graph, cycle detection)
- For
themedocuments: Token value validation - For
componentdocuments: Component semantic checks
Diagnostic Code Reference
| Code | Severity | Category | Description |
|---|---|---|---|
| E100 | error | schema | Unknown document type |
| E101 | error | schema | JSON Schema validation error |
| E200 | error | tree | Duplicate item key |
| E201 | error | tree | Duplicate item path |
| E300 | error | reference | Bind path does not resolve |
| E301 | error | reference | Shape target does not resolve |
| E302 | error | reference | Undefined optionSet |
| W300 | warning | reference | dataType incompatible with optionSet |
| E400 | error | expression | Invalid FEL syntax |
| E500 | error | dependency | Dependency cycle |
| W700 | warning | theme | Invalid color token |
| W701 | warning | theme | Invalid spacing/size token |
| W702 | warning | theme | Invalid font weight token |
| W703 | warning | theme | Unitless line-height expected |
| W704 | warning | theme | Undefined token reference |
| E800 | error | component | Root must be layout component |
| E801 | error | component | Undefined custom component |
| E802 | error | component | Incompatible component/dataType |
| W802 | warning | component | Fallback compatibility only |
| E803 | error | component | Missing options source |
| E804 | error | component | Richtext requires string field |
| E806 | error | component | Missing custom component params |
| E807 | error | component | Custom component cycle |
| W800 | warning | component | Unresolved bind path |
| W801 | warning | component | Layout/container should not bind |
| W803 | warning | component | Duplicate editable binding |
| W804 | warning | component | Summary/DataTable bind unresolved |
Component Compatibility Matrix (validator/component_matrix.py)
Maps 14 input components to their allowed dataTypes in strict and authoring modes: TextInput, NumberInput, DatePicker, Select, CheckboxGroup, Toggle, FileUpload, RadioGroup, MoneyInput, Slider, Rating, Signature.
def classify_compatibility(component_name: str, data_type: str) -> CompatibilityStatus
def requires_options_source(component_name: str) -> bool
Adapters — src/formspec/adapters/
Bidirectional format adapters. Each implements:
class Adapter(ABC):
@abstractmethod
def serialize(self, value: JsonValue) -> bytes
@abstractmethod
def deserialize(self, data: bytes) -> JsonValue
def get_adapter(format: str, config: dict | None = None, target_schema: dict | None = None) -> Adapter
def register_adapter(prefix: str, adapter_class: type) -> None # prefix must start with 'x-'
JsonAdapter
Config: pretty (bool), sortKeys (bool), nullHandling ("include" | "omit"). nullHandling="omit" recursively strips None-valued keys.
XmlAdapter
Config: declaration (bool, default true), indent (int, default 2), cdata (list of paths to wrap in CDATA).
@-prefixed keys become XML attributes; lists become repeated sibling elements; dicts become nested elements. Deserialization auto-detects repeated siblings as arrays. Supports namespace registration.
CsvAdapter
Config: delimiter (str, default ,), quote (str, default "), header (bool, default true), encoding (str, default "utf-8"), lineEnding ("crlf" | "lf", default "crlf").
Accepts a list of flat dicts, a single flat dict, or a dict with one list-valued key (repeat group expansion — scalars duplicate across rows). RFC 4180 compliant.
Mapping Engine — src/formspec/mapping/
from formspec.mapping import MappingEngine
engine = MappingEngine(mapping_doc)
target = engine.forward(response_data) # Response → Target format
source = engine.reverse(target_data) # Target → Response format
Mapping Document Shape
rules: list ofMappingRule(sorted byprioritydescending)defaults:Record<string, any>applied to forward outputautoMap: bool — copy unmentioned source fieldsdirection: strtargetSchema: dict
Rule Structure
{
"sourcePath": "a.b.c", # dot-notation with bracket indices
"targetPath": "x.y.z",
"transform": "preserve", # preserve | valueMap | coerce | constant | drop | expression | ...
"condition": "source.field = value", # or != variant
"priority": 10,
"reversePriority": 5,
"reverse": { ... } # Partial rule override for reverse direction
}
Array Descriptor Modes
whole— treat entire array as single valueeach— apply transform per elementindexed— map by positional index
Transform Types
| Transform | Description |
|---|---|
preserve |
Copy unchanged; supports default |
drop |
Discard value |
expression |
Evaluate FEL expression |
coerce |
Type conversion: string, number, integer, boolean, date, array, object |
valueMap |
Lookup table; unmapped handling: error / passthrough / drop / default |
flatten |
Nested object → flat string |
nest |
Flat string → nested object |
constant |
FEL expression ignoring source |
concat |
FEL expression for concatenation |
split |
FEL expression for splitting |
Condition guards evaluate FEL with $source and $target in the environment. valueMap auto-inverts for reverse if no explicit reverse mapping.
Changelog Generation — src/formspec/changelog.py
from formspec.changelog import generate_changelog
changelog = generate_changelog(old_def: dict, new_def: dict, definition_url: str) -> dict
Compares two definition documents and produces a changelog conforming to changelog.schema.json.
Diff targets: items (by key), binds (by path), shapes (by name), optionSets, dataSources, screener, migrations, metadata keys.
Impact classification:
- Items: added → compatible, removed → breaking, type change → breaking, label-only → cosmetic
- Binds: added with required → breaking, removed → breaking, added/removed required → breaking/compatible
- Shapes: added → compatible, removed → compatible (loosens constraints)
- optionSets/dataSources: added → compatible, removed → breaking
Semver impact: major if any breaking, minor if any compatible, patch otherwise.
Output: { definitionUrl, fromVersion, toVersion, generatedAt, semverImpact, changes: [{ type, target, path, impact, key?, before?, after?, description?, migrationHint? }] }
Definition Evaluator — src/formspec/evaluator.py
Server-side form processor. Runs four phases per submission: rebuild (init) → recalculate → revalidate → apply non-relevant behavior (NRB).
from formspec.evaluator import DefinitionEvaluator, ProcessingResult
ev = DefinitionEvaluator(definition)
result = ev.process(submitted_data) # ProcessingResult
results = ev.validate(submitted_data) # list[dict] convenience
ProcessingResult
@dataclass
class ProcessingResult:
valid: bool
results: list[dict] # Validation results
data: dict # Processed response data
variables: dict[str, FelValue]
counts: dict[str, int] # Repeat group instance counts
Instantiate DefinitionEvaluator once per definition; call process() for each submission. Accepts optional registries: list[Registry] for extension constraint validation. Also provides evaluate_screener(answers) for pre-form screening logic.
Extension Registry — src/formspec/registry.py
from formspec.registry import Registry, validate_lifecycle_transition
reg = Registry(registry_doc)
entry = reg.find_one("x-my-component", version=">=1.0.0", status="stable")
entries = reg.find("x-comp", version=">=1.0.0 <2.0.0", category="component")
entries = reg.list_by_category("component")
errors = reg.validate() # Returns list of error strings
valid = validate_lifecycle_transition("draft", "stable") # True
RegistryEntry fields: name, category, version, status, description, compatibility, publisher, spec_url, schema_url, license, deprecation_notice, base_type, parameters, returns, members.
Valid statuses: draft, stable, deprecated, retired.
Lifecycle transitions: draft, stable, or deprecated can transition to any other status. retired is terminal.
Registry.find supports semver constraints (e.g., ">=1.0.0 <2.0.0"), sorts by version descending.
Registry.validate checks: extension name pattern (x-[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*), deprecated entries have notices, dataType entries have baseType, function entries have parameters and returns.
WELL_KNOWN_PATH = '/.well-known/formspec-extensions'
Artifact Validator — src/formspec/validate.py
Auto-discovers and validates all Formspec JSON artifacts in a directory. Runs 10 passes that exercise the full toolchain: linting, schema validation, runtime evaluation, mapping, changelog generation, registry checks, and FEL expression parsing.
CLI
python3 -m formspec.validate path/to/artifacts/
python3 -m formspec.validate path/to/artifacts/ --registry common.registry.json
python3 -m formspec.validate path/to/artifacts/ --title "My Project"
Library API
from formspec.validate import discover_artifacts, validate_all, print_report
artifacts = discover_artifacts(Path("my-project/"))
report = validate_all(artifacts)
sys.exit(print_report(report)) # 0 = success, >0 = error count
Validation Passes
- Definition linting
- Sidecar linting
- Theme linting
- Component linting
- Response schema validation
- Runtime evaluation (via
DefinitionEvaluator) - Mapping forward transform
- Changelog generation
- Registry validation
- FEL expression parsing
Each pass returns a PassResult with per-item success/failure and diagnostics. print_report() renders colored terminal output.
Architectural Patterns
- Frozen dataclasses everywhere — AST nodes, diagnostics, FEL values, and type wrappers freeze for safe sharing and hashability.
- Singletons —
FelNull,FelTrue,FelFalse,_DROP_SENTINELenable identity comparison. - Special-form functions — Functions that need unevaluated AST (e.g.,
if(),countWhere(), MIP functions, repeat navigation) receive the evaluator and AST nodes rather than pre-evaluated arguments. propagate_nullflag onFuncDef— triggers automatic null propagation before invocation. Aggregates, type-checkers, and casts setpropagate_null=Falsefor custom null handling.- Multi-pass linter — Schema validation gates semantic analysis; structural errors halt further passes. Each pass lives in a separate module with defined inputs and outputs.
- Policy-driven severity — The authoring/strict split transforms diagnostics after each pass; check modules themselves stay mode-agnostic.
- Adapter abstraction — The
AdapterABC (serialize/deserialize) decouples the mapping engine from wire formats. Custom adapters use thex-prefix. - Environment scoping — Let-bindings and
countWhereelement bindings use a push/pop scope stack for lexical scoping without mutation.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
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 formspec_py-0.1.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: formspec_py-0.1.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c40bd84f586fe9ee138cc8f1a9f34bd90fe60e3fa1e2070bb67dbc4b55f410a
|
|
| MD5 |
b6f613fb7fbbbe75727235d55a334886
|
|
| BLAKE2b-256 |
b149e734699e811852274b55e512149192b43f8fd6485cdb0e1cc62d5829b8f9
|
Provenance
The following attestation bundles were made for formspec_py-0.1.0-cp312-cp312-win_amd64.whl:
Publisher:
publish-pypi.yml on Formspec-org/formspec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
formspec_py-0.1.0-cp312-cp312-win_amd64.whl -
Subject digest:
9c40bd84f586fe9ee138cc8f1a9f34bd90fe60e3fa1e2070bb67dbc4b55f410a - Sigstore transparency entry: 1186959523
- Sigstore integration time:
-
Permalink:
Formspec-org/formspec@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/Formspec-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Trigger Event:
push
-
Statement type:
File details
Details for the file formspec_py-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: formspec_py-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1046c1cefaf8b8e8922b00a32fe76a0d11721598ccc587c177b3d2a14a5c68b7
|
|
| MD5 |
c7aa6026c80f6500ce6959995867c7bd
|
|
| BLAKE2b-256 |
a0335ada4a2ccbc3ac98c77440972cc3624881bc9434bf448cfd6bf6511ad961
|
Provenance
The following attestation bundles were made for formspec_py-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish-pypi.yml on Formspec-org/formspec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
formspec_py-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
1046c1cefaf8b8e8922b00a32fe76a0d11721598ccc587c177b3d2a14a5c68b7 - Sigstore transparency entry: 1186959599
- Sigstore integration time:
-
Permalink:
Formspec-org/formspec@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/Formspec-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Trigger Event:
push
-
Statement type:
File details
Details for the file formspec_py-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: formspec_py-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f30751adb791397a0c7858118424af36bbd3c916f686b3dbbd85adf4f2e9662
|
|
| MD5 |
1ba0c3c7b7c7a55b3deaf1954cc77c4b
|
|
| BLAKE2b-256 |
39e0eac11b21315709ee8090484c05dee4fb2288b6cc5fa9738bff798502d1ca
|
Provenance
The following attestation bundles were made for formspec_py-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
publish-pypi.yml on Formspec-org/formspec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
formspec_py-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
2f30751adb791397a0c7858118424af36bbd3c916f686b3dbbd85adf4f2e9662 - Sigstore transparency entry: 1186959637
- Sigstore integration time:
-
Permalink:
Formspec-org/formspec@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/Formspec-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Trigger Event:
push
-
Statement type:
File details
Details for the file formspec_py-0.1.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: formspec_py-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27d0a32a070c99492937f1629874cf48d598c71656e68aeeeb5477ab4e576b9e
|
|
| MD5 |
0517ede35b29d8ce8d82ccd5b0227c86
|
|
| BLAKE2b-256 |
5871af0969ab3fb1cb40a50bd37121543cc84840f68e91353d6fe3962d535fb9
|
Provenance
The following attestation bundles were made for formspec_py-0.1.0-cp312-cp312-macosx_11_0_arm64.whl:
Publisher:
publish-pypi.yml on Formspec-org/formspec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
formspec_py-0.1.0-cp312-cp312-macosx_11_0_arm64.whl -
Subject digest:
27d0a32a070c99492937f1629874cf48d598c71656e68aeeeb5477ab4e576b9e - Sigstore transparency entry: 1186959696
- Sigstore integration time:
-
Permalink:
Formspec-org/formspec@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/Formspec-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Trigger Event:
push
-
Statement type:
File details
Details for the file formspec_py-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl.
File metadata
- Download URL: formspec_py-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.12, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa5fc60a86afaf191a7ef6011d7118562f9224c225d7deee997fd120bde61f0b
|
|
| MD5 |
ee1dc56cf71fe8193d058f3e4c38d2b8
|
|
| BLAKE2b-256 |
30620364d890c5a38bca5737ed6949c7fb45a8884dd76bea209792ff64db217c
|
Provenance
The following attestation bundles were made for formspec_py-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl:
Publisher:
publish-pypi.yml on Formspec-org/formspec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
formspec_py-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl -
Subject digest:
aa5fc60a86afaf191a7ef6011d7118562f9224c225d7deee997fd120bde61f0b - Sigstore transparency entry: 1186959560
- Sigstore integration time:
-
Permalink:
Formspec-org/formspec@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/Formspec-org
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@de21614e15a4dde2246b0d0b17bd8a1f345ce73f -
Trigger Event:
push
-
Statement type: