PyLinks 0.0.0.dev27__tar.gz → 0.0.0.dev29__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 (40) hide show
  1. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/PKG-INFO +3 -1
  2. pylinks-0.0.0.dev29/README.md +4 -0
  3. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/pyproject.toml +3 -1
  4. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/PyLinks.egg-info/PKG-INFO +3 -1
  5. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/PyLinks.egg-info/SOURCES.txt +2 -1
  6. pylinks-0.0.0.dev29/src/PyLinks.egg-info/requires.txt +3 -0
  7. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/__init__.py +1 -1
  8. pylinks-0.0.0.dev29/src/pylinks/exception/__init__.py +2 -0
  9. pylinks-0.0.0.dev29/src/pylinks/exception/api.py +166 -0
  10. pylinks-0.0.0.dev29/src/pylinks/exception/base.py +50 -0
  11. pylinks-0.0.0.dev29/src/pylinks/exception/media_type.py +34 -0
  12. pylinks-0.0.0.dev29/src/pylinks/exception/uri.py +20 -0
  13. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/http.py +32 -27
  14. pylinks-0.0.0.dev27/src/PyLinks.egg-info/requires.txt +0 -1
  15. pylinks-0.0.0.dev27/src/pylinks/exception/__init__.py +0 -2
  16. pylinks-0.0.0.dev27/src/pylinks/exception/base.py +0 -23
  17. pylinks-0.0.0.dev27/src/pylinks/exception/media_type.py +0 -20
  18. pylinks-0.0.0.dev27/src/pylinks/exception/uri.py +0 -13
  19. pylinks-0.0.0.dev27/src/pylinks/exceptions.py +0 -74
  20. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/setup.cfg +0 -0
  21. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/PyLinks.egg-info/dependency_links.txt +0 -0
  22. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/PyLinks.egg-info/not-zip-safe +0 -0
  23. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/PyLinks.egg-info/top_level.txt +0 -0
  24. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/_settings.py +0 -0
  25. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/api/__init__.py +0 -0
  26. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/api/doi.py +0 -0
  27. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/api/github.py +0 -0
  28. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/api/orcid.py +0 -0
  29. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/media_type.py +0 -0
  30. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/site/__init__.py +0 -0
  31. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/site/binder.py +0 -0
  32. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/site/conda.py +0 -0
  33. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/site/github.py +0 -0
  34. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/site/lib_io.py +0 -0
  35. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/site/pypi.py +0 -0
  36. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/site/readthedocs.py +0 -0
  37. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/string.py +0 -0
  38. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/uri/__init__.py +0 -0
  39. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/uri/data.py +0 -0
  40. {pylinks-0.0.0.dev27 → pylinks-0.0.0.dev29}/src/pylinks/url.py +0 -0
@@ -1,5 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyLinks
3
- Version: 0.0.0.dev27
3
+ Version: 0.0.0.dev29
4
4
  Requires-Python: >=3.10
5
5
  Requires-Dist: requests<3,>=2.31.0
6
+ Requires-Dist: ExceptionMan==0.0.0.dev16
7
+ Requires-Dist: MDit==0.0.0.dev16
@@ -0,0 +1,4 @@
1
+ # PyLinks
2
+
3
+ Web-API implementations and URI utilities for Python.
4
+ PyLinks also includes implementations for the following Web-APIs: GitHub, DOI, ORCID.
@@ -17,10 +17,12 @@ namespaces = true
17
17
  # ----------------------------------------- Project Metadata -------------------------------------
18
18
  #
19
19
  [project]
20
- version = "0.0.0.dev27"
20
+ version = "0.0.0.dev29"
21
21
  name = "PyLinks"
22
22
  dependencies = [
23
23
  "requests >= 2.31.0, < 3",
24
+ "ExceptionMan == 0.0.0.dev16",
25
+ "MDit == 0.0.0.dev16",
24
26
  ]
25
27
  requires-python = ">=3.10"
26
28
 
@@ -1,5 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyLinks
3
- Version: 0.0.0.dev27
3
+ Version: 0.0.0.dev29
4
4
  Requires-Python: >=3.10
5
5
  Requires-Dist: requests<3,>=2.31.0
