diff --git a/src/metaseed/seek/fairds.py b/src/metaseed/seek/fairds.py index b060aa0f..018c2a20 100644 --- a/src/metaseed/seek/fairds.py +++ b/src/metaseed/seek/fairds.py @@ -253,7 +253,11 @@ def walk(node: Any, parent_path: str) -> None: if key == "description": graph.add((uri, SCHEMA.description, Literal(value))) else: - graph.add((uri, SCHEMA[key], Literal(value))) + # Percent-encoded through the same helper provisioning uses: a + # field named with a space is what SEEK matches an imported + # sample to its attribute by, and rdflib refuses to serialize + # the unencoded form at all. + graph.add((uri, URIRef(property_uri(key)), Literal(value))) if key in entity_fields: used[key] = entity_fields[key] diff --git a/tests/test_seek/test_provision.py b/tests/test_seek/test_provision.py index bc78cee6..b3d61ac2 100644 --- a/tests/test_seek/test_provision.py +++ b/tests/test_seek/test_provision.py @@ -322,3 +322,54 @@ def test_the_data_rdf_uses_the_same_uri(self) -> None: emitted = {str(s) for s in graph.subjects()} assert property_uri("Source Name") in emitted assert URIRef("http://schema.org/Source Name") not in set(graph.subjects()) + + def test_a_dataset_with_a_spaced_field_name_exports(self) -> None: + """Exporting is where the unencoded URI actually bit. + + Provisioning was fixed first, and its tests passed, but the data RDF + built property URIs at a second site that still concatenated the field + name. rdflib refuses to serialize ``http://schema.org/Source Name`` at + all, so exporting any dataset on such a profile raised rather than + producing a graph SEEK could read. + """ + pytest.importorskip("rdflib") + from metaseed import MetaseedClient + from metaseed.seek.fairds import to_fair_data_station_rdf + from metaseed.seek.naming import property_uri + from metaseed.specs.schema import ( + EntityDefSpec, + FieldSpec, + FieldType, + ProfileSpec, + ) + + spec = ProfileSpec( + version="1.0", + name="spaced-export", + display_name="Spaced export", + description="d", + ontology="T", + root_entity="Investigation", + entities={ + "Investigation": EntityDefSpec( + description="d", + fields=[ + FieldSpec(name="title", type=FieldType.STRING), + FieldSpec(name="Source Name", type=FieldType.STRING), + ], + ) + }, + ) + + client = MetaseedClient.from_spec(spec.model_dump(mode="json")) + client.create_entity( + "Investigation", + {"title": "t", "Source Name": "S-1"}, + skip_validation=True, + ) + + rdf = to_fair_data_station_rdf(client) + text = rdf.decode() if isinstance(rdf, bytes) else rdf + + assert "schema.org/Source Name" not in text, "an unserializable URI" + assert property_uri("Source Name").rsplit("/", 1)[-1] in text