Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions assets/schemas/cell-instance.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@
"type": "string"
}
},
"license": {
"type": "string",
"minLength": 1,
"description": "License under which this record and its data are released, as an SPDX license identifier (e.g. \"cc-by-4.0\") or a license URL. Stamped from the workspace default (ws.license) and emitted as dcterms:license in JSON-LD."
},
"funding": {
"$ref": "#/$defs/Funding"
},
Expand Down
5 changes: 5 additions & 0 deletions assets/schemas/cell-spec.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@
"type": "string",
"description": "Usable extinguishing agent for the battery (EU Battery Regulation Annex VI Part A)."
},
"license": {
"type": "string",
"minLength": 1,
"description": "License under which this record and its data are released, as an SPDX license identifier (e.g. \"cc-by-4.0\") or a license URL. Stamped from the workspace default (ws.license) and emitted as dcterms:license in JSON-LD."
},
"funding": {
"$ref": "#/$defs/Funding"
},
Expand Down
5 changes: 5 additions & 0 deletions assets/schemas/test-protocol.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@
"type": "string"
}
},
"license": {
"type": "string",
"minLength": 1,
"description": "License under which this record and its data are released, as an SPDX license identifier (e.g. \"cc-by-4.0\") or a license URL. Stamped from the workspace default (ws.license) and emitted as dcterms:license in JSON-LD."
},
"funding": {
"$ref": "#/$defs/Funding"
},
Expand Down
5 changes: 5 additions & 0 deletions assets/schemas/test.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@
"type": "string"
}
},
"license": {
"type": "string",
"minLength": 1,
"description": "License under which this record and its data are released, as an SPDX license identifier (e.g. \"cc-by-4.0\") or a license URL. Stamped from the workspace default (ws.license) and emitted as dcterms:license in JSON-LD."
},
"funding": {
"$ref": "#/$defs/Funding"
},
Expand Down
5 changes: 5 additions & 0 deletions src/battinfo/data/schemas/cell-instance.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@
"type": "string"
}
},
"license": {
"type": "string",
"minLength": 1,
"description": "License under which this record and its data are released, as an SPDX license identifier (e.g. \"cc-by-4.0\") or a license URL. Stamped from the workspace default (ws.license) and emitted as dcterms:license in JSON-LD."
},
"funding": {
"$ref": "#/$defs/Funding"
},
Expand Down
5 changes: 5 additions & 0 deletions src/battinfo/data/schemas/cell-spec.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@
"type": "string",
"description": "Usable extinguishing agent for the battery (EU Battery Regulation Annex VI Part A)."
},
"license": {
"type": "string",
"minLength": 1,
"description": "License under which this record and its data are released, as an SPDX license identifier (e.g. \"cc-by-4.0\") or a license URL. Stamped from the workspace default (ws.license) and emitted as dcterms:license in JSON-LD."
},
"funding": {
"$ref": "#/$defs/Funding"
},
Expand Down
5 changes: 5 additions & 0 deletions src/battinfo/data/schemas/test-protocol.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@
"type": "string"
}
},
"license": {
"type": "string",
"minLength": 1,
"description": "License under which this record and its data are released, as an SPDX license identifier (e.g. \"cc-by-4.0\") or a license URL. Stamped from the workspace default (ws.license) and emitted as dcterms:license in JSON-LD."
},
"funding": {
"$ref": "#/$defs/Funding"
},
Expand Down
5 changes: 5 additions & 0 deletions src/battinfo/data/schemas/test.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@
"type": "string"
}
},
"license": {
"type": "string",
"minLength": 1,
"description": "License under which this record and its data are released, as an SPDX license identifier (e.g. \"cc-by-4.0\") or a license URL. Stamped from the workspace default (ws.license) and emitted as dcterms:license in JSON-LD."
},
"funding": {
"$ref": "#/$defs/Funding"
},
Expand Down
7 changes: 7 additions & 0 deletions src/battinfo/jsonld.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,13 @@ def record_to_jsonld(record: dict, record_type: str, *, context: str = "url") ->
people = contributor_to_jsonld(record.get("contributor"))
if people is not None:
node["schema:contributor"] = people
# Record-level license (FAIR R1.1) → dcterms:license, the same convention
# the dataset emitter uses. Cell specs/instances/tests carry it at the
# record top level (stamped from the workspace default); datasets carry it
# on the dataset body and emit it from dataset_to_jsonld, so this only
# reaches the non-dataset record kinds.
if record.get("license") and "dcterms:license" not in node:
node["dcterms:license"] = {"@id": record["license"]}
if context == "url" and isinstance(node.get("@context"), dict):
# Swap the inline records context for the hosted reference. Only the
# records-context nodes (a dict @context) are affected; material/component
Expand Down
28 changes: 28 additions & 0 deletions src/battinfo/validate/publication.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,33 @@ def _test_condition_issues(data: dict[str, Any], policy: ValidationPolicy) -> Va
return ValidationReport(issues=tuple(issues), policy=policy)


def _license_issues(data: dict[str, Any], policy: ValidationPolicy) -> ValidationReport:
"""Warn (never block) when the published catalog carries no license — a FAIR R1.1
nudge to set one so every served record states its reuse terms. Mirrors the
contributor/attribution nudge in tone: a warning pointing at ``ws.license(...)``,
not a publish blocker. Only the top catalog node is checked; per-member licenses
are propagated from it by the builder."""
issues: list[ValidationIssue] = []
for path, node in _graph_nodes(data):
types = _type_values(node)
if "dcat:Catalog" not in types and "schema:DataCatalog" not in types:
continue
if node.get("schema:license") or node.get("dcterms:license"):
continue
_append_issue(
issues,
code="publication.license_missing",
severity="warning", # explicit: a nudge, not a publish blocker
path=path,
message=(
"No license on the published record; consumers cannot tell how they "
"may reuse the data (FAIR R1.1). Set a default with "
'ws.license("cc-by-4.0") before publishing.'
),
)
return ValidationReport(issues=tuple(issues), policy=policy)


def _is_absolute_uri(value: Any) -> bool:
if not isinstance(value, str) or not value:
return False
Expand Down Expand Up @@ -379,6 +406,7 @@ def validate_publication_report(
_shape_issues(data, resolved_policy),
_shacl_publication_report(data, resolved_policy),
_test_condition_issues(data, resolved_policy),
_license_issues(data, resolved_policy),
policy=resolved_policy,
)

Expand Down
Loading
Loading