rudi-node-write 0.1.0__tar.gz → 1.0.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.
Files changed (45) hide show
  1. {rudi-node-write-0.1.0/src/rudi_node_write.egg-info → rudi_node_write-1.0.0}/PKG-INFO +18 -19
  2. rudi_node_write-1.0.0/README.md +30 -0
  3. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/pyproject.toml +28 -7
  4. rudi_node_write-1.0.0/requirements.txt +7 -0
  5. rudi_node_write-1.0.0/src/rudi_node_write/__init__.py +0 -0
  6. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/conf/meta_defaults.py +1 -1
  7. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/connectors/io_connector.py +81 -46
  8. rudi_node_write-1.0.0/src/rudi_node_write/connectors/io_rudi_manager_write.py +1308 -0
  9. rudi_node_write-1.0.0/src/rudi_node_write/rudi_node_writer.py +446 -0
  10. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_const.py +85 -22
  11. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_contact.py +7 -6
  12. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_dates.py +12 -15
  13. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_dictionary_entry.py +26 -19
  14. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_geo.py +9 -9
  15. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_licence.py +22 -34
  16. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_media.py +139 -93
  17. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_meta.py +44 -47
  18. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_meta_misc.py +17 -15
  19. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/rudi_org.py +5 -5
  20. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/rudi_types/serializable.py +35 -26
  21. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/dict_utils.py +73 -10
  22. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/err.py +14 -5
  23. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/file_utils.py +41 -12
  24. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/html_utils.py +4 -5
  25. rudi_node_write-1.0.0/src/rudi_node_write/utils/jwt.py +77 -0
  26. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/list_utils.py +11 -7
  27. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/log.py +10 -6
  28. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/str_utils.py +16 -13
  29. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/type_date.py +63 -11
  30. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/typing_utils.py +45 -16
  31. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write/utils/url_utils.py +14 -1
  32. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0/src/rudi_node_write.egg-info}/PKG-INFO +18 -19
  33. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write.egg-info/SOURCES.txt +7 -5
  34. rudi_node_write-1.0.0/src/rudi_node_write.egg-info/requires.txt +5 -0
  35. rudi_node_write-1.0.0/tests/test_rudi_node_write.py +66 -0
  36. rudi-node-write-0.1.0/README.md +0 -35
  37. rudi-node-write-0.1.0/src/rudi_node_write/connectors/io_rudi_api_write.py +0 -799
  38. rudi-node-write-0.1.0/src/rudi_node_write/connectors/io_rudi_jwt_factory.py +0 -75
  39. rudi-node-write-0.1.0/src/rudi_node_write/connectors/io_rudi_media_write.py +0 -221
  40. rudi-node-write-0.1.0/src/rudi_node_write/utils/date_utils.py +0 -43
  41. rudi-node-write-0.1.0/src/rudi_node_write/utils/jwt.py +0 -41
  42. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/LICENCE.md +0 -0
  43. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/setup.cfg +0 -0
  44. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write.egg-info/dependency_links.txt +0 -0
  45. {rudi-node-write-0.1.0 → rudi_node_write-1.0.0}/src/rudi_node_write.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rudi-node-write
3
- Version: 0.1.0
3
+ Version: 1.0.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>
@@ -9,49 +9,48 @@ 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: Changelog, https://github.com/OlivierMartineau/rudi-node-write/blob/release/CHANGELOG.md
11
11
  Project-URL: Repository, https://github.com/OlivierMartineau/rudi-node-write
12
- Keywords: rudi-node-write,rudi-node-get,RUDI,producer node,RUDI node,open-data,Univ. Rennes
13
- Classifier: Programming Language :: Python :: 3.10
12
+ Keywords: rudi-node-write,rudi-node-put,RUDI,producer node,RUDI node,open-data,Univ. Rennes
14
13
  Classifier: Programming Language :: Python :: 3.11
15
14
  Classifier: Programming Language :: Python :: 3.12
16
15
  Classifier: Natural Language :: English
17
16
  Classifier: Operating System :: OS Independent
18
17
  Classifier: License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)
19
- Requires-Python: >=3.10
18
+ Requires-Python: >=3.11
20
19
  Description-Content-Type: text/markdown
