Skip to content

Commit 8761788

Browse files
committed
RDF Containers (rdf:Alt/Bag/Seq) not supported
We were not sure whether RDF containers should be allowed, or whether they are even useful. As it turns out, SHACL does not support these types for constraints such as `sh:in`, thus, we can remove them entirely. If lists/sequences, alternatives/enums, sets/bags are needed, they can be implemented by using the collection type `rdf:List`.
1 parent 15f4e6c commit 8761788

4 files changed

Lines changed: 20 additions & 47 deletions

File tree

docs/appendices/ontology.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ sc:AllowedOuterType a owl:Class ;
8888
rdfs:label "Allowed Outer Type"@en ;
8989
rdfs:comment """The set of container types that may be used as outer types for parameters.
9090
This includes scalar (single value), ordered lists, and unordered bags."""@en ;
91-
owl:oneOf ( sc:Scalar rdf:List rdf:Bag ) ;
91+
owl:oneOf ( sc:Scalar rdf:List ) ;
9292
rdfs:isDefinedBy <https://schema.software-metadata.pub/software-card/2025-01/#> .
9393
9494
# Class Definition with cardinality restrictions
@@ -143,7 +143,7 @@ sc:parameterOuterType a owl:ObjectProperty ;
143143
rdfs:label "parameter outer type"@en ;
144144
rdfs:comment """Specifies the container/cardinality type of the parameter value.
145145
Determines whether the parameter represents a single value (sc:Scalar),
146-
an ordered collection (rdf:List), or an unordered collection (rdf:Bag)."""@en ;
146+
or a list of values (rdf:List)."""@en ;
147147
rdfs:domain sc:Parameter ;
148148
rdfs:range sc:AllowedOuterType ;
149149
rdfs:isDefinedBy <https://schema.software-metadata.pub/software-card/2025-01/#> .
@@ -171,7 +171,7 @@ sc:parameterDefaultValue a rdf:Property ;
171171
parameter becomes required and must be provided in the configuration file.
172172
When present, the default value must match the parameter's declared outer
173173
and inner types. For scalar parameters, this is a single literal or resource.
174-
For list or bag parameters, this is an rdf:List or rdf:Bag."""@en ;
174+
For list parameters, this is an rdf:List."""@en ;
175175
rdfs:domain sc:Parameter ;
176176
rdfs:isDefinedBy <https://schema.software-metadata.pub/software-card/2025-01/#> .
177177
@@ -241,8 +241,8 @@ sc:ParameterShape a sh:NodeShape ;
241241
sh:description "The container/cardinality type of the parameter."@en ;
242242
sh:minCount 1 ;
243243
sh:maxCount 1 ;
244-
sh:in ( sc:Scalar rdf:List rdf:Bag ) ;
245-
sh:message "Parameter must have exactly one outer type: sc:Scalar, rdf:List, or rdf:Bag."@en ;
244+
sh:in ( sc:Scalar rdf:List ) ;
245+
sh:message "Parameter must have exactly one outer type: sc:Scalar, or rdf:List."@en ;
246246
] ;
247247
248248
# Must have exactly one inner type from allowed set

docs/specification/parameterization.md

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ We mention dates as an example here but disallow them later.
9797
This separation allows the framework to correctly handle configurations like:
9898

9999
- A minimum character requirement for descriptions (outer: `sc:Scalar`, inner: `xsd:int`)
100-
- A list of license URIs (outer: `rdf:List`, inner: `xsd:anyURI`)
101-
- A set of organization names (outer: `rdf:Bag`, inner: `xsd:string`)
100+
- A selection of license URIs (outer: `rdf:List`, inner: `xsd:anyURI`)
101+
- A list of organization names (outer: `rdf:List`, inner: `xsd:string`)
102102

103103

104104
## `sc:parameterInnerType`
@@ -159,13 +159,13 @@ The outer type MUST be present and MUST specify how values are structured.
159159

160160
These types MUST be supported by implementations:
161161

162-
| Outer Type | Meaning | Use When | Example |
163-
| ----------- | ------------------ | -------------------------------------------- | ------------------------------------------ |
164-
| `sc:Scalar` | Single value | Only one value is needed | Minimum description length, a boolean flag |
165-
| `rdf:List` | Ordered sequence | Order matters and multiple values are needed | Priority-ordered list of licenses |
166-
| `rdf:Bag` | Unordered sequence | Order does not matter for multiple values | List of software dependencies |
162+
| Outer Type | Meaning | Use When | Examples |
163+
| ----------- | --------------------------------------------- | -------------------------- | ---------------------------------------------------------------- |
164+
| `sc:Scalar` | Single value | Only one value is needed | Minimum text length, a boolean flag, a single email address, ... |
165+
| `rdf:List` | Ordered and unordered sequences, enumerations | Multiple values are needed | A selection of allowed licenses, a list of persons, ... |
167166

168-
Ohter RDF collection types (like `rdf:Seq`, `rdf:Alt`) MAY be supported by a validation implementation.
167+
RDF container types (`rdf:Alt`, `rdf:Bag`, `rdf:Seq`) MAY be supported by validation implementations.
168+
However, these types are not supported by SHACL which means conversion has to be applied.
169169

170170
## `sc:parameterConfigKey`
171171

@@ -323,18 +323,3 @@ scex:requiredKeywords a sc:Parameter ;
323323
sc:parameterConfigKey "required_keywords" ;
324324
sc:parameterDefaultValue ( "research-software" "open-source" ) .
325325
```
326-
327-
Configuration:
328-
```toml
329-
[policies.keywords.parameters]
330-
required_keywords = ["fair-software", "reproducible-research", "scientific-computing"]
331-
```
332-
333-
**Bag of Strings (Unordered Collection):**
334-
```turtle
335-
scex:allowedLanguages a sc:Parameter ;
336-
sc:parameterOuterType rdf:Bag ;
337-
sc:parameterInnerType xsd:string ;
338-
sc:parameterConfigKey "allowed_programming_languages" ;
339-
sc:parameterDefaultValue ( "Python" "Java" "C++" ) .
340-
```

docs/specification/validation.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ Implementations MUST validate that configured parameter values match the declare
9090

9191
1. **Outer Type Validation:**
9292
- `sc:Scalar`: parameters MUST receive a single value (not an array/list)
93-
- `rdf:List`: parameters MUST receive an (ordered) array/list of values
94-
- `rdf:Bag`: parameters MUST receive an (unorderd) array/list of values
93+
- `rdf:List`: parameters MUST receive an array/list of values
9594

9695
2. **Inner Type Validation:**
9796
- Values MUST be compatible with the declared XSD datatype

src/software_card_policies/data_model.py

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from enum import Enum
88
from functools import reduce
99
from pathlib import Path
10+
from types import NoneType
1011
from typing import Any, Dict, List, Tuple
1112

1213
from pyshacl import validate
@@ -146,9 +147,6 @@ def from_graph(cls, reference: URIRef, graph: Graph):
146147
_ALLOWED_OUTER_TYPES = (
147148
SC.Scalar,
148149
RDF.List,
149-
RDF.Seq,
150-
RDF.Bag,
151-
RDF.Alt,
152150
)
153151

154152
_ALLOWED_INNER_TYPES = (
@@ -172,11 +170,10 @@ def read_rdf_resource(source: Path | str) -> Graph:
172170
return graph
173171

174172

175-
def _create_rdf_list_parameter(
173+
def _create_list_parameter(
176174
parameter: Parameter, graph: Graph, config_parameter: Any
177175
) -> Node:
178176
assert parameter.outer_type == RDF.List
179-
# assert (parameter.default_value, RDF.type, RDF.List) in graph
180177
assert (parameter.default_value, RDF.first, None) in graph
181178
assert (parameter.default_value, RDF.rest, None) in graph
182179

@@ -190,12 +187,11 @@ def _create_rdf_list_parameter(
190187
).uri
191188

192189

193-
def _create_sc_scalar_parameter(
190+
def _create_scalar_parameter(
194191
parameter: Parameter, graph: Graph, config_parameter: Any
195192
) -> Node:
196193
assert parameter.outer_type == SC.Scalar
197-
198-
assert isinstance(config_parameter, (str, int, float, type(None)))
194+
assert isinstance(config_parameter, (str, int, float, NoneType))
199195

200196
if config_parameter:
201197
return Literal(config_parameter)
@@ -228,17 +224,10 @@ def parameterize_graph(graph: Graph, config_parameters: Dict[str, Any]) -> Graph
228224
)
229225

230226
if parameter.outer_type == SC.Scalar:
231-
o = _create_sc_scalar_parameter(parameter, graph, config_parameter)
232-
233-
elif parameter.outer_type == RDF.List:
234-
o = _create_rdf_list_parameter(parameter, graph, config_parameter)
227+
o = _create_scalar_parameter(parameter, graph, config_parameter)
235228

236229
else:
237-
raise NotImplementedError(
238-
f"Parameter '{parameter.uri}' has outer type "
239-
f"'{parameter.outer_type}', the handling of which "
240-
"is currently not implemented"
241-
)
230+
o = _create_list_parameter(parameter, graph, config_parameter)
242231

243232
# Add replacements for all occurences of the parameter. Again, extract
244233
# occurences before modifying the graph!

0 commit comments

Comments
 (0)