internetdata 2.9.2__tar.gz → 2.9.3__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.
- {internetdata-2.9.2 → internetdata-2.9.3}/PKG-INFO +2 -2
- {internetdata-2.9.2 → internetdata-2.9.3}/README.md +1 -1
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/__init__.py +1 -1
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_core.py +46 -6
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/aio.py +3 -2
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/client.py +7 -2
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/models.py +90 -29
- {internetdata-2.9.2 → internetdata-2.9.3}/tests/test_client.py +153 -2
- {internetdata-2.9.2 → internetdata-2.9.3}/.gitignore +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/LICENSE +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/pyproject.toml +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/scripts/download-spec.sh +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/scripts/generate.sh +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/scripts/publish.sh +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/scripts/v2_subset.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/spec/openapi.yaml +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/__init__.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/__init__.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/account/__init__.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/account/account_identity.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/api_keys/__init__.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/api_keys/account_create_apikey.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/api_keys/account_list_apikeys.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/api_keys/account_reveal_apikey.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/api_keys/account_revoke_apikey.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/api_keys/account_rotate_apikey.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/authorization/__init__.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/authorization/oauth_authorize.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/authorization/oauth_device_authorization.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/authorization/oauth_metadata.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/authorization/oauth_register.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/authorization/oauth_revoke.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/authorization/oauth_token.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/database_v_2/__init__.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/database_v_2/database_checksum_v2.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/database_v_2/database_metadata_v2.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/database_v_2/download_database_v2.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/database_v_2/list_databases.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/database_v_2/list_downloads.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/organization/__init__.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/organization/account_org.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/organization/account_org_members.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/client.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/errors.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/__init__.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_create_apikey_request.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_created_apikey.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_org.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_org_ref.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_org_wrap.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_rc.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_revealed_apikey.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_user.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/apikey_detail.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/apikey_list.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/client_registration.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/client_registration_request.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_checksum_v2_response_200.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_format.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_license_type_type_1.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_license_type_type_2_type_1.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_license_type_type_3_type_1.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_metadata.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_metadata_column.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_metadata_sample.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_metadata_sample_additional_property_item.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_metadata_sample_size.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_metadata_schema.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_metadata_size.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_version.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/db_checksums.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/device_authorization.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/device_authorization_request.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/download.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/download_outcome.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/error.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/identity.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/list_databases_response_200.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/list_downloads_response_200.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/oauth_authorize_code_challenge_method.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/oauth_authorize_response_type.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/oauth_error.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/oauth_metadata.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/oauth_revoke_response_200.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/revoke_request.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/standing.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/token_request.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/token_response.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/types.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/errors.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/py.typed +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/testdata/testdata.json +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/tests/conftest.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/tests/helpers.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/tests/test_conformance.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/tests/test_download.py +0 -0
- {internetdata-2.9.2 → internetdata-2.9.3}/tests/test_oauth.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: internetdata
|
|
3
|
-
Version: 2.9.
|
|
3
|
+
Version: 2.9.3
|
|
4
4
|
Summary: Official Python client library for the InternetData API. Download and verify licensed IP datasets.
|
|
5
5
|
Project-URL: Homepage, https://internetdata.io
|
|
6
6
|
Project-URL: Documentation, https://docs.internetdata.io
|
|
@@ -180,7 +180,7 @@ From 2.3.0, `list`, `metadata`, `checksums`, `downloads` and `download_url` each
|
|
|
180
180
|
|
|
181
181
|
**Changed in 2.2.0:** a timeout of 0 or less, NaN or a string used to be accepted, and failed every call.
|
|
182
182
|
|
|
183
|
-
|
|
183
|
+
`rate_limited` is a 429 that carries `Retry-After`, and the library retries it for you, as it does server and network failures. `quota_exceeded` is a 429 without one, which it never retries, and it retries nothing else you sent either. InternetData's database API has no quota, so you won't see `quota_exceeded` from it.
|
|
184
184
|
|
|
185
185
|
### Sign in with OAuth (device flow)
|
|
186
186
|
|
|
@@ -146,7 +146,7 @@ From 2.3.0, `list`, `metadata`, `checksums`, `downloads` and `download_url` each
|
|
|
146
146
|
|
|
147
147
|
**Changed in 2.2.0:** a timeout of 0 or less, NaN or a string used to be accepted, and failed every call.
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
`rate_limited` is a 429 that carries `Retry-After`, and the library retries it for you, as it does server and network failures. `quota_exceeded` is a 429 without one, which it never retries, and it retries nothing else you sent either. InternetData's database API has no quota, so you won't see `quota_exceeded` from it.
|
|
150
150
|
|
|
151
151
|
### Sign in with OAuth (device flow)
|
|
152
152
|
|
|
@@ -167,15 +167,17 @@ def check_timeout(timeout: float | None) -> float | None:
|
|
|
167
167
|
`server_error` blaming the API. So is anything past `WAIT_CEILING`, infinity
|
|
168
168
|
included, since the sync client's wait cannot hold it: 1e300 failed every call with
|
|
169
169
|
a raw `OverflowError` (2.6.0, measured 2026-09-30). None is the spelling for no bound.
|
|
170
|
+
|
|
171
|
+
Compared rather than handed to `math.isfinite`, which raised a raw `OverflowError` for
|
|
172
|
+
an integer too large for a float, such as 10**400 (2.9.2, measured 2026-10-25). NaN
|
|
173
|
+
fails both comparisons.
|
|
170
174
|
"""
|
|
171
175
|
if timeout is None:
|
|
172
176
|
return None
|
|
173
177
|
if (
|
|
174
178
|
isinstance(timeout, bool)
|
|
175
179
|
or not isinstance(timeout, int | float)
|
|
176
|
-
or not
|
|
177
|
-
or timeout <= 0
|
|
178
|
-
or timeout > WAIT_CEILING
|
|
180
|
+
or not 0 < timeout <= WAIT_CEILING
|
|
179
181
|
):
|
|
180
182
|
raise ValueError(
|
|
181
183
|
f"timeout must be a number of seconds greater than 0 and at most "
|
|
@@ -184,6 +186,25 @@ def check_timeout(timeout: float | None) -> float | None:
|
|
|
184
186
|
return timeout
|
|
185
187
|
|
|
186
188
|
|
|
189
|
+
def check_retries(retries: float) -> float:
|
|
190
|
+
"""`retries`, once it is a count of retries: a whole number from 0, or `math.inf` to
|
|
191
|
+
retry a failing call until it succeeds.
|
|
192
|
+
|
|
193
|
+
Refused where it is SET, because nothing downstream refuses it: NaN compares false with
|
|
194
|
+
every attempt number, so a failing call was retried until it succeeded, a negative read
|
|
195
|
+
as 0, 1.5 as two retries, and a string or None raised a raw `TypeError` out of every
|
|
196
|
+
call that failed, a 404 included (2.9.2, measured 2026-10-25).
|
|
197
|
+
"""
|
|
198
|
+
if (
|
|
199
|
+
isinstance(retries, bool)
|
|
200
|
+
or not isinstance(retries, int | float)
|
|
201
|
+
or not retries >= 0
|
|
202
|
+
or (isinstance(retries, float) and not (retries.is_integer() or retries == math.inf))
|
|
203
|
+
):
|
|
204
|
+
raise ValueError(f"retries must be a whole number from 0, or math.inf, not {retries!r}")
|
|
205
|
+
return retries
|
|
206
|
+
|
|
207
|
+
|
|
187
208
|
def storage_refusal(res: httpx.Response) -> InternetDataError:
|
|
188
209
|
"""What object storage refusing a download link becomes.
|
|
189
210
|
|
|
@@ -553,12 +574,22 @@ def databases_of(body: dict[str, Any]) -> list[Database]:
|
|
|
553
574
|
Nothing is added here, and nothing may be: a family built for a single customer is
|
|
554
575
|
absent from this array for every organization that does not license it, so filling a
|
|
555
576
|
gap from any other source would publish the fact that the family exists.
|
|
577
|
+
|
|
578
|
+
An object where the list is due is refused rather than read as one with nothing in it:
|
|
579
|
+
`{"databases": {}}` answered an empty catalog (2.9.2, measured 2026-10-25).
|
|
556
580
|
"""
|
|
557
|
-
return [to_database(d) for d in body
|
|
581
|
+
return [to_database(d) for d in _listed(body, "databases")]
|
|
558
582
|
|
|
559
583
|
|
|
560
584
|
def downloads_of(body: dict[str, Any]) -> list[Download]:
|
|
561
|
-
return [to_download(d) for d in body
|
|
585
|
+
return [to_download(d) for d in _listed(body, "downloads")]
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def _listed(body: dict[str, Any], name: str) -> list[Any]:
|
|
589
|
+
value = body[name]
|
|
590
|
+
if not isinstance(value, list):
|
|
591
|
+
raise TypeError(f"{name} is not a list: {value!r}")
|
|
592
|
+
return value
|
|
562
593
|
|
|
563
594
|
|
|
564
595
|
def checksums_of(body: dict[str, Any]) -> dict[str, str]:
|
|
@@ -568,7 +599,16 @@ def checksums_of(body: dict[str, Any]) -> dict[str, str]:
|
|
|
568
599
|
The response carries `id` and `format` beside them, so reading a top-level `sha256`
|
|
569
600
|
finds nothing. That exact mistake shipped in another binding's 1.0.x, which is why
|
|
570
601
|
the shared corpus pins the depth.
|
|
602
|
+
|
|
603
|
+
`id` and `format` are read too, though nothing returns them: a null or numeric `id`
|
|
604
|
+
came back as a whole answer, and so did `checksums` sent as a list of pairs (2.9.2,
|
|
605
|
+
measured 2026-10-25).
|
|
571
606
|
"""
|
|
607
|
+
for member in ("id", "format"):
|
|
608
|
+
if not isinstance(body[member], str):
|
|
609
|
+
raise TypeError(f"the checksum answer's {member} is not a string: {body[member]!r}")
|
|
610
|
+
if not isinstance(body["checksums"], dict):
|
|
611
|
+
raise TypeError(f"checksums is not an object: {body['checksums']!r}")
|
|
572
612
|
digests = dict(body["checksums"])
|
|
573
613
|
for algorithm in ("md5", "sha1", "sha256", "sha512"):
|
|
574
614
|
if not isinstance(digests[algorithm], str):
|
|
@@ -576,7 +616,7 @@ def checksums_of(body: dict[str, Any]) -> dict[str, str]:
|
|
|
576
616
|
return digests
|
|
577
617
|
|
|
578
618
|
|
|
579
|
-
def retry_delay(err: InternetDataError, attempt: int, retries:
|
|
619
|
+
def retry_delay(err: InternetDataError, attempt: int, retries: float) -> float | None:
|
|
580
620
|
"""How long to wait before attempt `attempt + 1`, or None when there must not be one.
|
|
581
621
|
|
|
582
622
|
A server-supplied `Retry-After` wins over the backoff schedule outright: it is the
|
|
@@ -35,6 +35,7 @@ from ._core import (
|
|
|
35
35
|
authorization_url,
|
|
36
36
|
build_async_transfer_client,
|
|
37
37
|
build_client,
|
|
38
|
+
check_retries,
|
|
38
39
|
check_timeout,
|
|
39
40
|
checksums_of,
|
|
40
41
|
create_pkce,
|
|
@@ -109,7 +110,7 @@ class AsyncInternetData:
|
|
|
109
110
|
self._client = build_client(api_key, base_url, timeout, transport)
|
|
110
111
|
self._base_url = base_url
|
|
111
112
|
self._transfer = build_async_transfer_client(timeout, transport)
|
|
112
|
-
self._retries = retries
|
|
113
|
+
self._retries = check_retries(retries)
|
|
113
114
|
self._timeout = timeout
|
|
114
115
|
self.database = AsyncDatabaseApi(self)
|
|
115
116
|
self.oauth = AsyncOauthApi(self)
|
|
@@ -133,7 +134,7 @@ class AsyncInternetData:
|
|
|
133
134
|
def _bound(self, timeout: float | None) -> float | None:
|
|
134
135
|
return self._timeout if timeout is None else check_timeout(timeout)
|
|
135
136
|
|
|
136
|
-
async def _retrying(self, call: Callable[[], Awaitable[T]], retries:
|
|
137
|
+
async def _retrying(self, call: Callable[[], Awaitable[T]], retries: float) -> T:
|
|
137
138
|
attempt = 0
|
|
138
139
|
while True:
|
|
139
140
|
try:
|
|
@@ -30,6 +30,7 @@ from ._core import (
|
|
|
30
30
|
authorization_url,
|
|
31
31
|
build_client,
|
|
32
32
|
build_transfer_client,
|
|
33
|
+
check_retries,
|
|
33
34
|
check_timeout,
|
|
34
35
|
checksums_of,
|
|
35
36
|
create_pkce,
|
|
@@ -94,6 +95,10 @@ class InternetData:
|
|
|
94
95
|
Anything else that is not a finite number greater than 0 is a `ValueError` where it is
|
|
95
96
|
set, rather than a failure of every call.
|
|
96
97
|
|
|
98
|
+
`retries` is how many times a failed attempt is retried, 2 unless given: a whole number
|
|
99
|
+
from 0, or `math.inf` to retry until the call succeeds. Anything else is a `ValueError`
|
|
100
|
+
here too.
|
|
101
|
+
|
|
97
102
|
Holds an HTTP connection pool, so use it as a context manager or call `close()` when
|
|
98
103
|
you are done with it.
|
|
99
104
|
"""
|
|
@@ -117,7 +122,7 @@ class InternetData:
|
|
|
117
122
|
self._client = build_client(api_key, base_url, timeout, transport)
|
|
118
123
|
self._base_url = base_url
|
|
119
124
|
self._transfer = build_transfer_client(timeout, transport)
|
|
120
|
-
self._retries = retries
|
|
125
|
+
self._retries = check_retries(retries)
|
|
121
126
|
self._timeout = timeout
|
|
122
127
|
self.database = DatabaseApi(self)
|
|
123
128
|
self.oauth = OauthApi(self)
|
|
@@ -141,7 +146,7 @@ class InternetData:
|
|
|
141
146
|
def _bound(self, timeout: float | None) -> float | None:
|
|
142
147
|
return self._timeout if timeout is None else check_timeout(timeout)
|
|
143
148
|
|
|
144
|
-
def _retrying(self, call: Callable[[], T], retries:
|
|
149
|
+
def _retrying(self, call: Callable[[], T], retries: float) -> T:
|
|
145
150
|
attempt = 0
|
|
146
151
|
while True:
|
|
147
152
|
try:
|
|
@@ -10,6 +10,7 @@ them so a field this pinned spec predates is still reachable.
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import datetime
|
|
13
|
+
import re
|
|
13
14
|
from dataclasses import dataclass, field
|
|
14
15
|
from typing import Any, Literal, get_args
|
|
15
16
|
|
|
@@ -177,12 +178,12 @@ def to_database(body: dict[str, Any]) -> Database:
|
|
|
177
178
|
base=_present(body, "base", str),
|
|
178
179
|
name=_present(body, "name", str),
|
|
179
180
|
summary=_present(body, "summary", str),
|
|
180
|
-
standing=_present(body, "standing", str),
|
|
181
|
-
license_type=_nullable(body, "license_type", str),
|
|
182
|
-
starts=_datetime(body["starts"]),
|
|
183
|
-
expires=_datetime(body["expires"]),
|
|
184
|
-
renews_at=_datetime(body["renews_at"]),
|
|
185
|
-
notice_due_at=_datetime(body["notice_due_at"]),
|
|
181
|
+
standing=_one_of(_present(body, "standing", str), STANDINGS, "standing"),
|
|
182
|
+
license_type=_one_of(_nullable(body, "license_type", str), LICENSE_TYPES, "license_type"),
|
|
183
|
+
starts=_datetime(body["starts"], "starts"),
|
|
184
|
+
expires=_datetime(body["expires"], "expires"),
|
|
185
|
+
renews_at=_datetime(body["renews_at"], "renews_at"),
|
|
186
|
+
notice_due_at=_datetime(body["notice_due_at"], "notice_due_at"),
|
|
186
187
|
versions=tuple(to_version(v) for v in _present(body, "versions", list)),
|
|
187
188
|
raw=body,
|
|
188
189
|
open=_present(body, "open", bool),
|
|
@@ -190,26 +191,37 @@ def to_database(body: dict[str, Any]) -> Database:
|
|
|
190
191
|
|
|
191
192
|
|
|
192
193
|
def to_version(body: dict[str, Any]) -> DatabaseVersion:
|
|
194
|
+
sample_formats = _nullable(body, "sample_formats", list, absent=True)
|
|
193
195
|
return DatabaseVersion(
|
|
194
196
|
id=_present(body, "id", str),
|
|
195
197
|
version=_present(body, "version", int),
|
|
196
198
|
summary=_present(body, "summary", str),
|
|
197
199
|
formats=_strings(_present(body, "formats", list), "formats"),
|
|
198
|
-
sample_formats=
|
|
200
|
+
sample_formats=None
|
|
201
|
+
if sample_formats is None
|
|
202
|
+
else _strings(sample_formats, "sample_formats"),
|
|
199
203
|
)
|
|
200
204
|
|
|
201
205
|
|
|
202
206
|
def to_metadata(body: dict[str, Any]) -> DatabaseMetadata:
|
|
207
|
+
schema = _present(body, "schema", dict)
|
|
208
|
+
sample = _of_type(body.get("sample", {}), "sample", dict)
|
|
203
209
|
return DatabaseMetadata(
|
|
204
210
|
id=_present(body, "id", str),
|
|
205
|
-
updated=
|
|
211
|
+
updated=_date(_present(body, "updated", str), "updated"),
|
|
206
212
|
entries=_present(body, "entries", int),
|
|
207
213
|
schema={
|
|
208
|
-
fmt: tuple(
|
|
214
|
+
fmt: tuple(
|
|
215
|
+
to_column(_of_type(c, "schema", dict)) for c in _of_type(cols, "schema", list)
|
|
216
|
+
)
|
|
217
|
+
for fmt, cols in schema.items()
|
|
209
218
|
},
|
|
210
219
|
size=_sizes(_present(body, "size", dict), "size"),
|
|
211
|
-
update_freq=body
|
|
212
|
-
sample={
|
|
220
|
+
update_freq=_nullable(body, "update_freq", str, absent=True),
|
|
221
|
+
sample={
|
|
222
|
+
fmt: tuple(_of_type(row, "sample", dict) for row in _of_type(rows, "sample", list))
|
|
223
|
+
for fmt, rows in sample.items()
|
|
224
|
+
},
|
|
213
225
|
raw=body,
|
|
214
226
|
sample_size=_sizes(body["sample_size"], "sample_size")
|
|
215
227
|
if body.get("sample_size") is not None
|
|
@@ -222,7 +234,7 @@ def to_column(body: dict[str, Any]) -> MetadataColumn:
|
|
|
222
234
|
return MetadataColumn(
|
|
223
235
|
name=_present(body, "name", str),
|
|
224
236
|
type=_present(body, "type", str),
|
|
225
|
-
description=body
|
|
237
|
+
description=_nullable(body, "description", str, absent=True),
|
|
226
238
|
)
|
|
227
239
|
|
|
228
240
|
|
|
@@ -230,13 +242,13 @@ def to_download(body: dict[str, Any]) -> Download:
|
|
|
230
242
|
return Download(
|
|
231
243
|
dataset_id=_present(body, "dataset_id", str),
|
|
232
244
|
format=_present(body, "format", str),
|
|
233
|
-
outcome=_present(body, "outcome", str),
|
|
234
|
-
created=
|
|
245
|
+
outcome=_one_of(_present(body, "outcome", str), get_args(Outcome), "outcome"),
|
|
246
|
+
created=_date_time(_present(body, "created", str), "created"),
|
|
235
247
|
bytes=_nullable(body, "bytes", int),
|
|
236
248
|
http_status=_nullable(body, "http_status", int),
|
|
237
|
-
apikey_id=body
|
|
238
|
-
client_ip=body
|
|
239
|
-
user_agent=body
|
|
249
|
+
apikey_id=_nullable(body, "apikey_id", str),
|
|
250
|
+
client_ip=_nullable(body, "client_ip", str),
|
|
251
|
+
user_agent=_nullable(body, "user_agent", str),
|
|
240
252
|
sample=_present(body, "sample", bool),
|
|
241
253
|
open=_present(body, "open", bool),
|
|
242
254
|
)
|
|
@@ -273,25 +285,74 @@ def _strings(values: list[Any], name: str) -> tuple[Any, ...]:
|
|
|
273
285
|
return tuple(_of_type(v, name, str) for v in values)
|
|
274
286
|
|
|
275
287
|
|
|
276
|
-
def
|
|
277
|
-
|
|
288
|
+
def _one_of(value: Any, allowed: tuple[str, ...], name: str) -> Any:
|
|
289
|
+
"""`value`, a member of `allowed`, or None. One outside it is a value this client was not
|
|
290
|
+
built for: `license_type` came back as served while its type promised one of three, and
|
|
291
|
+
`standing` beside it was refused (2.9.2, measured 2026-10-25)."""
|
|
292
|
+
if value is not None and value not in allowed:
|
|
293
|
+
raise ValueError(f"{name} is not one of {', '.join(allowed)}: {value!r}")
|
|
294
|
+
return value
|
|
278
295
|
|
|
279
296
|
|
|
280
|
-
def
|
|
281
|
-
return
|
|
297
|
+
def _sizes(sizes: Any, name: str) -> dict[str, int]:
|
|
298
|
+
return {fmt: _of_type(n, name, int) for fmt, n in _of_type(sizes, name, dict).items()}
|
|
282
299
|
|
|
283
300
|
|
|
284
|
-
def _datetime(value: Any) -> datetime.datetime | None:
|
|
301
|
+
def _datetime(value: Any, name: str) -> datetime.datetime | None:
|
|
285
302
|
"""A NULLABLE wire timestamp. A license with no end date carries `expires: null`.
|
|
286
303
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
raises, and the caller reports it as the server's failure rather than as None, which
|
|
290
|
-
would quietly read as "no end date".
|
|
304
|
+
A value that is neither null nor readable raises, and the caller reports it as the
|
|
305
|
+
server's failure rather than as None, which would quietly read as "no end date".
|
|
291
306
|
"""
|
|
292
|
-
if value is None
|
|
293
|
-
|
|
294
|
-
|
|
307
|
+
return None if value is None else _date_time(value, name)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
# The spec's `date-time` and `date` are RFC 3339's, and only those are read: `fromisoformat`
|
|
311
|
+
# took a date-time with no offset as a naive datetime, which no aware one can be compared
|
|
312
|
+
# with, a date alone as midnight, `+0500`, `+05`, `+05:00:30`, `+05:60` as an hour more,
|
|
313
|
+
# a space for the `T`, no seconds, a comma for the point, week dates and `20261005`
|
|
314
|
+
# (2.9.2, measured 2026-10-25). RFC 3339 allows a lowercase `t` and `z`, which it refused.
|
|
315
|
+
_DIGITS2 = "([0-9]{2})"
|
|
316
|
+
_FULL_DATE = re.compile(rf"([0-9]{{4}})-{_DIGITS2}-{_DIGITS2}")
|
|
317
|
+
_DATE_TIME = re.compile(
|
|
318
|
+
rf"([0-9]{{4}})-{_DIGITS2}-{_DIGITS2}[Tt]{_DIGITS2}:{_DIGITS2}:{_DIGITS2}(?:\.([0-9]+))?"
|
|
319
|
+
rf"(?:[Zz]|([+-]){_DIGITS2}:{_DIGITS2})"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _date(value: str, name: str) -> datetime.date:
|
|
324
|
+
match = _FULL_DATE.fullmatch(value)
|
|
325
|
+
if match is None:
|
|
326
|
+
raise ValueError(f"{name} is not an RFC 3339 date: {value!r}")
|
|
327
|
+
# A day its month lacks, 30 February, raises here.
|
|
328
|
+
return datetime.date(*(int(part) for part in match.groups()))
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _date_time(value: Any, name: str) -> datetime.datetime:
|
|
332
|
+
match = _DATE_TIME.fullmatch(_of_type(value, name, str))
|
|
333
|
+
if match is None:
|
|
334
|
+
raise ValueError(f"{name} is not an RFC 3339 date-time: {value!r}")
|
|
335
|
+
year, month, day, hour, minute, second, fraction, sign, offset_hour, offset_minute = (
|
|
336
|
+
match.groups()
|
|
337
|
+
)
|
|
338
|
+
zone = datetime.UTC
|
|
339
|
+
if sign is not None:
|
|
340
|
+
if int(offset_hour) > 23 or int(offset_minute) > 59:
|
|
341
|
+
raise ValueError(f"{name} has no such offset: {value!r}")
|
|
342
|
+
offset = datetime.timedelta(hours=int(offset_hour), minutes=int(offset_minute))
|
|
343
|
+
zone = datetime.timezone(-offset if sign == "-" else offset)
|
|
344
|
+
# A day its month lacks, an hour of 24 and a leap second's 60 raise here; past six
|
|
345
|
+
# digits a fraction is cut, as `fromisoformat` cuts it.
|
|
346
|
+
return datetime.datetime(
|
|
347
|
+
int(year),
|
|
348
|
+
int(month),
|
|
349
|
+
int(day),
|
|
350
|
+
int(hour),
|
|
351
|
+
int(minute),
|
|
352
|
+
int(second),
|
|
353
|
+
int((fraction or "")[:6].ljust(6, "0")),
|
|
354
|
+
tzinfo=zone,
|
|
355
|
+
)
|
|
295
356
|
|
|
296
357
|
|
|
297
358
|
@dataclass(frozen=True, slots=True)
|
|
@@ -454,6 +454,86 @@ UNREADABLE_MEMBERS.update(
|
|
|
454
454
|
}
|
|
455
455
|
)
|
|
456
456
|
|
|
457
|
+
_CHECKSUM = {"id": "bogon_ip_v1", "format": "csvgz", "checksums": DIGESTS}
|
|
458
|
+
|
|
459
|
+
# Each of these came back from 2.9.2 as an answer (measured 2026-10-25): an object where a
|
|
460
|
+
# list is due as an empty one, a member typed nowhere but the spec as served, a
|
|
461
|
+
# `license_type` outside its three, and a checksum answer's unread `id` whatever it held.
|
|
462
|
+
UNREADABLE_MEMBERS.update(
|
|
463
|
+
{
|
|
464
|
+
"list databases as an object": (LIST_PATH, {"databases": {}}),
|
|
465
|
+
"downloads as an object": (DOWNLOADS_PATH, {"downloads": {}}),
|
|
466
|
+
"list license_type outside its enum": (
|
|
467
|
+
LIST_PATH,
|
|
468
|
+
{"databases": [_with("license_type", "trial", database("bogon_ip"))]},
|
|
469
|
+
),
|
|
470
|
+
"list sample_formats as an object": (
|
|
471
|
+
LIST_PATH,
|
|
472
|
+
{"databases": [_version_with("sample_formats", {})]},
|
|
473
|
+
),
|
|
474
|
+
"metadata update_freq as a number": (METADATA_PATH, _with("update_freq", 1, METADATA)),
|
|
475
|
+
"metadata column description as a number": (
|
|
476
|
+
METADATA_PATH,
|
|
477
|
+
{**METADATA, "schema": {"csvgz": [{"name": "ip", "type": "string", "description": 1}]}},
|
|
478
|
+
),
|
|
479
|
+
"metadata columns as an object": (METADATA_PATH, {**METADATA, "schema": {"csvgz": {}}}),
|
|
480
|
+
"metadata sample rows as an object": (METADATA_PATH, {**METADATA, "sample": {"csvgz": {}}}),
|
|
481
|
+
"metadata sample row as pairs": (
|
|
482
|
+
METADATA_PATH,
|
|
483
|
+
{**METADATA, "sample": {"csvgz": [[["first_ip", "10.0.0.0"]]]}},
|
|
484
|
+
),
|
|
485
|
+
**{
|
|
486
|
+
f"downloads {m} as a number": (DOWNLOADS_PATH, {"downloads": [_with(m, 7, _DOWNLOAD)]})
|
|
487
|
+
for m in ("apikey_id", "client_ip", "user_agent")
|
|
488
|
+
},
|
|
489
|
+
"checksums id as null": (CHECKSUM_PATH, _with("id", None, _CHECKSUM)),
|
|
490
|
+
"checksums id as a number": (CHECKSUM_PATH, _with("id", 7, _CHECKSUM)),
|
|
491
|
+
"checksums as pairs": (CHECKSUM_PATH, _with("checksums", list(DIGESTS.items()), _CHECKSUM)),
|
|
492
|
+
}
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
# What `fromisoformat` read as a date-time and RFC 3339 does not (2.9.2, measured
|
|
496
|
+
# 2026-10-25): no offset, which made a naive datetime, a date alone, a space for the `T`,
|
|
497
|
+
# offsets without their colon, with seconds or past 23:59, no seconds, a comma for the
|
|
498
|
+
# point, the basic format and a week date. Then what neither reads.
|
|
499
|
+
NOT_DATE_TIMES = [
|
|
500
|
+
"2026-10-05T10:00:00",
|
|
501
|
+
"2026-10-05",
|
|
502
|
+
"2026-10-05 10:00:00Z",
|
|
503
|
+
"2026-10-05T10:00:00+0500",
|
|
504
|
+
"2026-10-05T10:00:00+05",
|
|
505
|
+
"2026-10-05T10:00:00+05:00:30",
|
|
506
|
+
"2026-10-05T10:00:00+05:60",
|
|
507
|
+
"2026-10-05T10:00:00+24:00",
|
|
508
|
+
"2026-10-05T10:00Z",
|
|
509
|
+
"2026-10-05T10:00:00,5Z",
|
|
510
|
+
"20261005T100000Z",
|
|
511
|
+
"2026-W41-1T10:00:00Z",
|
|
512
|
+
"2026-10-5T10:00:00Z",
|
|
513
|
+
" 2026-10-05T10:00:00Z",
|
|
514
|
+
"2026-02-30T10:00:00Z",
|
|
515
|
+
"2026-10-05T23:59:60Z",
|
|
516
|
+
"tomorrow",
|
|
517
|
+
]
|
|
518
|
+
|
|
519
|
+
# The same for `updated`, a `date`: the basic format and week dates were read.
|
|
520
|
+
NOT_DATES = ["20261005", "2026-W41-1", "2026-W41", "2026-10-5", "2026-02-30", "2026-10-05T00:00Z"]
|
|
521
|
+
|
|
522
|
+
for _value in NOT_DATE_TIMES:
|
|
523
|
+
UNREADABLE_MEMBERS[f"list starts {_value!r}"] = (
|
|
524
|
+
LIST_PATH,
|
|
525
|
+
{"databases": [database("bogon_ip", starts=_value)]},
|
|
526
|
+
)
|
|
527
|
+
UNREADABLE_MEMBERS[f"downloads created {_value!r}"] = (
|
|
528
|
+
DOWNLOADS_PATH,
|
|
529
|
+
{"downloads": [_with("created", _value, _DOWNLOAD)]},
|
|
530
|
+
)
|
|
531
|
+
for _value in NOT_DATES:
|
|
532
|
+
UNREADABLE_MEMBERS[f"metadata updated {_value!r}"] = (
|
|
533
|
+
METADATA_PATH,
|
|
534
|
+
_with("updated", _value, METADATA),
|
|
535
|
+
)
|
|
536
|
+
|
|
457
537
|
MEMBER_CALLS = {LIST_PATH: "list", METADATA_PATH: "metadata", DOWNLOADS_PATH: "downloads"}
|
|
458
538
|
|
|
459
539
|
|
|
@@ -475,6 +555,32 @@ def test_an_answer_missing_what_the_spec_requires_is_a_retried_server_error(
|
|
|
475
555
|
assert len(stub.requests) == 3
|
|
476
556
|
|
|
477
557
|
|
|
558
|
+
@pytest.mark.parametrize(
|
|
559
|
+
"value",
|
|
560
|
+
[
|
|
561
|
+
"2026-10-05T10:00:00Z",
|
|
562
|
+
"2026-10-05t10:00:00z",
|
|
563
|
+
"2026-10-05T10:00:00-00:00",
|
|
564
|
+
"2026-10-05T15:30:00+05:30",
|
|
565
|
+
"2026-10-05T05:00:00.123456789-05:00",
|
|
566
|
+
],
|
|
567
|
+
)
|
|
568
|
+
def test_an_rfc_3339_date_time_is_read_as_the_instant_it_names(
|
|
569
|
+
make_client: ClientFactory, value: str
|
|
570
|
+
) -> None:
|
|
571
|
+
"""In each of RFC 3339's spellings, the lowercase ones `fromisoformat` refused included;
|
|
572
|
+
past six digits a fraction is cut."""
|
|
573
|
+
stub = Stub({LIST_PATH: {"body": {"databases": [database("bogon_ip", starts=value)]}}})
|
|
574
|
+
client = make_client(transport=stub.transport)
|
|
575
|
+
|
|
576
|
+
starts = client.database.list()[0].starts
|
|
577
|
+
|
|
578
|
+
assert starts is not None and starts.utcoffset() is not None
|
|
579
|
+
expected = datetime.datetime(2026, 10, 5, 10, tzinfo=datetime.UTC)
|
|
580
|
+
assert starts.replace(microsecond=0) == expected
|
|
581
|
+
assert starts.microsecond == (123456 if "." in value else 0)
|
|
582
|
+
|
|
583
|
+
|
|
478
584
|
@pytest.mark.parametrize(
|
|
479
585
|
("status", "body", "kind"),
|
|
480
586
|
[
|
|
@@ -538,6 +644,51 @@ def test_retries_are_configurable_on_the_client(make_client: ClientFactory) -> N
|
|
|
538
644
|
assert len(stub.requests) == 1
|
|
539
645
|
|
|
540
646
|
|
|
647
|
+
@pytest.mark.parametrize("client", [InternetData, AsyncInternetData])
|
|
648
|
+
@pytest.mark.parametrize(
|
|
649
|
+
"retries", [-1, float("nan"), 1.5, float("-inf"), "2", None, True, 10**400 * -1]
|
|
650
|
+
)
|
|
651
|
+
def test_a_retry_count_that_is_not_a_whole_number_from_0_is_refused_when_the_client_is_built(
|
|
652
|
+
client: type[InternetData | AsyncInternetData], retries: Any
|
|
653
|
+
) -> None:
|
|
654
|
+
"""Accepted by 2.9.2: NaN retried a failing call until it succeeded, -1 read as 0, 1.5 as
|
|
655
|
+
two retries, and a string or None raised a raw TypeError out of every failing call."""
|
|
656
|
+
with pytest.raises(ValueError, match="retries"):
|
|
657
|
+
client(API_KEY, retries=retries)
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
@pytest.mark.parametrize("retries", [0, 2, 2.0])
|
|
661
|
+
def test_a_whole_retry_count_is_what_a_failing_call_spends(
|
|
662
|
+
make_client: ClientFactory, monkeypatch: pytest.MonkeyPatch, retries: float
|
|
663
|
+
) -> None:
|
|
664
|
+
monkeypatch.setattr(_core, "_BACKOFF_BASE", 0.0)
|
|
665
|
+
stub = Stub({LIST_PATH: {"status": 503, "body": {"rc": "UNAVAILABLE"}}})
|
|
666
|
+
client = make_client(transport=stub.transport, retries=retries)
|
|
667
|
+
|
|
668
|
+
with pytest.raises(InternetDataError):
|
|
669
|
+
client.database.list()
|
|
670
|
+
|
|
671
|
+
assert len(stub.requests) == retries + 1
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def test_an_infinite_retry_count_retries_until_the_call_succeeds(
|
|
675
|
+
make_client: ClientFactory, monkeypatch: pytest.MonkeyPatch
|
|
676
|
+
) -> None:
|
|
677
|
+
monkeypatch.setattr(_core, "_BACKOFF_BASE", 0.0)
|
|
678
|
+
sent: list[httpx.Request] = []
|
|
679
|
+
|
|
680
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
681
|
+
sent.append(request)
|
|
682
|
+
if len(sent) <= 6:
|
|
683
|
+
return httpx.Response(503, json={"rc": "UNAVAILABLE"})
|
|
684
|
+
return httpx.Response(200, json={"databases": []})
|
|
685
|
+
|
|
686
|
+
client = make_client(transport=httpx.MockTransport(handler), retries=float("inf"))
|
|
687
|
+
|
|
688
|
+
assert client.database.list() == []
|
|
689
|
+
assert len(sent) == 7
|
|
690
|
+
|
|
691
|
+
|
|
541
692
|
def test_a_spent_quota_is_never_retried(make_client: ClientFactory) -> None:
|
|
542
693
|
stub = Stub({LIST_PATH: {"status": 429, "body": {"rc": "QUOTA_EXCEEDED"}}})
|
|
543
694
|
client = make_client(transport=stub.transport, retries=3)
|
|
@@ -745,7 +896,7 @@ def test_a_per_call_timeout_bounds_a_trickling_body_and_leaves_the_clients_own_a
|
|
|
745
896
|
_assert_bounded_by(default, CLIENT_TIMEOUT)
|
|
746
897
|
|
|
747
898
|
|
|
748
|
-
@pytest.mark.parametrize("timeout", [0, -1, float("nan"), float("inf"), 1e300, "30", True])
|
|
899
|
+
@pytest.mark.parametrize("timeout", [0, -1, float("nan"), float("inf"), 1e300, 10**400, "30", True])
|
|
749
900
|
@pytest.mark.parametrize("call", PER_CALL)
|
|
750
901
|
def test_a_per_call_timeout_no_attempt_can_meet_is_refused_before_any_request(
|
|
751
902
|
make_client: ClientFactory, call: str, timeout: Any
|
|
@@ -799,7 +950,7 @@ def test_the_default_timeout_is_thirty_seconds() -> None:
|
|
|
799
950
|
|
|
800
951
|
@pytest.mark.parametrize("client", [InternetData, AsyncInternetData])
|
|
801
952
|
@pytest.mark.parametrize(
|
|
802
|
-
"timeout", [0, -1, 0.0, float("nan"), float("inf"), 9223372037, 1e300, "30", True]
|
|
953
|
+
"timeout", [0, -1, 0.0, float("nan"), float("inf"), 9223372037, 1e300, 10**400, "30", True]
|
|
803
954
|
)
|
|
804
955
|
def test_a_timeout_no_attempt_can_meet_is_refused_when_the_client_is_built(
|
|
805
956
|
client: type[InternetData | AsyncInternetData], timeout: Any
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/account/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/api_keys/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/authorization/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/database_v_2/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/api/organization/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_org_ref.py
RENAMED
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_org_wrap.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/account_user.py
RENAMED
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/apikey_detail.py
RENAMED
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/client_registration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_format.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/database_version.py
RENAMED
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/db_checksums.py
RENAMED
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/device_authorization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/download_outcome.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/oauth_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/revoke_request.py
RENAMED
|
File without changes
|
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/token_request.py
RENAMED
|
File without changes
|
{internetdata-2.9.2 → internetdata-2.9.3}/src/internetdata/_generated/models/token_response.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|