internetdata 1.0.0__py3-none-any.whl

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 (46) hide show
  1. internetdata/__init__.py +49 -0
  2. internetdata/_core.py +287 -0
  3. internetdata/_generated/__init__.py +8 -0
  4. internetdata/_generated/api/__init__.py +1 -0
  5. internetdata/_generated/api/database_v_2/__init__.py +1 -0
  6. internetdata/_generated/api/database_v_2/database_checksum_v2.py +203 -0
  7. internetdata/_generated/api/database_v_2/database_metadata_v2.py +205 -0
  8. internetdata/_generated/api/database_v_2/download_database_v2.py +213 -0
  9. internetdata/_generated/api/database_v_2/list_databases.py +162 -0
  10. internetdata/_generated/api/database_v_2/list_downloads.py +178 -0
  11. internetdata/_generated/client.py +272 -0
  12. internetdata/_generated/errors.py +16 -0
  13. internetdata/_generated/models/__init__.py +53 -0
  14. internetdata/_generated/models/database.py +233 -0
  15. internetdata/_generated/models/database_checksum_v2_format.py +9 -0
  16. internetdata/_generated/models/database_checksum_v2_response_200.py +85 -0
  17. internetdata/_generated/models/database_checksum_v2_response_200_format.py +9 -0
  18. internetdata/_generated/models/database_metadata.py +132 -0
  19. internetdata/_generated/models/database_metadata_column.py +80 -0
  20. internetdata/_generated/models/database_metadata_sample.py +78 -0
  21. internetdata/_generated/models/database_metadata_sample_additional_property_item.py +45 -0
  22. internetdata/_generated/models/database_metadata_schema.py +72 -0
  23. internetdata/_generated/models/database_metadata_size.py +47 -0
  24. internetdata/_generated/models/database_redistribution_type_1.py +10 -0
  25. internetdata/_generated/models/database_redistribution_type_2_type_1.py +10 -0
  26. internetdata/_generated/models/database_redistribution_type_3_type_1.py +10 -0
  27. internetdata/_generated/models/database_standing.py +10 -0
  28. internetdata/_generated/models/database_version.py +97 -0
  29. internetdata/_generated/models/database_version_formats_item.py +9 -0
  30. internetdata/_generated/models/db_checksums.py +85 -0
  31. internetdata/_generated/models/download.py +161 -0
  32. internetdata/_generated/models/download_database_v2_format.py +9 -0
  33. internetdata/_generated/models/download_outcome.py +13 -0
  34. internetdata/_generated/models/error.py +62 -0
  35. internetdata/_generated/models/list_databases_response_200.py +75 -0
  36. internetdata/_generated/models/list_downloads_response_200.py +75 -0
  37. internetdata/_generated/types.py +54 -0
  38. internetdata/aio.py +268 -0
  39. internetdata/client.py +278 -0
  40. internetdata/errors.py +128 -0
  41. internetdata/models.py +197 -0
  42. internetdata/py.typed +0 -0
  43. internetdata-1.0.0.dist-info/METADATA +184 -0
  44. internetdata-1.0.0.dist-info/RECORD +46 -0
  45. internetdata-1.0.0.dist-info/WHEEL +4 -0
  46. internetdata-1.0.0.dist-info/licenses/LICENSE +21 -0
