diff --git a/rdflib/tools/defined_namespace_creator.py b/rdflib/tools/defined_namespace_creator.py index 0c93ea756..1076cd6e0 100644 --- a/rdflib/tools/defined_namespace_creator.py +++ b/rdflib/tools/defined_namespace_creator.py @@ -77,7 +77,7 @@ def get_target_namespace_elements( ) -> Tuple[List[Tuple[str, str]], List[str]]: namespaces = {"dcterms": DCTERMS, "owl": OWL, "rdfs": RDFS, "skos": SKOS} q = """ - SELECT DISTINCT ?s ?def + SELECT ?s (GROUP_CONCAT(DISTINCT STR(?def)) AS ?defs) WHERE { # all things in the RDF data (anything RDF.type...) ?s a ?o . @@ -90,6 +90,7 @@ def get_target_namespace_elements( # only get results for the target namespace (supplied by user) FILTER STRSTARTS(STR(?s), "xxx") } + GROUP BY ?s """.replace( "xxx", target_namespace ) diff --git a/test/data/contrived/README.md b/test/data/contrived/README.md new file mode 100644 index 000000000..fd1e0e7d3 --- /dev/null +++ b/test/data/contrived/README.md @@ -0,0 +1,5 @@ +# Contrived Test Data + +This directory contains test data contrived for specific purposes. Files in this +directory should clearly indicate their purpose with a comment. + diff --git a/test/data/contrived/multiple-comments.ttl b/test/data/contrived/multiple-comments.ttl new file mode 100644 index 000000000..a2c073712 --- /dev/null +++ b/test/data/contrived/multiple-comments.ttl @@ -0,0 +1,17 @@ +@prefix rdfs: . +@prefix owl: . +@prefix ex: . + +# This file contains a RDF class with multiple rdfs:comment properties and is +# used to verify the RDFLib defined namespace creator. It is used in +# . + + + a owl:Ontology . + +ex:SomeClass a rdfs:Class, owl:Class; + rdfs:label "Some class"@en; + rdfs:comment "If one uses multiple comment properties, "@en; + rdfs:comment "then it should still only create a single class variable."@en; + rdfs:isDefinedBy ; +. diff --git a/test/test_namespace/test_definednamespace_creator.py b/test/test_namespace/test_definednamespace_creator.py index 65734b217..8866a05d9 100644 --- a/test/test_namespace/test_definednamespace_creator.py +++ b/test/test_namespace/test_definednamespace_creator.py @@ -114,3 +114,52 @@ def test_definednamespace_creator_bad_ns(): universal_newlines=True, ) assert completed.returncode == 1, "subprocess exited incorrectly (failure expected)" + + +def test_definednamespace_creator_multiple_comments(): + """ + Tests that only a single URIRef is declared, even when multiple + rdfs:comments are linked to the resource. + """ + + definednamespace_script = ( + Path(__file__).parent.parent.parent + / "rdflib" + / "tools" + / "defined_namespace_creator.py" + ) + multiple_comments_data_file = ( + Path(__file__).parent.parent / "data" / "contrived" / "multiple-comments.ttl" + ) + print("\n") + print(f"Using {definednamespace_script}...") + print(f"Testing {multiple_comments_data_file}...") + completed = subprocess.run( + [ + sys.executable, + str(definednamespace_script), + str(multiple_comments_data_file), + "http://example.org/multiline-string-example#", + "MULTILINESTRINGEXAMPLE", + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + assert completed.returncode == 0, "subprocess exited incorrectly" + assert Path.is_file( + Path("_MULTILINESTRINGEXAMPLE.py") + ), "_MULTILINESTRINGEXAMPLE.py file not created" + + some_class_count = 0 + with open(Path("_MULTILINESTRINGEXAMPLE.py")) as f: + for line in f.readlines(): + if "SomeClass: URIRef" in line: + some_class_count += 1 + + assert ( + some_class_count == 1 + ), f"found {some_class_count} SomeClass definitions instead of 1." + + # cleanup + Path.unlink(Path("_MULTILINESTRINGEXAMPLE.py"))