cmem-cmemc 24.2.0rc2__py3-none-any.whl → 24.3.0rc1__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.
Files changed (51) hide show
  1. cmem_cmemc/__init__.py +7 -12
  2. cmem_cmemc/command.py +20 -0
  3. cmem_cmemc/command_group.py +70 -0
  4. cmem_cmemc/commands/__init__.py +0 -81
  5. cmem_cmemc/commands/acl.py +118 -62
  6. cmem_cmemc/commands/admin.py +46 -35
  7. cmem_cmemc/commands/client.py +2 -1
  8. cmem_cmemc/commands/config.py +3 -1
  9. cmem_cmemc/commands/dataset.py +27 -24
  10. cmem_cmemc/commands/graph.py +100 -16
  11. cmem_cmemc/commands/metrics.py +195 -79
  12. cmem_cmemc/commands/migration.py +265 -0
  13. cmem_cmemc/commands/project.py +62 -17
  14. cmem_cmemc/commands/python.py +57 -26
  15. cmem_cmemc/commands/query.py +23 -14
  16. cmem_cmemc/commands/resource.py +10 -2
  17. cmem_cmemc/commands/scheduler.py +10 -2
  18. cmem_cmemc/commands/store.py +118 -14
  19. cmem_cmemc/commands/user.py +8 -2
  20. cmem_cmemc/commands/validation.py +165 -78
  21. cmem_cmemc/commands/variable.py +10 -2
  22. cmem_cmemc/commands/vocabulary.py +48 -29
  23. cmem_cmemc/commands/workflow.py +86 -59
  24. cmem_cmemc/commands/workspace.py +27 -8
  25. cmem_cmemc/completion.py +185 -141
  26. cmem_cmemc/constants.py +2 -0
  27. cmem_cmemc/context.py +88 -42
  28. cmem_cmemc/manual_helper/graph.py +1 -0
  29. cmem_cmemc/manual_helper/multi_page.py +3 -1
  30. cmem_cmemc/migrations/__init__.py +1 -0
  31. cmem_cmemc/migrations/abc.py +84 -0
  32. cmem_cmemc/migrations/access_conditions_243.py +118 -0
  33. cmem_cmemc/migrations/bootstrap_data.py +30 -0
  34. cmem_cmemc/migrations/shapes_widget_integrations_243.py +194 -0
  35. cmem_cmemc/migrations/workspace_configurations.py +28 -0
  36. cmem_cmemc/object_list.py +53 -22
  37. cmem_cmemc/parameter_types/__init__.py +1 -0
  38. cmem_cmemc/parameter_types/path.py +69 -0
  39. cmem_cmemc/smart_path/__init__.py +94 -0
  40. cmem_cmemc/smart_path/clients/__init__.py +63 -0
  41. cmem_cmemc/smart_path/clients/http.py +65 -0
  42. cmem_cmemc/string_processor.py +77 -0
  43. cmem_cmemc/title_helper.py +41 -0
  44. cmem_cmemc/utils.py +114 -47
  45. {cmem_cmemc-24.2.0rc2.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/LICENSE +1 -1
  46. cmem_cmemc-24.3.0rc1.dist-info/METADATA +89 -0
  47. cmem_cmemc-24.3.0rc1.dist-info/RECORD +53 -0
  48. {cmem_cmemc-24.2.0rc2.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/WHEEL +1 -1
  49. cmem_cmemc-24.2.0rc2.dist-info/METADATA +0 -69
  50. cmem_cmemc-24.2.0rc2.dist-info/RECORD +0 -37
  51. {cmem_cmemc-24.2.0rc2.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,65 @@
1
+ """Provides functionality for interacting with http/https paths"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from cmem_cmemc.smart_path.clients import StoragePath
8
+
9
+ if TYPE_CHECKING:
10
+ from collections.abc import Generator
11
+
12
+
13
+ class HttpPath(StoragePath):
14
+ """Client class for interacting with Amazon S3 storage.
15
+
16
+ This class provides methods for working with http paths within the context
17
+ of the `Path` application.
18
+ """
19
+
20
+ @property
21
+ def suffix(self) -> str:
22
+ """Return the suffix of the path."""
23
+ raise NotImplementedError(f"suffix in {self.__class__} is not implemented yet.")
24
+
25
+ @property
26
+ def name(self) -> str:
27
+ """Determine the name of the path."""
28
+ return self.path.split("/")[-1]
29
+
30
+ @property
31
+ def parent(self) -> HttpPath:
32
+ """The logical parent of the path."""
33
+ raise NotImplementedError(f"parent in {self.__class__} is not implemented yet.")
34
+
35
+ def is_dir(self) -> bool:
36
+ """Determine if path is a directory or not."""
37
+ return False
38
+
39
+ def is_file(self) -> bool:
40
+ """Determine if path is a file or not."""
41
+ return not self.is_dir()
42
+
43
+ def exists(self) -> bool:
44
+ """Return the suffix of the path."""
45
+ raise NotImplementedError(f"exists in {self.__class__} is not implemented yet.")
46
+
47
+ def mkdir(self, parents: bool = False, exist_ok: bool = False) -> None:
48
+ """Return the suffix of the path."""
49
+ raise NotImplementedError(f"mkdir in {self.__class__} is not implemented yet.")
50
+
51
+ def absolute(self) -> HttpPath:
52
+ """Return an absolute version of this path"""
53
+ raise NotImplementedError(f"absolute in {self.__class__} is not implemented yet.")
54
+
55
+ def resolve(self) -> HttpPath:
56
+ """Resolve the resolved path of the path."""
57
+ raise NotImplementedError(f"resolve in {self.__class__} is not implemented yet.")
58
+
59
+ def glob(self, pattern: str) -> Generator[StoragePath, StoragePath, StoragePath]:
60
+ """Iterate over this subtree and yield all existing files"""
61
+ raise NotImplementedError(f"glob in {self.__class__} is not implemented yet.")
62
+
63
+ def __truediv__(self, key: str) -> HttpPath:
64
+ """Return path with appending the key"""
65
+ raise NotImplementedError(f"__truediv__ in {self.__class__} is not implemented yet.")
@@ -0,0 +1,77 @@
1
+ """Helper functions for rich text output"""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from datetime import datetime, timezone
5
+ from urllib.parse import quote
6
+
7
+ import timeago
8
+ from cmem.cmempy.config import get_cmem_base_uri
9
+
10
+ from cmem_cmemc.title_helper import TitleHelper
11
+ from cmem_cmemc.utils import get_graphs_as_dict
12
+
13
+
14
+ class StringProcessor(ABC):
15
+ """ABC of a table cell string processor"""
16
+
17
+ @abstractmethod
18
+ def process(self, text: str) -> str:
19
+ """Process a single string content and output the processed string."""
20
+
21
+
22
+ class TimeAgo(StringProcessor):
23
+ """Create a string similar to 'x minutes ago' from a timestamp"""
24
+
25
+ def process(self, text: str) -> str:
26
+ """Process a single string content and output the processed string."""
27
+ stamp = datetime.fromtimestamp(int(text) / 1000, tz=timezone.utc)
28
+ return str(timeago.format(stamp, datetime.now(tz=timezone.utc)))
29
+
30
+
31
+ class GraphLink(StringProcessor):
32
+ """Create a graph link from an IRI cell
33
+
34
+ "Visit my [link=https://www.willmcgugan.com]blog[/link]!"
35
+ """
36
+
37
+ def __init__(self) -> None:
38
+ self.cmem_base_uri = get_cmem_base_uri()
39
+ self.base = self.cmem_base_uri + "/explore?graph="
40
+ self.graph_labels: dict[str, str] = {}
41
+ for _ in get_graphs_as_dict().values():
42
+ self.graph_labels[_["iri"]] = _["label"]["title"]
43
+
44
+ def process(self, text: str) -> str:
45
+ """Process a single string content and output the processed string."""
46
+ link = self.base + quote(text)
47
+ label = self.graph_labels.get(text, None)
48
+ return f"[link={link}]{label}[/link]" if label else text
49
+
50
+
51
+ class ResourceLink(StringProcessor):
52
+ """Create a resource link from an IRI cell
53
+
54
+ "Visit my [link=https://www.willmcgugan.com]blog[/link]!"
55
+ """
56
+
57
+ def __init__(self, graph_iri: str, title_helper: TitleHelper | None = None):
58
+ self.graph_iri = graph_iri
59
+ self.base = get_cmem_base_uri() + "/explore?graph=" + quote(graph_iri) + "&resource="
60
+ self.title_helper = title_helper if title_helper else TitleHelper()
61
+
62
+ def process(self, text: str) -> str:
63
+ """Process a single string content and output the processed string."""
64
+ link = self.base + quote(text)
65
+ label = self.title_helper.get(text)
66
+ return f"[link={link}]{label}[/link]"
67
+
68
+
69
+ def process_row(row: list[str], hints: dict[int, StringProcessor]) -> list[str]:
70
+ """Process all cells in a row according to the StringProcessors"""
71
+ processed_row = []
72
+ for column_number, cell in enumerate(row):
73
+ if hints.get(column_number):
74
+ processed_row.append(hints[column_number].process(cell))
75
+ else:
76
+ processed_row.append(cell)
77
+ return processed_row
@@ -0,0 +1,41 @@
1
+ """Title helper functions."""
2
+
3
+ import json
4
+
5
+ from cmem.cmempy.api import get_json
6
+ from cmem.cmempy.config import get_dp_api_endpoint
7
+
8
+
9
+ class TitleHelper:
10
+ """Title helper class."""
11
+
12
+ fetched_labels: dict[str, dict]
13
+
14
+ def __init__(self) -> None:
15
+ self.fetched_labels = {}
16
+ self.endpoint = f"{get_dp_api_endpoint()}/api/explore/titles"
17
+
18
+ def get(self, iri: str | list[str]) -> str | dict[str, str]:
19
+ """Get the title of an IRI (or list of IRI)."""
20
+ output = {}
21
+ iris = [iri] if isinstance(iri, str) else list(set(iri))
22
+
23
+ iris_to_fetch = []
24
+ for _ in iris:
25
+ if _ in self.fetched_labels:
26
+ output[_] = self.fetched_labels[_]["title"]
27
+ else:
28
+ iris_to_fetch.append(_)
29
+
30
+ if len(iris_to_fetch) > 0:
31
+ titles: dict = get_json(
32
+ self.endpoint,
33
+ method="POST",
34
+ data=json.dumps(iris_to_fetch),
35
+ headers={"Content-type": "application/json"},
36
+ )
37
+ for title in titles.values():
38
+ self.fetched_labels[title["iri"]] = title
39
+ output[title["iri"]] = title["title"]
40
+
41
+ return output[iri] if isinstance(iri, str) else output
cmem_cmemc/utils.py CHANGED
@@ -1,27 +1,48 @@
1
1
  """Utility functions for CLI interface."""
2
+
2
3
  import json
3
4
  import os
5
+ import pathlib
4
6
  import re
7
+ import sys
5
8
  import unicodedata
6
9
  from dataclasses import dataclass
7
- from importlib.metadata import version
8
- from pathlib import Path
10
+ from importlib.metadata import version as cmemc_version
11
+ from typing import TYPE_CHECKING
12
+ from zipfile import BadZipFile, ZipFile
9
13
 
10
14
  import requests
11
15
  from bs4 import BeautifulSoup
12
- from cmem.cmempy.dp.admin import get_prometheus_data
13
16
  from cmem.cmempy.dp.proxy.graph import get_graphs_list
17
+ from cmem.cmempy.queries import QueryCatalog
14
18
  from cmem.cmempy.workspace.projects.project import get_projects
15
19
  from prometheus_client import Metric
16
- from prometheus_client.parser import text_string_to_metric_families
17
20
 
18
21
  from cmem_cmemc.constants import NAMESPACES
19
- from cmem_cmemc.context import ApplicationContext
22
+
23
+ if TYPE_CHECKING:
24
+ from cmem_cmemc.context import ApplicationContext
25
+ from cmem_cmemc.smart_path import SmartPath as Path
20
26
 
21
27
 
22
28
  def get_version() -> str:
23
29
  """Get the current version or SNAPSHOT."""
24
- return version("cmem-cmemc")
30
+ return cmemc_version("cmem-cmemc")
31
+
32
+
33
+ def check_python_version(ctx: "ApplicationContext") -> None:
34
+ """Check the runtime python version and warn or error."""
35
+ version = sys.version_info
36
+ major_expected = [3]
37
+ minor_expected = [10, 11, 12]
38
+ if version.major not in major_expected:
39
+ ctx.echo_error(f"Error: cmemc can not be executed with Python {version.major}.")
40
+ sys.exit(1)
41
+ if version.minor not in minor_expected and not ctx.is_completing():
42
+ ctx.echo_warning(
43
+ "Warning: You are running cmemc under a non-tested python "
44
+ f"environment ({version.major}.{version.minor})."
45
+ )
25
46
 
26
47
 
27
48
  def extract_error_message(error: Exception) -> str:
@@ -68,10 +89,16 @@ def read_rdf_graph_files(directory_path: str) -> list[tuple[str, str]]:
68
89
  rdf_graphs = []
69
90
  for root, _, files in os.walk(directory_path):
70
91
  for _file in files:
92
+ if _file.endswith(".graph"):
93
+ continue
71
94
  full_file_path = Path(root) / _file
72
- graph_file_name = _file + ".graph"
95
+ # Handle compressed files (like .gz)
96
+ if _file.endswith(".gz"):
97
+ graph_file_name = _file.replace(".gz", ".graph")
98
+ else:
99
+ graph_file_name = f"{_file}.graph"
73
100
  full_graph_file_name_path = Path(root) / graph_file_name
74
- if not _file.endswith(".graph") and Path(full_graph_file_name_path).exists():
101
+ if full_graph_file_name_path.exists():
75
102
  graph_name = read_file_to_string(str(full_graph_file_name_path)).strip()
76
103
  rdf_graphs.append((str(full_file_path.resolve()), graph_name))
77
104
  return rdf_graphs
@@ -80,7 +107,7 @@ def read_rdf_graph_files(directory_path: str) -> list[tuple[str, str]]:
80
107
  def read_file_to_string(file_path: str) -> str:
81
108
  """Read file to string."""
82
109
  with Path(file_path).open(mode="rb") as _file:
83
- return _file.read().decode("utf-8")
110
+ return str(_file.read().decode("utf-8"))
84
111
 
85
112
 
86
113
  def get_graphs(writeable: bool = True, readonly: bool = True) -> list:
@@ -211,28 +238,7 @@ def metric_get_labels(family: Metric, clean: bool = True) -> dict[str, list[str]
211
238
  return labels
212
239
 
213
240
 
214
- def metrics_get_dict(job_id: str = "DP") -> dict[str, Metric]:
215
- """Get metrics data as dict."""
216
- data = {}
217
- if job_id == "DP":
218
- for family in text_string_to_metric_families(get_prometheus_data().text):
219
- data[family.name] = family
220
- return data
221
- raise ValueError(f"job name {job_id} unknown.")
222
-
223
-
224
- def metrics_get_family(job_id: str, metric_id: str) -> Metric:
225
- """Get family data.
226
-
227
- This function returns a dictionary of metric families.
228
- """
229
- try:
230
- return metrics_get_dict(job_id=job_id)[metric_id]
231
- except KeyError as error:
232
- raise ValueError(f"The job {job_id} does not have a metric {metric_id}.") from error
233
-
234
-
235
- def check_or_select_project(app: ApplicationContext, project_id: str | None = None) -> str:
241
+ def check_or_select_project(app: "ApplicationContext", project_id: str | None = None) -> str:
236
242
  """Check for given project, select the first one if there is only one.
237
243
 
238
244
  Args:
@@ -281,28 +287,42 @@ class PublishedPackage:
281
287
 
282
288
  name: str
283
289
  description: str
284
- version: str
285
290
  published: str
286
291
 
287
292
 
288
293
  def get_published_packages() -> list[PublishedPackage]:
289
294
  """Get a scraped list of plugin packages scraped from pypi.org."""
290
- url = "https://pypi.org/search/?q=%22cmem-plugin-%22"
291
- soup = BeautifulSoup(requests.get(url, timeout=5).content, "html.parser")
295
+ url_pattern = "https://pypi.org/search/?q=%22cmem-plugin-%22&page={}"
292
296
  packages = []
293
- snippets = soup.find_all("a", class_="package-snippet")
294
- for _ in snippets:
295
- name = _.findChildren(class_="package-snippet__name")[0].getText()
296
- if name == "cmem-plugin-base":
297
- continue
298
- description = _.findChildren(class_="package-snippet__description")[0].getText()
299
- package_version = _.findChildren(class_="package-snippet__version")[0].getText()
300
- published = _.findChildren(name="time")[0].attrs["datetime"]
301
- packages.append(
302
- PublishedPackage(
303
- name=name, description=description, version=package_version, published=published
304
- )
305
- )
297
+ package_names = []
298
+ page = 0
299
+ while True:
300
+ page += 1
301
+ url = url_pattern.format(page)
302
+ soup = BeautifulSoup(requests.get(url, timeout=5).content, "html.parser")
303
+ snippets = soup.find_all("a", class_="package-snippet")
304
+ if len(snippets) == 0:
305
+ break
306
+ for _ in snippets:
307
+ name = _.findChildren(class_="package-snippet__name")[0].getText()
308
+ if name == "cmem-plugin-base":
309
+ continue
310
+ if not name.startswith("cmem-plugin-"):
311
+ continue
312
+ try:
313
+ description = _.findChildren(class_="package-snippet__description")[0].getText()
314
+ except IndexError:
315
+ description = "no description"
316
+ published = _.findChildren(name="time")[0].attrs["datetime"]
317
+ if name not in package_names:
318
+ package_names.append(name)
319
+ packages.append(
320
+ PublishedPackage(
321
+ name=name,
322
+ description=description,
323
+ published=published,
324
+ )
325
+ )
306
326
  return packages
307
327
 
308
328
 
@@ -325,3 +345,50 @@ def convert_qname_to_iri(qname: str, default_ns: str) -> str:
325
345
  return default_ns + qname[1:]
326
346
 
327
347
  return qname
348
+
349
+
350
+ def get_query_text(file_or_uri: str, required_projections: set) -> str:
351
+ """Get query text for a file or graph catalog URI.
352
+
353
+ Args:
354
+ ----
355
+ file_or_uri (str): The file path or URI to fetch the query from.
356
+ required_projections (set): A set of required projections.
357
+
358
+ Returns:
359
+ -------
360
+ str: The query text.
361
+
362
+ Raises:
363
+ ------
364
+ ValueError: If the input is not a readable file or a query URI,
365
+ or if the query contains placeholders,
366
+ or if the query does not include the required projections.
367
+
368
+ """
369
+ sparql_query = QueryCatalog().get_query(file_or_uri)
370
+ if sparql_query is None:
371
+ raise ValueError(f"{file_or_uri} is neither a readable file nor a query URI.")
372
+
373
+ if sparql_query.get_placeholder_keys():
374
+ raise ValueError("Placeholder queries are not supported.")
375
+
376
+ result = sparql_query.get_json_results()
377
+ projected_vars = set(result["head"]["vars"])
378
+
379
+ missing_projections = required_projections - projected_vars
380
+ if missing_projections:
381
+ missing = ", ".join(missing_projections)
382
+ raise ValueError(f"Select query must include projections for: {missing}")
383
+ txt: str = sparql_query.text
384
+ return txt
385
+
386
+
387
+ def validate_zipfile(zipfile: str | pathlib.Path) -> bool:
388
+ """Validate a zipfile."""
389
+ zipfile = pathlib.Path(zipfile)
390
+ try:
391
+ ZipFile(zipfile).testzip()
392
+ except BadZipFile:
393
+ return False
394
+ return True
@@ -199,4 +199,4 @@
199
199
  distributed under the License is distributed on an "AS IS" BASIS,
200
200
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
201
  See the License for the specific language governing permissions and
202
- limitations under the License.
202
+ limitations under the License.
@@ -0,0 +1,89 @@
1
+ Metadata-Version: 2.1
2
+ Name: cmem-cmemc
3
+ Version: 24.3.0rc1
4
+ Summary: Command line client for eccenca Corporate Memory
5
+ Home-page: https://eccenca.com/go/cmemc
6
+ License: Apache-2.0
7
+ Author: eccenca
8
+ Author-email: cmempy-developer@eccenca.com
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Customer Service
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Intended Audience :: System Administrators
17
+ Classifier: License :: OSI Approved :: Apache Software License
18
+ Classifier: Natural Language :: English
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3 :: Only
25
+ Classifier: Topic :: Database
26
+ Classifier: Topic :: Software Development :: Testing
27
+ Classifier: Topic :: Utilities
28
+ Requires-Dist: beautifulsoup4 (>=4.12.3,<5.0.0)
29
+ Requires-Dist: certifi (>=2024.2.2)
30
+ Requires-Dist: click (>=8.1.7,<9.0.0)
31
+ Requires-Dist: click-didyoumean (>=0.3.1,<0.4.0)
32
+ Requires-Dist: click-help-colors (>=0.9.4,<0.10.0)
33
+ Requires-Dist: cmem-cmempy (==24.3.0)
34
+ Requires-Dist: configparser (>=6.0.1,<7.0.0)
35
+ Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
36
+ Requires-Dist: junit-xml (>=1.9,<2.0)
37
+ Requires-Dist: natsort (>=8.4.0,<9.0.0)
38
+ Requires-Dist: packaging (>=24.2,<25.0)
39
+ Requires-Dist: pip (>=24.3.1,<25.0.0)
40
+ Requires-Dist: prometheus-client (>=0.21.0,<0.22.0)
41
+ Requires-Dist: pygments (>=2.18.0,<3.0.0)
42
+ Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
43
+ Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
44
+ Requires-Dist: requests (>=2.32.3,<3.0.0)
45
+ Requires-Dist: rich (>=13.9.1,<14.0.0)
46
+ Requires-Dist: six (>=1.16.0,<2.0.0)
47
+ Requires-Dist: smart-open (>=7.0.5,<8.0.0)
48
+ Requires-Dist: timeago (>=1.0.16,<2.0.0)
49
+ Requires-Dist: treelib (>=1.7.0,<2.0.0)
50
+ Requires-Dist: urllib3 (>=2.2.3,<3.0.0)
51
+ Description-Content-Type: text/markdown
52
+
53
+ # cmemc
54
+
55
+ cmemc is the official command line client for [eccenca Corporate Memory](https://documentation.eccenca.com/).
56
+
57
+ [![version][version-shield]][changelog] [![Python Versions][python-shield]][pypi] [![eccenca Corporate Memory][cmem-shield]][cmem]
58
+
59
+ [![teaser][teaser-image]][cmemc-docu]
60
+
61
+ ## Installation
62
+
63
+ In order to install the cmemc, run:
64
+
65
+ pipx install cmem-cmemc
66
+
67
+ Of course you can install cmemc also with pip, but we recommend [pipx](https://pypa.github.io/pipx/) for normal desktop usage.
68
+
69
+ ## Configuration and Usage
70
+
71
+ cmemc is intended for System Administrators and Linked Data Expert, who wants to automate and remote control activities on eccenca Corporate Memory.
72
+
73
+ The cmemc manual including basic usage pattern, configuration as well as a command reference is available at:
74
+
75
+ [https://eccenca.com/go/cmemc](https://eccenca.com/go/cmemc)
76
+
77
+ cmemc only works with Python 3 and refuses to work with Python 2.x.
78
+ In addition to that, cmemc will warn you in case an untested Python environment is used.
79
+
80
+
81
+ [version-shield]: https://badge.fury.io/py/cmem-cmemc.svg
82
+ [changelog]: https://pypi.org/project/cmem-cmemc/#history
83
+ [python-shield]: https://img.shields.io/pypi/pyversions/cmem-cmemc.svg
84
+ [pypi]: https://pypi.org/project/cmem-cmemc/
85
+ [cmem]: https://documentation.eccenca.com
86
+ [cmem-shield]: https://img.shields.io/badge/made%20for-eccenca%20Corporate%20Memory-blue?logo=data:image/svg%2bxml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgaWQ9IkxheWVyXzEiCiAgIGRhdGEtbmFtZT0iTGF5ZXIgMSIKICAgdmlld0JveD0iMCAwIDgxLjI5MDAwMSA4Mi4yODk4NiIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iODEuMjkwMDAxIgogICBoZWlnaHQ9IjgyLjI4OTg2NCIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzODI2Ij4KICAgIDxzdHlsZQogICAgICAgaWQ9InN0eWxlODI0Ij4KICAgICAgLmNscy0xIHsKICAgICAgICBmaWxsOiAjZjM5MjAwOwogICAgICB9CgogICAgICAuY2xzLTIgewogICAgICAgIGZpbGw6IG5vbmU7CiAgICAgICAgc3Ryb2tlOiAjZjM5MjAwOwogICAgICAgIHN0cm9rZS13aWR0aDogMS41cHg7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgogIDxnCiAgICAgaWQ9Imc4NDAiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMwLjc2LC0zMS4xNDAxMzkpIj4KICAgIDxwYXRoCiAgICAgICBjbGFzcz0iY2xzLTEiCiAgICAgICBkPSJNIDU1LjksODUuMTkgQSAyMC4xNCwyMC4xNCAwIDEgMCAzNS43Niw2NS4wNSAyMC4xNCwyMC4xNCAwIDAgMCA1NS45LDg1LjE5IFoiCiAgICAgICBpZD0icGF0aDgyOCIgLz4KICAgIDxwYXRoCiAgICAgICBjbGFzcz0iY2xzLTEiCiAgICAgICBkPSJtIDk4LDU0LjE0IGEgOSw5IDAgMSAwIC04Ljk1LC05IDguOTUsOC45NSAwIDAgMCA4Ljk1LDkgeiIKICAgICAgIGlkPSJwYXRoODMwIiAvPgogICAgPHBhdGgKICAgICAgIGNsYXNzPSJjbHMtMSIKICAgICAgIGQ9Ik0gODguMzUsMTA4LjQzIEEgMTIuMzEsMTIuMzEgMCAxIDAgNzYsOTYuMTIgMTIuMzEsMTIuMzEgMCAwIDAgODguMzEsMTA4LjQzIFoiCiAgICAgICBpZD0icGF0aDgzMiIgLz4KICAgIDxsaW5lCiAgICAgICBjbGFzcz0iY2xzLTIiCiAgICAgICB4MT0iODYuOTcwMDAxIgogICAgICAgeTE9IjkyLjA1OTk5OCIKICAgICAgIHgyPSI1OC43Nzk5OTkiCiAgICAgICB5Mj0iNjcuMzYwMDAxIgogICAgICAgaWQ9ImxpbmU4MzQiIC8+CiAgICA8bGluZQogICAgICAgY2xhc3M9ImNscy0yIgogICAgICAgeDE9Ijk5LjE4IgogICAgICAgeTE9IjQ1Ljg0IgogICAgICAgeDI9IjU1LjQ4IgogICAgICAgeTI9IjY2LjEyMDAwMyIKICAgICAgIGlkPSJsaW5lODM2IiAvPgogICAgPGxpbmUKICAgICAgIGNsYXNzPSJjbHMtMiIKICAgICAgIHgxPSI5Ny45ODk5OTgiCiAgICAgICB5MT0iNDQuNjUwMDAyIgogICAgICAgeDI9Ijg4LjM0OTk5OCIKICAgICAgIHkyPSI5Mi44Mzk5OTYiCiAgICAgICBpZD0ibGluZTgzOCIgLz4KICA8L2c+Cjwvc3ZnPgo=
87
+ [teaser-image]: https://documentation.eccenca.com/24.1/automate/cmemc-command-line-interface/configuration/completion-setup/22.1-cmemc-create-dataset.gif
88
+ [cmemc-docu]: https://eccenca.com/go/cmemc
89
+
@@ -0,0 +1,53 @@
1
+ cmem_cmemc/__init__.py,sha256=JP__el3oR8pNwDH4_D3mu6jE6ChdeBDnIgu5Vf_VHUg,5516
2
+ cmem_cmemc/_cmemc.zsh,sha256=fmkrBHIQxus8cp2AgO1tzZ5mNZdGL_83cYz3a9uAdsg,1326
3
+ cmem_cmemc/command.py,sha256=OsrQOqHpMjiucdpyac8xzxBaSWehYIA7xkO651z8iTs,702
4
+ cmem_cmemc/command_group.py,sha256=0ltd8xY0yN6_ARR2kkwx7Hibj4glT9M0_bnjKlMhz8g,3371
5
+ cmem_cmemc/commands/__init__.py,sha256=NaGM5jOzf0S_-4UIAwlVDOf2AZ3mliGPoRLXQJfTyZs,22
6
+ cmem_cmemc/commands/acl.py,sha256=zy27D_GeEaYEn3P6EEHtQ55sbWkjgwTgspCeuBWPL14,16006
7
+ cmem_cmemc/commands/admin.py,sha256=IrhWPNJxdE5GO9UumsI8lv9PqFc_0oUh72FmQIKdl9c,9192
8
+ cmem_cmemc/commands/client.py,sha256=gKh22OvYDi95q2U4czH4UPYyDRw_Ngk2K0frDywl3B4,5074
9
+ cmem_cmemc/commands/config.py,sha256=j0zc9EFWW7Kw9bzSb_r16m-A0LZersKbZ9j5GE0mGcQ,5734
10
+ cmem_cmemc/commands/dataset.py,sha256=xsIUiC2aMDiESjnZvjDY5Mh2fvSooOijQmo5A7RvY40,30397
11
+ cmem_cmemc/commands/graph.py,sha256=lYu0M3HKCeDhrv_cswDbyzYKqy5_9OPU548zbJZVQ1o,30743
12
+ cmem_cmemc/commands/metrics.py,sha256=zsyHezoYwig6jIdn7g9NZMqt9DxG6dQRoO0vP3Eu0Rc,12176
13
+ cmem_cmemc/commands/migration.py,sha256=KXxKnk4MxzUtc7iSiLipOJKCX4bkiUABXdA-PQPN6r8,9300
14
+ cmem_cmemc/commands/project.py,sha256=1BwAAZvupImqkW3Q3dXdkMir8-wnWRMsewnOyVui3QY,20545
15
+ cmem_cmemc/commands/python.py,sha256=nIxBgiznR7tarrw7JFE1XkGrVlFxQQQmxj2lyExxhtI,10738
16
+ cmem_cmemc/commands/query.py,sha256=KUck4w7PD0e5JYg5Eykf2QAMBfpwmgskEiIA-X_PqZs,26973
17
+ cmem_cmemc/commands/resource.py,sha256=ZC_0PM0YnEB3Xf4i0siaTKxHT0Ixjz2Y3QTXuVPuhRE,7739
18
+ cmem_cmemc/commands/scheduler.py,sha256=yKVGcewhrXFfSKEOlvEFwaIfWCOK1x7VLhm-i-SSw68,8729
19
+ cmem_cmemc/commands/store.py,sha256=hChKTSQ4zAQZ3bFforyYBW9d2CAitInKGW2WSaE8m7c,10411
20
+ cmem_cmemc/commands/user.py,sha256=9ju6Q4SdqQncbnFRmN0O27Md9KDl8SD-4SXsBDNw4oA,12464
21
+ cmem_cmemc/commands/validation.py,sha256=Iji13uzhWlyjKlEuEJCDIb-XPwCTO_wzThI1PB--8D8,29485
22
+ cmem_cmemc/commands/variable.py,sha256=DSNxiS5PlexzNdYz9f0-O0hxqakbsxv847U7I9UhKUI,11568
23
+ cmem_cmemc/commands/vocabulary.py,sha256=pAxRM-Y9lzmZ0dT3NBpBGKa2nlbY0thWBdfN2FESXQ8,17767
24
+ cmem_cmemc/commands/workflow.py,sha256=vQiaH3L1ZXjf5SuorwdjrD6nF_5nxZ9Xkd7eCNGwxk8,25512
25
+ cmem_cmemc/commands/workspace.py,sha256=IcZgBsvtulLRFofS70qpln6oKQIZunrVLfSAUeiFhCA,4579
26
+ cmem_cmemc/completion.py,sha256=gI64uJS1pMZS_iR8VgOldF4sNMTeV0AV51bF7lF2dlo,43925
27
+ cmem_cmemc/constants.py,sha256=VKNF5-6fzZXWzPgm1OAGhWvyL4YE8SRq52kkpJjUgB0,475
28
+ cmem_cmemc/context.py,sha256=fy2gwoW-15hl-yCCY9f0t59j4Sp2Mj2GNatZ2G-mrxA,19482
29
+ cmem_cmemc/exceptions.py,sha256=SpUHdmVM8cZpSjBv6ICgr9NLr3OJ5XO42DlvjohprVo,232
30
+ cmem_cmemc/manual_helper/__init__.py,sha256=G3Lqw2aPxo8x63Tg7L0aa5VD9BMaRzZDmhrog7IuEPg,43
31
+ cmem_cmemc/manual_helper/graph.py,sha256=qDchHdjRRDW2oZ66by81NxhoDgNxXaAUxq2keewEiVU,3598
32
+ cmem_cmemc/manual_helper/multi_page.py,sha256=5nvN1P7zTgzrnuoT7yA7abyT7EOVa24Jvp3Q2xZmXro,12236
33
+ cmem_cmemc/manual_helper/single_page.py,sha256=sVSeaZmPa-Cs6dtp27MqyiO6rIrskY9BtDyeAZhBWXM,1477
34
+ cmem_cmemc/migrations/__init__.py,sha256=i6Ri7qN58ou_MwOzm2KibPkXOD7u-1ELky-nUE5LjAA,24
35
+ cmem_cmemc/migrations/abc.py,sha256=Q4G0tRiFruawm6qvvSC_02FkDTC-Jav4VP2Suoy5hzE,3512
36
+ cmem_cmemc/migrations/access_conditions_243.py,sha256=kqSEDZkcj4FQcE_BkYA0MN8sAg8EjeDCEa18DoErVcc,4850
37
+ cmem_cmemc/migrations/bootstrap_data.py,sha256=4BLzwRAG5Jc9X1hzXvS1vq2_4dZ2IcKLIVHthgue8hE,971
38
+ cmem_cmemc/migrations/shapes_widget_integrations_243.py,sha256=hgNImornRV9dMJWyEWd0IsTQbHtqXTpT0MWQSXuAzDk,5941
39
+ cmem_cmemc/migrations/workspace_configurations.py,sha256=tFmCdfEL10ICjqMXQEIf-9fveE41HBQ_jaWNQJENz50,998
40
+ cmem_cmemc/object_list.py,sha256=NYArisZxCV4pws_Tgk_xyltLN6TStkxQAgy-WLlzOxc,14712
41
+ cmem_cmemc/parameter_types/__init__.py,sha256=Jqhwnw5a2oPNMClzUyovWiieK60RCl3rvSNr-t3wP84,36
42
+ cmem_cmemc/parameter_types/path.py,sha256=hrisrXA1V8AtlWv-zxMYFGyf3RBCet4CW-Z2yTmhcwg,2002
43
+ cmem_cmemc/smart_path/__init__.py,sha256=zDgm1kDrzLyCuIcNb8VXSdnb_CcVNjGkjgiIDVlsh74,3023
44
+ cmem_cmemc/smart_path/clients/__init__.py,sha256=YFOm69BfTCRvAcJjN_CoUmCv3kzEciyYOPUG337p_pA,1696
45
+ cmem_cmemc/smart_path/clients/http.py,sha256=3clZu2v4uuOvPY4MY_8SVSy7hIXJDNooahFRBRpy0ok,2347
46
+ cmem_cmemc/string_processor.py,sha256=266Mk9a2zTNzndlyOAsz0mYgpHkYvz9KC0NU-tcIN30,2730
47
+ cmem_cmemc/title_helper.py,sha256=7frjAR54_Xc1gszOWXfzSmKFTawNJQ7kkXhZcHmQLyw,1250
48
+ cmem_cmemc/utils.py,sha256=svkyYTq41SI7BCSaeyfJCe_O3gAdsKGw0IrqQYiLhrc,12782
49
+ cmem_cmemc-24.3.0rc1.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
50
+ cmem_cmemc-24.3.0rc1.dist-info/METADATA,sha256=sd9s-V-2tMI0Obi5v_ceKstENrCdr-cjpXWz4hw5zb0,5619
51
+ cmem_cmemc-24.3.0rc1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
52
+ cmem_cmemc-24.3.0rc1.dist-info/entry_points.txt,sha256=znWUTG-zgDITu6Frsd-OtNxBxj6Uo8Fa7bz6gaZYMrA,41
53
+ cmem_cmemc-24.3.0rc1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.8.1
2
+ Generator: poetry-core 1.9.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,69 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: cmem-cmemc
3
- Version: 24.2.0rc2
4
- Summary: Command line client for eccenca Corporate Memory
5
- Home-page: https://eccenca.com/go/cmemc
6
- License: Apache 2.0
7
- Author: eccenca
8
- Author-email: cmempy-developer@eccenca.com
9
- Requires-Python: >=3.9,<4.0
10
- Classifier: Development Status :: 5 - Production/Stable
11
- Classifier: Intended Audience :: Developers
12
- Classifier: Intended Audience :: Science/Research
13
- Classifier: Intended Audience :: System Administrators
14
- Classifier: License :: OSI Approved :: Apache Software License
15
- Classifier: License :: Other/Proprietary License
16
- Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.9
18
- Classifier: Programming Language :: Python :: 3.10
19
- Classifier: Programming Language :: Python :: 3.11
20
- Classifier: Programming Language :: Python :: 3.12
21
- Classifier: Topic :: Database
22
- Classifier: Topic :: Software Development :: Testing
23
- Classifier: Topic :: Utilities
24
- Requires-Dist: beautifulsoup4 (>=4.12.2,<5.0.0)
25
- Requires-Dist: certifi (>=2023.5.7)
26
- Requires-Dist: click (>=8.1.7,<9.0.0)
27
- Requires-Dist: click-didyoumean (>=0.3.0,<0.4.0)
28
- Requires-Dist: click-help-colors (>=0.9.1,<0.10.0)
29
- Requires-Dist: cmem-cmempy (==24.1.0)
30
- Requires-Dist: configparser (>=5.3.0,<6.0.0)
31
- Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
32
- Requires-Dist: junit-xml (>=1.9,<2.0)
33
- Requires-Dist: natsort (>=8.3.1,<9.0.0)
34
- Requires-Dist: prometheus-client (>=0.16.0,<0.17.0)
35
- Requires-Dist: pygments (>=2.15.1,<3.0.0)
36
- Requires-Dist: pyjwt (>=2.7.0,<3.0.0)
37
- Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
38
- Requires-Dist: requests (>=2.31.0,<3.0.0)
39
- Requires-Dist: rich (>=13.7.0,<14.0.0)
40
- Requires-Dist: six (>=1.16.0,<2.0.0)
41
- Requires-Dist: timeago (>=1.0.16,<2.0.0)
42
- Requires-Dist: treelib (>=1.6.4,<2.0.0)
43
- Requires-Dist: urllib3 (>=2,<3)
44
- Description-Content-Type: text/markdown
45
-
46
- # cmemc
47
-
48
- cmemc is the official command line client for [eccenca Corporate Memory](https://documentation.eccenca.com/).
49
-
50
- ## Installation
51
-
52
- In order to install the cmemc, run:
53
-
54
- pipx install cmem-cmemc
55
-
56
- Of course you can install cmemc also with pip, but we recommend [pipx](https://pypa.github.io/pipx/) for normal desktop usage.
57
-
58
- ## Configuration and Usage
59
-
60
- cmemc is intended for System Administrators and Linked Data Expert, who wants to automate and remote control activities on eccenca Corporate Memory.
61
-
62
- The cmemc manual including basic usage pattern, configuration as well as a command reference is available at:
63
-
64
- [https://eccenca.com/go/cmemc](https://eccenca.com/go/cmemc)
65
-
66
- cmemc only works with Python 3 and refuses to work with Python 2.x.
67
- In addition to that, cmemc will warn you in case an untested Python environment is used.
68
-
69
-