mustrd 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mustrd/README.md +29 -0
- mustrd/TestResult.py +1 -1
- mustrd/mustrd.py +90 -99
- mustrd/mustrdAnzo.py +30 -15
- mustrd/mustrdTestPlugin.py +48 -41
- mustrd/namespace.py +9 -8
- mustrd/run.py +3 -4
- mustrd/spec_component.py +109 -98
- mustrd/test/test_mustrd.py +1 -1
- mustrd/utils.py +1 -0
- {mustrd-0.2.1.dist-info → mustrd-0.2.3.dist-info}/METADATA +10 -5
- {mustrd-0.2.1.dist-info → mustrd-0.2.3.dist-info}/RECORD +15 -15
- mustrd/README.adoc +0 -210
- {mustrd-0.2.1.dist-info → mustrd-0.2.3.dist-info}/LICENSE +0 -0
- {mustrd-0.2.1.dist-info → mustrd-0.2.3.dist-info}/WHEEL +0 -0
- {mustrd-0.2.1.dist-info → mustrd-0.2.3.dist-info}/entry_points.txt +0 -0
mustrd/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Developer helper
|
2
|
+
|
3
|
+
## Try it out
|
4
|
+
|
5
|
+
Ensure you have python3 installed, before you begin.
|
6
|
+
To install the necessary dependencies, run the following command from the project root.
|
7
|
+
|
8
|
+
`pip3 install -r requirements.txt`
|
9
|
+
|
10
|
+
Run the following command to execute the accompanying tests specifications.
|
11
|
+
|
12
|
+
`python3 src/run.py -v -p "test/test-specs" -g "test/data" -w "test/data" -t "test/data"`
|
13
|
+
|
14
|
+
You will see some warnings. Do not worry, some tests specifications are invalid and intentionally skipped.
|
15
|
+
|
16
|
+
For a brief explanation of the meaning of these options use the help option.
|
17
|
+
|
18
|
+
`python3 src/run.py --help`
|
19
|
+
|
20
|
+
## Run the tests
|
21
|
+
|
22
|
+
Run `pytest` from the project root.
|
23
|
+
|
24
|
+
## Additional Notes for Developers
|
25
|
+
Mustrd remains very much under development. It is anticipated that additional functionality and triplestore support will be added over time. The project uses [Poetry](https://python-poetry.org/docs/) to manage dependencies so it will be necessary to have this installed to contribute towards the project. The link contains instructions on how to install and use this.
|
26
|
+
As the project is actually built from the requirements.txt file at the project root, it is necessary to export dependencies from poetry to this file before committing and pushing changes to the repository, using the following command.
|
27
|
+
|
28
|
+
`poetry export -f requirements.txt --without-hashes > requirements.txt`
|
29
|
+
|
mustrd/TestResult.py
CHANGED
@@ -43,7 +43,7 @@ class testStatus(Enum):
|
|
43
43
|
SKIPPED = "skipped"
|
44
44
|
|
45
45
|
|
46
|
-
TEMPLATE_FOLDER =
|
46
|
+
TEMPLATE_FOLDER = Path(os.path.join(get_mustrd_root(), "templates/"))
|
47
47
|
|
48
48
|
|
49
49
|
RESULT_LIST_MD_TEMPLATE = "md_ResultList_template.jinja"
|
mustrd/mustrd.py
CHANGED
@@ -46,12 +46,12 @@ import json
|
|
46
46
|
from pandas import DataFrame
|
47
47
|
|
48
48
|
from .spec_component import TableThenSpec, parse_spec_component, WhenSpec, ThenSpec
|
49
|
-
from .utils import
|
49
|
+
from .utils import is_json, get_mustrd_root
|
50
50
|
from colorama import Fore, Style
|
51
51
|
from tabulate import tabulate
|
52
52
|
from collections import defaultdict
|
53
53
|
from pyshacl import validate
|
54
|
-
import logging
|
54
|
+
import logging
|
55
55
|
from http.client import HTTPConnection
|
56
56
|
from .steprunner import upload_given, run_when
|
57
57
|
|
@@ -73,6 +73,7 @@ def debug_requests_on():
|
|
73
73
|
requests_log.setLevel(logging.DEBUG)
|
74
74
|
requests_log.propagate = True
|
75
75
|
|
76
|
+
|
76
77
|
def debug_requests_off():
|
77
78
|
'''Switches off logging of the requests module, might be some side-effects'''
|
78
79
|
HTTPConnection.debuglevel = 0
|
@@ -84,8 +85,10 @@ def debug_requests_off():
|
|
84
85
|
requests_log.setLevel(logging.WARNING)
|
85
86
|
requests_log.propagate = False
|
86
87
|
|
88
|
+
|
87
89
|
debug_requests_off()
|
88
90
|
|
91
|
+
|
89
92
|
@dataclass
|
90
93
|
class Specification:
|
91
94
|
spec_uri: URIRef
|
@@ -234,25 +237,18 @@ def validate_specs(run_config: dict, triple_stores: List, shacl_graph: Graph, on
|
|
234
237
|
if len(error_messages) > 0:
|
235
238
|
error_messages.sort()
|
236
239
|
error_message = "\n".join(msg for msg in error_messages)
|
237
|
-
invalid_specs += [SpecSkipped(subject_uri, triple_store["type"], error_message, file.name)
|
238
|
-
|
240
|
+
invalid_specs += [SpecSkipped(subject_uri, triple_store["type"], error_message, file.name)
|
241
|
+
for triple_store in triple_stores]
|
239
242
|
else:
|
240
243
|
subject_uris.add(subject_uri)
|
241
244
|
this_spec_graph = Graph()
|
242
245
|
this_spec_graph.parse(file)
|
243
246
|
spec_uris_in_this_file = list(this_spec_graph.subjects(RDF.type, MUST.TestSpec))
|
244
247
|
for spec in spec_uris_in_this_file:
|
245
|
-
# print(f"adding {tripleToAdd}")
|
246
248
|
this_spec_graph.add([spec, MUST.specSourceFile, Literal(file)])
|
247
249
|
this_spec_graph.add([spec, MUST.specFileName, Literal(file.name)])
|
248
|
-
# print(f"beforeadd: {spec_graph}" )
|
249
|
-
# print(f"beforeadd: {str(this_spec_graph.serialize())}" )
|
250
250
|
spec_graph += this_spec_graph
|
251
251
|
|
252
|
-
|
253
|
-
sourceFiles = list(spec_graph.subject_objects(MUST.specSourceFile))
|
254
|
-
# print(f"sourceFiles: {sourceFiles}")
|
255
|
-
|
256
252
|
valid_spec_uris = list(spec_graph.subjects(RDF.type, MUST.TestSpec))
|
257
253
|
|
258
254
|
if focus_uris:
|
@@ -264,7 +260,7 @@ def validate_specs(run_config: dict, triple_stores: List, shacl_graph: Graph, on
|
|
264
260
|
log.info(f"Collected {len(focus_uris)} focus test spec(s)")
|
265
261
|
return focus_uris, spec_graph, invalid_focus_specs
|
266
262
|
else:
|
267
|
-
log.info(f"Collected {len(valid_spec_uris)} valid test spec(s)")
|
263
|
+
log.info(f"Collected {len(valid_spec_uris)} valid test spec(s)")
|
268
264
|
return valid_spec_uris, spec_graph, invalid_specs
|
269
265
|
|
270
266
|
|
@@ -276,14 +272,16 @@ def get_specs(spec_uris: List[URIRef], spec_graph: Graph, triple_stores: List[di
|
|
276
272
|
for triple_store in triple_stores:
|
277
273
|
if "error" in triple_store:
|
278
274
|
log.error(f"{triple_store['error']}. No specs run for this triple store.")
|
279
|
-
skipped_results += [SpecSkipped(spec_uri, triple_store['type'], triple_store['error'],
|
275
|
+
skipped_results += [SpecSkipped(spec_uri, triple_store['type'], triple_store['error'],
|
276
|
+
get_spec_file(spec_uri, spec_graph)) for spec_uri in
|
280
277
|
spec_uris]
|
281
278
|
else:
|
282
279
|
for spec_uri in spec_uris:
|
283
280
|
try:
|
284
281
|
specs += [get_spec(spec_uri, spec_graph, run_config, triple_store)]
|
285
282
|
except (ValueError, FileNotFoundError, ConnectionError) as e:
|
286
|
-
skipped_results += [SpecSkipped(spec_uri, triple_store['type'],
|
283
|
+
skipped_results += [SpecSkipped(spec_uri, triple_store['type'],
|
284
|
+
e, get_spec_file(spec_uri, spec_graph))]
|
287
285
|
|
288
286
|
except (BadSyntax, FileNotFoundError) as e:
|
289
287
|
template = "An exception of type {0} occurred when trying to parse the triple store configuration file. " \
|
@@ -303,25 +301,28 @@ def run_specs(specs) -> List[SpecResult]:
|
|
303
301
|
results.append(run_spec(specification))
|
304
302
|
return results
|
305
303
|
|
304
|
+
|
306
305
|
def get_spec_file(spec_uri: URIRef, spec_graph: Graph):
|
307
|
-
return str(spec_graph.value(subject
|
306
|
+
return str(spec_graph.value(subject=spec_uri, predicate=MUST.specFileName, default="default.mustrd.ttl"))
|
307
|
+
|
308
308
|
|
309
309
|
def get_spec(spec_uri: URIRef, spec_graph: Graph, run_config: dict, mustrd_triple_store: dict = None) -> Specification:
|
310
310
|
try:
|
311
|
-
if mustrd_triple_store
|
311
|
+
if not mustrd_triple_store:
|
312
312
|
mustrd_triple_store = {"type": TRIPLESTORE.RdfLib}
|
313
313
|
components = []
|
314
314
|
for predicate in MUST.given, MUST.when, MUST.then:
|
315
315
|
components.append(parse_spec_component(subject=spec_uri,
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
316
|
+
predicate=predicate,
|
317
|
+
spec_graph=spec_graph,
|
318
|
+
run_config=run_config,
|
319
|
+
mustrd_triple_store=mustrd_triple_store))
|
320
320
|
|
321
321
|
spec_file_name = get_spec_file(spec_uri, spec_graph)
|
322
322
|
# https://github.com/Semantic-partners/mustrd/issues/92
|
323
|
-
return Specification(spec_uri, mustrd_triple_store,
|
324
|
-
|
323
|
+
return Specification(spec_uri, mustrd_triple_store,
|
324
|
+
components[0].value, components[1], components[2], spec_file_name)
|
325
|
+
|
325
326
|
except (ValueError, FileNotFoundError) as e:
|
326
327
|
template = "An exception of type {0} occurred. Arguments:\n{1!r}"
|
327
328
|
message = template.format(type(e).__name__, e.args)
|
@@ -333,7 +334,7 @@ def get_spec(spec_uri: URIRef, spec_graph: Graph, run_config: dict, mustrd_tripl
|
|
333
334
|
|
334
335
|
|
335
336
|
def check_result(spec, result):
|
336
|
-
if
|
337
|
+
if isinstance(spec.then, TableThenSpec):
|
337
338
|
return table_comparison(result, spec)
|
338
339
|
else:
|
339
340
|
graph_compare = graph_comparison(spec.then.value, result)
|
@@ -383,27 +384,30 @@ def run_spec(spec: Specification) -> SpecResult:
|
|
383
384
|
# if type(mustrd_triple_store) == MustrdAnzo and close_connection:
|
384
385
|
# mustrd_triple_store.clear_graph()
|
385
386
|
|
387
|
+
|
386
388
|
def get_triple_store_graph(triple_store_graph_path: Path, secrets: str):
|
387
389
|
if secrets:
|
388
|
-
return Graph().parse(triple_store_graph_path).parse(data
|
390
|
+
return Graph().parse(triple_store_graph_path).parse(data=secrets)
|
389
391
|
else:
|
390
|
-
secret_path = triple_store_graph_path.parent / Path(triple_store_graph_path.stem +
|
392
|
+
secret_path = triple_store_graph_path.parent / Path(triple_store_graph_path.stem +
|
393
|
+
"_secrets" + triple_store_graph_path.suffix)
|
391
394
|
return Graph().parse(triple_store_graph_path).parse(secret_path)
|
392
|
-
|
395
|
+
|
393
396
|
|
394
397
|
def get_triple_stores(triple_store_graph: Graph) -> list[dict]:
|
395
398
|
triple_stores = []
|
396
399
|
shacl_graph = Graph().parse(Path(os.path.join(get_mustrd_root(), "model/triplestoreshapes.ttl")))
|
397
400
|
ont_graph = Graph().parse(Path(os.path.join(get_mustrd_root(), "model/triplestoreOntology.ttl")))
|
398
401
|
conforms, results_graph, results_text = validate(
|
399
|
-
data_graph=
|
400
|
-
shacl_graph
|
401
|
-
ont_graph
|
402
|
-
advanced=
|
403
|
-
inference=
|
402
|
+
data_graph=triple_store_graph,
|
403
|
+
shacl_graph=shacl_graph,
|
404
|
+
ont_graph=ont_graph,
|
405
|
+
advanced=True,
|
406
|
+
inference='none'
|
404
407
|
)
|
405
408
|
if not conforms:
|
406
|
-
raise ValueError(f"Triple store configuration not conform to the shapes. SHACL report: {results_text}",
|
409
|
+
raise ValueError(f"Triple store configuration not conform to the shapes. SHACL report: {results_text}",
|
410
|
+
results_graph)
|
407
411
|
for triple_store_config, rdf_type, triple_store_type in triple_store_graph.triples((None, RDF.type, None)):
|
408
412
|
triple_store = {}
|
409
413
|
triple_store["type"] = triple_store_type
|
@@ -413,15 +417,18 @@ def get_triple_stores(triple_store_graph: Graph) -> list[dict]:
|
|
413
417
|
triple_store["url"] = triple_store_graph.value(subject=triple_store_config, predicate=TRIPLESTORE.url)
|
414
418
|
triple_store["port"] = triple_store_graph.value(subject=triple_store_config, predicate=TRIPLESTORE.port)
|
415
419
|
try:
|
416
|
-
triple_store["username"] = str(triple_store_graph.value(subject=triple_store_config,
|
417
|
-
|
420
|
+
triple_store["username"] = str(triple_store_graph.value(subject=triple_store_config,
|
421
|
+
predicate=TRIPLESTORE.username))
|
422
|
+
triple_store["password"] = str(triple_store_graph.value(subject=triple_store_config,
|
423
|
+
predicate=TRIPLESTORE.password))
|
418
424
|
except (FileNotFoundError, ValueError) as e:
|
419
425
|
triple_store["error"] = e
|
420
|
-
triple_store["gqe_uri"] = triple_store_graph.value(subject=triple_store_config,
|
426
|
+
triple_store["gqe_uri"] = triple_store_graph.value(subject=triple_store_config,
|
427
|
+
predicate=TRIPLESTORE.gqeURI)
|
421
428
|
triple_store["input_graph"] = triple_store_graph.value(subject=triple_store_config,
|
422
429
|
predicate=TRIPLESTORE.inputGraph)
|
423
430
|
triple_store["output_graph"] = triple_store_graph.value(subject=triple_store_config,
|
424
|
-
|
431
|
+
predicate=TRIPLESTORE.outputGraph)
|
425
432
|
try:
|
426
433
|
check_triple_store_params(triple_store, ["url", "port", "username", "password", "input_graph"])
|
427
434
|
except ValueError as e:
|
@@ -431,8 +438,10 @@ def get_triple_stores(triple_store_graph: Graph) -> list[dict]:
|
|
431
438
|
triple_store["url"] = triple_store_graph.value(subject=triple_store_config, predicate=TRIPLESTORE.url)
|
432
439
|
triple_store["port"] = triple_store_graph.value(subject=triple_store_config, predicate=TRIPLESTORE.port)
|
433
440
|
try:
|
434
|
-
triple_store["username"] = str(triple_store_graph.value(subject=triple_store_config,
|
435
|
-
|
441
|
+
triple_store["username"] = str(triple_store_graph.value(subject=triple_store_config,
|
442
|
+
predicate=TRIPLESTORE.username))
|
443
|
+
triple_store["password"] = str(triple_store_graph.value(subject=triple_store_config,
|
444
|
+
predicate=TRIPLESTORE.password))
|
436
445
|
except (FileNotFoundError, ValueError) as e:
|
437
446
|
log.error(f"Credential retrieval failed {e}")
|
438
447
|
triple_store["error"] = e
|
@@ -461,11 +470,9 @@ def check_triple_store_params(triple_store: dict, required_params: List[str]):
|
|
461
470
|
|
462
471
|
def get_credential_from_file(triple_store_name: URIRef, credential: str, config_path: Literal) -> str:
|
463
472
|
log.info(f"get_credential_from_file {triple_store_name}, {credential}, {config_path}")
|
464
|
-
if config_path
|
473
|
+
if not config_path:
|
465
474
|
raise ValueError(f"Cannot establish connection defined in {triple_store_name}. "
|
466
475
|
f"Missing required parameter: {credential}.")
|
467
|
-
# if os.path.isrelative(config_path)
|
468
|
-
# project_root = get_project_root()
|
469
476
|
path = Path(config_path)
|
470
477
|
log.info(f"get_credential_from_file {path}")
|
471
478
|
|
@@ -480,6 +487,7 @@ def get_credential_from_file(triple_store_name: URIRef, credential: str, config_
|
|
480
487
|
raise ValueError(f"Error reading credentials config file: {e}")
|
481
488
|
return config[str(triple_store_name)][credential]
|
482
489
|
|
490
|
+
|
483
491
|
# Convert sparql json query results as defined in https://www.w3.org/TR/rdf-sparql-json-res/
|
484
492
|
def json_results_to_panda_dataframe(result: str) -> pandas.DataFrame:
|
485
493
|
json_result = json.loads(result)
|
@@ -534,7 +542,8 @@ def table_comparison(result: str, spec: Specification) -> SpecResult:
|
|
534
542
|
|
535
543
|
# Scenario 1: expected no result but got a result
|
536
544
|
if then.empty:
|
537
|
-
message = f"Expected 0 row(s) and 0 column(s),
|
545
|
+
message = f"""Expected 0 row(s) and 0 column(s),
|
546
|
+
got {df.shape[0]} row(s) and {round(df.shape[1] / 2)} column(s)"""
|
538
547
|
empty_then = create_empty_dataframe_with_columns(df)
|
539
548
|
df_diff = empty_then.compare(df, result_names=("expected", "actual"))
|
540
549
|
|
@@ -546,14 +555,6 @@ def table_comparison(result: str, spec: Specification) -> SpecResult:
|
|
546
555
|
if ordered_result is True and not spec.then.ordered:
|
547
556
|
message += ". Actual result is ordered, must:then must contain sh:order on every row."
|
548
557
|
return SelectSpecFailure(spec.spec_uri, spec.triple_store["type"], None, message)
|
549
|
-
# if df.shape == then.shape and (df.columns == then.columns).all():
|
550
|
-
# df_diff = then.compare(df, result_names=("expected", "actual"))
|
551
|
-
# if df_diff.empty:
|
552
|
-
# df_diff = df
|
553
|
-
# print(df_diff.to_markdown())
|
554
|
-
# else:
|
555
|
-
# df_diff = construct_df_diff(df, then)
|
556
|
-
# print(df_diff.to_markdown())
|
557
558
|
else:
|
558
559
|
if len(columns) == len(then.columns):
|
559
560
|
if sorted_columns == sorted_then_cols:
|
@@ -579,15 +580,15 @@ def table_comparison(result: str, spec: Specification) -> SpecResult:
|
|
579
580
|
|
580
581
|
if then.empty:
|
581
582
|
# Scenario 3: expected no result, got no result
|
582
|
-
message =
|
583
|
+
message = "Expected 0 row(s) and 0 column(s), got 0 row(s) and 0 column(s)"
|
583
584
|
df = pandas.DataFrame()
|
584
585
|
else:
|
585
586
|
# Scenario 4: expected a result, but got an empty result
|
586
|
-
message = f"Expected {then.shape[0]} row(s)
|
587
|
+
message = f"""Expected {then.shape[0]} row(s)
|
588
|
+
and {round(then.shape[1] / 2)} column(s), got 0 row(s) and 0 column(s)"""
|
587
589
|
then = then[sorted_then_cols]
|
588
590
|
df = create_empty_dataframe_with_columns(then)
|
589
591
|
df_diff = then.compare(df, result_names=("expected", "actual"))
|
590
|
-
print(df_diff.to_markdown())
|
591
592
|
|
592
593
|
if df_diff.empty:
|
593
594
|
if warning:
|
@@ -595,13 +596,8 @@ def table_comparison(result: str, spec: Specification) -> SpecResult:
|
|
595
596
|
else:
|
596
597
|
return SpecPassed(spec.spec_uri, spec.triple_store["type"])
|
597
598
|
else:
|
598
|
-
|
599
|
+
log.error("\n" + df_diff.to_markdown())
|
599
600
|
log.error(message)
|
600
|
-
# print(spec.spec_uri)
|
601
|
-
# print("actual:")
|
602
|
-
# print(then)
|
603
|
-
# print("expected:")
|
604
|
-
# print(df)
|
605
601
|
return SelectSpecFailure(spec.spec_uri, spec.triple_store["type"], df_diff, message)
|
606
602
|
|
607
603
|
except ParseException as e:
|
@@ -622,18 +618,18 @@ def graph_comparison(expected_graph: Graph, actual_graph: Graph) -> GraphCompari
|
|
622
618
|
|
623
619
|
def get_then_update(spec_uri: URIRef, spec_graph: Graph) -> Graph:
|
624
620
|
then_query = f"""
|
625
|
-
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
621
|
+
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
626
622
|
|
627
623
|
CONSTRUCT {{ ?s ?p ?o }}
|
628
624
|
{{
|
629
|
-
<{spec_uri}> <{MUST.then}>
|
625
|
+
<{spec_uri}> <{MUST.then}>
|
630
626
|
a <{MUST.StatementsDataset}> ;
|
631
627
|
<{MUST.hasStatement}> [
|
632
628
|
a rdf:Statement ;
|
633
629
|
rdf:subject ?s ;
|
634
630
|
rdf:predicate ?p ;
|
635
631
|
rdf:object ?o ;
|
636
|
-
] ; ]
|
632
|
+
] ; ]
|
637
633
|
}}
|
638
634
|
"""
|
639
635
|
expected_results = spec_graph.query(then_query).graph
|
@@ -707,7 +703,7 @@ def create_empty_dataframe_with_columns(df: pandas.DataFrame) -> pandas.DataFram
|
|
707
703
|
|
708
704
|
|
709
705
|
def review_results(results: List[SpecResult], verbose: bool) -> None:
|
710
|
-
|
706
|
+
log.info("===== Result Overview =====")
|
711
707
|
# Init dictionaries
|
712
708
|
status_dict = defaultdict(lambda: defaultdict(int))
|
713
709
|
status_counts = defaultdict(lambda: defaultdict(int))
|
@@ -723,7 +719,8 @@ def review_results(results: List[SpecResult], verbose: bool) -> None:
|
|
723
719
|
|
724
720
|
# Convert dictionaries to list for tabulate
|
725
721
|
table_rows = [[spec_uri] + [
|
726
|
-
f"{colours.get(status_dict[spec_uri][triple_store], Fore.RED)}
|
722
|
+
f"""{colours.get(status_dict[spec_uri][triple_store], Fore.RED)}
|
723
|
+
{status_dict[spec_uri][triple_store].__name__}{Style.RESET_ALL}"""
|
727
724
|
for triple_store in triple_stores] for spec_uri in set(status_dict.keys())]
|
728
725
|
|
729
726
|
status_rows = [[f"{colours.get(status, Fore.RED)}{status.__name__}{Style.RESET_ALL}"] +
|
@@ -731,8 +728,8 @@ def review_results(results: List[SpecResult], verbose: bool) -> None:
|
|
731
728
|
for triple_store in triple_stores] for status in set(statuses)]
|
732
729
|
|
733
730
|
# Display tables with tabulate
|
734
|
-
|
735
|
-
|
731
|
+
log.info(tabulate(table_rows, headers=['Spec Uris / triple stores'] + triple_stores, tablefmt="pretty"))
|
732
|
+
log.info(tabulate(status_rows, headers=['Status / triple stores'] + triple_stores, tablefmt="pretty"))
|
736
733
|
|
737
734
|
pass_count = statuses.count(SpecPassed)
|
738
735
|
warning_count = statuses.count(SpecPassedWithWarning)
|
@@ -748,40 +745,34 @@ def review_results(results: List[SpecResult], verbose: bool) -> None:
|
|
748
745
|
overview_colour = Fore.GREEN
|
749
746
|
|
750
747
|
logger_setup.flush()
|
751
|
-
|
748
|
+
log.info(f"{overview_colour}===== {fail_count} failures, {skipped_count} skipped, {Fore.GREEN}{pass_count} passed, "
|
752
749
|
f"{overview_colour}{warning_count} passed with warnings =====")
|
753
750
|
|
754
751
|
if verbose and (fail_count or warning_count or skipped_count):
|
755
752
|
for res in results:
|
756
|
-
if
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
if
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
if
|
771
|
-
|
772
|
-
if
|
773
|
-
|
774
|
-
|
775
|
-
if
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
if
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
753
|
+
if isinstance(res, UpdateSpecFailure):
|
754
|
+
log.info(f"{Fore.RED}Failed {res.spec_uri} {res.triple_store}")
|
755
|
+
log.info(f"{Fore.BLUE} In Expected Not In Actual:")
|
756
|
+
log.info(res.graph_comparison.in_expected_not_in_actual.serialize(format="ttl"))
|
757
|
+
log.info()
|
758
|
+
log.info(f"{Fore.RED} in_actual_not_in_expected")
|
759
|
+
log.info(res.graph_comparison.in_actual_not_in_expected.serialize(format="ttl"))
|
760
|
+
log.info(f"{Fore.GREEN} in_both")
|
761
|
+
log.info(res.graph_comparison.in_both.serialize(format="ttl"))
|
762
|
+
|
763
|
+
if isinstance(res, SelectSpecFailure):
|
764
|
+
log.info(f"{Fore.RED}Failed {res.spec_uri} {res.triple_store}")
|
765
|
+
log.info(res.message)
|
766
|
+
log.info(res.table_comparison.to_markdown())
|
767
|
+
if isinstance(res, ConstructSpecFailure) or isinstance(res, UpdateSpecFailure):
|
768
|
+
log.info(f"{Fore.RED}Failed {res.spec_uri} {res.triple_store}")
|
769
|
+
if isinstance(res, SpecPassedWithWarning):
|
770
|
+
log.info(f"{Fore.YELLOW}Passed with warning {res.spec_uri} {res.triple_store}")
|
771
|
+
log.info(res.warning)
|
772
|
+
if isinstance(res, TripleStoreConnectionError) or type(res, SparqlExecutionError) or \
|
773
|
+
isinstance(res, SparqlParseFailure):
|
774
|
+
log.info(f"{Fore.RED}Failed {res.spec_uri} {res.triple_store}")
|
775
|
+
log.info(res.exception)
|
776
|
+
if isinstance(res, SpecSkipped):
|
777
|
+
log.info(f"{Fore.YELLOW}Skipped {res.spec_uri} {res.triple_store}")
|
778
|
+
log.info(res.message)
|
mustrd/mustrdAnzo.py
CHANGED
@@ -51,13 +51,16 @@ def query_with_bindings(bindings: dict, when: str) -> str:
|
|
51
51
|
split_query = when.lower().split("where {", 1)
|
52
52
|
return f"{split_query[0].strip()} WHERE {{ {values} {split_query[1].strip()}"
|
53
53
|
|
54
|
-
|
54
|
+
|
55
|
+
def execute_select(triple_store: dict, when: str, bindings: dict = None) -> str:
|
55
56
|
try:
|
56
57
|
if bindings:
|
57
58
|
when = query_with_bindings(bindings, when)
|
58
59
|
when = when.replace("${fromSources}", f"FROM <{triple_store['input_graph']}>\nFROM <{triple_store['output_graph']}>").replace(
|
59
60
|
"${targetGraph}", f"<{triple_store['output_graph']}>")
|
60
61
|
data = {'datasourceURI': triple_store['gqe_uri'], 'query': when,
|
62
|
+
'default-graph-uri': triple_store['input_graph'],
|
63
|
+
'named-graph-uri': triple_store['input_graph'],
|
61
64
|
'skipCache': 'true'}
|
62
65
|
url = f"https://{triple_store['url']}:{triple_store['port']}/sparql?format=application/sparql-results+json"
|
63
66
|
return manage_anzo_response(requests.post(url=url,
|
@@ -67,6 +70,7 @@ def execute_select (triple_store: dict, when: str, bindings: dict = None) -> st
|
|
67
70
|
except (ConnectionError, TimeoutError, HTTPError, ConnectTimeout):
|
68
71
|
raise
|
69
72
|
|
73
|
+
|
70
74
|
def execute_update(triple_store: dict, when: str, bindings: dict = None) -> Graph:
|
71
75
|
logging.debug(f"updating in anzo! {triple_store=} {when=}")
|
72
76
|
input_graph = triple_store['input_graph']
|
@@ -75,8 +79,11 @@ def execute_update(triple_store: dict, when: str, bindings: dict = None) -> Grap
|
|
75
79
|
substituted_query = when.replace("${usingSources}", f"USING <{triple_store['input_graph']}> \nUSING <{triple_store['output_graph']}>").replace(
|
76
80
|
"${targetGraph}", f"<{output_graph}>")
|
77
81
|
|
78
|
-
data = {'datasourceURI': triple_store['gqe_uri'],
|
79
|
-
|
82
|
+
data = {'datasourceURI': triple_store['gqe_uri'],
|
83
|
+
'update': substituted_query,
|
84
|
+
'using-graph-uri': [output_graph, input_graph],
|
85
|
+
'using-named-graph-uri': [output_graph, input_graph],
|
86
|
+
'skipCache': 'true'}
|
80
87
|
url = f"https://{triple_store['url']}:{triple_store['port']}/sparql?format=ttl"
|
81
88
|
response = manage_anzo_response(requests.post(url=url,
|
82
89
|
auth=(triple_store['username'],
|
@@ -85,7 +92,9 @@ def execute_update(triple_store: dict, when: str, bindings: dict = None) -> Grap
|
|
85
92
|
verify=False))
|
86
93
|
logging.debug(f'response {response}')
|
87
94
|
check_data = {'datasourceURI': triple_store['gqe_uri'], 'query': "construct {?s ?p ?o} { ?s ?p ?o }",
|
88
|
-
'default-graph-uri': output_graph,
|
95
|
+
'default-graph-uri': output_graph,
|
96
|
+
'named-graph-uri': output_graph,
|
97
|
+
'skipCache': 'true'}
|
89
98
|
everything_response = manage_anzo_response(requests.post(url=url,
|
90
99
|
auth=(triple_store['username'],
|
91
100
|
triple_store['password']),
|
@@ -102,7 +111,9 @@ def execute_construct(triple_store: dict, when: str, bindings: dict = None) -> G
|
|
102
111
|
if bindings:
|
103
112
|
when = query_with_bindings(bindings, when)
|
104
113
|
data = {'datasourceURI': triple_store['gqe_uri'], 'query': when,
|
105
|
-
'default-graph-uri': triple_store['input_graph'],
|
114
|
+
'default-graph-uri': triple_store['input_graph'],
|
115
|
+
'named-graph-uri': triple_store['input_graph'],
|
116
|
+
'skipCache': 'true'}
|
106
117
|
url = f"https://{triple_store['url']}:{triple_store['port']}/sparql?format=ttl"
|
107
118
|
response = requests.post(url=url,
|
108
119
|
auth=(triple_store['username'],
|
@@ -110,7 +121,9 @@ def execute_construct(triple_store: dict, when: str, bindings: dict = None) -> G
|
|
110
121
|
data=data,
|
111
122
|
verify=False)
|
112
123
|
logging.debug(f'response {response}')
|
113
|
-
|
124
|
+
g = Graph().parse(data=manage_anzo_response(response))
|
125
|
+
logging.debug(f"Actual Result = {g.serialize(format='ttl')}")
|
126
|
+
return g
|
114
127
|
except (ConnectionError, TimeoutError, HTTPError, ConnectTimeout) as e:
|
115
128
|
logging.error(f'response {e}')
|
116
129
|
raise
|
@@ -119,7 +132,7 @@ def execute_construct(triple_store: dict, when: str, bindings: dict = None) -> G
|
|
119
132
|
# Get Given or then from the content of a graphmart
|
120
133
|
def get_spec_component_from_graphmart(triple_store: dict, graphmart: URIRef, layer: URIRef = None) -> ConjunctiveGraph:
|
121
134
|
try:
|
122
|
-
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
135
|
+
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
123
136
|
username=triple_store['username'],
|
124
137
|
password=triple_store['password'])
|
125
138
|
return anzo_client.query_graphmart(graphmart=graphmart,
|
@@ -140,10 +153,10 @@ def get_query_from_querybuilder(triple_store: dict, folder_name: Literal, query_
|
|
140
153
|
?queryFolder a <http://www.cambridgesemantics.com/ontologies/QueryPlayground#QueryFolder>;
|
141
154
|
<http://purl.org/dc/elements/1.1/title> "{folder_name}"
|
142
155
|
}}"""
|
143
|
-
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
156
|
+
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
144
157
|
username=triple_store['username'],
|
145
158
|
password=triple_store['password'])
|
146
|
-
|
159
|
+
|
147
160
|
result = anzo_client.query_journal(query_string=query).as_table_results().as_record_dictionaries()
|
148
161
|
if len(result) == 0:
|
149
162
|
raise FileNotFoundError(f"Query {query_name} not found in folder {folder_name}")
|
@@ -158,7 +171,7 @@ def get_query_from_step(triple_store: dict, query_step_uri: URIRef) -> str:
|
|
158
171
|
<http://cambridgesemantics.com/ontologies/Graphmarts#transformQuery> ?query
|
159
172
|
}}
|
160
173
|
# """
|
161
|
-
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
174
|
+
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
162
175
|
username=triple_store['username'],
|
163
176
|
password=triple_store['password'])
|
164
177
|
record_dictionaries = anzo_client.query_journal(query_string=query).as_table_results().as_record_dictionaries()
|
@@ -175,7 +188,7 @@ def get_queries_from_templated_step(triple_store: dict, query_step_uri: URIRef)
|
|
175
188
|
<http://cambridgesemantics.com/ontologies/Graphmarts#template> ?query_template .
|
176
189
|
}}
|
177
190
|
"""
|
178
|
-
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
191
|
+
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
179
192
|
username=triple_store['username'],
|
180
193
|
password=triple_store['password'])
|
181
194
|
record_dictionaries = anzo_client.query_journal(query_string=query).as_table_results().as_record_dictionaries()
|
@@ -189,7 +202,7 @@ SELECT ?query ?param_query ?query_template
|
|
189
202
|
{{ <{graphmart_layer_uri}> graphmarts:step ?step .
|
190
203
|
?step anzo:index ?index ;
|
191
204
|
anzo:orderedValue ?query_step .
|
192
|
-
?query_step graphmarts:enabled true ;
|
205
|
+
?query_step graphmarts:enabled true ;
|
193
206
|
OPTIONAL {{ ?query_step
|
194
207
|
graphmarts:parametersTemplate ?param_query ;
|
195
208
|
graphmarts:template ?query_template ;
|
@@ -199,7 +212,7 @@ SELECT ?query ?param_query ?query_template
|
|
199
212
|
. }}
|
200
213
|
}}
|
201
214
|
ORDER BY ?index"""
|
202
|
-
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
215
|
+
anzo_client = AnzoClient(triple_store['url'], triple_store['port'],
|
203
216
|
username=triple_store['username'],
|
204
217
|
password=triple_store['password'])
|
205
218
|
return anzo_client.query_journal(query_string=query).as_table_results().as_record_dictionaries()
|
@@ -215,7 +228,10 @@ def upload_given(triple_store: dict, given: Graph):
|
|
215
228
|
clear_graph(triple_store, output_graph)
|
216
229
|
serialized_given = given.serialize(format="nt")
|
217
230
|
insert_query = f"INSERT DATA {{graph <{triple_store['input_graph']}>{{{serialized_given}}}}}"
|
218
|
-
data = {'datasourceURI': triple_store['gqe_uri'],
|
231
|
+
data = {'datasourceURI': triple_store['gqe_uri'],
|
232
|
+
'update': insert_query,
|
233
|
+
'using-graph-uri': input_graph,
|
234
|
+
'using-named-graph-uri': input_graph}
|
219
235
|
response = requests.post(url=f"https://{triple_store['url']}:{triple_store['port']}/sparql",
|
220
236
|
auth=(triple_store['username'], triple_store['password']), data=data, verify=False)
|
221
237
|
manage_anzo_response(response)
|
@@ -233,4 +249,3 @@ def clear_graph(triple_store: dict, graph_uri: str):
|
|
233
249
|
manage_anzo_response(response)
|
234
250
|
except (ConnectionError, TimeoutError, HTTPError, ConnectTimeout):
|
235
251
|
raise
|
236
|
-
|