rudi-node-write 1.4.2__tar.gz → 1.4.4__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.
Files changed (48) hide show
  1. {rudi_node_write-1.4.2/src/rudi_node_write.egg-info → rudi_node_write-1.4.4}/PKG-INFO +1 -1
  2. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/pyproject.toml +2 -2
  3. rudi_node_write-1.4.2/src/rudi_node_write/connectors/io_rudi_manager_write_v3.py → rudi_node_write-1.4.4/src/rudi_node_write/connectors/io_rudi_manager_write.py +67 -32
  4. rudi_node_write-1.4.4/src/rudi_node_write/connectors/io_rudi_manager_write_v2.py +12 -0
  5. rudi_node_write-1.4.4/src/rudi_node_write/connectors/io_rudi_manager_write_v3.py +12 -0
  6. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/connectors/rudi_node_auth.py +4 -1
  7. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_const.py +10 -130
  8. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/file_utils.py +1 -80
  9. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/jwt.py +7 -0
  10. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4/src/rudi_node_write.egg-info}/PKG-INFO +1 -1
  11. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/tests/test_rudi_node_write.py +1 -1
  12. rudi_node_write-1.4.2/src/rudi_node_write/connectors/io_rudi_manager_write.py +0 -1444
  13. rudi_node_write-1.4.2/src/rudi_node_write/connectors/io_rudi_manager_write_v2.py +0 -124
  14. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/LICENCE.md +0 -0
  15. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/README.md +0 -0
  16. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/requirements-dev.txt +0 -0
  17. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/requirements.txt +0 -0
  18. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/setup.cfg +0 -0
  19. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/__init__.py +0 -0
  20. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/conf/meta_defaults.py +0 -0
  21. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/connectors/io_connector.py +0 -0
  22. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/connectors/io_rudi_catalog_write.py +0 -0
  23. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/connectors/io_rudi_jwt_factory.py +0 -0
  24. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/connectors/io_rudi_storage_write.py +0 -0
  25. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_node_writer.py +0 -0
  26. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_contact.py +0 -0
  27. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_dates.py +0 -0
  28. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_dictionary_entry.py +0 -0
  29. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_geo.py +0 -0
  30. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_licence.py +0 -0
  31. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_media.py +0 -0
  32. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_meta.py +0 -0
  33. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_meta_misc.py +0 -0
  34. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/rudi_org.py +0 -0
  35. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/rudi_types/serializable.py +0 -0
  36. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/dict_utils.py +0 -0
  37. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/err.py +0 -0
  38. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/html_utils.py +0 -0
  39. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/list_utils.py +0 -0
  40. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/log.py +0 -0
  41. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/str_utils.py +0 -0
  42. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/type_date.py +0 -0
  43. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/typing_utils.py +0 -0
  44. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write/utils/url_utils.py +0 -0
  45. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write.egg-info/SOURCES.txt +0 -0
  46. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write.egg-info/dependency_links.txt +0 -0
  47. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write.egg-info/requires.txt +0 -0
  48. {rudi_node_write-1.4.2 → rudi_node_write-1.4.4}/src/rudi_node_write.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rudi-node-write
3
- Version: 1.4.2
3
+ Version: 1.4.4
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>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "rudi-node-write"
3
- version = "1.4.2"
3
+ version = "1.4.4"
4
4
  authors = [{ name = "Olivier Martineau", email = "olivier.martineau@irisa.fr" }]
