|
4 | 4 |
|
5 | 5 | import yaml
|
6 | 6 |
|
| 7 | +from owlrl import DeductiveClosure, RDFS_Semantics |
| 8 | + |
7 | 9 | from rdflib import URIRef, Literal
|
8 |
| -from rdflib.namespace import XSD, RDF |
| 10 | +from rdflib.namespace import Namespace, RDF, RDFS, XSD |
| 11 | +from rdflib.plugins.sparql import prepareQuery |
9 | 12 |
|
10 | 13 | import odml
|
11 | 14 |
|
12 | 15 | from odml.format import Format
|
13 |
| -from odml.tools.rdf_converter import RDFWriter |
| 16 | +from odml.tools.rdf_converter import ODML_NS, RDFWriter |
14 | 17 |
|
15 | 18 | from .test_samplefile import SampleFileCreator
|
16 | 19 | from .test_samplefile import parse
|
@@ -312,6 +315,11 @@ def test_rdf_subclassing_switch(self):
|
312 | 315 | self.assertNotIn("odml:Cell", result)
|
313 | 316 |
|
314 | 317 | def test_rdf_custom_subclasses(self):
|
| 318 | + """ |
| 319 | + Test collection of the odml RDF subclassing feature. |
| 320 | + Tests that the resulting output RDF document contains any required |
| 321 | + additional RDF subclasses. |
| 322 | + """ |
315 | 323 | sub_class_term = "cell"
|
316 | 324 |
|
317 | 325 | # Create minimal document
|
@@ -354,3 +362,157 @@ def test_rdf_custom_subclasses(self):
|
354 | 362 | rdf_writer = RDFWriter([doc], custom_subclasses=custom_class_dict)
|
355 | 363 | self.assertNotIn("odml:Cell", rdf_writer.get_rdf_str())
|
356 | 364 | self.assertIn("odml:Neuron", rdf_writer.get_rdf_str())
|
| 365 | + |
| 366 | + def test_rdf_subclassing_definitions(self): |
| 367 | + """ |
| 368 | + Test that RDF Subclass definitions are written to the resulting graph. |
| 369 | + """ |
| 370 | + # -- Test default subclassing |
| 371 | + doc = odml.Document() |
| 372 | + _ = odml.Section(name="test_subclassing", type="cell", parent=doc) |
| 373 | + |
| 374 | + rdf_writer = RDFWriter([doc]) |
| 375 | + curr_str = " ".join(rdf_writer.get_rdf_str().split()) |
| 376 | + self.assertIn("odml:Cell a rdfs:Class ; rdfs:subClassOf odml:Section", curr_str) |
| 377 | + self.assertIn("odml:Section a rdfs:Class", curr_str) |
| 378 | + |
| 379 | + # -- Test multiple entries; a definition should only occur once in an RDF document |
| 380 | + doc = odml.Document() |
| 381 | + sec = odml.Section(name="test_subclassing", type="cell", parent=doc) |
| 382 | + sub_sec = odml.Section(name="test_subclassing", type="cell", parent=sec) |
| 383 | + _ = odml.Section(name="test_subclassing", type="cell", parent=sub_sec) |
| 384 | + |
| 385 | + rdf_writer = RDFWriter([doc]) |
| 386 | + curr_str = " ".join(rdf_writer.get_rdf_str().split()) |
| 387 | + self.assertIn("odml:Cell a rdfs:Class ; rdfs:subClassOf odml:Section", curr_str) |
| 388 | + self.assertIs(curr_str.count("odml:Cell a rdfs:Class ; rdfs:subClassOf odml:Section"), 1) |
| 389 | + self.assertIn("odml:Section a rdfs:Class", curr_str) |
| 390 | + self.assertIs(curr_str.count("odml:Section a rdfs:Class"), 1) |
| 391 | + |
| 392 | + # -- Test custom subclassing |
| 393 | + type_custom_class = "species" |
| 394 | + custom_class_dict = {type_custom_class: "Species"} |
| 395 | + |
| 396 | + doc = odml.Document() |
| 397 | + _ = odml.Section(name="test_subclassing", type="cell", parent=doc) |
| 398 | + _ = odml.Section(name="test_custom_subclassing", type=type_custom_class, parent=doc) |
| 399 | + |
| 400 | + rdf_writer = RDFWriter([doc], custom_subclasses=custom_class_dict) |
| 401 | + curr_str = " ".join(rdf_writer.get_rdf_str().split()) |
| 402 | + self.assertIn("odml:Cell a rdfs:Class ; rdfs:subClassOf odml:Section", curr_str) |
| 403 | + self.assertIn("odml:Species a rdfs:Class ; rdfs:subClassOf odml:Section", curr_str) |
| 404 | + self.assertIn("odml:Section a rdfs:Class", curr_str) |
| 405 | + |
| 406 | + # -- Test inactive subclassing |
| 407 | + doc = odml.Document() |
| 408 | + _ = odml.Section(name="test_subclassing", type="cell", parent=doc) |
| 409 | + |
| 410 | + rdf_writer = RDFWriter([doc], rdf_subclassing=False) |
| 411 | + curr_str = " ".join(rdf_writer.get_rdf_str().split()) |
| 412 | + self.assertNotIn("odml:Section a rdfs:Class", curr_str) |
| 413 | + self.assertNotIn("odml:Cell a rdfs:Class ; rdfs:subClassOf odml:Section", curr_str) |
| 414 | + |
| 415 | + def test_rdf_subclassing_queries(self): |
| 416 | + """ |
| 417 | + Test the proper implementation of the RDF subclassing feature. Tests ensure, that queries |
| 418 | + relying on RDF Subclasses return appropriate results. |
| 419 | + """ |
| 420 | + namespace_map = {"odml": Namespace(ODML_NS), "rdf": RDF, "rdfs": RDFS} |
| 421 | + |
| 422 | + doc = odml.Document() |
| 423 | + _ = odml.Section(name="test_subclass", type="cell", parent=doc) |
| 424 | + _ = odml.Section(name="test_regular_class", type="regular", parent=doc) |
| 425 | + |
| 426 | + rdf_writer = RDFWriter([doc]) |
| 427 | + _ = rdf_writer.get_rdf_str() |
| 428 | + |
| 429 | + use_graph = rdf_writer.graph |
| 430 | + DeductiveClosure(RDFS_Semantics).expand(use_graph) |
| 431 | + |
| 432 | + q_string = "SELECT * WHERE {?s rdf:type odml:Section .}" |
| 433 | + curr_query = prepareQuery(q_string, initNs=namespace_map) |
| 434 | + |
| 435 | + # Make sure the query finds two sections |
| 436 | + self.assertIs(len(use_graph.query(curr_query)), 2) |
| 437 | + |
| 438 | + # Make sure the query finds |
| 439 | + result_section = [] |
| 440 | + for row in use_graph.query(curr_query): |
| 441 | + result_section.append(row.s) |
| 442 | + |
| 443 | + q_string = "SELECT * WHERE {?s rdf:type odml:Cell .}" |
| 444 | + curr_query = prepareQuery(q_string, initNs=namespace_map) |
| 445 | + |
| 446 | + self.assertIs(len(use_graph.query(curr_query)), 1) |
| 447 | + for row in use_graph.query(curr_query): |
| 448 | + self.assertIn(row.s, result_section) |
| 449 | + |
| 450 | + # -- Test custom subclassing queries |
| 451 | + type_custom_class = "species" |
| 452 | + type_overwrite_class = "cell" |
| 453 | + custom_class_dict = {type_custom_class: "Species", type_overwrite_class: "Neuron"} |
| 454 | + |
| 455 | + doc = odml.Document() |
| 456 | + sec = odml.Section(name="test_subclass", type="species", parent=doc) |
| 457 | + _ = odml.Section(name="test_subclass_overwrite", type="cell", parent=sec) |
| 458 | + _ = odml.Section(name="test_regular_class", type="regular", parent=sec) |
| 459 | + |
| 460 | + rdf_writer = RDFWriter([doc], custom_subclasses=custom_class_dict) |
| 461 | + _ = rdf_writer.get_rdf_str() |
| 462 | + |
| 463 | + use_graph = rdf_writer.graph |
| 464 | + DeductiveClosure(RDFS_Semantics).expand(use_graph) |
| 465 | + |
| 466 | + q_string = "SELECT * WHERE {?s rdf:type odml:Section .}" |
| 467 | + curr_query = prepareQuery(q_string, initNs=namespace_map) |
| 468 | + |
| 469 | + # Make sure the query finds three sections |
| 470 | + self.assertIs(len(use_graph.query(curr_query)), 3) |
| 471 | + |
| 472 | + # Make sure the query finds |
| 473 | + result_section = [] |
| 474 | + for row in use_graph.query(curr_query): |
| 475 | + result_section.append(row.s) |
| 476 | + |
| 477 | + # Custom class 'Species' should be found. |
| 478 | + q_string = "SELECT * WHERE {?s rdf:type odml:Species .}" |
| 479 | + curr_query = prepareQuery(q_string, initNs=namespace_map) |
| 480 | + |
| 481 | + self.assertIs(len(use_graph.query(curr_query)), 1) |
| 482 | + for row in use_graph.query(curr_query): |
| 483 | + self.assertIn(row.s, result_section) |
| 484 | + |
| 485 | + # Custom class 'Neuron' should be found. |
| 486 | + q_string = "SELECT * WHERE {?s rdf:type odml:Neuron .}" |
| 487 | + curr_query = prepareQuery(q_string, initNs=namespace_map) |
| 488 | + |
| 489 | + self.assertIs(len(use_graph.query(curr_query)), 1) |
| 490 | + for row in use_graph.query(curr_query): |
| 491 | + self.assertIn(row.s, result_section) |
| 492 | + |
| 493 | + # Default class 'Cell' was replaced and should not return any result. |
| 494 | + q_string = "SELECT * WHERE {?s rdf:type odml:Cell .}" |
| 495 | + curr_query = prepareQuery(q_string, initNs=namespace_map) |
| 496 | + |
| 497 | + self.assertIs(len(use_graph.query(curr_query)), 0) |
| 498 | + |
| 499 | + # -- Test inactivated subclassing |
| 500 | + doc = odml.Document() |
| 501 | + _ = odml.Section(name="test_regular_class", type="regular", parent=doc) |
| 502 | + _ = odml.Section(name="test_subclass", type="cell", parent=doc) |
| 503 | + |
| 504 | + rdf_writer = RDFWriter([doc], rdf_subclassing=False) |
| 505 | + _ = rdf_writer.get_rdf_str() |
| 506 | + |
| 507 | + use_graph = rdf_writer.graph |
| 508 | + DeductiveClosure(RDFS_Semantics).expand(use_graph) |
| 509 | + |
| 510 | + q_string = "SELECT * WHERE {?s rdf:type odml:Section .}" |
| 511 | + curr_query = prepareQuery(q_string, initNs=namespace_map) |
| 512 | + |
| 513 | + self.assertIs(len(use_graph.query(curr_query)), 2) |
| 514 | + |
| 515 | + q_string = "SELECT * WHERE {?s rdf:type odml:Cell .}" |
| 516 | + curr_query = prepareQuery(q_string, initNs=namespace_map) |
| 517 | + |
| 518 | + self.assertIs(len(use_graph.query(curr_query)), 0) |
0 commit comments