21
20
  License-File: LICENCE.md
21
+ Requires-Dist: beautifulsoup4==4.12.3
22
+ Requires-Dist: chardet==5.2.0
23
+ Requires-Dist: deepdiff==7.0.1
24
+ Requires-Dist: defusedxml==0.7.1
25
+ Requires-Dist: puremagic==1.24
22
26
 
23
27
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
24
-
25
- Caution: this librairy is still a work in progress.
28
+ [![Checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
26
29
 
27
30
  # RUDI Node tools: _rudi-node-write_ library
28
31
 
29
32
  This library offers tools to take advantage of
30
33
  the [internal API](https://app.swaggerhub.com/apis/OlivierMartineau/RudiProducer-InternalAPI) of a RUDI Producer node (
31
34
  also
32
- referred as RUDI node).
35
+ referred as RUDI node), through the API of the backend of the user interface, the "Producer node manager" or "Prodmanager" module.
33
36
 
34
37
  ## Installation
35
38
 
36
39
  ```bash
37
- $ pip install rudi_node_write
40
+ python3 -m venv .venv
41
+ source .venv/bin/activate
42
+ pip install rudi_node_write
38
43
  ```
39
44
 
40
- ## Usage
41
-
42
- ```python
43
- from rudi_node_write.connectors.io_rudi_api_write import RudiNodeApiConnector
45
+ ## Usage: RudiNodeWriter
44
46
 
45
- rudi_api = RudiNodeApiConnector('https://bacasable.fenix.rudi-univ-rennes1.fr')
46
- print(rudi_api.metadata_count)
47
- print(len(rudi_api.metadata_list))
48
- print(rudi_api.producer_names)
49
- print(rudi_api.find_metadata_with_media_name('toucan.jpg'))
50
-
51
- ```
47
+ The Jupyter notebook [`README.ipynb`](https://github.com/OlivierMartineau/rudi-node-write/blob/release/README.ipynb) details how to use the library through the [`RudiNodeWriter`](https://github.com/OlivierMartineau/rudi-node-write/blob/release/src/rudi_node_write/rudi_node_writer.py) object.
52
48
 
53
49
  ## Testing
54
50
 
51
+ The [tests](https://github.com/OlivierMartineau/rudi-node-write/tree/release/tests) can be analyzed for further
52
+ information about how to call the API
53
+
55
54
  ```bash
56
55
  $ pytest
57
56
  ```
@@ -0,0 +1,30 @@
1
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
2
+ [![Checked with pyright](https://microsoft.github.io/pyright/img/pyright_badge.svg)](https://microsoft.github.io/pyright/)
3
+
4
+ # RUDI Node tools: _rudi-node-write_ library
5
+
6
+ This library offers tools to take advantage of
7
+ the [internal API](https://app.swaggerhub.com/apis/OlivierMartineau/RudiProducer-InternalAPI) of a RUDI Producer node (
8
+ also
9
+ referred as RUDI node), through the API of the backend of the user interface, the "Producer node manager" or "Prodmanager" module.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ python3 -m venv .venv
15
+ source .venv/bin/activate
16
+ pip install rudi_node_write
17
+ ```
18
+
19
+ ## Usage: RudiNodeWriter
20
+
21
+ The Jupyter notebook [`README.ipynb`](https://github.com/OlivierMartineau/rudi-node-write/blob/release/README.ipynb) details how to use the library through the [`RudiNodeWriter`](https://github.com/OlivierMartineau/rudi-node-write/blob/release/src/rudi_node_write/rudi_node_writer.py) object.
22
+
23
+ ## Testing
24
+
25
+ The [tests](https://github.com/OlivierMartineau/rudi-node-write/tree/release/tests) can be analyzed for further
26
+ information about how to call the API
27
+
28
+ ```bash
29
+ $ pytest
30
+ ```
@@ -4,21 +4,22 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rudi-node-write"
7
- version = "0.1.0"
7
+ version = "1.0.0"
8
8
  authors = [{ name = "Olivier Martineau", email = "olivier.martineau@irisa.fr" }]
9
9
  maintainers = [{ name = "Olivier Martineau", email = "olivier.martineau@irisa.fr" }]
10
10
  description = "Use the internal API of a RUDI Producer node"
11
11
  readme = "README.md"
12
- requires-python = ">=3.10"
12
+ requires-python = ">=3.11"
13
13
  license = { text = "EUPL-1.2" }
14
- classifiers = ["Programming Language :: Python :: 3.10",
15
- "Programming Language :: Python :: 3.11",
14
+ classifiers = ["Programming Language :: Python :: 3.11",
16
15
  "Programming Language :: Python :: 3.12",
17
16
  "Natural Language :: English",
18
17
  "Operating System :: OS Independent",
19
18
  "License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)",
20
19
  ]
21
- keywords = ["rudi-node-write", "rudi-node-get", "RUDI", "producer node", "RUDI node", "open-data", "Univ. Rennes"]
20
+ keywords = ["rudi-node-write", "rudi-node-put", "RUDI", "producer node", "RUDI node", "open-data", "Univ. Rennes"]
21
+ dynamic = ["dependencies"]
22
+ # dependencies = ["beautifulsoup4", "chardet", "deepdiff", "defusedxml", "puremagic"]
22
23
 
23
24
  [project.urls]
24
25
  Homepage = "https://github.com/OlivierMartineau/rudi-node-write"
@@ -34,7 +35,7 @@ target-version = ['py311']
34
35
  # ----- Tool: commitizen
35
36
  [tool.commitizen]
36
37
  name = "cz_conventional_commits"
37
- version = "0.1.0"
38
+ version = "1.0.0"
38
39
  version_files = ["pyproject.toml:version"]
39
40
 
40
41
  # ----- Tool: pytest
@@ -42,4 +43,24 @@ version_files = ["pyproject.toml:version"]
42
43
  pythonpath = ["src"]
43
44
  norecursedirs = ["*.egg", ".eggs", "dist", "build"]
44
45
  filterwarnings = ["ignore:.*pkg_resources.*:DeprecationWarning"]
45
- addopts = ["--cov=rudi_node_write", "--cov-report=term-missing", "--cov-report=html"]
46
+ addopts = ["--cov=rudi_node_write", "--cov-report=term-missing", "--cov-report=html:reports/html_dir", "--cov-report=xml:reports/coverage.xml" ]
47
+
48
+ # ----- Tool: setuptools
49
+ [tool.setuptools.packages.find]
50
+ where = ["src"]
51
+ include = ["rudi_node_write*"]
52
+
53
+ [tool.setuptools.dynamic]
54
+ dependencies = {file = ["requirements.txt"]}
55
+
56
+ # ----- Tool: pyright
57
+ [tool.pyright]
58
+ exclude = ["**/node_modules", "**/__pycache__"]
59
+ include = ["src"]
60
+ pythonVersion = "3.11"
61
+ reportMissingImports = "true"
62
+ reportDuplicateImport = "true"
63
+ reportUnusedImport = "true"
64
+ reportImportCycles = "true"
65
+ venvPath = "."
66
+ venv = ".venv"
@@ -0,0 +1,7 @@
1
+ beautifulsoup4==4.12.3
2
+ chardet==5.2.0
3
+ deepdiff==7.0.1
4
+ defusedxml==0.7.1
5
+ puremagic==1.24
6
+ # ordered-set==4.1.0 # Installed as dependency for deepdiff
7
+ # soupsieve==2.5 # Installed as dependency for beautifulsoup4
File without changes
@@ -13,7 +13,7 @@ ODS_API_VERSION: str = "2.1"
13
13
 
14
14
  # Default contact when none is provided in the source metadata
15
15
  # Structure: https://app.swaggerhub.com/apis/OlivierMartineau/RUDI-PRODUCER/1.3.0#/Contact
16
- DEFAULT_CONTACT: dict = dict(contact_name="Rudi node admin", email="community@rudi-univ-rennes1.fr")
16
+ DEFAULT_CONTACT: dict = {"contact_name": "Rudi node admin", "email": "community@rudi-univ-rennes1.fr"}
17
17
 
18
18
  # Default producer when none is provided in the source metadata
19
19
  # Structure: https://app.swaggerhub.com/apis/OlivierMartineau/RUDI-PRODUCER/1.3.0#/Organization
@@ -4,18 +4,17 @@ from typing import Literal, get_args, BinaryIO, TextIO
4
4
  from urllib.parse import urlsplit
5
5
 
6
6
  from rudi_node_write.rudi_types.rudi_const import check_is_literal
7
- from rudi_node_write.utils.dict_utils import is_dict
7
+ from rudi_node_write.rudi_types.serializable import Serializable
8
+ from rudi_node_write.utils.dict_utils import is_dict, safe_get_key
8
9
  from rudi_node_write.utils.err import HttpError
9
10
  from rudi_node_write.utils.log import log_d_if, log_e, log_d
10
11
  from rudi_node_write.utils.str_utils import slash_join
11
- from rudi_node_write.utils.url_utils import url_encode_req_params
12
+ from rudi_node_write.utils.url_utils import get_response_cookies, url_encode_req_params
12
13
 
13
- HttpRequestMethod = Literal["GET", "PUT", "DEL", "POST"]
14
+ HttpRequestMethod = Literal["GET", "PUT", "DELETE", "POST"]
14
15
  HTTP_REQUEST_METHODS = get_args(HttpRequestMethod)
15
16
 
16
- CONTENT_TYPE_KEY = "Content-Type"
17
-
18
- DEFAULT_HEADERS = {CONTENT_TYPE_KEY: "text/plain; ", "Accept": "application/json"}
17
+ DEFAULT_HEADERS = {"Content-Type": "text/plain; ", "Accept": "application/json"}
19
18
 
20
19
  STATUS = "status"
21
20
  REDIRECTION = "redirection"
@@ -26,9 +25,9 @@ def https_download(resource_url: str, headers=None, should_show_debug_line: bool
26
25
  headers = DEFAULT_HEADERS
27
26
  here = "https_download"
28
27
  (scheme, netloc, path, query, fragment) = urlsplit(resource_url)
29
- if scheme != "https":
28
+ if scheme not in ("https", "http"):
30
29
  raise NotImplementedError(f"only HTTPS protocol is supported, cannot treat this url: {resource_url}")
31
- connection = HTTPSConnection(netloc)
30
+ connection = (HTTPSConnection if scheme == "https" else HTTPConnection)(netloc)
32
31
 
33
32
  connection.request(method="GET", url=resource_url, headers=headers)
34
33
  response = connection.getresponse()
@@ -53,18 +52,18 @@ class Connector:
53
52
  self.connection = None
54
53
 
55
54
  self._set_url(server_url)
55
+ self._cookies = None
56
56
 
57
57
  def _set_url(self, server_url: str):
58
- fun = f"super.{self.class_name}._set_url"
58
+ here = f"super.{self.class_name}._set_url"
59
59
  (scheme, netloc, path, query, fragment) = urlsplit(server_url)
60
- if scheme != "http" and scheme != "https":
60
+ if scheme not in ("https", "http"):
61
61
  raise NotImplementedError(f"only http and https are supported, got '{scheme}'")
62
- # self.scheme = scheme
63
- self.scheme = "https"
62
+ self.scheme = scheme
64
63
  self.host = netloc
65
64
  self.path = path
66
65
  self.base_url = slash_join(f"{self.scheme}://{self.host}", self.path)
67
- log_d(fun, "base_url", self.base_url)
66
+ log_d(here, "base_url", self.base_url)
68
67
 
69
68
  @property
70
69
  def class_name(self):
@@ -76,17 +75,23 @@ class Connector:
76
75
  def full_path(self, relative_url: str = "/"):
77
76
  return slash_join("/", self.path, url_encode_req_params(relative_url))
78
77
 
79
- def test_connection(self):
80
- return self.request()
78
+ def test_connection(self) -> bool | str | dict:
79
+ return self.request() # type: ignore
81
80
 
82
81
  def close_connection(self):
82
+ if self.connection is None:
83
+ raise ConnectionAbortedError("The connection should be alive still")
83
84
  try:
84
85
  self.connection.close()
85
86
  except Exception as e: # pragma: no cover
86
87
  log_e(self.class_name, "close_connection ERROR", e)
87
88
 
88
89
  def download(
89
- self, relative_url: str, headers: dict = None, keep_alive: bool = False, should_log_response: bool = False
90
+ self,
91
+ relative_url: str,
92
+ headers: dict | None = None,
93
+ keep_alive: bool = False,
94
+ should_log_response: bool = False,
90
95
  ):
91
96
  """
92
97
  Download a file on the connector server
@@ -98,6 +103,8 @@ class Connector:
98
103
  :return: a status
99
104
  """
100
105
  here = f"{self.class_name}.download"
106
+ if self.host is None:
107
+ raise AttributeError("The host was not defined")
101
108
  if headers is None:
102
109
  headers = DEFAULT_HEADERS
103
110
 
@@ -122,11 +129,12 @@ class Connector:
122
129
  self,
123
130
  relative_url: str = "/",
124
131
  req_method: HttpRequestMethod = "GET",
125
- body: dict | str | BinaryIO | TextIO = None,
132
+ body: dict | str | list | Serializable | BinaryIO | TextIO | None = None,
126
133
  headers=None,
127
134
  keep_alive: bool = False,
135
+ should_log_request: bool = False,
128
136
  should_log_response: bool = False,
129
- ) -> (str, dict):
137
+ ):
130
138
  """
131
139
  Send a http(s) request
132
140
  :param relative_url: a relative URL that will be joined to the connector's base URL to form the request URL
@@ -138,30 +146,35 @@ class Connector:
138
146
  :param should_log_response: True if some log lines should be displayed (defaults to False).
139
147
  :return: the data returned from the request
140
148
  """
141
- fun = f"{self.class_name}.request"
149
+ here = f"{self.class_name}.request"
142
150
 
143
151
  check_is_literal(req_method, HTTP_REQUEST_METHODS, "incorrect type for request method")
144
152
 
145
153
  if headers is None:
146
154
  headers = DEFAULT_HEADERS
147
- if is_dict(body):
148
- headers[CONTENT_TYPE_KEY] = "application/json"
149
- body = dumps(body)
155
+ if isinstance(body, dict):
156
+ headers["Content-Type"] = "application/json"
157
+ body_str = dumps(body)
158
+ elif isinstance(body, Serializable):
159
+ headers["Content-Type"] = "application/json"
160
+ body_str = body.to_json_str(ensure_ascii=True)
161
+ elif isinstance(body, list):
162
+ body_str = str(list)
163
+ else:
164
+ body_str = body
150
165
 
151
166
  path_url = self.full_path(relative_url)
167
+ if self.host is None:
168
+ raise ConnectionError("The connector host should be defined")
169
+ self.connection = HTTPConnection(self.host) if self.scheme == "http" else HTTPSConnection(self.host)
152
170
 
153
- if self.scheme == "http": # pragma: no cover
154
- self.connection = HTTPConnection(self.host)
155
- else:
156
- self.connection = HTTPSConnection(self.host)
157
- log_d(fun, req_method, self.full_url(relative_url))
171
+ log_d_if(should_log_request, here, req_method, self.full_url(relative_url))
158
172
 
159
173
  try:
160
- # log_d(fun, "request details", "method=", req_method, "url=", path_url, "body=", body, "headers=", headers)
161
- self.connection.request(method=req_method, url=path_url, body=body, headers=headers)
174
+ self.connection.request(method=req_method, url=path_url, body=body_str, headers=headers) # type: ignore
162
175
  except ConnectionRefusedError as e:
163
- log_e(fun, "Error on request", req_method, self.full_url(relative_url))
164
- log_e(fun, "ERR", e)
176
+ log_e(here, "Error on request", req_method, self.full_url(relative_url))
177
+ log_e(here, "ERR", e)
165
178
  raise e
166
179
  return self.parse_response(
167
180
  relative_url=relative_url,
@@ -178,9 +191,12 @@ class Connector:
178
191
  should_log_response: bool = True,
179
192
  ):
180
193
  """Basic parsing of the result"""
181
- fun = f"{self.class_name}.parse_response"
194
+ here = f"{self.class_name}.parse_response"
195
+ if self.connection is None:
196
+ raise ConnectionError("The connector HTTPSConnection should be defined")
182
197
  response = self.connection.getresponse()
183
- # log_d(fun, "Response", response.getcode(), response.getheaders(), response.info())
198
+ self._cookies = get_response_cookies(response)
199
+
184
200
  if response.status in [301, 302]:
185
201
  return {STATUS: response.status, REDIRECTION: response.getheader("location")}
186
202
  if (
@@ -191,25 +207,26 @@ class Connector:
191
207
  return None
192
208
 
193
209
  rdata = response.read()
194
- # log_d(fun, "rdata", rdata)
210
+ # log_d(here, "rdata", rdata)
195
211
  try:
196
212
  response_data = loads(rdata)
197
- log_d_if(should_log_response, fun, "Response is a JSON", response_data)
213
+ log_d_if(should_log_response, here, "Response is a JSON", response_data)
198
214
  except (TypeError, JSONDecodeError):
199
215
  response_data = repr(rdata)
200
- log_d_if(should_log_response, fun, "Response is not a JSON", response_data)
216
+ log_d_if(should_log_response, here, "Response is not a JSON", response_data)
201
217
  if not keep_alive:
202
218
  self.close_connection()
203
219
 
204
220
  if type(response_data) is str:
205
- log_d_if(should_log_response, fun, "Response is a string", response_data)
221
+ log_d_if(should_log_response, here, "Response is a string", response_data)
206
222
  if response.status == 200:
207
223
  return rdata.decode("utf8")
208
224
  if response.status == 200:
209
225
  return response_data
210
226
  if response.status >= 400:
211
- log_e(fun, "Connection error", response_data)
212
- log_e(fun, "Request in error", req_method, self.full_url(relative_url))
227
+ log_e(here, "Connection error", response_data)
228
+ log_e(here, "Request in error", req_method, self.full_url(relative_url))
229
+ # log_e(here, "Headers", response.headers)
213
230
  raise HttpError(response_data, req_method, self.base_url, relative_url)
214
231
 
215
232
 
@@ -217,13 +234,31 @@ if __name__ == "__main__": # pragma: no cover
217
234
  tests = "Connector tests"
218
235
  connector = Connector("https://bacasable.fenix.rudi-univ-rennes1.fr/api/version")
219
236
  log_d(tests, "testing connection, got version", connector.test_connection())
220
- # data = connector.request(relative_url="resources?limit=1")
221
- # print(data)
222
237
 
223
238
  connector = Connector("https://bacasable.fenix.rudi-univ-rennes1.fr/api/v1")
224
- res = connector.request("resources")
225
-
226
- log_d(tests, "number of resources declared", res["total"])
239
+ metadata_list = connector.request("resources")
240
+ if isinstance(metadata_list, dict) and metadata_list["total"] is not None:
241
+ log_d(tests, "number of resources declared", f"{metadata_list['total']}")
242
+ else:
243
+ log_e(
244
+ tests,
245
+ f"An error occurred, result should be a dict with 'total' and 'items' properties, got {metadata_list}",
246
+ )
227
247
 
228
- url = "https://bacasable.fenix.rudi-univ-rennes1.fr/media/download/b086c7b2-bd6d-401f-86f5-f1f207023bae"
229
- log_d("https_utils", url, https_download(url))
248
+ url = "resources?available_formats.file_storage_status=available&fields=available_formats"
249
+ meta_list: list = connector.request(url)["items"] # type: ignore
250
+ # print(tests, "media_list", meta_list)
251
+ available_files = []
252
+ for meta in meta_list:
253
+ for media in meta["available_formats"]:
254
+ # log_d(tests, "media", media)
255
+ file_storage_status = safe_get_key(media, "file_storage_status")
256
+ if file_storage_status == "available":
257
+ available_files.append(media)
258
+
259
+ if len(available_files) == 0:
260
+ print("no media available, quiting")
261
+ else:
262
+ media_1 = available_files[0]
263
+ url = media_1["connector"]["url"]
264
+ log_d("https_utils", url, https_download(url))