5
5
  maintainers = [
6
6
  { name = "Olivier Martineau", email = "olivier.martineau@irisa.fr" },
@@ -45,7 +45,7 @@ target-version = ['py311']
45
45
  # ----- Tool: commitizen
46
46
  [tool.commitizen]
47
47
  name = "cz_conventional_commits"
48
- version = "1.4.2"
48
+ version = "1.4.4"
49
49
  version_files = ["pyproject.toml:version"]
50
50
 
51
51
  # ----- Tool: pytest
@@ -6,10 +6,6 @@ from typing import Literal
6
6
  from urllib.parse import quote
7
7
 
8
8
  from rudi_node_write.connectors.io_connector import Connector, https_download
9
- from rudi_node_write.connectors.io_rudi_manager_write import (
10
- CONSOLE_JWT_NAME,
11
- RudiNodeManagerConnector,
12
- )
13
9
  from rudi_node_write.connectors.rudi_node_auth import RudiNodeAuth
14
10
  from rudi_node_write.rudi_types.rudi_const import (
15
11
  MEDIA_TYPE_FILE,
@@ -49,22 +45,28 @@ from rudi_node_write.utils.typing_utils import check_is_int, get_type_name
49
45
  from rudi_node_write.utils.url_utils import ensure_url_startswith
50
46
 
51
47
  # Defaults for constructor
52
- _DEFAULT_USER_AGENT = "RudiNodeManagerConnectorV3"
48
+ _DEFAULT_USER_AGENT = "RudiNodeManagerConnector"
49
+
50
+ # Cookie names
51
+ MANAGER_JWT_NAME = "pmFrontToken"
52
+ CONSOLE_JWT_NAME = "consoleToken"
53
53
 
54
54
  # Manager API prefixes
55
55
  MGR_CATALOG_PREFIX = "catalog"
56
56
  OLD_MGR_CATALOG_PREFIX = "data"
57
57
 
58
+ # Data retrieving, cache
58
59
  REQ_LIMIT = 500
59
60
  _DELAY_REFRESH_S = 60 # seconds
60
61
  _REFRESH_KEY = "refresh_time" # seconds
61
62
 
63
+ # Download status
62
64
  _STATUS_SKIPPED = "skipped"
63
65
  _STATUS_MISSING = "missing"
64
66
  _STATUS_DOWNLOADED = "downloaded"
65
67
 
66
68
 
67
- here = "RudiNodeManagerConnectorV3"
69
+ here = "RudiNodeManagerConnector"
68
70
 
69
71
 
70
72
  def ensure_url_startswith_catalog(url):
@@ -73,13 +75,10 @@ def ensure_url_startswith_catalog(url):
73
75
  return ensure_url_startswith(url, MGR_CATALOG_PREFIX)
74
76
 
75
77
 
76
- JWT = "eyJhbGciOiJFZERTQSJ9.eyJqdGkiOiI3YTc1NzY1OS0wZjJlLTQ1NjItYjc5Yy03OWZjM2IyMTQ5Y2UiLCJpYXQiOjE3NTkxNDczNDcsImV4cCI6MTc2MzI5NDU0Nywic3ViIjoicG9zdG1hbl9vbSIsImNsaWVudF9pZCI6Im9tIiwicmVxX210ZCI6ImFsbCIsInJlcV91cmwiOiJhbGwifQ.VQURaFDBBCCywv7Tsq0eQt_Kes6G1APzjm8awUJp2EXBrCTP5MzRupNISZ79gXhzajX-KH9jPDPxbg1FGzfxAA"
77
-
78
-
79
- class RudiNodeManagerConnectorV3(RudiNodeManagerConnector):
78
+ class RudiNodeManagerConnector(Connector):
80
79
  """
81
- Every RUDI node has a UI module called "RUDI node manager", or "Manager" for shorts,
82
- that offers to list, edit or create RUDI metadata, given that you have the required level of access.
80
+ Every RUDI node has a UI module called "RUDI node manager", or "Manager" for shorts.
81
+ It offers to list, edit or create RUDI metadata, given that you have the required level of access.
83
82
  This library takes advantage of the manager backend API to send data and metadata.
84
83
  "GenC" stands for "Generation C", as this particular file takes advantage of the 3rd generation of RUDI node interface.
85
84
  """
@@ -92,28 +91,51 @@ class RudiNodeManagerConnectorV3(RudiNodeManagerConnector):
92
91
  headers_user_agent: str = _DEFAULT_USER_AGENT,
93
92
  keep_connection: bool = False,
94
93
  ):
95
- super().__init__(
96
- server_url=server_url,
97
- auth=auth,
98
- name=name,
99
- headers_user_agent=headers_user_agent,
100
- keep_connection=keep_connection,
101
- )
94
+ super().__init__(server_url=server_url, keep_connection=keep_connection)
95
+
96
+ self.server_url = server_url
97
+
98
+ if isinstance(auth, RudiNodeAuth):
99
+ self._auth = auth
100
+ elif isinstance(auth, dict):
101
+ self._auth = RudiNodeAuth(b64url_auth=auth["b64url_auth"], usr=auth["usr"], pwd=auth["pwd"])
102
+ else:
103
+ raise TypeError("Input 'auth' parameter should either be a 'RudiNodeAuth' object or a dict.")
104
+
105
+ self.name = name
106
+ if self.name is None:
107
+ self.name = self.server_url.split(".")[0].split("/")[-1]
108
+
109
+ self._headers_user_agent = headers_user_agent
110
+
102
111
  self._gen = 3
103
112
 
104
- self._cached_api_version = None
105
- self._cached_conf = None
113
+ self._cached_api_version: str | None = None
114
+ self._cached_conf: dict | None = None
115
+
116
+ self._cached_manager_jwt: str | None = None
117
+ self._cached_manager_headers: dict | None = None
106
118
 
107
- self._cached_manager_jwt = None
108
- self._cached_manager_headers = None
119
+ self._cached_storage_url: str | None = None
120
+ self._cached_storage_jwt: str | None = None
121
+ self._cached_storage_connector: RudiNodeStorageConnector | None = None
109
122
 
110
- self._cached_storage_url = None
111
- self._cached_storage_jwt = None
112
- self._cached_storage_connector = None
123
+ self.manager_url: str | None = None
124
+ self.manager_path: str | None = None
125
+
126
+ self._data_cache = {}
113
127
 
114
128
  self.conf
115
129
  # self.test_identified_connection()
116
130
 
131
+ @property
132
+ def _usr(self):
133
+ return self._auth.usr
134
+
135
+ @property
136
+ def _pwd(self):
137
+ return self._auth.pwd
138
+
117
139
  @property
118
140
  def conf(self):
119
141
  if self._cached_conf is None:
@@ -138,6 +160,16 @@ class RudiNodeManagerConnectorV3(RudiNodeManagerConnector):
138
160
  raise NotImplementedError("This node version is not compatible with this object") from e
139
161
  return self._cached_conf
140
162
 
163
+ @property
164
+ def storage_url(self) -> str:
165
+ return self._cached_storage_url or self.conf["storagePubUrl"]
166
+
167
+ @property
168
+ def portal_url(self) -> str | None:
169
+ if self.node_urls is not None:
170
+ return self.node_urls.get("portal_url")
171
+ return None
172
+
141
173
  # ----------[ Basic API calls ]-------------------------------------------------------------------------------------
142
174
  def get_api(self, url: str, headers: dict, keep_alive: bool = False):
143
175
  """
@@ -303,7 +335,7 @@ class RudiNodeManagerConnectorV3(RudiNodeManagerConnector):
303
335
  @property
304
336
  def storage_connector(self):
305
337
  if self._cached_storage_connector is None:
306
- self._cached_storage_connector = RudiNodeStorageConnectorV3(self.storage_url, self._storage_jwt)
338
+ self._cached_storage_connector = RudiNodeStorageConnector(self.storage_url, self._storage_jwt)
307
339
  if is_jwt_expired(self._cached_storage_connector.jwt):
308
340
  self._cached_storage_connector.jwt = self._storage_jwt
309
341
  return self._cached_storage_connector
@@ -417,7 +449,7 @@ class RudiNodeManagerConnectorV3(RudiNodeManagerConnector):
417
449
  :param obj_type: one of RUDI object types
418
450
  :return: the list of objects for this type
419
451
  """
420
- here = f"{self.class_name}.get_data"
452
+ here = f"{self.class_name}.get_catalog_cached"
421
453
 
422
454
  if obj_type in RUDI_OBJECT_TYPES:
423
455
  if not (self._gen == 1 and obj_type == "media"):
@@ -428,6 +460,9 @@ class RudiNodeManagerConnectorV3(RudiNodeManagerConnector):
428
460
  else:
429
461
  return self.get_cache(ensure_url_startswith_catalog(obj_type))
430
462
 
463
+ def get_data(self, obj_type: RudiObjectTypeStr | str) -> list[dict] | dict: # type: ignore
464
+ return self.get_catalog_cached(obj_type)
465
+
431
466
  # ----------[ Requesting data ]-------------------------------------------------------------------------------------
432
467
 
433
468
  def _count_obj(self, obj_type: RudiObjectTypeStr | str) -> int:
@@ -1225,7 +1260,7 @@ class RudiNodeManagerConnectorV3(RudiNodeManagerConnector):
1225
1260
  return ack
1226
1261
 
1227
1262
 
1228
- class RudiNodeStorageConnectorV3(Connector):
1263
+ class RudiNodeStorageConnector(Connector):
1229
1264
  def __init__(self, server_url: str, jwt: str):
1230
1265
  super().__init__(server_url)
1231
1266
  self.jwt = jwt
@@ -1407,14 +1442,14 @@ class FileTooBigException(Exception):
1407
1442
 
1408
1443
  if __name__ == "__main__": # pragma: no cover
1409
1444
  begin = time()
1410
- tests = "RudiNodeManagerConnectorV3 tests"
1445
+ tests = "RudiNodeManagerConnector tests"
1411
1446
  creds_file = "../creds/creds_pytest.json"
1412
1447
  rudi_node_creds = read_json_file(creds_file)
1413
1448
  manager_url = slash_join(rudi_node_creds["url"], "manager")
1414
1449
  log_d(tests, "node_url", manager_url)
1415
1450
  auth = RudiNodeAuth.from_json(rudi_node_creds)
1416
1451
 
1417
- manager = RudiNodeManagerConnectorV3(server_url=manager_url, auth=auth)
1452
+ manager = RudiNodeManagerConnector(server_url=manager_url, auth=auth)
1418
1453
  log_d(tests, "catalog_url", manager.catalog_url)
1419
1454
  log_d(tests, "storage_url", manager.storage_url)
1420
1455
  log_d(tests, "manager_url", manager.manager_url)
@@ -1443,7 +1478,7 @@ if __name__ == "__main__": # pragma: no cover
1443
1478
  log_d(tests, "rudi_media_url", storage_url)
1444
1479
 
1445
1480
  # "Hack" when no SSL connection is available
1446
- storage = RudiNodeStorageConnectorV3(server_url=storage_url, jwt=manager._storage_jwt)
1481
+ storage = RudiNodeStorageConnector(server_url=storage_url, jwt=manager._storage_jwt)
1447
1482
  storage.scheme = "http"
1448
1483
  storage.should_log_response = True
1449
1484
  manager._cached_storage_connector = storage
@@ -0,0 +1,12 @@
1
+ from rudi_node_write.connectors.io_rudi_manager_write import (
2
+ RudiNodeManagerConnector,
3
+ RudiNodeStorageConnector,
4
+ )
5
+
6
+
7
+ class RudiNodeManagerConnectorV2(RudiNodeManagerConnector):
8
+ pass
9
+
10
+
11
+ class RudiNodeStorageConnectorV2(RudiNodeStorageConnector):
12
+ pass
@@ -0,0 +1,12 @@
1
+ from rudi_node_write.connectors.io_rudi_manager_write import (
2
+ RudiNodeManagerConnector,
3
+ RudiNodeStorageConnector,
4
+ )
5
+
6
+
7
+ class RudiNodeManagerConnectorV3(RudiNodeManagerConnector):
8
+ pass
9
+
10
+
11
+ class RudiNodeStorageConnectorV3(RudiNodeStorageConnector):
12
+ pass
@@ -2,6 +2,7 @@ from base64 import urlsafe_b64decode, urlsafe_b64encode
2
2
 
3
3
  from rudi_node_write.rudi_types.serializable import Serializable
4
4
  from rudi_node_write.utils.jwt import is_base64_url, pad_b64_str
5
+ from rudi_node_write.utils.log import log_d
5
6
 
6
7
 
7
8
  class RudiNodeAuth(Serializable):
@@ -16,12 +17,14 @@ class RudiNodeAuth(Serializable):
16
17
  - either a `b64url_auth` URL-safe Base64 encoded `usr:pwd` string
17
18
  - or with a couple of `usr` and `pwd` strings
18
19
  """
20
+ here = "RudiNodeAuth"
19
21
  if b64url_auth is not None:
20
22
  self._b64_auth = pad_b64_str(b64url_auth)
23
+ log_d(here, "self._b64_auth", self._b64_auth)
21
24
  if not is_base64_url(self._b64_auth):
22
25
  raise ValueError("The input `b64url_auth` should be a urlsafe-base64 string.")
23
26
  try:
24
- self.usr, self.pwd = urlsafe_b64decode(b64url_auth).decode("utf-8").split(":")
27
+ self.usr, self.pwd = urlsafe_b64decode(self._b64_auth).decode("utf-8").split(":")
25
28
  except Exception as e:
26
29
  raise ValueError(
27
30
  "The input `b64url_auth` should be a urlsafe-base64 string that encodes a `usr:pwd` string couple"
@@ -109,6 +109,7 @@ FileExtensions: Final = {
109
109
  ".bmp": "image/bmp",
110
110
  ".bz": "application/x-bzip",
111
111
  ".bz2": "application/x-bzip2",
112
+ ".cdf": "application/netcdf",
112
113
  ".css": "text/css",
113
114
  ".csv": "text/csv",
114
115
  ".doc": "application/msword",
@@ -118,6 +119,7 @@ FileExtensions: Final = {
118
119
  ".flif": "image/flif",
119
120
  ".geojson": "application/geo+json",
120
121
  ".gif": "image/gif",
122
+ ".gpkg": "application/geopackage+sqlite3",
121
123
  ".gz": "application/gzip",
122
124
  ".gzip": "application/gzip",
123
125
  ".htm": "text/html",
@@ -129,6 +131,7 @@ FileExtensions: Final = {
129
131
  ".json": "application/json",
130
132
  ".jsonld": "application/ld+json",
131
133
  ".m4a": "audio/m4a",
134
+ ".md": "text/markdown",
132
135
  ".mkv": "video/x-matroska",
133
136
  ".mng": "image/x-mng",
134
137
  ".mov": "video/quicktime",
@@ -136,6 +139,7 @@ FileExtensions: Final = {
136
139
  ".mp4": "video/mp4",
137
140
  ".mpeg": "video/mpeg",
138
141
  ".mpg": "video/mpeg",
142
+ ".nc": "application/netcdf",
139
143
  ".odp": "application/vnd.oasis.opendocument.presentation",
140
144
  ".ods": "application/vnd.oasis.opendocument.spreadsheet",
141
145
  ".odt": "application/vnd.oasis.opendocument.text",
@@ -148,7 +152,6 @@ FileExtensions: Final = {
148
152
  ".png": "image/png",
149
153
  ".ppt": "application/vnd.ms-powerpoint",
150
154
  ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
151
- ".py": "text/x-python",
152
155
  ".sql": "application/sql",
153
156
  ".tar": "application/x-tar",
154
157
  ".tar.bz": "application/x-bzip",
@@ -157,6 +160,7 @@ FileExtensions: Final = {
157
160
  ".tgz": "application/gzip",
158
161
  ".tif": "image/tiff",
159
162
  ".tiff": "image/tiff",
163
+ ".toml": "application/toml",
160
164
  ".ttf": "font/ttf",
161
165
  ".txt": "text/plain",
162
166
  ".wav": "audio/wav",
@@ -174,141 +178,17 @@ FileExtensions: Final = {
174
178
  }
175
179
  FILE_EXTENSIONS = get_args(FileExtensions)
176
180
 
177
- MimeTypes = Literal[
178
- "application/epub+zip",
179
- "application/geo+json",
181
+ _MIME_TYPES_EXTRA: Final[tuple[str, ...]] = (
180
182
  "application/graphql",
181
- "application/gzip",
182
- "application/javascript",
183
- "application/json",
184
- "application/ld+json",
185
- "application/msword",
186
- "application/octet-stream",
187
- "application/pdf",
188
- "application/sql",
189
183
  "application/vnd.api+json",
190
- "application/vnd.ms-excel",
191
- "application/vnd.ms-powerpoint",
192
- "application/vnd.oasis.opendocument.presentation",
193
- "application/vnd.oasis.opendocument.spreadsheet",
194
- "application/vnd.oasis.opendocument.text",
195
- "application/vnd.openxmlformats-officedocument.presentationml.presentation",
196
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
197
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
198
- "application/x-7z-compressed",
199
- "application/x-bzip",
200
- "application/x-bzip2",
201
- "application/x-executable",
202
- "application/x-tar",
203
184
  "application/x-www-form-urlencoded",
204
185
  "application/xml",
205
- "application/zip",
206
- "application/zstd",
207
- "audio/aac",
208
- "audio/m4a",
209
- "audio/mpeg",
210
- "audio/ogg",
211
- "audio/wav",
212
- "audio/webm",
213
- "font/otf",
214
- "font/ttf",
215
- "image/apng",
216
- "image/bmp",
217
- "image/flif",
218
- "image/gif",
219
- "image/jpeg",
220
- "image/png",
221
- "image/tiff",
222
- "image/vnd.microsoft.icon",
223
- "image/webp",
224
- "image/x-mng",
225
186
  "multipart/form-data",
226
- "text/css",
227
- "text/csv",
228
- "text/html",
229
- "text/markdown",
230
- "text/php",
231
- "text/plain",
232
187
  "text/x-markdown",
233
- "text/x-yaml",
234
- "text/xml",
235
- "video/3gpp",
236
- "video/mp4",
237
- "video/mpeg",
238
- "video/ogg",
239
- "video/quicktime",
240
- "video/webm",
241
- "video/x-matroska",
242
- "video/x-ms-wmv",
243
- "video/x-msvideo",
244
- "application/epub+zip+crypt",
245
- "application/geo+json+crypt",
246
- "application/graphql+crypt",
247
- "application/gzip+crypt",
248
- "application/javascript+crypt",
249
- "application/json+crypt",
250
- "application/ld+json+crypt",
251
- "application/msword+crypt",
252
- "application/octet-stream+crypt",
253
- "application/pdf+crypt",
254
- "application/sql+crypt",
255
- "application/vnd.api+json+crypt",
256
- "application/vnd.ms-excel+crypt",
257
- "application/vnd.ms-powerpoint+crypt",
258
- "application/vnd.oasis.opendocument.presentation+crypt",
259
- "application/vnd.oasis.opendocument.spreadsheet+crypt",
260
- "application/vnd.oasis.opendocument.text+crypt",
261
- "application/vnd.openxmlformats-officedocument.presentationml.presentation+crypt",
262
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet+crypt",
263
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document+crypt",
264
- "application/x-7z-compressed+crypt",
265
- "application/x-bzip+crypt",
266
- "application/x-bzip2+crypt",
267
- "application/x-executable+crypt",
268
- "application/x-tar+crypt",
269
- "application/x-www-form-urlencoded+crypt",
270
- "application/xml+crypt",
271
- "application/zip+crypt",
272
- "application/zstd+crypt",
273
- "audio/aac+crypt",
274
- "audio/m4a+crypt",
275
- "audio/mpeg+crypt",
276
- "audio/ogg+crypt",
277
- "audio/wav+crypt",
278
- "audio/webm+crypt",
279
- "font/otf+crypt",
280
- "font/ttf+crypt",
281
- "image/apng+crypt",
282
- "image/bmp+crypt",
283
- "image/flif+crypt",
284
- "image/gif+crypt",
285
- "image/jpeg+crypt",
286
- "image/png+crypt",
287
- "image/tiff+crypt",
288
- "image/vnd.microsoft.icon+crypt",
289
- "image/webp+crypt",
290
- "image/x-mng+crypt",
291
- "multipart/form-data+crypt",
292
- "text/css+crypt",
293
- "text/csv+crypt",
294
- "text/html+crypt",
295
- "text/markdown+crypt",
296
- "text/php+crypt",
297
- "text/plain+crypt",
298
- "text/x-markdown+crypt",
299
- "text/x-yaml+crypt",
300
- "text/xml+crypt",
301
- "video/3gpp+crypt",
302
- "video/mp4+crypt",
303
- "video/mpeg+crypt",
304
- "video/ogg+crypt",
305
- "video/quicktime+crypt",
306
- "video/webm+crypt",
307
- "video/x-matroska+crypt",
308
- "video/x-ms-wmv+crypt",
309
- "video/x-msvideo+crypt",
310
- ]
311
- MIME_TYPES = get_args(MimeTypes)
188
+ )
189
+
190
+ _MIME_TYPES_BASE: Final[tuple[str, ...]] = tuple(sorted(set(FileExtensions.values()) | set(_MIME_TYPES_EXTRA)))
191
+ MIME_TYPES: Final[tuple[str, ...]] = _MIME_TYPES_BASE + tuple(f"{m}+crypt" for m in _MIME_TYPES_BASE)
312
192
 
313
193
  MimeTypesUtf8Text = Literal[
314
194
  "application/geo+json",
@@ -13,85 +13,6 @@ from rudi_node_write.rudi_types.rudi_const import FileExtensions
13
13
  from rudi_node_write.rudi_types.serializable import Serializable
14
14
  from rudi_node_write.utils.log import log_d, log_w
15
15
 
16
- EXTENSIONS = {
17
- ".3gp": "video/3gpp",
18
- ".3gpp": "video/3gpp",
19
- ".7z": "application/x-7z-compressed",
20
- ".aac": "audio/aac",
21
- ".apng": "image/apng",
22
- ".avi": "video/x-msvideo",
23
- ".bin": "application/octet-stream",
24
- ".bmp": "image/bmp",
25
- ".bz": "application/x-bzip",
26
- ".bz2": "application/x-bzip2",
27
- ".cdf": "application/netcdf",
28
- ".css": "text/css",
29
- ".csv": "text/csv",
30
- ".doc": "application/msword",
31
- ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
32
- ".epub": "application/epub+zip",
33
- ".exe": "application/x-executable",
34
- ".flif": "image/flif",
35
- ".geojson": "application/geo+json",
36
- ".gif": "image/gif",
37
- ".gpkg": "application/geopackage+sqlite3",
38
- ".gz": "application/gzip",
39
- ".gzip": "application/gzip",
40
- ".htm": "text/html",
41
- ".html": "text/html",
42
- ".ico": "image/vnd.microsoft.icon",
43
- ".jpeg": "image/jpeg",
44
- ".jpg": "image/jpeg",
45
- ".js": "application/javascript",
46
- ".json": "application/json",
47
- ".jsonld": "application/ld+json",
48
- ".m4a": "audio/m4a",
49
- ".md": "text/markdown",
50
- ".mkv": "video/x-matroska",
51
- ".mng": "image/x-mng",
52
- ".mov": "video/quicktime",
53
- ".mp3": "audio/mpeg",
54
- ".mp4": "video/mp4",
55
- ".mpeg": "video/mpeg",
56
- ".mpg": "video/mpeg",
57
- ".nc": "application/netcdf",
58
- ".odp": "application/vnd.oasis.opendocument.presentation",
59
- ".ods": "application/vnd.oasis.opendocument.spreadsheet",
60
- ".odt": "application/vnd.oasis.opendocument.text",
61
- ".oga": "audio/ogg",
62
- ".ogg": "audio/ogg",
63
- ".ogv": "video/ogg",
64
- ".otf": "font/otf",
65
- ".pdf": "application/pdf",
66
- ".php": "text/php",
67
- ".png": "image/png",
68
- ".ppt": "application/vnd.ms-powerpoint",
69
- ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
70
- ".sql": "application/sql",
71
- ".tar": "application/x-tar",
72
- ".tar.bz": "application/x-bzip",
73
- ".tar.bz2": "application/x-bzip2",
74
- ".tar.gz": "application/gzip",
75
- ".tgz": "application/gzip",
76
- ".tif": "image/tiff",
77
- ".tiff": "image/tiff",
78
- ".toml": "application/toml",
79
- ".ttf": "font/ttf",
80
- ".txt": "text/plain",
81
- ".wav": "audio/wav",
82
- ".weba": "audio/webm",
83
- ".webm": "video/webm",
84
- ".webp": "image/webp",
85
- ".wmv": "video/x-ms-wmv",
86
- ".xls": "application/vnd.ms-excel",
87
- ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
88
- ".xml": "text/xml",
89
- ".yaml": "text/x-yaml",
90
- ".yml": "text/x-yaml",
91
- ".zip": "application/zip",
92
- ".zst": "application/zstd",
93
- }
94
-
95
16
 
96
17
  def is_dir(dir_local_path: str):
97
18
  return Path(dir_local_path).is_dir()
@@ -157,7 +78,7 @@ def get_file_mime(file_local_path: str) -> str:
157
78
  """
158
79
  here = "get_file_mime"
159
80
  file_ext = get_file_extension(file_local_path)
160
- if mime := EXTENSIONS.get(file_ext):
81
+ if mime := FileExtensions.get(file_ext):
161
82
  return mime
162
83
 
163
84
  check_is_file(file_local_path)
@@ -67,3 +67,10 @@ def is_jwt_expired(jwt) -> bool:
67
67
  except ValueError as e:
68
68
  log_e("is_jwt_expired", f"this is not a JWT: '{jwt}'", e)
69
69
  return True
70
+
71
+
72
+ if __name__ == "__main__": # pragma: no cover
73
+ for arg in ["testing", "YrmFjpOshYMxl0tth73NhYmtl4GFzew"]:
74
+ print("* is_base64_url", f"'{arg}'? ->", is_base64_url(arg))
75
+ arg = pad_b64_str(arg)
76
+ print("* is_base64_url", f"'{arg}'? ->", is_base64_url(arg))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rudi-node-write
3
- Version: 1.4.2
3
+ Version: 1.4.4
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>
@@ -1,9 +1,9 @@
1
1
  from time import time
2
+
2
3
  from rudi_node_write.connectors.rudi_node_auth import RudiNodeAuth
3
4
  from rudi_node_write.rudi_node_writer import RudiNodeWriter
4
5
  from rudi_node_write.rudi_types.rudi_org import RudiOrganization
5
6
  from rudi_node_write.utils.file_utils import read_json_file
6
- from rudi_node_write.utils.log import log_d
7
7
  from rudi_node_write.utils.str_utils import is_uuid_v4, slash_join
8
8
 
9
9
  begin = time()