rudi-node-write 1.2.2__tar.gz → 1.3.0__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.
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/PKG-INFO +24 -17
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/README.md +1 -1
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/pyproject.toml +30 -14
- rudi_node_write-1.3.0/requirements-dev.txt +112 -0
- rudi_node_write-1.3.0/requirements.txt +7 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/connectors/io_connector.py +63 -37
- rudi_node_write-1.2.2/src/rudi_node_write/connectors/io_rudi_api_write.py → rudi_node_write-1.3.0/src/rudi_node_write/connectors/io_rudi_catalog_write.py +20 -24
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/connectors/io_rudi_jwt_factory.py +1 -1
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/connectors/io_rudi_manager_write.py +151 -113
- rudi_node_write-1.3.0/src/rudi_node_write/connectors/io_rudi_manager_write_v2.py +122 -0
- rudi_node_write-1.3.0/src/rudi_node_write/connectors/io_rudi_manager_write_v3.py +1414 -0
- rudi_node_write-1.2.2/src/rudi_node_write/connectors/io_rudi_media_write.py → rudi_node_write-1.3.0/src/rudi_node_write/connectors/io_rudi_storage_write.py +4 -4
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_node_writer.py +75 -23
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_const.py +3 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_dictionary_entry.py +1 -1
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_media.py +2 -1
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_meta.py +8 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/err.py +5 -4
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/file_utils.py +23 -3
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/list_utils.py +2 -4
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/str_utils.py +1 -1
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write.egg-info/PKG-INFO +24 -17
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write.egg-info/SOURCES.txt +4 -2
- rudi_node_write-1.3.0/src/rudi_node_write.egg-info/requires.txt +31 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/tests/test_rudi_node_write.py +5 -8
- rudi_node_write-1.2.2/requirements-dev.txt +0 -102
- rudi_node_write-1.2.2/requirements.txt +0 -6
- rudi_node_write-1.2.2/src/rudi_node_write.egg-info/requires.txt +0 -24
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/LICENCE.md +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/setup.cfg +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/__init__.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/conf/meta_defaults.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/connectors/rudi_node_auth.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_contact.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_dates.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_geo.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_licence.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_meta_misc.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/rudi_org.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/rudi_types/serializable.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/dict_utils.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/html_utils.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/jwt.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/log.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/type_date.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/typing_utils.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/utils/url_utils.py +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write.egg-info/dependency_links.txt +0 -0
- {rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write.egg-info/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: rudi-node-write
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Use the internal API of a RUDI Producer node
|
|
5
5
|
Author-email: Olivier Martineau <olivier.martineau@irisa.fr>
|
|
6
6
|
Maintainer-email: Olivier Martineau <olivier.martineau@irisa.fr>
|
|
7
|
-
License: EUPL-1.2
|
|
7
|
+
License-Expression: EUPL-1.2
|
|
8
8
|
Project-URL: Homepage, https://github.com/OlivierMartineau/rudi-node-write
|
|
9
9
|
Project-URL: Documentation, https://app.swaggerhub.com/apis/OlivierMartineau/RudiProducer-InternalAPI
|
|
10
10
|
Project-URL: Repository, https://github.com/OlivierMartineau/rudi-node-write
|
|
@@ -13,33 +13,40 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
14
|
Classifier: Natural Language :: English
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
|
-
Classifier: License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)
|
|
17
16
|
Requires-Python: >=3.11
|
|
18
17
|
Description-Content-Type: text/markdown
|
|
19
18
|
License-File: LICENCE.md
|
|
20
|
-
Requires-Dist: beautifulsoup4==4.
|
|
19
|
+
Requires-Dist: beautifulsoup4==4.13.4
|
|
21
20
|
Requires-Dist: chardet==5.2.0
|
|
22
|
-
Requires-Dist: deepdiff==8.
|
|
21
|
+
Requires-Dist: deepdiff==8.4.2
|
|
23
22
|
Requires-Dist: puremagic==1.28
|
|
24
23
|
Provides-Extra: dev
|
|
25
|
-
Requires-Dist:
|
|
24
|
+
Requires-Dist: backports.tarfile==1.2.0; extra == "dev"
|
|
25
|
+
Requires-Dist: black==25.1.0; extra == "dev"
|
|
26
26
|
Requires-Dist: build==1.2.2.post1; extra == "dev"
|
|
27
|
-
Requires-Dist: commitizen==
|
|
28
|
-
Requires-Dist:
|
|
29
|
-
Requires-Dist:
|
|
27
|
+
Requires-Dist: commitizen==4.6.0; extra == "dev"
|
|
28
|
+
Requires-Dist: flake8==7.2.0; extra == "dev"
|
|
29
|
+
Requires-Dist: importlib-metadata==8.6.1; extra == "dev"
|
|
30
|
+
Requires-Dist: importlib-resources==6.5.2; extra == "dev"
|
|
31
|
+
Requires-Dist: inflect==7.5.0; extra == "dev"
|
|
30
32
|
Requires-Dist: ipykernel==6.29.5; extra == "dev"
|
|
31
33
|
Requires-Dist: jaraco.collections==5.1.0; extra == "dev"
|
|
32
|
-
Requires-Dist: nbstripout==0.
|
|
34
|
+
Requires-Dist: nbstripout==0.8.1; extra == "dev"
|
|
33
35
|
Requires-Dist: ordered-set==4.1.0; extra == "dev"
|
|
34
36
|
Requires-Dist: pip-autoremove==0.10.0; extra == "dev"
|
|
35
37
|
Requires-Dist: pip-chill==1.0.3; extra == "dev"
|
|
36
38
|
Requires-Dist: pip-upgrade-outdated==1.5; extra == "dev"
|
|
37
39
|
Requires-Dist: pip3-autoremove==1.2.2; extra == "dev"
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Requires-Dist:
|
|
41
|
-
Requires-Dist:
|
|
42
|
-
Requires-Dist:
|
|
40
|
+
Requires-Dist: pkginfo==1.12.1.2; extra == "dev"
|
|
41
|
+
Requires-Dist: pre-commit==4.2.0; extra == "dev"
|
|
42
|
+
Requires-Dist: pre-commit-hooks==5.0.0; extra == "dev"
|
|
43
|
+
Requires-Dist: py-env==0.0.1; extra == "dev"
|
|
44
|
+
Requires-Dist: pyright==1.1.399; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-check==2.5.3; extra == "dev"
|
|
46
|
+
Requires-Dist: pytest-cov==6.1.1; extra == "dev"
|
|
47
|
+
Requires-Dist: tomli==2.2.1; extra == "dev"
|
|
48
|
+
Requires-Dist: twine==6.1.0; extra == "dev"
|
|
49
|
+
Dynamic: license-file
|
|
43
50
|
|
|
44
51
|
[](https://github.com/psf/black)
|
|
45
52
|
[](https://microsoft.github.io/pyright/)
|
|
@@ -49,7 +56,7 @@ Requires-Dist: twine==5.1.1; extra == "dev"
|
|
|
49
56
|
This library offers tools to take advantage of
|
|
50
57
|
the [internal API](https://app.swaggerhub.com/apis/OlivierMartineau/RudiProducer-InternalAPI) of a RUDI Producer node (
|
|
51
58
|
also
|
|
52
|
-
referred as RUDI node), through the API of the backend of the user interface, the "Producer node manager" or "
|
|
59
|
+
referred as RUDI node), through the API of the backend of the user interface, the "Producer node manager" or "RUDI Manager" module.
|
|
53
60
|
|
|
54
61
|
## Installation
|
|
55
62
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
This library offers tools to take advantage of
|
|
7
7
|
the [internal API](https://app.swaggerhub.com/apis/OlivierMartineau/RudiProducer-InternalAPI) of a RUDI Producer node (
|
|
8
8
|
also
|
|
9
|
-
referred as RUDI node), through the API of the backend of the user interface, the "Producer node manager" or "
|
|
9
|
+
referred as RUDI node), through the API of the backend of the user interface, the "Producer node manager" or "RUDI Manager" module.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -4,20 +4,31 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rudi-node-write"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.3.0"
|
|
8
8
|
authors = [{ name = "Olivier Martineau", email = "olivier.martineau@irisa.fr" }]
|
|
9
|
-
maintainers = [
|
|
9
|
+
maintainers = [
|
|
10
|
+
{ name = "Olivier Martineau", email = "olivier.martineau@irisa.fr" },
|
|
11
|
+
]
|
|
10
12
|
description = "Use the internal API of a RUDI Producer node"
|
|
11
13
|
readme = "README.md"
|
|
12
14
|
requires-python = ">=3.11"
|
|
13
|
-
license =
|
|
14
|
-
|
|
15
|
+
license-files = ["LICENCE.md"]
|
|
16
|
+
license = "EUPL-1.2"
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
15
19
|
"Programming Language :: Python :: 3.12",
|
|
16
20
|
"Natural Language :: English",
|
|
17
21
|
"Operating System :: OS Independent",
|
|
18
|
-
"License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)",
|
|
19
22
|
]
|
|
20
|
-
keywords = [
|
|
23
|
+
keywords = [
|
|
24
|
+
"rudi-node-write",
|
|
25
|
+
"rudi-node-put",
|
|
26
|
+
"RUDI",
|
|
27
|
+
"producer node",
|
|
28
|
+
"RUDI node",
|
|
29
|
+
"open-data",
|
|
30
|
+
"Univ. Rennes",
|
|
31
|
+
]
|
|
21
32
|
dynamic = ["dependencies", "optional-dependencies"]
|
|
22
33
|
# dependencies = ["beautifulsoup4", "chardet", "deepdiff", "puremagic"]
|
|
23
34
|
|
|
@@ -34,7 +45,7 @@ target-version = ['py311']
|
|
|
34
45
|
# ----- Tool: commitizen
|
|
35
46
|
[tool.commitizen]
|
|
36
47
|
name = "cz_conventional_commits"
|
|
37
|
-
version = "1.
|
|
48
|
+
version = "1.3.0"
|
|
38
49
|
version_files = ["pyproject.toml:version"]
|
|
39
50
|
|
|
40
51
|
# ----- Tool: pytest
|
|
@@ -42,7 +53,12 @@ version_files = ["pyproject.toml:version"]
|
|
|
42
53
|
pythonpath = ["src"]
|
|
43
54
|
norecursedirs = ["*.egg", ".eggs", "dist", "build", "wip"]
|
|
44
55
|
filterwarnings = ["ignore:.*pkg_resources.*:DeprecationWarning"]
|
|
45
|
-
addopts = [
|
|
56
|
+
addopts = [
|
|
57
|
+
"--cov=rudi_node_write",
|
|
58
|
+
"--cov-report=term-missing",
|
|
59
|
+
"--cov-report=html:reports/html_dir",
|
|
60
|
+
"--cov-report=xml:reports/coverage.xml",
|
|
61
|
+
]
|
|
46
62
|
|
|
47
63
|
# ----- Tool: setuptools
|
|
48
64
|
[tool.setuptools.packages.find]
|
|
@@ -50,17 +66,17 @@ where = ["src"]
|
|
|
50
66
|
include = ["rudi_node_write*"]
|
|
51
67
|
|
|
52
68
|
[tool.setuptools.dynamic]
|
|
53
|
-
dependencies = {file = ["requirements.txt"]}
|
|
54
|
-
optional-dependencies = {dev = { file = ["requirements-dev.txt"] }}
|
|
69
|
+
dependencies = { file = ["requirements.txt"] }
|
|
70
|
+
optional-dependencies = { dev = { file = ["requirements-dev.txt"] } }
|
|
55
71
|
|
|
56
72
|
# ----- Tool: pyright
|
|
57
73
|
[tool.pyright]
|
|
58
74
|
exclude = ["**/node_modules", "**/__pycache__"]
|
|
59
75
|
include = ["src"]
|
|
60
76
|
pythonVersion = "3.11"
|
|
61
|
-
reportMissingImports =
|
|
62
|
-
reportDuplicateImport =
|
|
63
|
-
reportUnusedImport =
|
|
64
|
-
reportImportCycles =
|
|
77
|
+
reportMissingImports = true
|
|
78
|
+
reportDuplicateImport = true
|
|
79
|
+
reportUnusedImport = true
|
|
80
|
+
reportImportCycles = true
|
|
65
81
|
venvPath = "."
|
|
66
82
|
venv = ".venv"
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
backports.tarfile==1.2.0
|
|
2
|
+
black==25.1.0
|
|
3
|
+
build==1.2.2.post1
|
|
4
|
+
commitizen==4.6.0
|
|
5
|
+
flake8==7.2.0
|
|
6
|
+
importlib-metadata==8.6.1
|
|
7
|
+
importlib-resources==6.5.2
|
|
8
|
+
inflect==7.5.0
|
|
9
|
+
ipykernel==6.29.5
|
|
10
|
+
jaraco.collections==5.1.0
|
|
11
|
+
nbstripout==0.8.1
|
|
12
|
+
ordered-set==4.1.0
|
|
13
|
+
pip-autoremove==0.10.0
|
|
14
|
+
pip-chill==1.0.3
|
|
15
|
+
pip-upgrade-outdated==1.5
|
|
16
|
+
pip3-autoremove==1.2.2
|
|
17
|
+
pkginfo==1.12.1.2
|
|
18
|
+
pre-commit==4.2.0
|
|
19
|
+
pre-commit-hooks==5.0.0
|
|
20
|
+
py-env==0.0.1
|
|
21
|
+
pyright==1.1.399
|
|
22
|
+
pytest-check==2.5.3
|
|
23
|
+
pytest-cov==6.1.1
|
|
24
|
+
tomli==2.2.1
|
|
25
|
+
twine==6.1.0
|
|
26
|
+
# appnope==0.1.4 # Installed as dependency for ipykernel
|
|
27
|
+
# argcomplete==3.6.2 # Installed as dependency for commitizen
|
|
28
|
+
# asttokens==3.0.0 # Installed as dependency for stack-data
|
|
29
|
+
# attrs==25.3.0 # Installed as dependency for jsonschema, referencing
|
|
30
|
+
# autocommand==2.2.2 # Installed as dependency for jaraco.text
|
|
31
|
+
# certifi==2025.1.31 # Installed as dependency for requests
|
|
32
|
+
# cfgv==3.4.0 # Installed as dependency for pre-commit
|
|
33
|
+
# charset-normalizer==3.4.1 # Installed as dependency for commitizen, requests
|
|
34
|
+
# click==8.1.8 # Installed as dependency for black
|
|
35
|
+
# colorama==0.4.6 # Installed as dependency for commitizen
|
|
36
|
+
# comm==0.2.2 # Installed as dependency for ipykernel
|
|
37
|
+
# coverage==7.8.0 # Installed as dependency for pytest-cov
|
|
38
|
+
# debugpy==1.8.14 # Installed as dependency for ipykernel
|
|
39
|
+
# decli==0.6.2 # Installed as dependency for commitizen
|
|
40
|
+
# decorator==5.2.1 # Installed as dependency for ipython
|
|
41
|
+
# distlib==0.3.9 # Installed as dependency for virtualenv
|
|
42
|
+
# docutils==0.21.2 # Installed as dependency for readme-renderer
|
|
43
|
+
# executing==2.2.0 # Installed as dependency for stack-data
|
|
44
|
+
# fastjsonschema==2.21.1 # Installed as dependency for nbformat
|
|
45
|
+
# filelock==3.18.0 # Installed as dependency for virtualenv
|
|
46
|
+
# id==1.5.0 # Installed as dependency for twine
|
|
47
|
+
# identify==2.6.10 # Installed as dependency for pre-commit
|
|
48
|
+
# idna==3.10 # Installed as dependency for requests
|
|
49
|
+
# iniconfig==2.1.0 # Installed as dependency for pytest
|
|
50
|
+
# ipython==9.1.0 # Installed as dependency for ipykernel
|
|
51
|
+
# ipython-pygments-lexers==1.1.1 # Installed as dependency for ipython
|
|
52
|
+
# jaraco.classes==3.4.0 # Installed as dependency for keyring
|
|
53
|
+
# jaraco.context==6.0.1 # Installed as dependency for jaraco.text, keyring
|
|
54
|
+
# jaraco.functools==4.1.0 # Installed as dependency for jaraco.text, keyring
|
|
55
|
+
# jaraco.text==4.0.0 # Installed as dependency for jaraco.collections
|
|
56
|
+
# jedi==0.19.2 # Installed as dependency for ipython
|
|
57
|
+
# jinja2==3.1.6 # Installed as dependency for commitizen
|
|
58
|
+
# jsonschema==4.23.0 # Installed as dependency for nbformat
|
|
59
|
+
# jsonschema-specifications==2024.10.1 # Installed as dependency for jsonschema
|
|
60
|
+
# jupyter-client==8.6.3 # Installed as dependency for ipykernel
|
|
61
|
+
# jupyter-core==5.7.2 # Installed as dependency for ipykernel, jupyter-client, nbformat
|
|
62
|
+
# keyring==25.6.0 # Installed as dependency for twine
|
|
63
|
+
# markdown-it-py==3.0.0 # Installed as dependency for rich
|
|
64
|
+
# markupsafe==3.0.2 # Installed as dependency for jinja2
|
|
65
|
+
# matplotlib-inline==0.1.7 # Installed as dependency for ipykernel, ipython
|
|
66
|
+
# mccabe==0.7.0 # Installed as dependency for flake8
|
|
67
|
+
# mdurl==0.1.2 # Installed as dependency for markdown-it-py
|
|
68
|
+
# more-itertools==10.7.0 # Installed as dependency for inflect, jaraco.classes, jaraco.functools, jaraco.text
|
|
69
|
+
# mypy-extensions==1.1.0 # Installed as dependency for black
|
|
70
|
+
# nbformat==5.10.4 # Installed as dependency for nbstripout
|
|
71
|
+
# nest-asyncio==1.6.0 # Installed as dependency for ipykernel
|
|
72
|
+
# nh3==0.2.21 # Installed as dependency for readme-renderer
|
|
73
|
+
# nodeenv==1.9.1 # Installed as dependency for pre-commit, pyright
|
|
74
|
+
# packaging==25.0 # Installed as dependency for black, build, commitizen, ipykernel, pytest, twine
|
|
75
|
+
# parso==0.8.4 # Installed as dependency for jedi
|
|
76
|
+
# pathspec==0.12.1 # Installed as dependency for black
|
|
77
|
+
# pexpect==4.9.0 # Installed as dependency for ipython
|
|
78
|
+
# platformdirs==4.3.7 # Installed as dependency for black, jupyter-core, virtualenv
|
|
79
|
+
# pluggy==1.5.0 # Installed as dependency for pytest
|
|
80
|
+
# prompt-toolkit==3.0.51 # Installed as dependency for ipython, questionary
|
|
81
|
+
# psutil==7.0.0 # Installed as dependency for ipykernel
|
|
82
|
+
# ptyprocess==0.7.0 # Installed as dependency for pexpect
|
|
83
|
+
# pure-eval==0.2.3 # Installed as dependency for stack-data
|
|
84
|
+
# pycodestyle==2.13.0 # Installed as dependency for flake8
|
|
85
|
+
# pyflakes==3.3.2 # Installed as dependency for flake8
|
|
86
|
+
# pygments==2.19.1 # Installed as dependency for ipython, ipython-pygments-lexers, readme-renderer, rich
|
|
87
|
+
# pyproject-hooks==1.2.0 # Installed as dependency for build
|
|
88
|
+
# pytest==8.3.5 # Installed as dependency for pytest-check, pytest-cov
|
|
89
|
+
# python-dateutil==2.9.0.post0 # Installed as dependency for jupyter-client
|
|
90
|
+
# pyyaml==6.0.2 # Installed as dependency for commitizen, pre-commit
|
|
91
|
+
# pyzmq==26.4.0 # Installed as dependency for ipykernel, jupyter-client
|
|
92
|
+
# questionary==2.1.0 # Installed as dependency for commitizen
|
|
93
|
+
# readme-renderer==44.0 # Installed as dependency for twine
|
|
94
|
+
# referencing==0.36.2 # Installed as dependency for jsonschema, jsonschema-specifications
|
|
95
|
+
# requests==2.32.3 # Installed as dependency for id, requests-toolbelt, twine
|
|
96
|
+
# requests-toolbelt==1.0.0 # Installed as dependency for twine
|
|
97
|
+
# rfc3986==2.0.0 # Installed as dependency for twine
|
|
98
|
+
# rich==14.0.0 # Installed as dependency for twine
|
|
99
|
+
# rpds-py==0.24.0 # Installed as dependency for jsonschema, referencing
|
|
100
|
+
# ruamel.yaml==0.18.10 # Installed as dependency for pre-commit-hooks
|
|
101
|
+
# ruamel.yaml.clib==0.2.12 # Installed as dependency for ruamel.yaml
|
|
102
|
+
# six==1.17.0 # Installed as dependency for python-dateutil
|
|
103
|
+
# stack-data==0.6.3 # Installed as dependency for ipython
|
|
104
|
+
# termcolor==3.0.1 # Installed as dependency for commitizen
|
|
105
|
+
# tomlkit==0.13.2 # Installed as dependency for commitizen
|
|
106
|
+
# tornado==6.4.2 # Installed as dependency for ipykernel, jupyter-client
|
|
107
|
+
# traitlets==5.14.3 # Installed as dependency for comm, ipykernel, ipython, jupyter-client, jupyter-core, matplotlib-inline, nbformat
|
|
108
|
+
# typeguard==4.4.2 # Installed as dependency for inflect
|
|
109
|
+
# urllib3==2.4.0 # Installed as dependency for requests, twine
|
|
110
|
+
# virtualenv==20.30.0 # Installed as dependency for pre-commit
|
|
111
|
+
# wcwidth==0.2.13 # Installed as dependency for prompt-toolkit
|
|
112
|
+
# zipp==3.21.0 # Installed as dependency for importlib-metadata
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
beautifulsoup4==4.13.4
|
|
2
|
+
chardet==5.2.0
|
|
3
|
+
deepdiff==8.4.2
|
|
4
|
+
puremagic==1.28
|
|
5
|
+
# orderly-set==5.4.0 # Installed as dependency for deepdiff
|
|
6
|
+
# soupsieve==2.7 # Installed as dependency for beautifulsoup4
|
|
7
|
+
# typing-extensions==4.13.2 # Installed as dependency for beautifulsoup4, pyright, referencing, typeguard
|
{rudi_node_write-1.2.2 → rudi_node_write-1.3.0}/src/rudi_node_write/connectors/io_connector.py
RENAMED
|
@@ -7,7 +7,7 @@ from rudi_node_write.rudi_types.rudi_const import check_is_literal
|
|
|
7
7
|
from rudi_node_write.rudi_types.serializable import Serializable
|
|
8
8
|
from rudi_node_write.utils.dict_utils import is_dict, safe_get_key
|
|
9
9
|
from rudi_node_write.utils.err import HttpError
|
|
10
|
-
from rudi_node_write.utils.log import log_d_if, log_e, log_d
|
|
10
|
+
from rudi_node_write.utils.log import log_d_if, log_e, log_d, log_w
|
|
11
11
|
from rudi_node_write.utils.str_utils import slash_join
|
|
12
12
|
from rudi_node_write.utils.url_utils import get_response_cookies, url_encode_req_params
|
|
13
13
|
|
|
@@ -55,6 +55,9 @@ class Connector:
|
|
|
55
55
|
self._set_url(server_url)
|
|
56
56
|
self._cookies = None
|
|
57
57
|
|
|
58
|
+
self.should_log_request: bool = True
|
|
59
|
+
self.should_log_response: bool = False
|
|
60
|
+
|
|
58
61
|
def _set_url(self, server_url: str):
|
|
59
62
|
here = f"super.{self.class_name}._set_url"
|
|
60
63
|
(scheme, netloc, path, query, fragment) = urlsplit(server_url)
|
|
@@ -73,6 +76,10 @@ class Connector:
|
|
|
73
76
|
def full_url(self, relative_url: str = "/"):
|
|
74
77
|
return slash_join(self.base_url, url_encode_req_params(relative_url))
|
|
75
78
|
|
|
79
|
+
def set_path(self, new_path: str):
|
|
80
|
+
self.path = new_path
|
|
81
|
+
self.base_url = slash_join(f"{self.scheme}://{self.host}", self.path)
|
|
82
|
+
|
|
76
83
|
def full_path(self, relative_url: str = "/"):
|
|
77
84
|
return slash_join("/", self.path, url_encode_req_params(relative_url))
|
|
78
85
|
|
|
@@ -92,7 +99,6 @@ class Connector:
|
|
|
92
99
|
relative_url: str,
|
|
93
100
|
headers: dict | None = None,
|
|
94
101
|
keep_alive: bool = False,
|
|
95
|
-
should_log_response: bool = False,
|
|
96
102
|
):
|
|
97
103
|
"""
|
|
98
104
|
Download a file on the connector server
|
|
@@ -118,7 +124,7 @@ class Connector:
|
|
|
118
124
|
log_e(here, f"ERR {response.status}", path_url)
|
|
119
125
|
return None
|
|
120
126
|
else:
|
|
121
|
-
log_d_if(should_log_response, here, f"OK {response.status}", path_url)
|
|
127
|
+
log_d_if(self.should_log_response, here, f"OK {response.status}", path_url)
|
|
122
128
|
res_data = response.read()
|
|
123
129
|
if not keep_alive and not self.keep_connection:
|
|
124
130
|
self.connection.close()
|
|
@@ -133,9 +139,7 @@ class Connector:
|
|
|
133
139
|
body: dict | str | list | Serializable | BinaryIO | TextIO | None = None,
|
|
134
140
|
headers=None,
|
|
135
141
|
keep_alive: bool = False,
|
|
136
|
-
|
|
137
|
-
should_log_response: bool = False,
|
|
138
|
-
):
|
|
142
|
+
) -> dict | str | list | None:
|
|
139
143
|
"""
|
|
140
144
|
Send a http(s) request
|
|
141
145
|
:param relative_url: a relative URL that will be joined to the connector's base URL to form the request URL
|
|
@@ -153,23 +157,28 @@ class Connector:
|
|
|
153
157
|
|
|
154
158
|
if headers is None:
|
|
155
159
|
headers = DEFAULT_HEADERS
|
|
156
|
-
if
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
if req_method == "POST" or req_method == "PUT":
|
|
161
|
+
if isinstance(body, dict):
|
|
162
|
+
headers["Content-Type"] = "application/json"
|
|
163
|
+
body_str = dumps(body)
|
|
164
|
+
elif isinstance(body, Serializable):
|
|
165
|
+
headers["Content-Type"] = "application/json"
|
|
166
|
+
body_str = body.to_json_str(ensure_ascii=True)
|
|
167
|
+
elif isinstance(body, list):
|
|
168
|
+
body_str = str(list)
|
|
169
|
+
else:
|
|
170
|
+
body_str = body
|
|
164
171
|
else:
|
|
165
|
-
|
|
172
|
+
# log_w(here, f"Body is ignored since http method used is {req_method}")
|
|
173
|
+
body_str = None
|
|
166
174
|
|
|
167
175
|
path_url = self.full_path(relative_url)
|
|
168
176
|
if self.host is None:
|
|
169
177
|
raise ConnectionError("The connector host should be defined")
|
|
170
178
|
self.connection = HTTPConnection(self.host) if self.scheme == "http" else HTTPSConnection(self.host)
|
|
171
179
|
|
|
172
|
-
log_d_if(should_log_request, here, req_method, self.full_url(relative_url))
|
|
180
|
+
# log_d_if(self.should_log_request, here, req_method, self.full_url(relative_url))
|
|
181
|
+
log_d_if(self.should_log_request, here, req_method, self.full_url(relative_url))
|
|
173
182
|
|
|
174
183
|
try:
|
|
175
184
|
self.connection.request(method=req_method, url=path_url, body=body_str, headers=headers) # type: ignore
|
|
@@ -177,19 +186,35 @@ class Connector:
|
|
|
177
186
|
log_e(here, "Error on request", req_method, self.full_url(relative_url))
|
|
178
187
|
log_e(here, "ERR", e)
|
|
179
188
|
raise e
|
|
180
|
-
|
|
189
|
+
res = self.parse_response(
|
|
181
190
|
relative_url=relative_url,
|
|
182
191
|
req_method=req_method,
|
|
183
192
|
keep_alive=keep_alive,
|
|
184
|
-
should_log_response=should_log_response,
|
|
185
193
|
)
|
|
194
|
+
return res
|
|
195
|
+
# if not isinstance(res, dict):
|
|
196
|
+
# return res
|
|
197
|
+
# redirect_url = res.get("redirection")
|
|
198
|
+
# if redirect_url is None:
|
|
199
|
+
# return res
|
|
200
|
+
|
|
201
|
+
# try:
|
|
202
|
+
# self.request(method=req_method, url=redirect_url, body=body_str, headers=headers) # type: ignore
|
|
203
|
+
# except ConnectionRefusedError as e:
|
|
204
|
+
# log_e(here, "Error on redirected request", req_method, self.full_url(relative_url))
|
|
205
|
+
# log_e(here, "ERR", e)
|
|
206
|
+
# raise e
|
|
207
|
+
# return self.parse_response(
|
|
208
|
+
# relative_url=relative_url,
|
|
209
|
+
# req_method=req_method,
|
|
210
|
+
# keep_alive=keep_alive,
|
|
211
|
+
# )
|
|
186
212
|
|
|
187
213
|
def parse_response(
|
|
188
214
|
self,
|
|
189
215
|
relative_url: str,
|
|
190
216
|
req_method: HttpRequestMethod,
|
|
191
217
|
keep_alive: bool = False,
|
|
192
|
-
should_log_response: bool = True,
|
|
193
218
|
):
|
|
194
219
|
"""Basic parsing of the result"""
|
|
195
220
|
here = f"{self.class_name}.parse_response"
|
|
@@ -198,37 +223,38 @@ class Connector:
|
|
|
198
223
|
response = self.connection.getresponse()
|
|
199
224
|
self._cookies = get_response_cookies(response)
|
|
200
225
|
|
|
201
|
-
if response.status in [301, 302]:
|
|
202
|
-
return {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
)
|
|
208
|
-
|
|
226
|
+
if response.status in [301, 302, 307, 308]:
|
|
227
|
+
return {"status": response.status, "from": relative_url, "redirection": response.getheader("location")}
|
|
228
|
+
|
|
229
|
+
# if (
|
|
230
|
+
# response.status not in [200, 500, 501]
|
|
231
|
+
# and not (530 <= response.status < 540)
|
|
232
|
+
# and not (400 <= response.status < 500)
|
|
233
|
+
# ):
|
|
234
|
+
# return None
|
|
209
235
|
|
|
210
236
|
rdata = response.read()
|
|
211
237
|
# log_d(here, "rdata", rdata)
|
|
212
238
|
try:
|
|
213
239
|
response_data = loads(rdata)
|
|
214
|
-
log_d_if(should_log_response, here, "Response is a JSON", response_data)
|
|
240
|
+
log_d_if(self.should_log_response, here, "Response is a JSON", response_data)
|
|
215
241
|
except (TypeError, JSONDecodeError):
|
|
216
242
|
response_data = repr(rdata)
|
|
217
|
-
log_d_if(should_log_response, here, "Response is not a JSON", response_data)
|
|
243
|
+
log_d_if(self.should_log_response, here, "Response is not a JSON", response_data)
|
|
218
244
|
if not keep_alive and not self.keep_connection:
|
|
219
245
|
self.close_connection()
|
|
220
246
|
|
|
221
247
|
if type(response_data) is str:
|
|
222
|
-
log_d_if(should_log_response, here, "Response is a string", response_data)
|
|
223
|
-
if response.status
|
|
248
|
+
log_d_if(self.should_log_response, here, "Response is a string", response_data)
|
|
249
|
+
if response.status < 400:
|
|
224
250
|
return rdata.decode("utf8")
|
|
225
|
-
if response.status
|
|
251
|
+
if response.status < 400:
|
|
226
252
|
return response_data
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
253
|
+
|
|
254
|
+
log_e(here, "Connection error", response_data)
|
|
255
|
+
log_e(here, "Request in error", req_method, self.full_url(relative_url))
|
|
256
|
+
# log_e(here, "Headers", response.headers)
|
|
257
|
+
raise HttpError(response_data, response.status, req_method, self.base_url, relative_url)
|
|
232
258
|
|
|
233
259
|
|
|
234
260
|
if __name__ == "__main__": # pragma: no cover
|
|
@@ -41,20 +41,20 @@ _STATUS_SKIPPED = "skipped"
|
|
|
41
41
|
_STATUS_MISSING = "missing"
|
|
42
42
|
_STATUS_DOWNLOADED = "downloaded"
|
|
43
43
|
|
|
44
|
-
here = "
|
|
44
|
+
here = "RudiNodeCatalogConnector"
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def ensure_url_startswith_api_admin(url):
|
|
48
48
|
return ensure_url_startswith(url, "api/admin")
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
class
|
|
51
|
+
class RudiNodeCatalogConnector(Connector):
|
|
52
52
|
def __init__(
|
|
53
53
|
self,
|
|
54
54
|
server_url: str,
|
|
55
55
|
jwt_factory: RudiNodeJwtFactory | None = None,
|
|
56
56
|
jwt: str | None = None,
|
|
57
|
-
headers_user_agent: str = "
|
|
57
|
+
headers_user_agent: str = "RudiNodeCatalogConnector",
|
|
58
58
|
):
|
|
59
59
|
"""
|
|
60
60
|
Creates a connector to the internal API of the API/proxy module of a RUDI producer node.
|
|
@@ -116,9 +116,7 @@ class RudiNodeApiConnector(Connector):
|
|
|
116
116
|
def _headers(self):
|
|
117
117
|
return self._initial_headers | {"Authorization": f"Bearer {self._jwt}"}
|
|
118
118
|
|
|
119
|
-
def get_admin_api(
|
|
120
|
-
self, url: str, keep_alive: bool = False, should_log_request=False, should_log_response=False
|
|
121
|
-
) -> str | int | list | dict:
|
|
119
|
+
def get_admin_api(self, url: str, keep_alive: bool = False) -> str | int | list | dict:
|
|
122
120
|
"""
|
|
123
121
|
Performs an identified GET request through /api/admin path
|
|
124
122
|
:param url: part of the URL that comes after /api/admin
|
|
@@ -131,8 +129,6 @@ class RudiNodeApiConnector(Connector):
|
|
|
131
129
|
relative_url=ensure_url_startswith_api_admin(url),
|
|
132
130
|
headers=self._headers,
|
|
133
131
|
keep_alive=keep_alive,
|
|
134
|
-
should_log_request=should_log_request,
|
|
135
|
-
should_log_response=should_log_response,
|
|
136
132
|
) # type: ignore
|
|
137
133
|
|
|
138
134
|
def put_admin_api(
|
|
@@ -637,7 +633,7 @@ class RudiNodeApiConnector(Connector):
|
|
|
637
633
|
:param local_download_dir: the path to a local folder
|
|
638
634
|
:return: an object that states if the file was downloaded, skipped or found missing
|
|
639
635
|
"""
|
|
640
|
-
here = "
|
|
636
|
+
here = "RudiNodeCatalogConnector.download_file_from_media_info"
|
|
641
637
|
|
|
642
638
|
media_type = media.get("media_type")
|
|
643
639
|
|
|
@@ -771,26 +767,26 @@ class RudiNodeApiConnector(Connector):
|
|
|
771
767
|
|
|
772
768
|
if __name__ == "__main__": # pragma: no cover
|
|
773
769
|
# ----------- INIT -----------
|
|
774
|
-
tests = "
|
|
770
|
+
tests = "RudiNodeCatalogConnector tests"
|
|
775
771
|
begin = time()
|
|
776
772
|
creds_file = "../creds/creds_bas.json"
|
|
777
773
|
rudi_node_creds = read_json_file(creds_file)
|
|
778
774
|
url = rudi_node_creds["url"]
|
|
779
775
|
|
|
780
|
-
|
|
781
|
-
|
|
776
|
+
jwt_factory = RudiNodeJwtFactory(url, rudi_node_creds)
|
|
777
|
+
catalog = RudiNodeCatalogConnector(server_url=url, jwt_factory=jwt_factory)
|
|
782
778
|
|
|
783
779
|
# ----------- TESTS -----------
|
|
784
780
|
test_dir = "../dwnld"
|
|
785
|
-
log_d(tests, "producers", len(
|
|
786
|
-
log_d(tests, "producer names",
|
|
787
|
-
log_d(tests, "metadata_contacts", len(
|
|
788
|
-
log_d(tests, "contact names",
|
|
781
|
+
log_d(tests, "producers", len(catalog.organization_list))
|
|
782
|
+
log_d(tests, "producer names", catalog.producer_names)
|
|
783
|
+
log_d(tests, "metadata_contacts", len(catalog.contact_list))
|
|
784
|
+
log_d(tests, "contact names", catalog.contact_names)
|
|
789
785
|
|
|
790
|
-
log_d(tests, "themes", len(
|
|
791
|
-
log_d(tests, "used_themes", len(
|
|
792
|
-
log_d(tests, "keywords", len(
|
|
793
|
-
log_d(tests, "used_keywords", len(
|
|
786
|
+
log_d(tests, "themes", len(catalog.themes))
|
|
787
|
+
log_d(tests, "used_themes", len(catalog.used_themes))
|
|
788
|
+
log_d(tests, "keywords", len(catalog.keywords))
|
|
789
|
+
log_d(tests, "used_keywords", len(catalog.used_keywords))
|
|
794
790
|
|
|
795
791
|
#
|
|
796
792
|
# log_d(here, ' get_metadata_with_media_uuid',
|
|
@@ -800,25 +796,25 @@ if __name__ == "__main__": # pragma: no cover
|
|
|
800
796
|
log_d(
|
|
801
797
|
tests,
|
|
802
798
|
"download_files_for_metadata",
|
|
803
|
-
|
|
799
|
+
catalog.download_files_for_metadata("65d99589-7a7a-46a3-afe8-c5a47b964310", test_dir),
|
|
804
800
|
)
|
|
805
801
|
|
|
806
802
|
log_d(
|
|
807
803
|
tests,
|
|
808
804
|
"download_file_with_media_uuid '782bab2d-7ee8-4633-9c0a-173649b4d879'",
|
|
809
|
-
|
|
805
|
+
catalog.download_file_with_media_uuid("fef11852-0756-4cbe-bdfb-3722a1751de9", test_dir),
|
|
810
806
|
)
|
|
811
807
|
|
|
812
808
|
log_d(
|
|
813
809
|
tests,
|
|
814
810
|
"download_file_with_name '782bab2d-7ee8-4633-9c0a-173649b4d879'",
|
|
815
|
-
|
|
811
|
+
catalog.download_file_with_name("782bab2d-7ee8-4633-9c0a-173649b4d879", test_dir),
|
|
816
812
|
)
|
|
817
813
|
|
|
818
814
|
log_d(
|
|
819
815
|
tests,
|
|
820
816
|
"download_file_with_name 'toucan.jpg'",
|
|
821
|
-
"\n" + str(
|
|
817
|
+
"\n" + str(catalog.download_file_with_name("toucan.jpg", test_dir)),
|
|
822
818
|
)
|
|
823
819
|
|
|
824
820
|
log_d(tests, "exec. time", time() - begin)
|
|
@@ -46,7 +46,7 @@ class RudiNodeJwtFactory(Connector):
|
|
|
46
46
|
|
|
47
47
|
def test_connection(self):
|
|
48
48
|
test = self.request(relative_url="crypto/jwt", req_method="GET", headers=self._headers)
|
|
49
|
-
if not isinstance(test, dict) or test
|
|
49
|
+
if not isinstance(test, dict) or test.get("RUDI") != "JWT":
|
|
50
50
|
log_e("RudiNodeJwtFactory", f"!! Node '{self.host}'", "no connection!")
|
|
51
51
|
raise ConnectionError(f"An error occurred while connecting to RUDI node JWT server {self.base_url}")
|
|
52
52
|
# log_d("RudiNodeJwtFactory", f"Node '{self.host}'", "connection OK")
|