From 6eeed661b603c30e6dc32f66aa331480d215d543 Mon Sep 17 00:00:00 2001 From: David Linke Date: Mon, 14 Aug 2023 21:12:22 +0200 Subject: [PATCH 1/2] Fix modified date handling; add env.var support for version. --- CHANGELOG.md | 12 +++ src/voc4cat/models.py | 40 +++++---- src/voc4cat/transform.py | 34 +++++++- .../043_exhaustive_example.xlsx | Bin 51733 -> 51746 bytes .../043_exhaustive_example_perfect_output.ttl | 2 +- tests/test_models.py | 77 ++++++++++++++++-- tests/test_template043.py | 4 + tests/test_transform.py | 70 ++++++++++++++++ 8 files changed, 211 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 108379f..ad590ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change log +## Release 0.6.x (2023-08-dd) + +New features: + +- Support for two environment variables was added. Both changes enable achieving consistent version/tag info in the gh-based vocabulary management (related [voc4cat-template #11](https://github.com/nfdi4cat/voc4cat-template/issues/11)). #148 + - `VOC4CAT_MODIFIED` - If set to a truthy value, the current date is used as modified date; the date in the source is ignored. + - `VOC4CAT_VERSION` - version string; if present this version info has highest precedence. A leading "v" will be removed. + +Bug fixes: + +- Modified date of concept scheme was not transferred from xlsx to rdf. #147, #148 + ## Release 0.6.2 (2023-08-10) New features: diff --git a/src/voc4cat/models.py b/src/voc4cat/models.py index 44dab3c..e907251 100644 --- a/src/voc4cat/models.py +++ b/src/voc4cat/models.py @@ -1,5 +1,6 @@ import datetime import logging +import os from itertools import chain from typing import List, Union @@ -169,6 +170,12 @@ def creator_must_be_from_list(cls, v): raise ValueError(msg) return v + @validator("modified") + def set_modified_date_if_missing(cls, v): + if os.getenv("CI") is not None: # Don't track modified date in GitHub. + v = None + return v + @validator("publisher") def publisher_must_be_from_list(cls, v): if v not in ORGANISATIONS: @@ -176,6 +183,18 @@ def publisher_must_be_from_list(cls, v): raise ValueError(msg) return v + @validator("version") + def version_from_env(cls, v): + if os.getenv("CI") is not None: # Don't track version in GitHub. + v = None + version_from_env = os.getenv("VOC4CAT_VERSION") + if version_from_env is not None: + if not version_from_env.startswith("v"): + msg = f'Invalid environment variable VOC4CAT_VERSION "{version_from_env}". Version must start with letter "v".' + raise ValueError(msg) + v = version_from_env + return v + def to_graph(self): g = Graph() v = URIRef(self.uri) @@ -187,25 +206,10 @@ def to_graph(self): g.add((v, SKOS.prefLabel, Literal(self.title, lang="en"))) g.add((v, SKOS.definition, Literal(self.description, lang="en"))) g.add((v, DCTERMS.created, Literal(self.created, datatype=XSD.date))) - if self.modified is not None: - g.add((v, DCTERMS.modified, Literal(self.created, datatype=XSD.date))) - else: - g.add( - ( - v, - DCTERMS.modified, - Literal( - datetime.datetime.now(datetime.timezone.utc).strftime( - "%Y-%m-%d" - ), - datatype=XSD.date, - ), - ) - ) + g.add((v, DCTERMS.modified, Literal(self.modified, datatype=XSD.date))), g.add((v, DCTERMS.creator, ORGANISATIONS[self.creator])) g.add((v, DCTERMS.publisher, ORGANISATIONS[self.publisher])) - if self.version is not None: - g.add((v, OWL.versionInfo, Literal(self.version))) + g.add((v, OWL.versionInfo, Literal(self.version))) g.add((v, DCTERMS.provenance, Literal(self.provenance, lang="en"))) if self.custodian is not None: g.add((v, DCAT.contactPoint, Literal(self.custodian))) @@ -224,7 +228,7 @@ def to_excel(self, wb: Workbook): ws["B3"] = self.title ws["B4"] = self.description ws["B5"] = self.created.isoformat() - ws["B6"] = self.modified.isoformat() + ws["B6"] = None if self.modified is None else self.modified.isoformat() ws["B7"] = self.creator ws["B8"] = self.publisher ws["B9"] = self.version diff --git a/src/voc4cat/transform.py b/src/voc4cat/transform.py index 454e34a..5ce4404 100644 --- a/src/voc4cat/transform.py +++ b/src/voc4cat/transform.py @@ -1,4 +1,6 @@ +import datetime import logging +import os import shutil from collections import defaultdict from itertools import count, zip_longest @@ -7,8 +9,8 @@ import openpyxl from openpyxl.styles import Alignment -from rdflib import Graph -from rdflib.namespace import SKOS +from rdflib import Graph, Literal +from rdflib.namespace import DCTERMS, OWL, RDF, SKOS, XSD from voc4cat import config from voc4cat.checks import Voc4catError @@ -27,7 +29,7 @@ def extract_numeric_id_from_iri(iri): iri_path = urlsplit(iri).path reverse_id = [] - for char in reversed(iri_path): # pragma: no cover + for char in reversed(iri_path): if char.isdigit(): reverse_id.append(char) elif char == "/": @@ -63,6 +65,27 @@ def write_split_turtle(vocab_graph: Graph, outdir: Path) -> None: logger.debug("-> wrote %i %ss-file(s).", len(qresults), skos_class) +def autoversion_cs(graph: Graph) -> Graph: + """Set modified date and version if "requested" via environment variables.""" + if any(graph.triples((None, RDF.type, SKOS.ConceptScheme))): + cs, _, _ = next(graph.triples((None, RDF.type, SKOS.ConceptScheme))) + if os.getenv("VOC4CAT_MODIFIED") is not None: + graph.remove((None, DCTERMS.modified, None)) + date_modified = os.getenv("VOC4CAT_MODIFIED") + graph.add((cs, DCTERMS.modified, Literal(date_modified, datatype=XSD.date))) + if os.getenv("VOC4CAT_VERSION") is not None: + graph.remove((None, OWL.versionInfo, None)) + version = os.getenv("VOC4CAT_VERSION") + if version is not None and not version.startswith("v"): + msg = 'Invalid environment variable VOC4CAT_VERSION "%s". Version must start with letter "v".' + logger.error(msg, version) + raise Voc4catError(msg % version) + graph.add( + (cs, OWL.versionInfo, Literal(version)), + ) + return graph + + def join_split_turtle(vocab_dir: Path) -> Graph: # Search recursively all turtle files belonging to the concept scheme turtle_files = vocab_dir.rglob("*.ttl") @@ -71,6 +94,11 @@ def join_split_turtle(vocab_dir: Path) -> Graph: # Load each turtle file into a separate graph and merge it into the concept scheme graph for file in turtle_files: graph = Graph().parse(file, format="turtle") + # Set modified date if "requested" via environment variable. + if file.name == "concept_scheme.ttl" or any( + graph.triples((None, RDF.type, SKOS.ConceptScheme)) + ): + graph = autoversion_cs(graph) cs_graph += graph cs_graph.serialize(destination=vocab_dir.with_suffix(".ttl"), format="turtle") return cs_graph diff --git a/tests/templ_versions/043_exhaustive_example.xlsx b/tests/templ_versions/043_exhaustive_example.xlsx index 17a6fd46457bf9c923eb8574234260d4fb8f4ee4..a23968b026860f74e29d02799ea238082e7eb476 100644 GIT binary patch delta 4414 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 ; dcterms:hasPart ; - dcterms:modified "2022-03-07"^^xsd:date ; + dcterms:modified "2022-03-10"^^xsd:date ; dcterms:provenance "Example Provenance"@en ; dcterms:publisher ; rdfs:seeAlso "1.2.3.4" ; diff --git a/tests/test_models.py b/tests/test_models.py index 3d304cb..d79eb3d 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,3 +1,7 @@ +import datetime +import os +from unittest import mock + import pytest from pydantic.error_wrappers import ValidationError from rdflib import Graph @@ -81,20 +85,81 @@ def test_check_uri_vs_config(datadir, temp_config): # === From here on: "old" tests from rdflib.vocexcel === +@mock.patch.dict(os.environ, clear=True) # required to hide gh-action environment vars def test_vocabulary_valid(): - ConceptScheme( + cs = ConceptScheme( + uri="https://linked.data.gov.au/def/borehole-start-point", + title="Borehole Start Point", + description="Indicates the nature of the borehole start point location", + created="2020-04-02", + modified="2020-04-04", + creator="GSQ", + publisher="GSQ", + version="1.0", + provenance="Derived from the 2011-09 version of CGI Borehole start point list", + custodian="Vance Kelly", + pid="http://pid.geoscience.gov.au/dataset/ga/114541", + ) + assert cs.modified == datetime.date(2020, 4, 4) + assert cs.version == "1.0" + + +@mock.patch.dict(os.environ, {"CI": ""}) +def test_vocabulary_valid_in_ci(): + cs = ConceptScheme( + uri="https://linked.data.gov.au/def/borehole-start-point", + title="Borehole Start Point", + description="Indicates the nature of the borehole start point location", + created="2020-04-02", + modified="2020-04-04", + creator="GSQ", + publisher="GSQ", + version="1.0", + provenance="Derived from the 2011-09 version of CGI Borehole start point list", + custodian="Vance Kelly", + pid="http://pid.geoscience.gov.au/dataset/ga/114541", + ) + assert cs.modified is None + assert cs.version is None + + +@mock.patch.dict(os.environ, {"CI": "", "VOC4CAT_VERSION": "v2023-08-15"}) +def test_vocabulary_valid_version_via_envvar(): + cs = ConceptScheme( uri="https://linked.data.gov.au/def/borehole-start-point", title="Borehole Start Point", description="Indicates the nature of the borehole start point location", created="2020-04-02", - modified="2020-04-02", + modified="2020-04-04", creator="GSQ", publisher="GSQ", - version="", + version="1.0", provenance="Derived from the 2011-09 version of CGI Borehole start point list", custodian="Vance Kelly", pid="http://pid.geoscience.gov.au/dataset/ga/114541", ) + assert cs.modified is None + assert cs.version == "v2023-08-15" + + +@mock.patch.dict(os.environ, {"CI": "", "VOC4CAT_VERSION": "2023-08-15"}) +def test_vocabulary_invalid_version_via_envvar(): + with pytest.raises( + ValidationError, match="Invalid environment variable VOC4CAT_VERSION" + ): + ConceptScheme( + uri="https://linked.data.gov.au/def/borehole-start-point", + title="Borehole Start Point", + description="Indicates the nature of the borehole start point location", + created="2020-04-02", + modified="2020-04-04", + creator="GSQ", + publisher="GSQ", + version="1.0", + provenance="Derived from the 2011-09 version of CGI Borehole start point list", + custodian="Vance Kelly", + pid="http://pid.geoscience.gov.au/dataset/ga/114541", + ) def test_vocabulary_invalid_uri(): @@ -104,7 +169,7 @@ def test_vocabulary_invalid_uri(): title="Borehole Start Point", description="Indicates the nature of the borehole start point location", created="2020-04-02", - modified="02/042020", + modified=None, creator="GSQ", publisher="GSQ", version="", @@ -121,7 +186,7 @@ def test_vocabulary_invalid_created_date(): title="Borehole Start Point", description="Indicates the nature of the borehole start point location", created="2020-04", - modified="2020-04-02", + modified="2020-04-04", creator="GSQ", publisher="GSQ", version="", @@ -138,7 +203,7 @@ def test_vocabulary_invalid_publisher(): title="Borehole Start Point", description="Indicates the nature of the borehole start point location", created="2020-04-02", - modified="2020-04-02", + modified="2020-04-04", creator="GSQ", publisher="WHO", version="", diff --git a/tests/test_template043.py b/tests/test_template043.py index 8de5bb2..beebabc 100644 --- a/tests/test_template043.py +++ b/tests/test_template043.py @@ -1,4 +1,6 @@ +import os from pathlib import Path +from unittest import mock import pytest import voc4cat @@ -39,6 +41,7 @@ def test_simple(): ) in g, "Provenance for vocab is not correct" +@mock.patch.dict(os.environ, clear=True) # required to hide gh-action environment vars def test_exhaustive_template_is_isomorphic(): g1 = Graph().parse( Path(__file__).parent @@ -52,6 +55,7 @@ def test_exhaustive_template_is_isomorphic(): assert compare.isomorphic(g1, g2), "Graphs are not Isomorphic" +@mock.patch.dict(os.environ, clear=True) # required to hide gh-action environment vars def test_rdf_to_excel(): g1 = Graph().parse( Path(__file__).parent diff --git a/tests/test_transform.py b/tests/test_transform.py index 5b0daa0..064d6d0 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -1,8 +1,12 @@ import logging +import os import shutil +from unittest import mock import pytest from openpyxl import load_workbook +from rdflib import Graph, Literal +from rdflib.namespace import DCTERMS, OWL, SKOS, XSD from test_cli import ( CS_CYCLES, CS_CYCLES_INDENT_DOT, @@ -600,3 +604,69 @@ def test_join(monkeypatch, datadir, tmp_path, opt, caplog): assert (vocdir.parent / CS_SIMPLE_TURTLE).exists() if opt: assert not vocdir.exists() + + +@mock.patch.dict( + os.environ, {"CI": "", "VOC4CAT_VERSION": "v2.0", "VOC4CAT_MODIFIED": "2023-08-15"} +) +def test_join_with_envvars(monkeypatch, datadir, tmp_path, caplog): + monkeypatch.chdir(tmp_path) + shutil.copy(datadir / CS_SIMPLE_TURTLE, tmp_path) + # create dir with split files + main_cli(["transform", "-v", "--split", "--inplace", str(tmp_path)]) + # join files again as test + cmd = ["transform", "-v", "--join"] + cmd.append(str(tmp_path)) + with caplog.at_level(logging.DEBUG): + main_cli(cmd) + assert "-> joined vocabulary into" in caplog.text + # Were version and modified date correctly set? + graph = Graph().parse(CS_SIMPLE_TURTLE, format="turtle") + cs_query = "SELECT ?iri WHERE {?iri a skos:ConceptScheme.}" + qresults = [*graph.query(cs_query, initNs={"skos": SKOS})] + assert len(qresults) == 1 + + cs_iri = qresults[0][0] + assert ( + len( + [ + *graph.triples( + (cs_iri, OWL.versionInfo, Literal("v2.0")), + ) + ] + ) + == 1 + ) + + assert ( + len( + [ + *graph.triples( + ( + cs_iri, + DCTERMS.modified, + Literal("2023-08-15", datatype=XSD.date), + ), + ) + ] + ) + == 1 + ) + + +@mock.patch.dict( + os.environ, {"CI": "", "VOC4CAT_VERSION": "2.0", "VOC4CAT_MODIFIED": "2023-08-15"} +) +def test_join_with_invalid_envvar(monkeypatch, datadir, tmp_path, caplog): + monkeypatch.chdir(tmp_path) + shutil.copy(datadir / CS_SIMPLE_TURTLE, tmp_path) + # create dir with split files + main_cli(["transform", "-v", "--split", "--inplace", str(tmp_path)]) + # join files again as test + cmd = ["transform", "-v", "--join"] + cmd.append(str(tmp_path)) + with caplog.at_level(logging.ERROR), pytest.raises( + Voc4catError, match="Invalid environment variable VOC4CAT_VERSION" + ): + main_cli(cmd) + assert 'Invalid environment variable VOC4CAT_VERSION "2.0"' in caplog.text From 1707153ac1a44f7ce4ea3da811ecfe1f06d04e71 Mon Sep 17 00:00:00 2001 From: David Linke Date: Tue, 15 Aug 2023 23:56:28 +0200 Subject: [PATCH 2/2] pylode docs: correct ttl-file location --- src/voc4cat/docs.py | 8 ++++++++ src/voc4cat/transform.py | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/voc4cat/docs.py b/src/voc4cat/docs.py index 2f94da2..bf39c08 100644 --- a/src/voc4cat/docs.py +++ b/src/voc4cat/docs.py @@ -32,6 +32,14 @@ def run_pylode(turtle_file: Path, output_path: Path) -> None: '
', '