6
+ Requires-Dist: ExceptionMan==0.0.0.dev16
7
+ Requires-Dist: MDit==0.0.0.dev16
@@ -1,3 +1,4 @@
1
+ README.md
1
2
  pyproject.toml
2
3
  src/PyLinks.egg-info/PKG-INFO
3
4
  src/PyLinks.egg-info/SOURCES.txt
@@ -7,7 +8,6 @@ src/PyLinks.egg-info/requires.txt
7
8
  src/PyLinks.egg-info/top_level.txt
8
9
  src/pylinks/__init__.py
9
10
  src/pylinks/_settings.py
10
- src/pylinks/exceptions.py
11
11
  src/pylinks/http.py
12
12
  src/pylinks/media_type.py
13
13
  src/pylinks/string.py
@@ -17,6 +17,7 @@ src/pylinks/api/doi.py
17
17
  src/pylinks/api/github.py
18
18
  src/pylinks/api/orcid.py
19
19
  src/pylinks/exception/__init__.py
20
+ src/pylinks/exception/api.py
20
21
  src/pylinks/exception/base.py
21
22
  src/pylinks/exception/media_type.py
22
23
  src/pylinks/exception/uri.py
@@ -0,0 +1,3 @@
1
+ requests<3,>=2.31.0
2
+ ExceptionMan==0.0.0.dev16
3
+ MDit==0.0.0.dev16
@@ -12,4 +12,4 @@ Other available modules offer shortcuts for creating useful URLs for popular onl
12
12
  """
13
13
 
14
14
  from pylinks._settings import settings
15
- from pylinks import url, http, api, site, exceptions, uri, media_type, string
15
+ from pylinks import url, http, api, site, uri, media_type, string
@@ -0,0 +1,2 @@
1
+ from pylinks.exception.base import PyLinksError
2
+ from pylinks.exception import media_type
@@ -0,0 +1,166 @@
1
+ """Custom exceptions raised by the package."""
2
+
3
+ from __future__ import annotations as _annotations
4
+
5
+ from typing import TYPE_CHECKING as _TYPE_CHECKING
6
+
7
+ import mdit as _mdit
8
+ from pylinks.exception import PyLinksError
9
+
10
+ if _TYPE_CHECKING:
11
+ from typing import Any, Callable
12
+ from requests import PreparedRequest, Request, Response
13
+ from requests.exceptions import RequestException
14
+
15
+
16
+ class WebAPIError(PyLinksError):
17
+ """Base Exception class for all web API exceptions."""
18
+ pass
19
+
20
+
21
+ class WebAPIRequestError(WebAPIError):
22
+ def __init__(self, request_error: RequestException):
23
+ self.request = request_error.request
24
+ self.response = request_error.response
25
+ details = []
26
+ if self.request:
27
+ details.append(_process_request(self.request))
28
+ if self.response:
29
+ summary, response_details = _process_response(self.response)
30
+ details.append(response_details)
31
+
32
+ super().__init__(
33
+ title="Web API Request Error",
34
+ intro=str(request_error),
35
+ details=_mdit.block_container(*details) if details else None,
36
+ )
37
+ return
38
+
39
+
40
+ class WebAPIStatusCodeError(WebAPIError):
41
+ """
42
+ Base Exception class for web API status code related exceptions.
43
+ By default, raised when status code is in range [400, 600).
44
+ """
45
+
46
+ def __init__(self, response: Response):
47
+ self.request = response.request
48
+ self.response = response
49
+ response_summary, response_details = _process_response(response)
50
+ details = _mdit.block_container(
51
+ _process_request(self.request),
52
+ response_details,
53
+ )
54
+ super().__init__(
55
+ title="Web API Status Code Error",
56
+ intro=response_summary,
57
+ details=details,
58
+ )
59
+ return
60
+
61
+
62
+ class WebAPITemporaryStatusCodeError(WebAPIStatusCodeError):
63
+ """
64
+ Exception class for status code errors related to temporary issues.
65
+ By default, raised when status code is in (408, 429, 500, 502, 503, 504).
66
+ """
67
+ pass
68
+
69
+
70
+ class WebAPIPersistentStatusCodeError(WebAPIStatusCodeError):
71
+ """
72
+ Exception class for status code errors related to persistent issues.
73
+ By default, raised when status code is in range [400, 600),
74
+ but not in (408, 429, 500, 502, 503, 504).
75
+ """
76
+ pass
77
+
78
+
79
+ class WebAPIValueError(WebAPIError):
80
+ """
81
+ Exception class for response value errors.
82
+ """
83
+
84
+ def __init__(self, response_value: Any, response_verifier: Callable[[Any], bool]):
85
+ self.response_value = response_value
86
+ self.response_verifier = response_verifier
87
+ error_msg = (
88
+ f"Response verifier function {response_verifier} failed to verify {response_value}."
89
+ )
90
+ super().__init__(
91
+ title="Web API Response Verification Error",
92
+ intro=error_msg,
93
+ )
94
+ return
95
+
96
+
97
+ def _process_response(response: Response):
98
+ # Decode error reason from server
99
+ # This part is adapted from `requests` library; See PR #3538 on their GitHub
100
+ if isinstance(response.reason, bytes):
101
+ try:
102
+ reason = response.reason.decode("utf-8")
103
+ except UnicodeDecodeError:
104
+ reason = response.reason.decode("iso-8859-1")
105
+ else:
106
+ reason = response.reason
107
+
108
+ response_info = []
109
+ response_summary = _mdit.element.field_list()
110
+ side = "Client" if response.status_code < 500 else "Server"
111
+ for title, value in (
112
+ ("Status Code", response.status_code),
113
+ ("Side", side),
114
+ ("Reason", reason),
115
+ ("URL", response.url),
116
+ ):
117
+ if value:
118
+ response_summary.append(
119
+ title=title,
120
+ body=_mdit.element.code_span(str(value)),
121
+ )
122
+ if response_summary.content.elements():
123
+ response_info.append(response_summary)
124
+ if response.text:
125
+ response_info.append(
126
+ _mdit.element.code_block(response.text, caption="Content")
127
+ )
128
+ summary = f"HTTP {response.status_code} error ({side.lower()} side) from {response.url}: {reason}"
129
+ return summary, _mdit.element.dropdown(
130
+ title="Response",
131
+ body=response_info,
132
+ icon="📥"
133
+ )
134
+
135
+
136
+ def _process_request(request: Request | PreparedRequest):
137
+ request_info = []
138
+ request_summary = _mdit.element.field_list()
139
+ for title, attr_name in (
140
+ ("Method", "method"),
141
+ ("URL", "url"),
142
+ ):
143
+ value = getattr(request, attr_name, None)
144
+ if value:
145
+ request_summary.append(
146
+ title=title,
147
+ body=_mdit.element.code_span(value),
148
+ )
149
+ if request_summary.content.elements():
150
+ request_info.append(request_summary)
151
+ for title, attr_name in (
152
+ ("Data", "data"),
153
+ ("JSON", "json"),
154
+ ("Parameters", "params"),
155
+ ("Body", "body"),
156
+ ):
157
+ value = getattr(request, attr_name, None)
158
+ if value:
159
+ request_info.append(
160
+ _mdit.element.code_block(str(value), caption=title)
161
+ )
162
+ return _mdit.element.dropdown(
163
+ title="Request",
164
+ body=request_info,
165
+ icon="📤"
166
+ )
@@ -0,0 +1,50 @@
1
+ """PyLinks base exception."""
2
+
3
+ from __future__ import annotations as _annotations
4
+ from typing import TYPE_CHECKING as _TYPE_CHECKING
5
+ from functools import partial as _partial
6
+
7
+ from exceptionman import ReporterException as _ReporterException
8
+ import mdit as _mdit
9
+
10
+ if _TYPE_CHECKING:
11
+ from pathlib import Path
12
+
13
+
14
+ class PyLinksError(_ReporterException):
15
+ """Base exception for PyLinks.
16
+
17
+ All exceptions raised by PyLinks inherit from this class.
18
+ """
19
+ def __init__(
20
+ self,
21
+ title: str,
22
+ intro,
23
+ details = None,
24
+ ):
25
+ sphinx_config = {"html_title": "PyLinks Error Report"}
26
+ sphinx_target_config = _mdit.target.sphinx(
27
+ renderer=_partial(
28
+ _mdit.render.sphinx,
29
+ config=_mdit.render.get_sphinx_config(sphinx_config)
30
+ )
31
+ )
32
+ report = _mdit.document(
33
+ heading=title,
34
+ body={"intro": intro},
35
+ section={"details": _mdit.document(heading="Details", body=details)} if details else None,
36
+ target_configs_md={"sphinx": sphinx_target_config},
37
+ )
38
+ super().__init__(report=report)
39
+ return
40
+
41
+
42
+ class PyLinksFileNotFoundError(PyLinksError):
43
+ """File not found error."""
44
+ def __init__(self, path: Path):
45
+ super().__init__(
46
+ title="File Not Found Error",
47
+ intro=_mdit.inline_container("No file found at input path ", _mdit.element.code_span(str(path))),
48
+ )
49
+ self.path = path
50
+ return
@@ -0,0 +1,34 @@
1
+ import mdit as _mdit
2
+
3
+ from pylinks.exception import PyLinksError as _PyLinksError
4
+
5
+
6
+ class PyLinksMediaTypeParseError(_PyLinksError):
7
+ """Error parsing a media type."""
8
+ def __init__(self, problem: str, media_type: str):
9
+ super().__init__(
10
+ title="Media Type Parse Error",
11
+ intro=_mdit.inline_container(
12
+ "Failed to parse media type ",
13
+ _mdit.element.code_span(media_type),
14
+ ". ",
15
+ problem,
16
+ )
17
+ )
18
+ self.problem = problem
19
+ self.media_type = media_type
20
+ return
21
+
22
+
23
+ class PyLinksMediaTypeGuessError(_PyLinksError):
24
+ """Error guessing the media type of a data URI."""
25
+ def __init__(self, path: str):
26
+ super().__init__(
27
+ title="Media Type Guess Error",
28
+ intro=_mdit.inline_container(
29
+ "Failed to guess the media type of the file at path ",
30
+ _mdit.element.code_span(path),
31
+ )
32
+ )
33
+ self.path = path
34
+ return
@@ -0,0 +1,20 @@
1
+ import mdit as _mdit
2
+
3
+ from pylinks.exception import PyLinksError as _PyLinksError
4
+
5
+
6
+ class PyLinksDataURIParseError(_PyLinksError):
7
+ """Error parsing a data URI."""
8
+ def __init__(self, problem: str, data_uri: str):
9
+ super().__init__(
10
+ title="Data URI Parse Error",
11
+ intro=_mdit.inline_container(
12
+ "Failed to parse data URI ",
13
+ _mdit.element.code_span(data_uri),
14
+ ". ",
15
+ problem,
16
+ )
17
+ )
18
+ self.problem = problem
19
+ self.data_uri = data_uri
20
+ return
@@ -1,29 +1,35 @@
1
1
  """
