cmem-cmemc 24.3.0rc2__tar.gz → 24.3.3__tar.gz
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.
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/PKG-INFO +4 -4
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/__init__.py +1 -1
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/graph.py +40 -51
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/migration.py +2 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/context.py +2 -2
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/migrations/abc.py +1 -0
- cmem_cmemc-24.3.3/cmem_cmemc/migrations/sparql_query_texts_242.py +53 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/utils.py +4 -4
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/pyproject.toml +2 -2
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/LICENSE +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/README-public.md +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/_cmemc.zsh +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/command.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/command_group.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/__init__.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/acl.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/admin.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/client.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/config.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/dataset.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/metrics.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/project.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/python.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/query.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/resource.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/scheduler.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/store.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/user.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/validation.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/variable.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/vocabulary.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/workflow.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/commands/workspace.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/completion.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/constants.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/exceptions.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/manual_helper/__init__.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/manual_helper/graph.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/manual_helper/multi_page.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/manual_helper/single_page.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/migrations/__init__.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/migrations/access_conditions_243.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/migrations/bootstrap_data.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/migrations/shapes_widget_integrations_243.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/migrations/workspace_configurations.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/object_list.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/parameter_types/__init__.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/parameter_types/path.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/smart_path/__init__.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/smart_path/clients/__init__.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/smart_path/clients/http.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/string_processor.py +0 -0
- {cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/title_helper.py +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: cmem-cmemc
|
|
3
|
-
Version: 24.3.
|
|
3
|
+
Version: 24.3.3
|
|
4
4
|
Summary: Command line client for eccenca Corporate Memory
|
|
5
|
-
Home-page: https://eccenca.com/go/cmemc
|
|
6
5
|
License: Apache-2.0
|
|
7
6
|
Author: eccenca
|
|
8
7
|
Author-email: cmempy-developer@eccenca.com
|
|
@@ -21,6 +20,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
24
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
25
|
Classifier: Topic :: Database
|
|
26
26
|
Classifier: Topic :: Software Development :: Testing
|
|
@@ -36,7 +36,6 @@ Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
|
|
|
36
36
|
Requires-Dist: junit-xml (>=1.9,<2.0)
|
|
37
37
|
Requires-Dist: natsort (>=8.4.0,<9.0.0)
|
|
38
38
|
Requires-Dist: packaging (>=24.2,<25.0)
|
|
39
|
-
Requires-Dist: pip (>=24.3.1,<25.0.0)
|
|
40
39
|
Requires-Dist: prometheus-client (>=0.21.0,<0.22.0)
|
|
41
40
|
Requires-Dist: pygments (>=2.18.0,<3.0.0)
|
|
42
41
|
Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
|
|
@@ -48,6 +47,7 @@ Requires-Dist: smart-open (>=7.0.5,<8.0.0)
|
|
|
48
47
|
Requires-Dist: timeago (>=1.0.16,<2.0.0)
|
|
49
48
|
Requires-Dist: treelib (>=1.7.0,<2.0.0)
|
|
50
49
|
Requires-Dist: urllib3 (>=2.2.3,<3.0.0)
|
|
50
|
+
Project-URL: Homepage, https://eccenca.com/go/cmemc
|
|
51
51
|
Description-Content-Type: text/markdown
|
|
52
52
|
|
|
53
53
|
# cmemc
|
|
@@ -95,7 +95,7 @@ def cli(
|
|
|
95
95
|
|
|
96
96
|
https://eccenca.com/go/cmemc
|
|
97
97
|
|
|
98
|
-
cmemc is ©
|
|
98
|
+
cmemc is © 2025 eccenca GmbH, licensed under the Apache License 2.0.
|
|
99
99
|
"""
|
|
100
100
|
ctx.obj = CONTEXT
|
|
101
101
|
# hidden feature: 'CMEMC_MANUAL=true cmemc -q config list' will output
|
|
@@ -6,14 +6,12 @@ import io
|
|
|
6
6
|
import json
|
|
7
7
|
import mimetypes
|
|
8
8
|
import os
|
|
9
|
-
from json import JSONDecodeError
|
|
10
9
|
from xml.dom import minidom # nosec
|
|
11
10
|
from xml.etree.ElementTree import ( # nosec
|
|
12
11
|
Element,
|
|
13
12
|
SubElement,
|
|
14
13
|
tostring,
|
|
15
14
|
)
|
|
16
|
-
from xml.sax import SAXParseException
|
|
17
15
|
|
|
18
16
|
import click
|
|
19
17
|
from click import Argument
|
|
@@ -23,9 +21,6 @@ from cmem.cmempy.dp.proxy import graph as graph_api
|
|
|
23
21
|
from cmem.cmempy.dp.proxy.graph import get_graph_import_tree, get_graph_imports
|
|
24
22
|
from cmem.cmempy.dp.proxy.sparql import get as sparql_api
|
|
25
23
|
from jinja2 import Template
|
|
26
|
-
from rdflib import Graph
|
|
27
|
-
from rdflib.exceptions import ParserError
|
|
28
|
-
from rdflib.plugins.parsers.notation3 import BadSyntax
|
|
29
24
|
from six.moves.urllib.parse import quote
|
|
30
25
|
from treelib import Tree
|
|
31
26
|
|
|
@@ -35,7 +30,7 @@ from cmem_cmemc.command_group import CmemcGroup
|
|
|
35
30
|
from cmem_cmemc.commands.validation import validation_group
|
|
36
31
|
from cmem_cmemc.context import ApplicationContext
|
|
37
32
|
from cmem_cmemc.parameter_types.path import ClickSmartPath
|
|
38
|
-
from cmem_cmemc.smart_path import SmartPath
|
|
33
|
+
from cmem_cmemc.smart_path import SmartPath
|
|
39
34
|
from cmem_cmemc.utils import (
|
|
40
35
|
convert_uri_to_filename,
|
|
41
36
|
get_graphs,
|
|
@@ -75,7 +70,7 @@ def _get_graph_to_file( # noqa: PLR0913
|
|
|
75
70
|
|
|
76
71
|
numbers is a tuple of current and count (for output only).
|
|
77
72
|
"""
|
|
78
|
-
if
|
|
73
|
+
if SmartPath(file_path).exists():
|
|
79
74
|
if overwrite is True:
|
|
80
75
|
app.echo_warning(f"Output file {file_path} does exist: will overwrite it.")
|
|
81
76
|
else:
|
|
@@ -309,7 +304,7 @@ def _create_xml_catalog_file(app: ApplicationContext, names: dict, output_dir: s
|
|
|
309
304
|
output_dir: path where to create the XML file
|
|
310
305
|
|
|
311
306
|
"""
|
|
312
|
-
file_name =
|
|
307
|
+
file_name = SmartPath(output_dir) / "catalog-v001.xml"
|
|
313
308
|
catalog = Element("catalog")
|
|
314
309
|
catalog.set("prefer", "public")
|
|
315
310
|
catalog.set("xmlns", "urn:oasis:names:tc:entity:xmlns:xml:catalog")
|
|
@@ -601,16 +596,16 @@ def export_command( # noqa: PLR0913
|
|
|
601
596
|
)
|
|
602
597
|
_graph_file_names = _get_export_names(app, iris, template, f"{extension}.graph")
|
|
603
598
|
# create directory
|
|
604
|
-
if not
|
|
599
|
+
if not SmartPath(output_dir).exists():
|
|
605
600
|
app.echo_warning("Output directory does not exist: " + "will create it.")
|
|
606
|
-
|
|
601
|
+
SmartPath(output_dir).mkdir(parents=True)
|
|
607
602
|
# one .graph, one .ttl file per named graph
|
|
608
603
|
for current, iri in enumerate(iris, start=1):
|
|
609
604
|
# join with given output directory and normalize full path
|
|
610
|
-
triple_file_name = os.path.normpath(
|
|
611
|
-
graph_file_name = os.path.normpath(
|
|
605
|
+
triple_file_name = os.path.normpath(SmartPath(output_dir) / _names[iri])
|
|
606
|
+
graph_file_name = os.path.normpath(SmartPath(output_dir) / _graph_file_names[iri])
|
|
612
607
|
# output directory is created lazy
|
|
613
|
-
|
|
608
|
+
SmartPath(triple_file_name).parent.mkdir(parents=True, exist_ok=True)
|
|
614
609
|
# create and write the .ttl.graph metadata file
|
|
615
610
|
graph_file = click.open_file(graph_file_name, "w")
|
|
616
611
|
graph_file.write(iri + "\n")
|
|
@@ -673,50 +668,42 @@ def validate_input_path(input_path: str) -> None:
|
|
|
673
668
|
def _get_graph_supported_formats() -> dict[str, str]:
|
|
674
669
|
return {
|
|
675
670
|
"application/rdf+xml": "xml",
|
|
676
|
-
"application/ld+json": "
|
|
671
|
+
"application/ld+json": "jsonld",
|
|
677
672
|
"text/turtle": "turtle",
|
|
678
673
|
"application/n-triples": "nt",
|
|
679
674
|
}
|
|
680
675
|
|
|
681
676
|
|
|
682
|
-
def
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
677
|
+
def _get_buffer_and_content_type(
|
|
678
|
+
triple_file: str, app: ApplicationContext
|
|
679
|
+
) -> tuple[io.BytesIO, str]:
|
|
680
|
+
"""Get the io.BytesIO buffer and the content type of triple_file"""
|
|
681
|
+
smart_file = SmartPath(triple_file)
|
|
682
|
+
content_type, encoding = mimetypes.guess_type(triple_file)
|
|
683
|
+
if content_type is None:
|
|
684
|
+
content_type = "text/turtle"
|
|
685
|
+
for supported_type, supported_suffix in _get_graph_supported_formats().items():
|
|
686
|
+
if smart_file.name.endswith(f".{supported_suffix}") or smart_file.name.endswith(
|
|
687
|
+
f".{supported_suffix}.gz"
|
|
688
|
+
):
|
|
689
|
+
content_type = supported_type
|
|
690
|
+
elif content_type not in _get_graph_supported_formats():
|
|
691
|
+
app.echo_warning(
|
|
692
|
+
f"Content type {content_type} of {triple_file} is "
|
|
693
|
+
f"not one of {', '.join(_get_graph_supported_formats().keys())} "
|
|
694
|
+
"(but will try to import anyways)."
|
|
695
|
+
)
|
|
694
696
|
|
|
695
|
-
def _parse_triple_file(triple_file: str) -> tuple[io.BytesIO, str]:
|
|
696
|
-
"""Parse the content of the triple file."""
|
|
697
|
-
buffer = io.BytesIO()
|
|
698
697
|
transport_params = {}
|
|
699
|
-
|
|
700
|
-
if Path(str(triple_file)).schema in ["http", "https"]:
|
|
698
|
+
if smart_file.schema in ["http", "https"]:
|
|
701
699
|
transport_params["headers"] = {
|
|
702
700
|
"Accept": "text/turtle; q=1.0, application/x-turtle; q=0.9, text/n3;"
|
|
703
701
|
" q=0.8, application/rdf+xml; q=0.5, text/plain; q=0.1"
|
|
704
702
|
}
|
|
705
703
|
|
|
704
|
+
buffer = io.BytesIO()
|
|
706
705
|
with ClickSmartPath.open(triple_file, transport_params=transport_params) as file_obj:
|
|
707
706
|
buffer.write(file_obj.read())
|
|
708
|
-
|
|
709
|
-
buffer.seek(0)
|
|
710
|
-
is_gzip = buffer.read(2) == b"\x1f\x8b"
|
|
711
|
-
buffer.seek(0)
|
|
712
|
-
|
|
713
|
-
if is_gzip:
|
|
714
|
-
with gzip.GzipFile(fileobj=buffer, mode="rb") as gzip_file:
|
|
715
|
-
graph_content = gzip_file.read().decode("utf-8")
|
|
716
|
-
else:
|
|
717
|
-
graph_content = buffer.read().decode("utf-8")
|
|
718
|
-
|
|
719
|
-
content_type = _guess_rdf_mime_type(graph_content)
|
|
720
707
|
buffer.seek(0)
|
|
721
708
|
return buffer, content_type
|
|
722
709
|
|
|
@@ -748,7 +735,7 @@ def import_command(
|
|
|
748
735
|
input_path: str,
|
|
749
736
|
replace: bool,
|
|
750
737
|
skip_existing: bool,
|
|
751
|
-
iri:
|
|
738
|
+
iri: str,
|
|
752
739
|
) -> None:
|
|
753
740
|
"""Import graph(s) to the store.
|
|
754
741
|
|
|
@@ -767,14 +754,14 @@ def import_command(
|
|
|
767
754
|
|
|
768
755
|
Note: Directories are scanned on the first level only (not recursively).
|
|
769
756
|
"""
|
|
770
|
-
# is an array of tuples like this [('path/to/triple.file', 'graph IRI')]
|
|
771
757
|
if replace and skip_existing:
|
|
772
758
|
raise ValueError(
|
|
773
759
|
"The options --replace and --skip-existing are mutually "
|
|
774
760
|
"exclusive, so please remove one of them."
|
|
775
761
|
)
|
|
776
|
-
|
|
777
|
-
|
|
762
|
+
# is an array of tuples like this [('path/to/triple.file', 'graph IRI')]
|
|
763
|
+
graphs: list[tuple[str, str]]
|
|
764
|
+
if SmartPath(input_path).is_dir():
|
|
778
765
|
validate_input_path(input_path)
|
|
779
766
|
if iri is None:
|
|
780
767
|
# in case a directory is the source (and no IRI is given),
|
|
@@ -785,10 +772,12 @@ def import_command(
|
|
|
785
772
|
graphs = []
|
|
786
773
|
for _ in _get_graph_supported_formats():
|
|
787
774
|
extension = mimetypes.guess_extension(_)
|
|
788
|
-
graphs += [(file, iri) for file in
|
|
789
|
-
graphs += [
|
|
775
|
+
graphs += [(str(file), iri) for file in SmartPath(input_path).glob(f"*{extension}")]
|
|
776
|
+
graphs += [
|
|
777
|
+
(str(file), iri) for file in SmartPath(input_path).glob(f"*{extension}.gz")
|
|
778
|
+
]
|
|
790
779
|
|
|
791
|
-
elif
|
|
780
|
+
elif SmartPath(input_path).is_file():
|
|
792
781
|
if iri is None:
|
|
793
782
|
raise ValueError(
|
|
794
783
|
"Either specify an input file AND a graph IRI or an input directory ONLY."
|
|
@@ -812,7 +801,7 @@ def import_command(
|
|
|
812
801
|
continue
|
|
813
802
|
# prevents re-replacing of graphs in a single run
|
|
814
803
|
_replace = False if graph_iri in processed_graphs else replace
|
|
815
|
-
_buffer, content_type =
|
|
804
|
+
_buffer, content_type = _get_buffer_and_content_type(triple_file, app)
|
|
816
805
|
response = graph_api.post_streamed(
|
|
817
806
|
graph_iri, _buffer, replace=_replace, content_type=content_type
|
|
818
807
|
)
|
|
@@ -21,6 +21,7 @@ from cmem_cmemc.migrations.shapes_widget_integrations_243 import (
|
|
|
21
21
|
TableReportPropertyShapesToWidgetIntegrations,
|
|
22
22
|
WorkflowTriggerPropertyShapesToWidgetIntegrations,
|
|
23
23
|
)
|
|
24
|
+
from cmem_cmemc.migrations.sparql_query_texts_242 import SparqlDatatypesToXsdString
|
|
24
25
|
from cmem_cmemc.migrations.workspace_configurations import MigrateWorkspaceConfiguration
|
|
25
26
|
from cmem_cmemc.object_list import (
|
|
26
27
|
DirectListPropertyFilter,
|
|
@@ -56,6 +57,7 @@ def get_migrations(ctx: click.Context) -> list[dict]: # noqa: ARG001
|
|
|
56
57
|
ChartsOnPropertyShapesToWidgetIntegrations(),
|
|
57
58
|
WorkflowTriggerPropertyShapesToWidgetIntegrations(),
|
|
58
59
|
TableReportPropertyShapesToWidgetIntegrations(),
|
|
60
|
+
SparqlDatatypesToXsdString(),
|
|
59
61
|
]
|
|
60
62
|
]
|
|
61
63
|
data.sort(key=lambda x: x["first_version"])
|
|
@@ -27,9 +27,9 @@ from urllib3.exceptions import InsecureRequestWarning
|
|
|
27
27
|
from cmem_cmemc.exceptions import InvalidConfigurationError
|
|
28
28
|
from cmem_cmemc.string_processor import StringProcessor, process_row
|
|
29
29
|
|
|
30
|
-
DI_TARGET_VERSION = "v24.
|
|
30
|
+
DI_TARGET_VERSION = "v24.3.0"
|
|
31
31
|
|
|
32
|
-
EXPLORE_TARGET_VERSION = "v24.
|
|
32
|
+
EXPLORE_TARGET_VERSION = "v24.3.0"
|
|
33
33
|
|
|
34
34
|
KNOWN_CONFIG_KEYS = {
|
|
35
35
|
"CMEM_BASE_URI": cmempy_config.get_cmem_base_uri,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Migration: Chart and Workflow Property Shapes to Widget Integration"""
|
|
2
|
+
|
|
3
|
+
from typing import ClassVar
|
|
4
|
+
|
|
5
|
+
from cmem_cmemc.migrations.abc import MigrationRecipe, components
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SparqlDatatypesToXsdString(MigrationRecipe):
|
|
9
|
+
"""24.2 Migrate shui:sparqlQuery|sparqlUpdate datatype literals to xsd:string literals"""
|
|
10
|
+
|
|
11
|
+
id = "sparql-query-datatypes-24.2"
|
|
12
|
+
description = "Migrate shui SPARQL datatype literals to xsd:string literals"
|
|
13
|
+
component: components = "explore"
|
|
14
|
+
first_version = "24.2"
|
|
15
|
+
tags: ClassVar[list[str]] = ["shapes", "user"]
|
|
16
|
+
check_query = """{{DEFAULT_PREFIXES}}
|
|
17
|
+
SELECT DISTINCT ?query
|
|
18
|
+
WHERE {
|
|
19
|
+
GRAPH ?shapeOrQueryGraph {
|
|
20
|
+
?query shui:queryText ?text .
|
|
21
|
+
FILTER ( datatype(?text) IN (shui:sparqlQuery, shui:sparqlUpdate) )
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
"""
|
|
25
|
+
move_query = """{{DEFAULT_PREFIXES}}
|
|
26
|
+
DELETE {
|
|
27
|
+
GRAPH ?shapeOrQueryGraph {
|
|
28
|
+
?query shui:queryText ?oldLiteral .
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
INSERT {
|
|
32
|
+
GRAPH ?shapeOrQueryGraph {
|
|
33
|
+
?query shui:queryText ?newLiteral .
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
# SELECT DISTINCT ?query
|
|
37
|
+
WHERE {
|
|
38
|
+
GRAPH ?shapeOrQueryGraph {
|
|
39
|
+
?query shui:queryText ?oldLiteral .
|
|
40
|
+
FILTER ( datatype(?oldLiteral) IN (shui:sparqlQuery, shui:sparqlUpdate) )
|
|
41
|
+
BIND (STRDT(STR(?oldLiteral), xsd:string) AS ?newLiteral)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def is_applicable(self) -> bool:
|
|
47
|
+
"""Test if the recipe can be applied."""
|
|
48
|
+
queries_with_old_literals = self._select(self.check_query)
|
|
49
|
+
return len(queries_with_old_literals) > 0
|
|
50
|
+
|
|
51
|
+
def apply(self) -> None:
|
|
52
|
+
"""Apply the recipe to the current version."""
|
|
53
|
+
self._update(self.move_query)
|
|
@@ -21,7 +21,7 @@ from cmem_cmemc.constants import NAMESPACES
|
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
23
|
from cmem_cmemc.context import ApplicationContext
|
|
24
|
-
from cmem_cmemc.smart_path import SmartPath
|
|
24
|
+
from cmem_cmemc.smart_path import SmartPath
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def get_version() -> str:
|
|
@@ -90,13 +90,13 @@ def read_rdf_graph_files(directory_path: str) -> list[tuple[str, str]]:
|
|
|
90
90
|
for _file in files:
|
|
91
91
|
if _file.endswith(".graph"):
|
|
92
92
|
continue
|
|
93
|
-
full_file_path =
|
|
93
|
+
full_file_path = SmartPath(root) / _file
|
|
94
94
|
# Handle compressed files (like .gz)
|
|
95
95
|
if _file.endswith(".gz"):
|
|
96
96
|
graph_file_name = _file.replace(".gz", ".graph")
|
|
97
97
|
else:
|
|
98
98
|
graph_file_name = f"{_file}.graph"
|
|
99
|
-
full_graph_file_name_path =
|
|
99
|
+
full_graph_file_name_path = SmartPath(root) / graph_file_name
|
|
100
100
|
if full_graph_file_name_path.exists():
|
|
101
101
|
graph_name = read_file_to_string(str(full_graph_file_name_path)).strip()
|
|
102
102
|
rdf_graphs.append((str(full_file_path.resolve()), graph_name))
|
|
@@ -105,7 +105,7 @@ def read_rdf_graph_files(directory_path: str) -> list[tuple[str, str]]:
|
|
|
105
105
|
|
|
106
106
|
def read_file_to_string(file_path: str) -> str:
|
|
107
107
|
"""Read file to string."""
|
|
108
|
-
with
|
|
108
|
+
with SmartPath(file_path).open(mode="rb") as _file:
|
|
109
109
|
return str(_file.read().decode("utf-8"))
|
|
110
110
|
|
|
111
111
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "cmem-cmemc"
|
|
3
|
-
version = "24.3.
|
|
3
|
+
version = "24.3.3"
|
|
4
4
|
description = "Command line client for eccenca Corporate Memory"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
classifiers = [
|
|
@@ -39,7 +39,6 @@ configparser = "^6.0.1"
|
|
|
39
39
|
jinja2 = "^3.1.4"
|
|
40
40
|
junit-xml = "^1.9"
|
|
41
41
|
natsort = "^8.4.0"
|
|
42
|
-
pip = "^24.3.1"
|
|
43
42
|
prometheus-client = "^0.21.0"
|
|
44
43
|
pygments = "^2.18.0"
|
|
45
44
|
pyjwt = "^2.9.0"
|
|
@@ -59,6 +58,7 @@ cmemc = 'cmem_cmemc:main'
|
|
|
59
58
|
[tool.poetry.group.dev.dependencies]
|
|
60
59
|
genbadge = {extras = ["coverage"], version = "^1.1.1"}
|
|
61
60
|
mypy = "^1.13.0"
|
|
61
|
+
pip = "^25"
|
|
62
62
|
pytest = "^8.3.3"
|
|
63
63
|
pytest-cov = "^6.0.0"
|
|
64
64
|
pytest-dotenv = "^0.5.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/migrations/shapes_widget_integrations_243.py
RENAMED
|
File without changes
|
{cmem_cmemc-24.3.0rc2 → cmem_cmemc-24.3.3}/cmem_cmemc/migrations/workspace_configurations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|