zipcodes 1.3.0__tar.gz → 2.0.1__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.
- zipcodes-2.0.1/Cargo.lock +240 -0
- zipcodes-2.0.1/Cargo.toml +15 -0
- zipcodes-2.0.1/PKG-INFO +299 -0
- zipcodes-2.0.1/README.md +275 -0
- zipcodes-2.0.1/crates/zipcodes/Cargo.toml +19 -0
- zipcodes-2.0.1/crates/zipcodes/README.md +150 -0
- zipcodes-2.0.1/crates/zipcodes/src/lib.rs +352 -0
- zipcodes-2.0.1/crates/zipcodes/src/zips.json.bz2 +0 -0
- zipcodes-2.0.1/crates/zipcodes-py/Cargo.toml +20 -0
- zipcodes-2.0.1/crates/zipcodes-py/src/lib.rs +156 -0
- zipcodes-2.0.1/pyproject.toml +40 -0
- zipcodes-2.0.1/python/zipcodes/__init__.py +174 -0
- zipcodes-2.0.1/python/zipcodes/_zipcodes.pyi +14 -0
- zipcodes-2.0.1/python/zipcodes/py.typed +0 -0
- zipcodes-1.3.0/MANIFEST.in +0 -4
- zipcodes-1.3.0/PKG-INFO +0 -267
- zipcodes-1.3.0/README.md +0 -245
- zipcodes-1.3.0/VERSION.txt +0 -1
- zipcodes-1.3.0/pyproject.toml +0 -42
- zipcodes-1.3.0/setup.cfg +0 -11
- zipcodes-1.3.0/zipcodes/__init__.py +0 -124
- zipcodes-1.3.0/zipcodes/__pycache__/__init__.cpython-37.pyc +0 -0
- zipcodes-1.3.0/zipcodes/__pycache__/__init__.cpython-39.pyc +0 -0
- zipcodes-1.3.0/zipcodes/zips.json.bz2 +0 -0
- zipcodes-1.3.0/zipcodes.egg-info/PKG-INFO +0 -267
- zipcodes-1.3.0/zipcodes.egg-info/SOURCES.txt +0 -14
- zipcodes-1.3.0/zipcodes.egg-info/dependency_links.txt +0 -1
- zipcodes-1.3.0/zipcodes.egg-info/top_level.txt +0 -2
- {zipcodes-1.3.0 → zipcodes-2.0.1}/LICENSE.txt +0 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 3
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "bzip2"
|
|
7
|
+
version = "0.6.1"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"libbz2-rs-sys",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "heck"
|
|
16
|
+
version = "0.5.0"
|
|
17
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
18
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
19
|
+
|
|
20
|
+
[[package]]
|
|
21
|
+
name = "itoa"
|
|
22
|
+
version = "1.0.18"
|
|
23
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
24
|
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
25
|
+
|
|
26
|
+
[[package]]
|
|
27
|
+
name = "libbz2-rs-sys"
|
|
28
|
+
version = "0.2.5"
|
|
29
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
30
|
+
checksum = "34b357333733e8260735ba5894eb928c02ecc69c78715f01a8019e7fa7f2db4c"
|
|
31
|
+
|
|
32
|
+
[[package]]
|
|
33
|
+
name = "libc"
|
|
34
|
+
version = "0.2.186"
|
|
35
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
36
|
+
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
37
|
+
|
|
38
|
+
[[package]]
|
|
39
|
+
name = "memchr"
|
|
40
|
+
version = "2.8.2"
|
|
41
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
42
|
+
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
|
43
|
+
|
|
44
|
+
[[package]]
|
|
45
|
+
name = "once_cell"
|
|
46
|
+
version = "1.21.4"
|
|
47
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
48
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
49
|
+
|
|
50
|
+
[[package]]
|
|
51
|
+
name = "portable-atomic"
|
|
52
|
+
version = "1.13.1"
|
|
53
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
54
|
+
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|
55
|
+
|
|
56
|
+
[[package]]
|
|
57
|
+
name = "proc-macro2"
|
|
58
|
+
version = "1.0.106"
|
|
59
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
60
|
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
61
|
+
dependencies = [
|
|
62
|
+
"unicode-ident",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[[package]]
|
|
66
|
+
name = "pyo3"
|
|
67
|
+
version = "0.29.0"
|
|
68
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
69
|
+
checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c"
|
|
70
|
+
dependencies = [
|
|
71
|
+
"libc",
|
|
72
|
+
"once_cell",
|
|
73
|
+
"portable-atomic",
|
|
74
|
+
"pyo3-build-config",
|
|
75
|
+
"pyo3-ffi",
|
|
76
|
+
"pyo3-macros",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
[[package]]
|
|
80
|
+
name = "pyo3-build-config"
|
|
81
|
+
version = "0.29.0"
|
|
82
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
83
|
+
checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078"
|
|
84
|
+
dependencies = [
|
|
85
|
+
"target-lexicon",
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
[[package]]
|
|
89
|
+
name = "pyo3-ffi"
|
|
90
|
+
version = "0.29.0"
|
|
91
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
92
|
+
checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b"
|
|
93
|
+
dependencies = [
|
|
94
|
+
"libc",
|
|
95
|
+
"pyo3-build-config",
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
[[package]]
|
|
99
|
+
name = "pyo3-macros"
|
|
100
|
+
version = "0.29.0"
|
|
101
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
102
|
+
checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771"
|
|
103
|
+
dependencies = [
|
|
104
|
+
"proc-macro2",
|
|
105
|
+
"pyo3-macros-backend",
|
|
106
|
+
"quote",
|
|
107
|
+
"syn",
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
[[package]]
|
|
111
|
+
name = "pyo3-macros-backend"
|
|
112
|
+
version = "0.29.0"
|
|
113
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
114
|
+
checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362"
|
|
115
|
+
dependencies = [
|
|
116
|
+
"heck",
|
|
117
|
+
"proc-macro2",
|
|
118
|
+
"quote",
|
|
119
|
+
"syn",
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
[[package]]
|
|
123
|
+
name = "quote"
|
|
124
|
+
version = "1.0.45"
|
|
125
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
126
|
+
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
|
127
|
+
dependencies = [
|
|
128
|
+
"proc-macro2",
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
[[package]]
|
|
132
|
+
name = "serde"
|
|
133
|
+
version = "1.0.228"
|
|
134
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
135
|
+
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
|
136
|
+
dependencies = [
|
|
137
|
+
"serde_core",
|
|
138
|
+
"serde_derive",
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
[[package]]
|
|
142
|
+
name = "serde_core"
|
|
143
|
+
version = "1.0.228"
|
|
144
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
145
|
+
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
|
146
|
+
dependencies = [
|
|
147
|
+
"serde_derive",
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
[[package]]
|
|
151
|
+
name = "serde_derive"
|
|
152
|
+
version = "1.0.228"
|
|
153
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
154
|
+
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|
155
|
+
dependencies = [
|
|
156
|
+
"proc-macro2",
|
|
157
|
+
"quote",
|
|
158
|
+
"syn",
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
[[package]]
|
|
162
|
+
name = "serde_json"
|
|
163
|
+
version = "1.0.150"
|
|
164
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
165
|
+
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
|
166
|
+
dependencies = [
|
|
167
|
+
"itoa",
|
|
168
|
+
"memchr",
|
|
169
|
+
"serde",
|
|
170
|
+
"serde_core",
|
|
171
|
+
"zmij",
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
[[package]]
|
|
175
|
+
name = "syn"
|
|
176
|
+
version = "2.0.117"
|
|
177
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
178
|
+
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
179
|
+
dependencies = [
|
|
180
|
+
"proc-macro2",
|
|
181
|
+
"quote",
|
|
182
|
+
"unicode-ident",
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
[[package]]
|
|
186
|
+
name = "target-lexicon"
|
|
187
|
+
version = "0.13.5"
|
|
188
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
189
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
190
|
+
|
|
191
|
+
[[package]]
|
|
192
|
+
name = "thiserror"
|
|
193
|
+
version = "2.0.18"
|
|
194
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
195
|
+
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
|
196
|
+
dependencies = [
|
|
197
|
+
"thiserror-impl",
|
|
198
|
+
]
|
|
199
|
+
|
|
200
|
+
[[package]]
|
|
201
|
+
name = "thiserror-impl"
|
|
202
|
+
version = "2.0.18"
|
|
203
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
204
|
+
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|
205
|
+
dependencies = [
|
|
206
|
+
"proc-macro2",
|
|
207
|
+
"quote",
|
|
208
|
+
"syn",
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
[[package]]
|
|
212
|
+
name = "unicode-ident"
|
|
213
|
+
version = "1.0.24"
|
|
214
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
215
|
+
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
216
|
+
|
|
217
|
+
[[package]]
|
|
218
|
+
name = "zipcodes"
|
|
219
|
+
version = "2.0.1"
|
|
220
|
+
dependencies = [
|
|
221
|
+
"bzip2",
|
|
222
|
+
"serde",
|
|
223
|
+
"serde_json",
|
|
224
|
+
"thiserror",
|
|
225
|
+
]
|
|
226
|
+
|
|
227
|
+
[[package]]
|
|
228
|
+
name = "zipcodes-py"
|
|
229
|
+
version = "2.0.1"
|
|
230
|
+
dependencies = [
|
|
231
|
+
"pyo3",
|
|
232
|
+
"serde_json",
|
|
233
|
+
"zipcodes",
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
[[package]]
|
|
237
|
+
name = "zmij"
|
|
238
|
+
version = "1.0.21"
|
|
239
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
240
|
+
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[workspace]
|
|
2
|
+
members = ["crates/zipcodes", "crates/zipcodes-py"]
|
|
3
|
+
resolver = "2"
|
|
4
|
+
|
|
5
|
+
[workspace.package]
|
|
6
|
+
version = "2.0.1"
|
|
7
|
+
edition = "2021"
|
|
8
|
+
rust-version = "1.82"
|
|
9
|
+
authors = ["Sean Pianka <pianka@eml.cc>"]
|
|
10
|
+
license = "MIT"
|
|
11
|
+
repository = "https://github.com/seanpianka/zipcodes"
|
|
12
|
+
homepage = "https://github.com/seanpianka/zipcodes"
|
|
13
|
+
|
|
14
|
+
[profile.release]
|
|
15
|
+
lto = true
|
zipcodes-2.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zipcodes
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Classifier: Programming Language :: Rust
|
|
13
|
+
License-File: LICENSE.txt
|
|
14
|
+
Summary: Query U.S. state zipcodes without SQLite.
|
|
15
|
+
Keywords: zipcode,zip,code,us,state,query,filter,validate,sqlite
|
|
16
|
+
Home-Page: https://github.com/seanpianka/zipcodes
|
|
17
|
+
Author-email: Sean Pianka <pianka@eml.cc>
|
|
18
|
+
License-Expression: MIT
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
21
|
+
Project-URL: Homepage, https://github.com/seanpianka/zipcodes
|
|
22
|
+
Project-URL: Issues, https://github.com/seanpianka/zipcodes/issues
|
|
23
|
+
|
|
24
|
+
# Zipcodes
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
[](https://pypi.org/project/zipcodes/)
|
|
28
|
+
[](https://crates.io/crates/zipcodes)
|
|
29
|
+
[](https://pepy.tech/project/zipcodes)
|
|
30
|
+
[](https://github.com/seanpianka/zipcodes/graphs/contributors)
|
|
31
|
+
|
|
32
|
+
Zipcodes is a simple library for querying U.S. zipcodes. No SQLite, no
|
|
33
|
+
network, no runtime data files — the full dataset is embedded in the package.
|
|
34
|
+
|
|
35
|
+
Since 2.0, the library is implemented in Rust and published from a single
|
|
36
|
+
codebase as both the [`zipcodes` Python package](https://pypi.org/project/zipcodes/)
|
|
37
|
+
and the [`zipcodes` Rust crate](https://crates.io/crates/zipcodes). The Python
|
|
38
|
+
API is a drop-in replacement for 1.x — same functions, same dicts, same
|
|
39
|
+
exceptions — just faster:
|
|
40
|
+
|
|
41
|
+
| Operation | 1.x (pure Python) | 2.0 (Rust) |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `import zipcodes` | ~330 ms (loads dataset) | ~5 ms (dataset loads lazily on first query, ~200 ms) |
|
|
44
|
+
| `is_real("06903")` | ~4.2 ms | ~0.03 ms |
|
|
45
|
+
| `matching("77429")` | ~4.2 ms | ~0.3 ms |
|
|
46
|
+
| `similar_to("1018")` | ~7.2 ms | ~0.3 ms |
|
|
47
|
+
| `filter_by(state="TX")` | ~9.7 ms | ~3.7 ms |
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
>>> import zipcodes
|
|
51
|
+
>>> assert zipcodes.is_real('77429')
|
|
52
|
+
>>> assert len(zipcodes.similar_to('7742')) != 0
|
|
53
|
+
>>> exact_zip = zipcodes.matching('77429')[0]
|
|
54
|
+
>>> filtered_zips = zipcodes.filter_by(city="Cypress", state="TX")
|
|
55
|
+
>>> assert exact_zip in filtered_zips
|
|
56
|
+
>>> pprint.pprint(exact_zip)
|
|
57
|
+
{'acceptable_cities': [],
|
|
58
|
+
'active': True,
|
|
59
|
+
'area_codes': ['281', '346', '713', '832'],
|
|
60
|
+
'city': 'Cypress',
|
|
61
|
+
'country': 'US',
|
|
62
|
+
'county': 'Harris County',
|
|
63
|
+
'lat': '29.9766',
|
|
64
|
+
'long': '-95.6358',
|
|
65
|
+
'state': 'TX',
|
|
66
|
+
'timezone': 'America/Chicago',
|
|
67
|
+
'unacceptable_cities': [],
|
|
68
|
+
'world_region': 'NA',
|
|
69
|
+
'zip_code': '77429',
|
|
70
|
+
'zip_code_type': 'STANDARD'}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The zipcode data is refreshed automatically every month — see
|
|
74
|
+
[Zipcode Data](#zipcode-data).
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
### Python
|
|
79
|
+
|
|
80
|
+
```console
|
|
81
|
+
$ python -m pip install zipcodes
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Zipcodes 2.x supports Python 3.9+ and ships prebuilt wheels for Linux
|
|
85
|
+
(x86_64, aarch64, musl), macOS, and Windows. Installing from the source
|
|
86
|
+
distribution requires a Rust toolchain. Python 2.6+/3.2+ users are
|
|
87
|
+
automatically served the pure-Python 1.3.0 release by pip.
|
|
88
|
+
|
|
89
|
+
### Rust
|
|
90
|
+
|
|
91
|
+
```console
|
|
92
|
+
$ cargo add zipcodes
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### New in 2.0
|
|
96
|
+
|
|
97
|
+
- Implemented in Rust; the dataset is compiled into the extension module and
|
|
98
|
+
decompressed lazily on first query, so `import zipcodes` is effectively free.
|
|
99
|
+
- New functions: `contains`, `filter_by_state`, `filter_by_city`,
|
|
100
|
+
`filter_by_county`, `filter_by_timezone`, `filter_by_zip_code_type`,
|
|
101
|
+
`filter_by_coordinates`, and `haversine`.
|
|
102
|
+
- `is_valid` now actually emits its `DeprecationWarning` (in 1.x it raised
|
|
103
|
+
`AttributeError`); use `is_real`.
|
|
104
|
+
- PyInstaller users no longer need `--add-data` for `zips.json.bz2` — there is
|
|
105
|
+
no data file anymore.
|
|
106
|
+
- Behavioral notes for upgraders: query results are fresh dicts (mutating a
|
|
107
|
+
result no longer mutates the shared database list), and
|
|
108
|
+
`filter_by(active=1)` no longer matches `active=True` (pass a bool).
|
|
109
|
+
|
|
110
|
+
## Zipcode Data
|
|
111
|
+
|
|
112
|
+
The embedded dataset (`crates/zipcodes/src/zips.json.bz2`) is assembled from
|
|
113
|
+
three sources:
|
|
114
|
+
|
|
115
|
+
- **[unitedstateszipcodes.org](https://www.unitedstateszipcodes.org)** — the
|
|
116
|
+
rich base data (city aliases, zip type, area codes, county, timezone),
|
|
117
|
+
committed in-repo as `scripts/data/zip_code_database.csv`. Its bot
|
|
118
|
+
protection prevents automated downloads, so this file is refreshed manually
|
|
119
|
+
on occasion.
|
|
120
|
+
- **[GeoNames](https://www.geonames.org/)** (`download.geonames.org/export/zip/US.zip`) —
|
|
121
|
+
GPS coordinates, fetched fresh on every update. Licensed
|
|
122
|
+
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
|
123
|
+
- **USPS ZIP Locale Detail** ([postalpro.usps.com](https://postalpro.usps.com/ZIP_Locale_Detail)) —
|
|
124
|
+
the authoritative list of active delivery ZIPs, fetched fresh on every
|
|
125
|
+
update and used to add zipcodes missing from the base CSV
|
|
126
|
+
([#23](https://github.com/seanpianka/Zipcodes/issues/23)). Public domain.
|
|
127
|
+
|
|
128
|
+
A GitHub Actions workflow ([`update-data.yml`](.github/workflows/update-data.yml))
|
|
129
|
+
rebuilds the dataset on the 1st of every month
|
|
130
|
+
([#7](https://github.com/seanpianka/Zipcodes/issues/7)). If anything changed,
|
|
131
|
+
it opens a pull request with a summary of added/removed/modified records;
|
|
132
|
+
merging that PR tags a patch release, which publishes to PyPI and crates.io
|
|
133
|
+
automatically.
|
|
134
|
+
|
|
135
|
+
To rebuild the dataset manually:
|
|
136
|
+
|
|
137
|
+
```shell script
|
|
138
|
+
$ pip install xlrd
|
|
139
|
+
$ curl -fsSL https://download.geonames.org/export/zip/US.zip -o /tmp/geonames_us.zip
|
|
140
|
+
$ # download the .xls linked from https://postalpro.usps.com/ZIP_Locale_Detail
|
|
141
|
+
$ python scripts/update_zipcode_dataset.py \
|
|
142
|
+
--base scripts/data/zip_code_database.csv \
|
|
143
|
+
--gps scripts/data/zip-codes-database-FREE.csv \
|
|
144
|
+
--geonames-zip /tmp/geonames_us.zip \
|
|
145
|
+
--usps-xls /tmp/usps_zip_locale.xls \
|
|
146
|
+
--output-bz2 crates/zipcodes/src/zips.json.bz2 \
|
|
147
|
+
--summary-output /tmp/change_summary.json
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Tests
|
|
151
|
+
|
|
152
|
+
The tests are defined in a declarative, table-based format that generates test
|
|
153
|
+
cases.
|
|
154
|
+
|
|
155
|
+
```shell script
|
|
156
|
+
$ cargo test # Rust unit tests
|
|
157
|
+
$ python tests/__init__.py # Python suite (or: pytest tests/)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Examples
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
>>> from pprint import pprint
|
|
164
|
+
>>> import zipcodes
|
|
165
|
+
|
|
166
|
+
>>> # Simple zip-code matching.
|
|
167
|
+
>>> pprint(zipcodes.matching('77429'))
|
|
168
|
+
[{'acceptable_cities': [],
|
|
169
|
+
'active': True,
|
|
170
|
+
'area_codes': ['281', '346', '713', '832'],
|
|
171
|
+
'city': 'Cypress',
|
|
172
|
+
'country': 'US',
|
|
173
|
+
'county': 'Harris County',
|
|
174
|
+
'lat': '29.9766',
|
|
175
|
+
'long': '-95.6358',
|
|
176
|
+
'state': 'TX',
|
|
177
|
+
'timezone': 'America/Chicago',
|
|
178
|
+
'unacceptable_cities': [],
|
|
179
|
+
'world_region': 'NA',
|
|
180
|
+
'zip_code': '77429',
|
|
181
|
+
'zip_code_type': 'STANDARD'}]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
>>> # Handles Zip+4 zip-codes nicely. :)
|
|
185
|
+
>>> pprint(zipcodes.matching('77429-1145'))
|
|
186
|
+
[{'acceptable_cities': [],
|
|
187
|
+
'active': True,
|
|
188
|
+
'area_codes': ['281', '346', '713', '832'],
|
|
189
|
+
'city': 'Cypress',
|
|
190
|
+
'country': 'US',
|
|
191
|
+
'county': 'Harris County',
|
|
192
|
+
'lat': '29.9766',
|
|
193
|
+
'long': '-95.6358',
|
|
194
|
+
'state': 'TX',
|
|
195
|
+
'timezone': 'America/Chicago',
|
|
196
|
+
'unacceptable_cities': [],
|
|
197
|
+
'world_region': 'NA',
|
|
198
|
+
'zip_code': '77429',
|
|
199
|
+
'zip_code_type': 'STANDARD'}]
|
|
200
|
+
|
|
201
|
+
>>> # Will try to handle invalid zip-codes gracefully...
|
|
202
|
+
>>> print(zipcodes.matching('06463'))
|
|
203
|
+
[]
|
|
204
|
+
|
|
205
|
+
>>> # Until it cannot.
|
|
206
|
+
>>> zipcodes.matching('0646a')
|
|
207
|
+
Traceback (most recent call last):
|
|
208
|
+
...
|
|
209
|
+
ValueError: Invalid characters, zipcode may only contain digits and "-".
|
|
210
|
+
|
|
211
|
+
>>> zipcodes.matching('064690')
|
|
212
|
+
Traceback (most recent call last):
|
|
213
|
+
...
|
|
214
|
+
ValueError: Invalid format, zipcode must be of the format: "#####" or "#####-####"
|
|
215
|
+
|
|
216
|
+
>>> zipcodes.matching(None)
|
|
217
|
+
Traceback (most recent call last):
|
|
218
|
+
...
|
|
219
|
+
TypeError: Invalid type, zipcode must be a string.
|
|
220
|
+
|
|
221
|
+
>>> # Whether the zip-code exists within the database.
|
|
222
|
+
>>> print(zipcodes.is_real('06463'))
|
|
223
|
+
False
|
|
224
|
+
|
|
225
|
+
>>> # How handy!
|
|
226
|
+
>>> print(zipcodes.is_real('06469'))
|
|
227
|
+
True
|
|
228
|
+
|
|
229
|
+
>>> # Search for zipcodes that begin with a pattern.
|
|
230
|
+
>>> pprint(zipcodes.similar_to('1018'))
|
|
231
|
+
[{'acceptable_cities': [],
|
|
232
|
+
'active': False,
|
|
233
|
+
'area_codes': ['212'],
|
|
234
|
+
'city': 'New York',
|
|
235
|
+
'country': 'US',
|
|
236
|
+
'county': 'New York County',
|
|
237
|
+
'lat': '40.71',
|
|
238
|
+
'long': '-74',
|
|
239
|
+
'state': 'NY',
|
|
240
|
+
'timezone': 'America/New_York',
|
|
241
|
+
'unacceptable_cities': ['J C Penney'],
|
|
242
|
+
'world_region': 'NA',
|
|
243
|
+
'zip_code': '10184',
|
|
244
|
+
'zip_code_type': 'UNIQUE'},
|
|
245
|
+
{'acceptable_cities': [],
|
|
246
|
+
'active': True,
|
|
247
|
+
'area_codes': ['212'],
|
|
248
|
+
'city': 'New York',
|
|
249
|
+
'country': 'US',
|
|
250
|
+
'county': 'New York County',
|
|
251
|
+
'lat': '40.7808',
|
|
252
|
+
'long': '-73.9772',
|
|
253
|
+
'state': 'NY',
|
|
254
|
+
'timezone': 'America/New_York',
|
|
255
|
+
'unacceptable_cities': ['Manhattan', 'New York City', 'NY', 'Ny City', 'Nyc'],
|
|
256
|
+
'world_region': 'NA',
|
|
257
|
+
'zip_code': '10185',
|
|
258
|
+
'zip_code_type': 'PO BOX'}]
|
|
259
|
+
|
|
260
|
+
>>> # Use filter_by to filter a list of zip-codes by specific attribute->value pairs.
|
|
261
|
+
>>> pprint(zipcodes.filter_by(city="Old Saybrook"))
|
|
262
|
+
[{'acceptable_cities': [],
|
|
263
|
+
'active': True,
|
|
264
|
+
'area_codes': ['860', '959'],
|
|
265
|
+
'city': 'Old Saybrook',
|
|
266
|
+
'country': 'US',
|
|
267
|
+
'county': 'Middlesex County',
|
|
268
|
+
'lat': '41.2913',
|
|
269
|
+
'long': '-72.385',
|
|
270
|
+
'state': 'CT',
|
|
271
|
+
'timezone': 'America/New_York',
|
|
272
|
+
'unacceptable_cities': ['Fenwick'],
|
|
273
|
+
'world_region': 'NA',
|
|
274
|
+
'zip_code': '06475',
|
|
275
|
+
'zip_code_type': 'STANDARD'}]
|
|
276
|
+
|
|
277
|
+
>>> # Arbitrary nesting of similar_to and filter_by calls, allowing for great precision while filtering.
|
|
278
|
+
>>> pprint([z['zip_code'] for z in zipcodes.similar_to('2', zips=zipcodes.filter_by(active=True, city='Windsor'))])
|
|
279
|
+
['23487', '27983', '29856']
|
|
280
|
+
|
|
281
|
+
>>> # Find zipcodes within a radius (miles) of a coordinate.
|
|
282
|
+
>>> pprint([z['zip_code'] for z in zipcodes.filter_by_coordinates(41.3015, -72.3879, 5)])
|
|
283
|
+
['06371', '06409', '06426', '06442', '06475', '06498']
|
|
284
|
+
|
|
285
|
+
>>> # Have any other ideas? Make a pull request and start contributing today!
|
|
286
|
+
>>> # Made with love by Sean Pianka
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Repository layout
|
|
290
|
+
|
|
291
|
+
This repository builds both packages from one Rust core:
|
|
292
|
+
|
|
293
|
+
- `crates/zipcodes` — the core library, published to
|
|
294
|
+
[crates.io](https://crates.io/crates/zipcodes).
|
|
295
|
+
- `crates/zipcodes-py` — PyO3 bindings (not published to crates.io).
|
|
296
|
+
- `python/zipcodes` — the thin Python compatibility layer; together with the
|
|
297
|
+
bindings it forms the [PyPI package](https://pypi.org/project/zipcodes/),
|
|
298
|
+
built with [maturin](https://github.com/PyO3/maturin).
|
|
299
|
+
|