2
2
  Handling HTTP requests and responses.
3
3
  """
4
+ from __future__ import annotations as _annotations
4
5
 
6
+ from typing import TYPE_CHECKING as _TYPE_CHECKING, NamedTuple as _NamedTuple
5
7
 
6
- from typing import (
7
- Any,
8
- Callable,
9
- List,
10
- Literal,
11
- NamedTuple,
12
- NoReturn,
13
- Optional,
14
- Sequence,
15
- Tuple,
16
- Union,
17
- Type,
18
- )
19
8
  import time
20
9
  from functools import wraps
21
10
  from pathlib import Path
22
11
  import requests
23
- import pylinks as _pylinks
12
+
13
+ from pylinks.exception import api as _exception
14
+
15
+ if _TYPE_CHECKING:
16
+ from typing import (
17
+ Any,
18
+ Callable,
19
+ List,
20
+ Literal,
21
+ NoReturn,
22
+ Optional,
23
+ Sequence,
24
+ Tuple,
25
+ Union,
26
+ Type,
27
+ )
28
+ from pylinks.url import URL
29
+
24
30
 
25
31
 
26
- class RetryConfig(NamedTuple):
32
+ class RetryConfig(_NamedTuple):
27
33
  """
28
34
  Configuration for the `retry_on_exception` decorator.
