iporigin 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
iporigin-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yuix Networks Inc
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.
@@ -0,0 +1,247 @@
1
+ Metadata-Version: 2.4
2
+ Name: iporigin
3
+ Version: 1.0.0
4
+ Summary: Is this IP a datacenter, VPN, Tor exit or a home connection? Offline lookup, no API key.
5
+ Author-email: Yuix Networks <info@yuix.org>
6
+ License: MIT
7
+ Project-URL: Homepage, https://www.unblockmaster.com/free-ip-api/
8
+ Project-URL: Source, https://github.com/Yuix-Networks/iporigin
9
+ Project-URL: Issues, https://github.com/Yuix-Networks/iporigin/issues
10
+ Project-URL: Changelog, https://github.com/Yuix-Networks/iporigin/blob/main/CHANGELOG.md
11
+ Keywords: ip,geolocation,datacenter,hosting,vpn,proxy,cloud,cidr,abuse,fraud,bot-detection,tor,hetzner,ovh
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Internet
25
+ Classifier: Topic :: Security
26
+ Classifier: Topic :: System :: Networking
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # iporigin
36
+
37
+ Tell a datacenter IP from a home connection — offline, with no API key.
38
+
39
+ ```python
40
+ >>> import iporigin
41
+ >>> iporigin.classify("52.95.110.1")
42
+ Origin(ip='52.95.110.1', kind='hosting', provider='Amazon AWS', source='local')
43
+ >>> iporigin.is_datacenter("8.8.8.8")
44
+ True
45
+ >>> iporigin.is_datacenter("127.0.0.1")
46
+ False
47
+ ```
48
+
49
+ No network calls. No signup. No runtime dependencies. The answer comes from
50
+ a bundled table of 33,000 ranges covering 37 hosting providers, CDNs,
51
+ consumer VPNs, Tor and declared crawlers.
52
+
53
+ ## Install
54
+
55
+ ```
56
+ pip install iporigin
57
+ ```
58
+
59
+ ## Why
60
+
61
+ "Is this visitor on a server or on a home connection?" comes up constantly —
62
+ scoring signups, filtering scrapers out of analytics, deciding whether an
63
+ abuse report is worth acting on, flagging logins from hosting ranges. The
64
+ usual answers are a paid API or a hand-maintained list of CIDRs that goes
65
+ stale in a month.
66
+
67
+ This is a third option: the providers publish their own ranges, so the list
68
+ can be compiled from source and rebuilt on a schedule. You get a local
69
+ lookup in microseconds, and you can verify every byte of the data by
70
+ re-running the build script.
71
+
72
+ ## Use
73
+
74
+ ### Classify one address
75
+
76
+ ```python
77
+ import iporigin
78
+
79
+ origin = iporigin.classify("140.82.121.4")
80
+ origin.kind # 'hosting'
81
+ origin.provider # 'GitHub'
82
+ origin.is_datacenter # True
83
+ ```
84
+
85
+ `kind` is one of:
86
+
87
+ | kind | meaning | examples |
88
+ | --- | --- | --- |
89
+ | `hosting` | a machine in a cloud or hosting provider | AWS, Hetzner, OVHcloud |
90
+ | `cdn` | edge infrastructure fronting other people's sites | Cloudflare, Akamai |
91
+ | `vpn` | a consumer VPN or private relay exit | Mullvad, ProtonVPN, Apple Private Relay |
92
+ | `tor` | a Tor exit node | |
93
+ | `bot` | a declared crawler | Googlebot, GPTBot, ClaudeBot |
94
+ | `reserved` | private, loopback, link-local, documentation | `127.0.0.1`, `10.0.0.0/8` |
95
+ | `unknown` | in none of our lists — most often a residential ISP | |
96
+
97
+ Two sets are exported for the common decisions:
98
+
99
+ ```python
100
+ origin.kind in iporigin.DATACENTER_KINDS # a machine, not a home line
101
+ origin.kind in iporigin.ANONYMIZER_KINDS # vpn or tor
102
+ ```
103
+
104
+ They are deliberately different questions. Someone arriving through Mullvad
105
+ is a person at home, but the address they arrive *from* is a server — so it
106
+ is in both sets, and you may well want to rate-limit one and refuse the
107
+ other.
108
+
109
+ `unknown` means *absence of evidence*. It is not a positive claim that the
110
+ address is residential, and the difference matters if you are going to block
111
+ someone over it.
112
+
113
+ ### Scan a lot of them
114
+
115
+ ```python
116
+ for origin in iporigin.classify_many(ip_list):
117
+ if origin.is_datacenter:
118
+ print(origin.ip, origin.provider)
119
+ ```
120
+
121
+ `classify_many` loads the table once for the whole batch.
122
+
123
+ ### From the shell
124
+
125
+ ```console
126
+ $ iporigin 8.8.8.8 140.82.121.4 192.168.1.1
127
+ 8.8.8.8 hosting Google
128
+ 140.82.121.4 hosting GitHub
129
+ 192.168.1.1 reserved
130
+
131
+ $ cut -d' ' -f1 access.log | iporigin --datacenter-only --json
132
+ {"ip": "34.82.1.5", "kind": "hosting", "provider": "Google Cloud", ...}
133
+ ```
134
+
135
+ `iporigin --info` prints what is in the bundled dataset and when it was built.
136
+
137
+ ### Going beyond the bundled table
138
+
139
+ The table covers the VPN providers whose exits are publicly tracked —
140
+ Mullvad, ProtonVPN, Apple Private Relay. Most VPN companies are not in that
141
+ set. When you need broader coverage, `iporigin.online` asks the free
142
+ [Unblock Master IP API](https://www.unblockmaster.com/free-ip-api/), which
143
+ does its own detection:
144
+
145
+ ```python
146
+ from iporigin.online import classify_online
147
+
148
+ classify_online("203.0.113.10") # may return kind='vpn'
149
+ ```
150
+
151
+ It falls back to the offline answer if the request fails, so it is safe in a
152
+ request path. Nothing else in the library touches the network — you have to
153
+ import this module on purpose. No key required.
154
+
155
+ ## What is in the dataset
156
+
157
+ 37 providers, in two tiers.
158
+
159
+ **Published by the provider.** The authoritative tier — each of these is the
160
+ company's own feed, fetched at build time:
161
+
162
+ | Provider | Feed |
163
+ | --- | --- |
164
+ | Amazon AWS | `ip-ranges.amazonaws.com/ip-ranges.json` |
165
+ | Google, Google Cloud | `gstatic.com/ipranges/goog.json`, `cloud.json` |
166
+ | Microsoft Azure | Service Tags JSON |
167
+ | DigitalOcean | `digitalocean.com/geo/google.csv` |
168
+ | Linode | RFC 8805 geofeed |
169
+ | Vultr | `geofeed.constant.com` |
170
+ | Oracle Cloud | `public_ip_ranges.json` |
171
+ | GitHub | `api.github.com/meta` |
172
+ | Cloudflare | `cloudflare.com/ips-v4`, `ips-v6` |
173
+ | Fastly | `api.fastly.com/public-ip-list` |
174
+
175
+ **Community-maintained lists.** Some providers publish nothing
176
+ machine-readable — Hetzner and OVH being the two that matter most, since a
177
+ large share of abusive traffic comes from them. Consumer VPN exits, Tor and
178
+ crawler ranges have the same problem for a different reason: nobody with the
179
+ data has an interest in publishing it. Those come from two community repos,
180
+ and are second-hand by definition:
181
+
182
+ - [`rezmoss/cloud-provider-ip-addresses`](https://github.com/rezmoss/cloud-provider-ip-addresses) (CC0)
183
+ - [`lord-alfred/ipranges`](https://github.com/lord-alfred/ipranges) (CC0)
184
+
185
+ Covering Hetzner, OVHcloud, Scaleway, Alibaba Cloud, Leaseweb, UpCloud, IBM
186
+ Cloud, Huawei Cloud, Tencent Cloud, Rackspace, Akamai, Gcore, Mullvad,
187
+ ProtonVPN, Apple Private Relay, Tor, and ten declared crawlers.
188
+
189
+ Both are CC0, which is why these two and not the half-dozen other repos
190
+ covering the same ground. Redistributing an unlicensed list inside an MIT
191
+ package is not something a dependency should ask of the people who install
192
+ it.
193
+
194
+ About 449,000 published prefixes collapse into 33,647 disjoint ranges
195
+ (17,169 IPv4, 16,478 IPv6). Rebuild it yourself at any time:
196
+
197
+ ```
198
+ python tools/build_dataset.py
199
+ ```
200
+
201
+ A GitHub Action re-runs that weekly and opens a PR when the ranges move.
202
+
203
+ ### Known gaps
204
+
205
+ Being explicit about these is more useful than pretending they are not there:
206
+
207
+ - **Most consumer VPNs.** Only the ones whose exits are publicly tracked are
208
+ in the table. Use `iporigin.online` for the rest.
209
+ - **Some provider-owned addresses** sit outside the ranges the provider
210
+ publishes. `1.1.1.1` is Cloudflare's resolver but is not in Cloudflare's
211
+ published edge list, so it comes back `unknown`.
212
+ - **Second-hand data is second-hand.** The community tier is as good as
213
+ those repos are, and they are not the provider speaking.
214
+ - The data is **as accurate as the feeds**. A range reassigned yesterday is
215
+ wrong until the next rebuild.
216
+
217
+ ## How the lookup works
218
+
219
+ Ranges are stored as inclusive integer start/end pairs in sorted, *disjoint*
220
+ order, so a lookup is one `bisect` plus one comparison.
221
+
222
+ Making them disjoint is the part that matters. Feeds overlap each other —
223
+ GitHub runs on Azure and AWS, so its prefixes sit inside theirs. A bisect
224
+ inspects exactly one candidate, and with overlapping ranges that candidate
225
+ can be a narrow range that ends before the address while a wider range still
226
+ contains it, which returns `unknown` for an address plainly in the table. The
227
+ build script therefore sweeps the ranges into a disjoint partition, and where
228
+ they overlap the narrowest one wins — GitHub inside Azure answers GitHub,
229
+ which is the more specific truth.
230
+
231
+ The table loads lazily on the first lookup, so importing the library and
232
+ never calling it costs nothing.
233
+
234
+ ## Compatibility
235
+
236
+ Python 3.8+. No dependencies.
237
+
238
+ ## License
239
+
240
+ MIT. The compiled dataset is derived from the providers' own public feeds,
241
+ each published for exactly this purpose.
242
+
243
+ ---
244
+
245
+ Built by [Yuix Networks](https://yuix.org), who also run
246
+ [Unblock Master](https://www.unblockmaster.com/) and its
247
+ [free IP lookup API](https://www.unblockmaster.com/free-ip-api/).
@@ -0,0 +1,213 @@
1
+ # iporigin
2
+
3
+ Tell a datacenter IP from a home connection — offline, with no API key.
4
+
5
+ ```python
6
+ >>> import iporigin
7
+ >>> iporigin.classify("52.95.110.1")
8
+ Origin(ip='52.95.110.1', kind='hosting', provider='Amazon AWS', source='local')
9
+ >>> iporigin.is_datacenter("8.8.8.8")
10
+ True
11
+ >>> iporigin.is_datacenter("127.0.0.1")
12
+ False
13
+ ```
14
+
15
+ No network calls. No signup. No runtime dependencies. The answer comes from
16
+ a bundled table of 33,000 ranges covering 37 hosting providers, CDNs,
17
+ consumer VPNs, Tor and declared crawlers.
18
+
19
+ ## Install
20
+
21
+ ```
22
+ pip install iporigin
23
+ ```
24
+
25
+ ## Why
26
+
27
+ "Is this visitor on a server or on a home connection?" comes up constantly —
28
+ scoring signups, filtering scrapers out of analytics, deciding whether an
29
+ abuse report is worth acting on, flagging logins from hosting ranges. The
30
+ usual answers are a paid API or a hand-maintained list of CIDRs that goes
31
+ stale in a month.
32
+
33
+ This is a third option: the providers publish their own ranges, so the list
34
+ can be compiled from source and rebuilt on a schedule. You get a local
35
+ lookup in microseconds, and you can verify every byte of the data by
36
+ re-running the build script.
37
+
38
+ ## Use
39
+
40
+ ### Classify one address
41
+
42
+ ```python
43
+ import iporigin
44
+
45
+ origin = iporigin.classify("140.82.121.4")
46
+ origin.kind # 'hosting'
47
+ origin.provider # 'GitHub'
48
+ origin.is_datacenter # True
49
+ ```
50
+
51
+ `kind` is one of:
52
+
53
+ | kind | meaning | examples |
54
+ | --- | --- | --- |
55
+ | `hosting` | a machine in a cloud or hosting provider | AWS, Hetzner, OVHcloud |
56
+ | `cdn` | edge infrastructure fronting other people's sites | Cloudflare, Akamai |
57
+ | `vpn` | a consumer VPN or private relay exit | Mullvad, ProtonVPN, Apple Private Relay |
58
+ | `tor` | a Tor exit node | |
59
+ | `bot` | a declared crawler | Googlebot, GPTBot, ClaudeBot |
60
+ | `reserved` | private, loopback, link-local, documentation | `127.0.0.1`, `10.0.0.0/8` |
61
+ | `unknown` | in none of our lists — most often a residential ISP | |
62
+
63
+ Two sets are exported for the common decisions:
64
+
65
+ ```python
66
+ origin.kind in iporigin.DATACENTER_KINDS # a machine, not a home line
67
+ origin.kind in iporigin.ANONYMIZER_KINDS # vpn or tor
68
+ ```
69
+
70
+ They are deliberately different questions. Someone arriving through Mullvad
71
+ is a person at home, but the address they arrive *from* is a server — so it
72
+ is in both sets, and you may well want to rate-limit one and refuse the
73
+ other.
74
+
75
+ `unknown` means *absence of evidence*. It is not a positive claim that the
76
+ address is residential, and the difference matters if you are going to block
77
+ someone over it.
78
+
79
+ ### Scan a lot of them
80
+
81
+ ```python
82
+ for origin in iporigin.classify_many(ip_list):
83
+ if origin.is_datacenter:
84
+ print(origin.ip, origin.provider)
85
+ ```
86
+
87
+ `classify_many` loads the table once for the whole batch.
88
+
89
+ ### From the shell
90
+
91
+ ```console
92
+ $ iporigin 8.8.8.8 140.82.121.4 192.168.1.1
93
+ 8.8.8.8 hosting Google
94
+ 140.82.121.4 hosting GitHub
95
+ 192.168.1.1 reserved
96
+
97
+ $ cut -d' ' -f1 access.log | iporigin --datacenter-only --json
98
+ {"ip": "34.82.1.5", "kind": "hosting", "provider": "Google Cloud", ...}
99
+ ```
100
+
101
+ `iporigin --info` prints what is in the bundled dataset and when it was built.
102
+
103
+ ### Going beyond the bundled table
104
+
105
+ The table covers the VPN providers whose exits are publicly tracked —
106
+ Mullvad, ProtonVPN, Apple Private Relay. Most VPN companies are not in that
107
+ set. When you need broader coverage, `iporigin.online` asks the free
108
+ [Unblock Master IP API](https://www.unblockmaster.com/free-ip-api/), which
109
+ does its own detection:
110
+
111
+ ```python
112
+ from iporigin.online import classify_online
113
+
114
+ classify_online("203.0.113.10") # may return kind='vpn'
115
+ ```
116
+
117
+ It falls back to the offline answer if the request fails, so it is safe in a
118
+ request path. Nothing else in the library touches the network — you have to
119
+ import this module on purpose. No key required.
120
+
121
+ ## What is in the dataset
122
+
123
+ 37 providers, in two tiers.
124
+
125
+ **Published by the provider.** The authoritative tier — each of these is the
126
+ company's own feed, fetched at build time:
127
+
128
+ | Provider | Feed |
129
+ | --- | --- |
130
+ | Amazon AWS | `ip-ranges.amazonaws.com/ip-ranges.json` |
131
+ | Google, Google Cloud | `gstatic.com/ipranges/goog.json`, `cloud.json` |
132
+ | Microsoft Azure | Service Tags JSON |
133
+ | DigitalOcean | `digitalocean.com/geo/google.csv` |
134
+ | Linode | RFC 8805 geofeed |
135
+ | Vultr | `geofeed.constant.com` |
136
+ | Oracle Cloud | `public_ip_ranges.json` |
137
+ | GitHub | `api.github.com/meta` |
138
+ | Cloudflare | `cloudflare.com/ips-v4`, `ips-v6` |
139
+ | Fastly | `api.fastly.com/public-ip-list` |
140
+
141
+ **Community-maintained lists.** Some providers publish nothing
142
+ machine-readable — Hetzner and OVH being the two that matter most, since a
143
+ large share of abusive traffic comes from them. Consumer VPN exits, Tor and
144
+ crawler ranges have the same problem for a different reason: nobody with the
145
+ data has an interest in publishing it. Those come from two community repos,
146
+ and are second-hand by definition:
147
+
148
+ - [`rezmoss/cloud-provider-ip-addresses`](https://github.com/rezmoss/cloud-provider-ip-addresses) (CC0)
149
+ - [`lord-alfred/ipranges`](https://github.com/lord-alfred/ipranges) (CC0)
150
+
151
+ Covering Hetzner, OVHcloud, Scaleway, Alibaba Cloud, Leaseweb, UpCloud, IBM
152
+ Cloud, Huawei Cloud, Tencent Cloud, Rackspace, Akamai, Gcore, Mullvad,
153
+ ProtonVPN, Apple Private Relay, Tor, and ten declared crawlers.
154
+
155
+ Both are CC0, which is why these two and not the half-dozen other repos
156
+ covering the same ground. Redistributing an unlicensed list inside an MIT
157
+ package is not something a dependency should ask of the people who install
158
+ it.
159
+
160
+ About 449,000 published prefixes collapse into 33,647 disjoint ranges
161
+ (17,169 IPv4, 16,478 IPv6). Rebuild it yourself at any time:
162
+
163
+ ```
164
+ python tools/build_dataset.py
165
+ ```
166
+
167
+ A GitHub Action re-runs that weekly and opens a PR when the ranges move.
168
+
169
+ ### Known gaps
170
+
171
+ Being explicit about these is more useful than pretending they are not there:
172
+
173
+ - **Most consumer VPNs.** Only the ones whose exits are publicly tracked are
174
+ in the table. Use `iporigin.online` for the rest.
175
+ - **Some provider-owned addresses** sit outside the ranges the provider
176
+ publishes. `1.1.1.1` is Cloudflare's resolver but is not in Cloudflare's
177
+ published edge list, so it comes back `unknown`.
178
+ - **Second-hand data is second-hand.** The community tier is as good as
179
+ those repos are, and they are not the provider speaking.
180
+ - The data is **as accurate as the feeds**. A range reassigned yesterday is
181
+ wrong until the next rebuild.
182
+
183
+ ## How the lookup works
184
+
185
+ Ranges are stored as inclusive integer start/end pairs in sorted, *disjoint*
186
+ order, so a lookup is one `bisect` plus one comparison.
187
+
188
+ Making them disjoint is the part that matters. Feeds overlap each other —
189
+ GitHub runs on Azure and AWS, so its prefixes sit inside theirs. A bisect
190
+ inspects exactly one candidate, and with overlapping ranges that candidate
191
+ can be a narrow range that ends before the address while a wider range still
192
+ contains it, which returns `unknown` for an address plainly in the table. The
193
+ build script therefore sweeps the ranges into a disjoint partition, and where
194
+ they overlap the narrowest one wins — GitHub inside Azure answers GitHub,
195
+ which is the more specific truth.
196
+
197
+ The table loads lazily on the first lookup, so importing the library and
198
+ never calling it costs nothing.
199
+
200
+ ## Compatibility
201
+
202
+ Python 3.8+. No dependencies.
203
+
204
+ ## License
205
+
206
+ MIT. The compiled dataset is derived from the providers' own public feeds,
207
+ each published for exactly this purpose.
208
+
209
+ ---
210
+
211
+ Built by [Yuix Networks](https://yuix.org), who also run
212
+ [Unblock Master](https://www.unblockmaster.com/) and its
213
+ [free IP lookup API](https://www.unblockmaster.com/free-ip-api/).
@@ -0,0 +1,59 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "iporigin"
7
+ version = "1.0.0"
8
+ description = "Is this IP a datacenter, VPN, Tor exit or a home connection? Offline lookup, no API key."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ authors = [{name = "Yuix Networks", email = "info@yuix.org"}]
13
+ keywords = [
14
+ "ip", "geolocation", "datacenter", "hosting", "vpn", "proxy",
15
+ "cloud", "cidr", "abuse", "fraud", "bot-detection", "tor", "hetzner", "ovh",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 5 - Production/Stable",
19
+ "Intended Audience :: Developers",
20
+ "Intended Audience :: System Administrators",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.8",
25
+ "Programming Language :: Python :: 3.9",
26
+ "Programming Language :: Python :: 3.10",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Topic :: Internet",
31
+ "Topic :: Security",
32
+ "Topic :: System :: Networking",
33
+ "Typing :: Typed",
34
+ ]
35
+ # No runtime dependencies on purpose: this is the kind of library that gets
36
+ # pulled into a request path, and every dependency it adds becomes someone
37
+ # else's supply-chain problem.
38
+ dependencies = []
39
+
40
+ [project.urls]
41
+ Homepage = "https://www.unblockmaster.com/free-ip-api/"
42
+ Source = "https://github.com/Yuix-Networks/iporigin"
43
+ Issues = "https://github.com/Yuix-Networks/iporigin/issues"
44
+ Changelog = "https://github.com/Yuix-Networks/iporigin/blob/main/CHANGELOG.md"
45
+
46
+ [project.scripts]
47
+ iporigin = "iporigin.cli:main"
48
+
49
+ [project.optional-dependencies]
50
+ dev = ["pytest>=7"]
51
+
52
+ [tool.setuptools.packages.find]
53
+ where = ["src"]
54
+
55
+ [tool.setuptools.package-data]
56
+ iporigin = ["data/ranges.bin", "py.typed"]
57
+
58
+ [tool.pytest.ini_options]
59
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,51 @@
1
+ """Tell a datacenter IP from a home connection, offline.
2
+
3
+ >>> import iporigin
4
+ >>> iporigin.classify("52.95.110.1")
5
+ Origin(ip='52.95.110.1', kind='hosting', provider='Amazon AWS', source='local')
6
+ >>> iporigin.is_datacenter("8.8.8.8")
7
+ True
8
+
9
+ No network calls, no API key: the answer comes from a table compiled from
10
+ the providers' own published feeds. See iporigin.online for the optional
11
+ live lookup that also covers consumer VPN exit nodes.
12
+ """
13
+
14
+ from ._data import DatasetError
15
+ from .core import (
16
+ ANONYMIZER_KINDS,
17
+ BOT,
18
+ CDN,
19
+ DATACENTER_KINDS,
20
+ HOSTING,
21
+ RESERVED,
22
+ TOR,
23
+ UNKNOWN,
24
+ VPN,
25
+ Origin,
26
+ classify,
27
+ classify_many,
28
+ dataset_info,
29
+ is_datacenter,
30
+ )
31
+
32
+ __version__ = "1.0.0"
33
+
34
+ __all__ = [
35
+ "ANONYMIZER_KINDS",
36
+ "BOT",
37
+ "CDN",
38
+ "DATACENTER_KINDS",
39
+ "DatasetError",
40
+ "HOSTING",
41
+ "Origin",
42
+ "RESERVED",
43
+ "TOR",
44
+ "UNKNOWN",
45
+ "VPN",
46
+ "classify",
47
+ "classify_many",
48
+ "dataset_info",
49
+ "is_datacenter",
50
+ "__version__",
51
+ ]