internetdata/errors.py ADDED
@@ -0,0 +1,128 @@
1
+ """The one exception this library raises, and how a response becomes one."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import datetime
6
+ import email.utils
7
+ import math
8
+ from typing import Any, Literal
9
+
10
+ import httpx
11
+
12
+ __all__ = ["ErrorKind", "InternetDataError"]
13
+
14
+ ErrorKind = Literal[
15
+ "bad_request",
16
+ "unauthorized",
17
+ "forbidden",
18
+ "rate_limited",
19
+ "quota_exceeded",
20
+ "server_error",
21
+ "network",
22
+ ]
23
+ """Why a request failed.
24
+
25
+ `rate_limited` and `quota_exceeded` both arrive as HTTP 429 and are NOT the same thing.
26
+ A rate limit is the API protecting itself and carries `Retry-After`; retrying works. A
27
+ spent quota carries no such header and retrying will not help until the window rolls
28
+ over or the limit is raised. The header is the only thing that distinguishes them.
29
+ """
30
+
31
+ _RETRYABLE: frozenset[str] = frozenset({"rate_limited", "server_error", "network"})
32
+
33
+
34
+ class InternetDataError(Exception):
35
+ """Every failure this library reports, discriminated by `kind`."""
36
+
37
+ kind: ErrorKind
38
+ status: int | None
39
+ retry_after_seconds: float | None
40
+
41
+ def __init__(
42
+ self,
43
+ kind: ErrorKind,
44
+ message: str,
45
+ status: int | None = None,
46
+ retry_after_seconds: float | None = None,
47
+ ) -> None:
48
+ super().__init__(message)
49
+ self.kind = kind
50
+ self.status = status
51
+ self.retry_after_seconds = retry_after_seconds
52
+
53
+ @property
54
+ def message(self) -> str:
55
+ return str(self)
56
+
57
+ @property
58
+ def retryable(self) -> bool:
59
+ """Whether retrying this exact request could succeed."""
60
+ return self.kind in _RETRYABLE
61
+
62
+ def __repr__(self) -> str:
63
+ return (
64
+ f"InternetDataError(kind={self.kind!r}, status={self.status!r}, message={str(self)!r})"
65
+ )
66
+
67
+
68
+ def error_from_response(status: int, headers: httpx.Headers, body: Any) -> InternetDataError:
69
+ """Classify a failed response.
70
+
71
+ Everything outside the four named statuses is decided by its RANGE rather than by an
72
+ enumerated list, which is the whole point: a 404 from a database id that does not
73
+ exist has to land on a client error, and mapping 400/401/403/429 and letting the rest
74
+ fall through to `server_error` retries it twice before failing. Three of the four
75
+ first SDKs shipped exactly that bug, so the shared corpus pins both 404 shapes.
76
+ """
77
+ message = _message_of(body) or f"request failed with status {status}"
78
+ retry_after = _parse_retry_after(headers.get("retry-after"))
79
+
80
+ if status == 429:
81
+ # Present means transient, absent means an allowance is spent. Nothing else in
82
+ # the response separates the two.
83
+ if retry_after is None:
84
+ return InternetDataError("quota_exceeded", message, status)
85
+ return InternetDataError("rate_limited", message, status, retry_after)
86
+ if status == 401:
87
+ return InternetDataError("unauthorized", message, status)
88
+ if status == 403:
89
+ return InternetDataError("forbidden", message, status)
90
+ if 400 <= status < 500:
91
+ return InternetDataError("bad_request", message, status)
92
+ return InternetDataError("server_error", message, status)
93
+
94
+
95
+ def _message_of(body: Any) -> str | None:
96
+ """The API's own result code, which is the whole error envelope.
97
+
98
+ `rc` is deliberately not an enum in the spec, so a code added later stays readable by
99
+ a client generated today. Passing it through verbatim is what keeps that promise: a
100
+ caller switching on `NOT_LICENSED` versus `LICENSE_EXPIRED` needs the string, not a
101
+ status.
102
+ """
103
+ if not isinstance(body, dict):
104
+ return None
105
+ code = body.get("rc")
106
+ if isinstance(code, str) and code != "":
107
+ return code
108
+ return None
109
+
110
+
111
+ def _parse_retry_after(value: str | None) -> float | None:
112
+ if value is None or value.strip() == "":
113
+ return None
114
+ try:
115
+ seconds = float(value)
116
+ except ValueError:
117
+ pass
118
+ else:
119
+ return seconds if seconds >= 0 else None
120
+ # The header also permits an HTTP date.
121
+ try:
122
+ when = email.utils.parsedate_to_datetime(value)
123
+ except (TypeError, ValueError):
124
+ return None
125
+ if when.tzinfo is None:
126
+ when = when.replace(tzinfo=datetime.UTC)
127
+ delta = (when - datetime.datetime.now(datetime.UTC)).total_seconds()
128
+ return max(0.0, math.ceil(delta))
internetdata/models.py ADDED
@@ -0,0 +1,197 @@
1
+ """What the API answers, and the one place the wire shape becomes an idiomatic one.
2
+
3
+ The generated models are a wire contract rather than an API: the spec spells
4
+ `redistribution` as a nullable enum, which the generator renders as a union of three
5
+ single-member enum classes, and nobody should have to read that. These are frozen
6
+ dataclasses of plain values, built straight from the served JSON, with `raw` kept beside
7
+ them so a field this pinned spec predates is still reachable.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import datetime
13
+ from dataclasses import dataclass, field
14
+ from typing import Any, Literal
15
+
16
+ __all__ = [
17
+ "Database",
18
+ "DatabaseMetadata",
19
+ "DatabaseVersion",
20
+ "Download",
21
+ "Format",
22
+ "MetadataColumn",
23
+ "Outcome",
24
+ "Redistribution",
25
+ "Standing",
26
+ ]
27
+
28
+ Format = Literal["csvgz", "mmdb"]
29
+ """The file formats a database version can be built in.
30
+
31
+ Which of them a given version HAS is `DatabaseVersion.formats`; asking for another is a
32
+ `bad_request` rather than a gap, because the `_provider` catalogs are keyed by provider
33
+ id and no MMDB exists for them.
34
+ """
35
+
36
+ Standing = Literal["licensed", "expired", "unlicensed"]
37
+ """Where your organization stands with one database family."""
38
+
39
+ Redistribution = Literal["evaluation", "internal", "redistribute"]
40
+ """What a licence permits you to do with the data. `None` when there is no licence."""
41
+
42
+ Outcome = Literal["ok", "unauthorized", "denied", "expired", "unknown", "unavailable"]
43
+ """How one download attempt ended, refusals included."""
44
+
45
+
46
+ @dataclass(frozen=True, slots=True)
47
+ class DatabaseVersion:
48
+ """One published version of a family.
49
+
50
+ Old versions are frozen rather than migrated, so several stay downloadable at once.
51
+ `id` is what `download`, `checksums` and `metadata` take; the family `base` is what a
52
+ licence is held against.
53
+ """
54
+
55
+ id: str
56
+ version: int
57
+ summary: str
58
+ formats: tuple[Format, ...]
59
+
60
+
61
+ @dataclass(frozen=True, slots=True)
62
+ class Database:
63
+ """One database FAMILY, with your organization's licence beside it.
64
+
65
+ A family your organization has never licensed is still listed, with `standing` set to
66
+ `unlicensed`, so you can see what else exists. A family commissioned for a single
67
+ customer is a different matter: it is absent from this listing entirely for everyone
68
+ who does not license it. Absence here means "not yours to see", never "does not
69
+ exist", so the catalog is not the same document for every key.
70
+ """
71
+
72
+ base: str
73
+ name: str
74
+ summary: str
75
+ standing: Standing
76
+ redistribution: Redistribution | None
77
+ starts: datetime.datetime | None
78
+ expires: datetime.datetime | None
79
+ versions: tuple[DatabaseVersion, ...]
80
+ raw: dict[str, Any] = field(default_factory=dict)
81
+
82
+
83
+ @dataclass(frozen=True, slots=True)
84
+ class MetadataColumn:
85
+ """One column of a published file. `description` is absent on older builds."""
86
+
87
+ name: str
88
+ type: str
89
+ description: str | None = None
90
+
91
+
92
+ @dataclass(frozen=True, slots=True)
93
+ class DatabaseMetadata:
94
+ """What is inside one database: freshness, row count, columns, samples and sizes.
95
+
96
+ Poll this to decide whether today's build is worth fetching. `size` is keyed by
97
+ format and is in bytes, which is what a caller should budget a transfer against
98
+ before starting one.
99
+ """
100
+
101
+ id: str
102
+ updated: datetime.date
103
+ entries: int
104
+ schema: dict[str, tuple[MetadataColumn, ...]]
105
+ size: dict[str, int]
106
+ update_freq: str | None = None
107
+ sample: dict[str, tuple[dict[str, Any], ...]] = field(default_factory=dict)
108
+ raw: dict[str, Any] = field(default_factory=dict)
109
+
110
+
111
+ @dataclass(frozen=True, slots=True)
112
+ class Download:
113
+ """One download ATTEMPT by your organization, refusals included.
114
+
115
+ `bytes` is the object size when the link was minted rather than bytes delivered: the
116
+ transfer is a presigned redirect straight to object storage, so the API never
117
+ observes how much of it was taken.
118
+ """
119
+
120
+ dataset_id: str
121
+ format: str
122
+ outcome: Outcome
123
+ created: datetime.datetime
124
+ bytes: int | None = None
125
+ http_status: int | None = None
126
+ apikey_id: str | None = None
127
+ client_ip: str | None = None
128
+ user_agent: str | None = None
129
+
130
+
131
+ def to_database(body: dict[str, Any]) -> Database:
132
+ return Database(
133
+ base=body["base"],
134
+ name=body["name"],
135
+ summary=body["summary"],
136
+ standing=body["standing"],
137
+ redistribution=body["redistribution"],
138
+ starts=_datetime(body["starts"]),
139
+ expires=_datetime(body["expires"]),
140
+ versions=tuple(to_version(v) for v in body["versions"]),
141
+ raw=body,
142
+ )
143
+
144
+
145
+ def to_version(body: dict[str, Any]) -> DatabaseVersion:
146
+ return DatabaseVersion(
147
+ id=body["id"],
148
+ version=body["version"],
149
+ summary=body["summary"],
150
+ formats=tuple(body["formats"]),
151
+ )
152
+
153
+
154
+ def to_metadata(body: dict[str, Any]) -> DatabaseMetadata:
155
+ return DatabaseMetadata(
156
+ id=body["id"],
157
+ updated=datetime.date.fromisoformat(body["updated"]),
158
+ entries=body["entries"],
159
+ schema={
160
+ fmt: tuple(to_column(c) for c in columns) for fmt, columns in body["schema"].items()
161
+ },
162
+ size=dict(body["size"]),
163
+ update_freq=body.get("update_freq"),
164
+ sample={fmt: tuple(rows) for fmt, rows in body.get("sample", {}).items()},
165
+ raw=body,
166
+ )
167
+
168
+
169
+ def to_column(body: dict[str, Any]) -> MetadataColumn:
170
+ return MetadataColumn(name=body["name"], type=body["type"], description=body.get("description"))
171
+
172
+
173
+ def to_download(body: dict[str, Any]) -> Download:
174
+ return Download(
175
+ dataset_id=body["dataset_id"],
176
+ format=body["format"],
177
+ outcome=body["outcome"],
178
+ created=datetime.datetime.fromisoformat(body["created"]),
179
+ bytes=body["bytes"],
180
+ http_status=body["http_status"],
181
+ apikey_id=body["apikey_id"],
182
+ client_ip=body["client_ip"],
183
+ user_agent=body["user_agent"],
184
+ )
185
+
186
+
187
+ def _datetime(value: Any) -> datetime.datetime | None:
188
+ """A NULLABLE wire timestamp. A licence with no end date carries `expires: null`.
189
+
190
+ `fromisoformat` only learned to read a trailing `Z` in 3.11, which is one of the
191
+ three reasons this package floors there. A value that is neither null nor readable
192
+ raises, and the caller reports it as the server's failure rather than as None, which
193
+ would quietly read as "no end date".
194
+ """
195
+ if value is None:
196
+ return None
197
+ return datetime.datetime.fromisoformat(value)
internetdata/py.typed ADDED
File without changes
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.5
2
+ Name: internetdata
3
+ Version: 1.0.0
4
+ Summary: Official Python client library for the InternetData API. Download and verify licensed IP datasets.
5
+ Project-URL: Homepage, https://internetdata.io
6
+ Project-URL: Documentation, https://docs.internetdata.io
7
+ Project-URL: Source, https://github.com/internetdata/sdk-python
8
+ Project-URL: Issues, https://github.com/internetdata/sdk-python/issues
9
+ Author-email: Mslm Dev <support@internetdata.io>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: asn,bogon,dataset,geolocation,hosting,internetdata,ip-database,ip-intelligence,mmdb,proxy,vpn
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Classifier: Topic :: Internet
22
+ Classifier: Topic :: Security
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: attrs>=22.2.0
26
+ Requires-Dist: httpx<1,>=0.27
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.11; extra == 'dev'
29
+ Requires-Dist: openapi-python-client<0.30,>=0.29; extra == 'dev'
30
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
31
+ Requires-Dist: pytest>=8.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.6; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # [<img src="https://s3.internetdata.io/internetdata-public/brand/mark.svg" alt="InternetData" width="24"/>](https://internetdata.io/) InternetData Python Client Library
36
+
37
+ [![PyPI](https://img.shields.io/pypi/v/internetdata.svg)](https://pypi.org/project/internetdata/)
38
+ [![license](https://img.shields.io/pypi/l/internetdata.svg)](LICENSE)
39
+
40
+ The official Python client library for the [InternetData](https://internetdata.io) API.
41
+
42
+ The library helps you browse the databases your organization is licensed for, check what is in each build before you fetch it, and download and verify the files.
43
+
44
+ ## Getting Started
45
+
46
+ ```bash
47
+ pip install internetdata
48
+ ```
49
+
50
+ Requires Python 3.11 or newer. Type hints are included, and the package ships `py.typed`.
51
+
52
+ ## Usage
53
+
54
+ Every call needs an API key carrying the `db.download` scope. Create one in the console, then:
55
+
56
+ ```python
57
+ import os
58
+ from internetdata import InternetData
59
+
60
+ client = InternetData(os.environ["INTERNETDATA_API_KEY"])
61
+
62
+ for family in client.database.list():
63
+ print(family.base, family.standing, [v.id for v in family.versions])
64
+ ```
65
+
66
+ The client holds an HTTP connection pool, so use it as a context manager, or call `client.close()` when you are done with it:
67
+
68
+ ```python
69
+ with InternetData(api_key) as client:
70
+ print(len(client.database.list()))
71
+ ```
72
+
73
+ ### The catalog
74
+
75
+ `list` answers database FAMILIES. A licence is held against a family, while a download names a specific version, so the ids the other calls take come from each family's `versions`:
76
+
77
+ ```python
78
+ for family in client.database.list():
79
+ if family.standing != "licensed":
80
+ continue
81
+ for version in family.versions:
82
+ print(version.id, version.formats) # 'bogon_ip_v1' ('csvgz', 'mmdb')
83
+ ```
84
+
85
+ `standing` is `licensed`, `expired` or `unlicensed`, and `redistribution` is what your licence lets you do with the data (`evaluation`, `internal`, `redistribute`, or `None` when there is no licence). A family you have never bought is still listed, as `unlicensed`, so you can see what else exists.
86
+
87
+ **The catalog is not the same document for every key.** Databases commissioned for a single customer are absent from the listing entirely for everyone else, rather than shown as `unlicensed`. The server decides that per key, so treat what you get back as the answer for the key you asked with: this library never caches a listing, never reuses one across clients, and has no built-in list of database ids to fall back on.
88
+
89
+ ### What is inside a build
90
+
91
+ `metadata` is cheap enough to poll. It answers when the build was generated, how many rows it has, its columns and a few real rows, and the size of each format in bytes, all without moving the file:
92
+
93
+ ```python
94
+ meta = client.database.metadata("bogon_ip_v1")
95
+
96
+ print(meta.updated) # datetime.date(2026, 9, 4)
97
+ print(meta.entries) # 1234
98
+ print(meta.size["csvgz"]) # 760
99
+ print([c.name for c in meta.schema["csvgz"]])
100
+ ```
101
+
102
+ Checking `size` before a download is worth the round trip: the catalog spans a few hundred bytes to several gigabytes.
103
+
104
+ ### Downloading
105
+
106
+ Three ways, depending on what you want to do with the bytes:
107
+
108
+ ```python
109
+ url = client.database.download_url("bogon_ip_v1", "csvgz")
110
+ raw = client.database.download_bytes("bogon_ip_v1", "csvgz")
111
+ written = client.database.download("bogon_ip_v1", "mmdb", "./bogon_ip_v1.mmdb")
112
+ ```
113
+
114
+ `download_url` hands back a time-limited link straight to object storage. It carries its own signature and none of your API key, so you can pass it to `curl`, a job runner or anything else that speaks HTTP. The link authorizes the START of a transfer, so one already running is not cut off when it lapses.
115
+
116
+ `download` streams to a file, so nothing larger than a chunk is ever held in memory. The bytes land in a neighboring `.part` file that is moved into place only once the whole transfer has arrived, so a failed refresh leaves the copy you already had untouched. `download_bytes` holds the whole file in memory, so reach for it only at the small end of the catalog.
117
+
118
+ Either way a short transfer fails rather than handing you a truncated file, and the key is never sent to object storage.
119
+
120
+ Verify what you fetched against the published digests:
121
+
122
+ ```python
123
+ import hashlib
124
+
125
+ digests = client.database.checksums("bogon_ip_v1", "csvgz")
126
+ assert hashlib.sha256(raw).hexdigest() == digests["sha256"]
127
+ ```
128
+
129
+ ### Download history
130
+
131
+ `downloads` answers your organization's recent attempts, newest first, refusals included. A denial is what answers "it stopped working", and its absence answers nothing:
132
+
133
+ ```python
134
+ for attempt in client.database.downloads(limit=20):
135
+ print(attempt.created, attempt.dataset_id, attempt.outcome, attempt.http_status)
136
+ ```
137
+
138
+ ### Async
139
+
140
+ Everything above works the same way under asyncio, with `AsyncInternetData`:
141
+
142
+ ```python
143
+ import asyncio
144
+ from internetdata import AsyncInternetData
145
+
146
+ async def main():
147
+ async with AsyncInternetData(api_key) as client:
148
+ meta = await client.database.metadata("bogon_ip_v1")
149
+ await client.database.download("bogon_ip_v1", "csvgz", "./bogon_ip_v1.csv.gz")
150
+ print(meta.entries)
151
+
152
+ asyncio.run(main())
153
+ ```
154
+
155
+ ### Errors
156
+
157
+ Failures raise an `InternetDataError` carrying a `kind` and a `retryable` flag:
158
+
159
+ ```python
160
+ from internetdata import InternetDataError
161
+
162
+ try:
163
+ client.database.download_url("vpn_ip_v1", "mmdb")
164
+ except InternetDataError as err:
165
+ print(err.kind, err.retryable, err.message) # forbidden False NOT_LICENSED
166
+ ```
167
+
168
+ `kind` is one of `bad_request`, `unauthorized`, `forbidden`, `rate_limited`, `quota_exceeded`, `server_error` or `network`. `message` is the API's own result code, passed through as it was sent, so you can switch on `NOT_LICENSED` against `LICENSE_EXPIRED` without reading the status.
169
+
170
+ Note that `rate_limited` and `quota_exceeded` both arrive as HTTP 429 and are not the same thing. A rate limit is the API facing a traffic burst, and retrying later works; a spent quota needs your allowance raised or the window to roll over. The library retries rate limits for you, and server and network failures, but never a spent quota or anything else you sent.
171
+
172
+ ## Other Libraries
173
+
174
+ There are official InternetData client libraries available for many languages including PHP, Python, Go, Java, Ruby, and many popular frameworks such as Django, Rails, and Laravel. See our GitHub at https://github.com/internetdata for more.
175
+
176
+ ## About InternetData
177
+
178
+ InternetData: IP and network intelligence databases, published as CSV and MMDB, licensed by contract and downloadable on demand.
179
+
180
+ [<img src="https://s3.internetdata.io/internetdata-public/brand/mark.svg" alt="InternetData" width="96"/>](https://internetdata.io/)
181
+
182
+ ## License
183
+
184
+ This project is licensed under the [MIT License](LICENSE).
@@ -0,0 +1,46 @@
1
+ internetdata/__init__.py,sha256=RxzMbXKap5PrHulNUwHJSLGkrIM1mMcD88CR1ShEWiY,1105
2
+ internetdata/_core.py,sha256=3waAQnkS_0KYaSl-7bHmBDjwOiR-R0A0z6G0oi8jnKU,11064
3
+ internetdata/aio.py,sha256=KF-8PX7MQYIDFupvzyI7LUkP4vHl9AljdHAFDFzyVww,10311
4
+ internetdata/client.py,sha256=42dL-9pyLetDFpkDbOypWkUBjsS4TjRn2zd-uwMMlOc,10379
5
+ internetdata/errors.py,sha256=dYmFTImvgNqNPgIrcPCw2fGTZf8c_Ws7Clu8otiDLxw,4316
6
+ internetdata/models.py,sha256=M-w6AyqV7l1uM9FsRHkGsc_bXN2TGxE5Me6ylp2nNdY,6495
7
+ internetdata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ internetdata/_generated/__init__.py,sha256=wqKoc5J-jEpNI_y90nHagEpn2sTWbwTYnMmCgqDEBq0,159
9
+ internetdata/_generated/client.py,sha256=MHk8TC1YjyaLkvQ3tF0HBP561cJZmQY8Ih6seOCcOMI,12382
10
+ internetdata/_generated/errors.py,sha256=gO8GBmKqmSNgAg-E5oT-oOyxztvp7V_6XG7OUTT15q0,546
11
+ internetdata/_generated/types.py,sha256=0We4NPvhIYASRpQ3le41nmJeEAVm42-2VKdzlJ4Ogok,1343
12
+ internetdata/_generated/api/__init__.py,sha256=zTSiG_ujSjAqWPyc435YXaX9XTlpMjiJWBbV-f-YtdA,45
13
+ internetdata/_generated/api/database_v_2/__init__.py,sha256=5vd9uJWAjRqa9xzxzYkLD1yoZ12Ld_bAaNB5WX4fbE8,56
14
+ internetdata/_generated/api/database_v_2/database_checksum_v2.py,sha256=MI-zxBNO8y-_ZGJ8zNbnv_eIrMgrGyHxeIoZ18w3Ir0,5448
15
+ internetdata/_generated/api/database_v_2/database_metadata_v2.py,sha256=WVv8-Qe_rGtkvLxyOb50_HcrwixB3z6PqlzOaPX0rFI,5446
16
+ internetdata/_generated/api/database_v_2/download_database_v2.py,sha256=Qf_PDFwAn1rHxsI3P9Db2KhUoekIN6ik_Vn1t5uCPlk,5554
17
+ internetdata/_generated/api/database_v_2/list_databases.py,sha256=u8hDrKC2BEdKuh-a9p4jKxVBKfzlQD7ufAGf5j52uJ8,4958
18
+ internetdata/_generated/api/database_v_2/list_downloads.py,sha256=-2WV7ghS4e5On8xPRzAuHAHBmhkl83rWYZEVyJy5SaI,4820
19
+ internetdata/_generated/models/__init__.py,sha256=KyWrvMFBzQIxvajNAth3TEIQXOTPhtOKgmRNbmOwo1g,2170
20
+ internetdata/_generated/models/database.py,sha256=v_zZZ_9EUbNXRoJNstk8H_uX8VTIPJr__uQElLCVqG4,7983
21
+ internetdata/_generated/models/database_checksum_v2_format.py,sha256=nof7_Q3xI2VhEN3GzhqUc-nGqEp5UiyUQSVGKqOqDSo,168
22
+ internetdata/_generated/models/database_checksum_v2_response_200.py,sha256=bw21224pDJtt28sQNuddVCv4gA57DmqzBjU6-5O9mow,2311
23
+ internetdata/_generated/models/database_checksum_v2_response_200_format.py,sha256=PIn4sLd4drgU1Y90enf3NC39Z4acdH8WRZ85ohdPOS0,179
24
+ internetdata/_generated/models/database_metadata.py,sha256=yMjTI9YHiQ61E4F9tzAFciRjcANy494mVf-yaFrOA4k,4039
25
+ internetdata/_generated/models/database_metadata_column.py,sha256=7EaGGmKkeFTSdUvsNKGuVJRx_gwQQZ63dapiJNhpm3A,2005
26
+ internetdata/_generated/models/database_metadata_sample.py,sha256=LaS_rGlKTljIItUN9giTM-HXUAG3mnjV1iat51BtQUM,2642
27
+ internetdata/_generated/models/database_metadata_sample_additional_property_item.py,sha256=fapR9XWubK3WS07JfgKrnbQbLQN1OOagR7pnTt8TM_Q,1401
28
+ internetdata/_generated/models/database_metadata_schema.py,sha256=DiWZkwkbJr3KqseZbq0837GuLsn9QzZe6in74M0Uhqk,2394
29
+ internetdata/_generated/models/database_metadata_size.py,sha256=yZ9lYIK2fM3npNC6Cz10l8Gw1CfvF12rSA_GWRFH8SU,1301
30
+ internetdata/_generated/models/database_redistribution_type_1.py,sha256=4XI7wpGnmbQ52EGB-bTlOXD1_G5ubbq0kXkGSRBXIJo,223
31
+ internetdata/_generated/models/database_redistribution_type_2_type_1.py,sha256=3eHBM6r-0F8epfzr14yq8hpncuqY1NjA9wWaRl4mAIw,228
32
+ internetdata/_generated/models/database_redistribution_type_3_type_1.py,sha256=h3eqMgSTEEM47Q-ATEqueDLcsAtzKRJGy1l18XKwfZI,228
33
+ internetdata/_generated/models/database_standing.py,sha256=fOhY--mUbtkr188IySudfuyub5XpjnNjudrQ93MRUvU,202
34
+ internetdata/_generated/models/database_version.py,sha256=cqkfPCiY4BBQIiC5sAtFZp75RSkTctlFS1dbWqeki_Y,2723
35
+ internetdata/_generated/models/database_version_formats_item.py,sha256=IGjztCYren6snoX0zb-m0KTtwzNKGBmfBA4EZ3aJ_jc,170
36
+ internetdata/_generated/models/db_checksums.py,sha256=4hB_YuDm7gVqhyJB2h-YuYjRqxyI9Jq3Dw2RJEP-NFo,2038
37
+ internetdata/_generated/models/download.py,sha256=REGcSs5HF3atMI-vocxd2cY6-y-aoEExnYJhnc6BFdk,4586
38
+ internetdata/_generated/models/download_database_v2_format.py,sha256=XRhb_e2-eJwtQ6mJJ0qzqi3T2kYBFgpbWCAh8fF8Egc,168
39
+ internetdata/_generated/models/download_outcome.py,sha256=C_xdtqtpFbgg3M2WdT2nE48NPhErO4WMbqAx7_ZPJUA,271
40
+ internetdata/_generated/models/error.py,sha256=n6JO5D33IFfQ7UoB5LANoJzKdVGfdO0nhwra1uNJFaY,1558
41
+ internetdata/_generated/models/list_databases_response_200.py,sha256=c_qDy3Nq0Ymr2o8J6wsifvm_lWlnwtcZxGEJ86Q3Dhs,2071
42
+ internetdata/_generated/models/list_downloads_response_200.py,sha256=HWd_62XgkIAnNbnJ8Kft-D2Et6qaZWe64QCHkS7tMuU,2071
43
+ internetdata-1.0.0.dist-info/METADATA,sha256=bCspIg9ZfRhKtueBjhnxmBAzN-qBWpbYen71ljeZQGU,8224
44
+ internetdata-1.0.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
45
+ internetdata-1.0.0.dist-info/licenses/LICENSE,sha256=wglb3Uww0HrX4-4rYO9Xe4j8Sn9STPtK2M9Tt5NKTrQ,1065
46
+ internetdata-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mslm Dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.