29
35
 
@@ -46,7 +52,7 @@ class RetryConfig(NamedTuple):
46
52
  sleep_time_scale: float = 3
47
53
 
48
54
 
49
- class HTTPRequestRetryConfig(NamedTuple):
55
+ class HTTPRequestRetryConfig(_NamedTuple):
50
56
  """
51
57
  Configurations for retrying an HTTP request
52
58
  sent by `opencadd.webapi.http_request.response_http_request`.
@@ -73,7 +79,7 @@ class HTTPRequestRetryConfig(NamedTuple):
73
79
 
74
80
 
75
81
  def request(
76
- url: str | _pylinks.url.URL,
82
+ url: str | URL,
77
83
  verb: Union[str, Literal["GET", "POST", "PUT", "PATCH", "OPTIONS", "DELETE"]] = "GET",
78
84
  params: Optional[Union[dict, List[tuple], bytes]] = None,
79
85
  data: Optional[Union[dict, List[tuple], bytes]] = None,
@@ -170,7 +176,7 @@ def request(
170
176
  json=json,
171
177
  )
172
178
  except requests.exceptions.RequestException as e:
173
- raise _pylinks.exceptions.WebAPIRequestError(e) from e
179
+ raise _exception.WebAPIRequestError(e) from e
174
180
  _raise_for_status_code(
175
181
  response=response,
176
182
  temporary_error_status_codes=(
@@ -192,7 +198,7 @@ def request(
192
198
  else _retry_on_exception(
193
199
  get_response,
194
200
  config=retry_config.config_status,
195
- catch=_pylinks.exceptions.WebAPITemporaryStatusCodeError,
201
+ catch=_exception.WebAPITemporaryStatusCodeError,
196
202
  )
197
203
  )
198
204
  # Call the (decorated or non-decorated) response function.
@@ -215,13 +221,12 @@ def request(
215
221
  if response_verifier is None or response_verifier(response_value):
216
222
  return response_value
217
223
  # otherwise raise
218
- raise _pylinks.exceptions.WebAPIValueError(response_value=response_value, response_verifier=response_verifier)
224
+ raise _exception.WebAPIValueError(response_value=response_value, response_verifier=response_verifier)
219
225
 
220
226
  # Depending on specifications in argument `retry_config`, either decorate `get_response_value`
221
227
  # with `retry_on_exception`, or leave it as is.
222
228
  response_val_func = (
223
- get_response_value
224
- if (
229
+ get_response_value if (
225
230
  retry_config is None
226
231
  or retry_config.config_response is None
227
232
  or response_verifier is None
@@ -229,7 +234,7 @@ def request(
229
234
  else _retry_on_exception(
230
235
  get_response_value,
231
236
  config=retry_config.config_response,
232
- catch=_pylinks.exceptions.WebAPIValueError,
237
+ catch=_exception.WebAPIValueError,
233
238
  )
234
239
  )
235
240
  # Call the (decorated or non-decorated) response-value function and return.
@@ -269,9 +274,9 @@ def graphql_query(
269
274
  response = request(**args)
270
275
  if isinstance(response, dict):
271
276
  if "errors" in response:
272
- raise _pylinks.exceptions.WebAPIError(response)
277
+ raise _exception.WebAPIError(response)
273
278
  elif "data" not in response:
274
- raise _pylinks.exceptions.WebAPIError(response)
279
+ raise _exception.WebAPIError(response)
275
280
  else:
276
281
  response = response["data"]
277
282
  return response
@@ -355,9 +360,9 @@ def _raise_for_status_code(
355
360
  temporary_error_status_codes is not None
356
361
  and response.status_code in temporary_error_status_codes
357
362
  ):
358
- raise _pylinks.exceptions.WebAPITemporaryStatusCodeError(response)
363
+ raise _exception.WebAPITemporaryStatusCodeError(response)
359
364
  if error_status_code_range[0] <= response.status_code <= error_status_code_range[1]:
360
- raise _pylinks.exceptions.WebAPIPersistentStatusCodeError(response)
365
+ raise _exception.WebAPIPersistentStatusCodeError(response)
361
366
  return
362
367
 
363
368
 
@@ -1 +0,0 @@
1
- requests<3,>=2.31.0
@@ -1,2 +0,0 @@
1
- from pylinks.exception.base import PyLinksException
2
- from pylinks.exception import media_type
@@ -1,23 +0,0 @@
1
- """PyLinks base exception."""
2
-
3
- from pathlib import Path as _Path
4
-
5
-
6
- class PyLinksException(Exception):
7
- """Base exception for PyLinks.
8
-
9
- All exceptions raised by PyLinks inherit from this class.
10
- """
11
- def __init__(self, message: str):
12
- self.message = message
13
- super().__init__(message)
14
- return
15
-
16
-
17
- class PyLinksFileNotFoundError(PyLinksException):
18
- """File not found error."""
19
- def __init__(self, path: str | _Path):
20
- msg = f"No file found at input path '{path}.'"
21
- super().__init__(message=msg)
22
- self.path = path
23
- return
@@ -1,20 +0,0 @@
1
- from pylinks.exception import PyLinksException as _PyLinksException
2
-
3
-
4
- class PyLinksMediaTypeParseError(_PyLinksException):
5
- """Error parsing a media type."""
6
- def __init__(self, message: str, media_type: str):
7
- msg = f"Failed to parse media type '{media_type}': {message}"
8
- super().__init__(message=msg)
9
- self.message = message
10
- self.media_type = media_type
11
- return
12
-
13
-
14
- class PyLinksMediaTypeGuessError(_PyLinksException):
15
- """Error guessing the media type of a data URI."""
16
- def __init__(self, path: str):
17
- msg = f"Failed to guess the media type of '{path}'."
18
- super().__init__(message=msg)
19
- self.path = path
20
- return
@@ -1,13 +0,0 @@
1
- from pathlib import Path as _Path
2
-
3
- from pylinks.exception import PyLinksException as _PyLinksException
4
-
5
-
6
- class PyLinksDataURIParseError(_PyLinksException):
7
- """Error parsing a data URI."""
8
- def __init__(self, message: str, data_uri: str):
9
- msg = f"Failed to parse data URI '{data_uri}': {message}"
10
- super().__init__(message=msg)
11
- self.message = message
12
- self.data_uri = data_uri
13
- return
@@ -1,74 +0,0 @@
1
- """Custom exceptions raised by the package."""
2
-
3
-
4
- from typing import Any, Callable
5
- import requests
6
-
7
-
8
- class WebAPIError(IOError):
9
- """Base Exception class for all web API exceptions."""
10
- pass
11
-
12
-
13
- class WebAPIStatusCodeError(WebAPIError):
14
- """
15
- Base Exception class for web API status code related exceptions.
16
- By default, raised when status code is in range [400, 600).
17
- """
18
-
19
- def __init__(self, response: requests.Response):
20
- self.response: requests.Response = response
21
- # Decode error reason from server
22
- # This part is adapted from `requests` library; See PR #3538 on their GitHub
23
- if isinstance(response.reason, bytes):
24
- try:
25
- self.reason = response.reason.decode("utf-8")
26
- except UnicodeDecodeError:
27
- self.reason = response.reason.decode("iso-8859-1")
28
- else:
29
- self.reason = response.reason
30
- self.response_msg = response.text
31
- self.side = "client" if response.status_code < 500 else "server"
32
- self.status_code = response.status_code
33
- self.url = response.url
34
-
35
- error_msg = (
36
- f"HTTP {self.side} error (status code: {self.status_code})\n"
37
- f"- From: {self.url}\n"
38
- f"- Reason: {self.reason}\n"
39
- f"- Response: {self.response_msg}"
40
- )
41
- super().__init__(error_msg)
42
- return
43
-
44
-
45
- class WebAPITemporaryStatusCodeError(WebAPIStatusCodeError):
46
- """
47
- Exception class for status code errors related to temporary issues.
48
- By default, raised when status code is in (408, 429, 500, 502, 503, 504).
49
- """
50
- pass
51
-
52
-
53
- class WebAPIPersistentStatusCodeError(WebAPIStatusCodeError):
54
- """
55
- Exception class for status code errors related to persistent issues.
56
- By default, raised when status code is in range [400, 600),
57
- but not in (408, 429, 500, 502, 503, 504).
58
- """
59
- pass
60
-
61
-
62
- class WebAPIValueError(WebAPIError):
63
- """
64
- Exception class for response value errors.
65
- """
66
-
67
- def __init__(self, response_value: Any, response_verifier: Callable[[Any], bool]):
68
- self.response_value = response_value
69
- self.response_verifier = response_verifier
70
- error_msg = (
71
- f"Response verifier function {response_verifier} failed to verify {response_value}."
72
- )
73
- super().__init__(error_msg)
74
- return
File without changes