zipcodes 1.3.0__tar.gz → 3.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.
@@ -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 = "3.0.0"
220
+ dependencies = [
221
+ "bzip2",
222
+ "serde",
223
+ "serde_json",
224
+ "thiserror",
225
+ ]
226
+
227
+ [[package]]
228
+ name = "zipcodes-py"
229
+ version = "3.0.0"
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 = "3.0.0"
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
@@ -0,0 +1,310 @@
1
+ Metadata-Version: 2.4
2
+ Name: zipcodes
3
+ Version: 3.0.0
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
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/zipcodes)
27
+ [![PyPI](https://img.shields.io/pypi/v/zipcodes)](https://pypi.org/project/zipcodes/)
28
+ [![crates.io](https://img.shields.io/crates/v/zipcodes)](https://crates.io/crates/zipcodes)
29
+ [![Downloads](https://static.pepy.tech/badge/zipcodes/month)](https://pepy.tech/project/zipcodes)
30
+ [![Contributors](https://img.shields.io/github/contributors/seanpianka/zipcodes.svg)](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
+ - **Unified validation.** Input validation now lives once, in the Rust core,
110
+ instead of a separate Python validator. This changes a few edge cases:
111
+ - **Breaking:** `is_real`/`matching` now raise `ValueError` for input shorter
112
+ than five characters (after trimming), instead of returning `False`/`[]`.
113
+ - **Relaxations:** surrounding whitespace (`" 06903 "`) and space-separated
114
+ Zip+4 (`"12345 6789"`) are now accepted; any input of five or more
115
+ characters is normalized to its first five digits, generalizing the
116
+ existing `#####-####` handling.
117
+ - **Private API removal:** the undocumented helpers `zipcodes._clean` and
118
+ `zipcodes._contains_nondigits` (and the `_digits`/`_valid_zipcode_length`
119
+ module attributes) no longer exist.
120
+
121
+ ## Zipcode Data
122
+
123
+ The embedded dataset (`crates/zipcodes/src/zips.json.bz2`) is assembled from
124
+ three sources:
125
+
126
+ - **[unitedstateszipcodes.org](https://www.unitedstateszipcodes.org)** — the
127
+ rich base data (city aliases, zip type, area codes, county, timezone),
128
+ committed in-repo as `scripts/data/zip_code_database.csv`. Its bot
129
+ protection prevents automated downloads, so this file is refreshed manually
130
+ on occasion.
131
+ - **[GeoNames](https://www.geonames.org/)** (`download.geonames.org/export/zip/US.zip`) —
132
+ GPS coordinates, fetched fresh on every update. Licensed
133
+ [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
134
+ - **USPS ZIP Locale Detail** ([postalpro.usps.com](https://postalpro.usps.com/ZIP_Locale_Detail)) —
135
+ the authoritative list of active delivery ZIPs, fetched fresh on every
136
+ update and used to add zipcodes missing from the base CSV
137
+ ([#23](https://github.com/seanpianka/Zipcodes/issues/23)). Public domain.
138
+
139
+ A GitHub Actions workflow ([`update-data.yml`](.github/workflows/update-data.yml))
140
+ rebuilds the dataset on the 1st of every month
141
+ ([#7](https://github.com/seanpianka/Zipcodes/issues/7)). If anything changed,
142
+ it opens a pull request with a summary of added/removed/modified records;
143
+ merging that PR tags a patch release, which publishes to PyPI and crates.io
144
+ automatically.
145
+
146
+ To rebuild the dataset manually:
147
+
148
+ ```shell script
149
+ $ pip install xlrd
150
+ $ curl -fsSL https://download.geonames.org/export/zip/US.zip -o /tmp/geonames_us.zip
151
+ $ # download the .xls linked from https://postalpro.usps.com/ZIP_Locale_Detail
152
+ $ python scripts/update_zipcode_dataset.py \
153
+ --base scripts/data/zip_code_database.csv \
154
+ --gps scripts/data/zip-codes-database-FREE.csv \
155
+ --geonames-zip /tmp/geonames_us.zip \
156
+ --usps-xls /tmp/usps_zip_locale.xls \
157
+ --output-bz2 crates/zipcodes/src/zips.json.bz2 \
158
+ --summary-output /tmp/change_summary.json
159
+ ```
160
+
161
+ ## Tests
162
+
163
+ The tests are defined in a declarative, table-based format that generates test
164
+ cases.
165
+
166
+ ```shell script
167
+ $ cargo test # Rust unit tests
168
+ $ python tests/__init__.py # Python suite (or: pytest tests/)
169
+ ```
170
+
171
+ ## Examples
172
+
173
+ ```python
174
+ >>> from pprint import pprint
175
+ >>> import zipcodes
176
+
177
+ >>> # Simple zip-code matching.
178
+ >>> pprint(zipcodes.matching('77429'))
179
+ [{'acceptable_cities': [],
180
+ 'active': True,
181
+ 'area_codes': ['281', '346', '713', '832'],
182
+ 'city': 'Cypress',
183
+ 'country': 'US',
184
+ 'county': 'Harris County',
185
+ 'lat': '29.9766',
186
+ 'long': '-95.6358',
187
+ 'state': 'TX',
188
+ 'timezone': 'America/Chicago',
189
+ 'unacceptable_cities': [],
190
+ 'world_region': 'NA',
191
+ 'zip_code': '77429',
192
+ 'zip_code_type': 'STANDARD'}]
193
+
194
+
195
+ >>> # Handles Zip+4 zip-codes nicely. :)
196
+ >>> pprint(zipcodes.matching('77429-1145'))
197
+ [{'acceptable_cities': [],
198
+ 'active': True,
199
+ 'area_codes': ['281', '346', '713', '832'],
200
+ 'city': 'Cypress',
201
+ 'country': 'US',
202
+ 'county': 'Harris County',
203
+ 'lat': '29.9766',
204
+ 'long': '-95.6358',
205
+ 'state': 'TX',
206
+ 'timezone': 'America/Chicago',
207
+ 'unacceptable_cities': [],
208
+ 'world_region': 'NA',
209
+ 'zip_code': '77429',
210
+ 'zip_code_type': 'STANDARD'}]
211
+
212
+ >>> # Will try to handle invalid zip-codes gracefully...
213
+ >>> print(zipcodes.matching('06463'))
214
+ []
215
+
216
+ >>> # Until it cannot.
217
+ >>> zipcodes.matching('0646a')
218
+ Traceback (most recent call last):
219
+ ...
220
+ ValueError: Invalid characters, zipcode may only contain digits and "-".
221
+
222
+ >>> zipcodes.matching('0646')
223
+ Traceback (most recent call last):
224
+ ...
225
+ ValueError: Invalid format, zipcode must be of the format: "#####" or "#####-####"
226
+
227
+ >>> zipcodes.matching(None)
228
+ Traceback (most recent call last):
229
+ ...
230
+ TypeError: Invalid type, zipcode must be a string.
231
+
232
+ >>> # Whether the zip-code exists within the database.
233
+ >>> print(zipcodes.is_real('06463'))
234
+ False
235
+
236
+ >>> # How handy!
237
+ >>> print(zipcodes.is_real('06469'))
238
+ True
239
+
240
+ >>> # Search for zipcodes that begin with a pattern.
241
+ >>> pprint(zipcodes.similar_to('1018'))
242
+ [{'acceptable_cities': [],
243
+ 'active': False,
244
+ 'area_codes': ['212'],
245
+ 'city': 'New York',
246
+ 'country': 'US',
247
+ 'county': 'New York County',
248
+ 'lat': '40.71',
249
+ 'long': '-74',
250
+ 'state': 'NY',
251
+ 'timezone': 'America/New_York',
252
+ 'unacceptable_cities': ['J C Penney'],
253
+ 'world_region': 'NA',
254
+ 'zip_code': '10184',
255
+ 'zip_code_type': 'UNIQUE'},
256
+ {'acceptable_cities': [],
257
+ 'active': True,
258
+ 'area_codes': ['212'],
259
+ 'city': 'New York',
260
+ 'country': 'US',
261
+ 'county': 'New York County',
262
+ 'lat': '40.7808',
263
+ 'long': '-73.9772',
264
+ 'state': 'NY',
265
+ 'timezone': 'America/New_York',
266
+ 'unacceptable_cities': ['Manhattan', 'New York City', 'NY', 'Ny City', 'Nyc'],
267
+ 'world_region': 'NA',
268
+ 'zip_code': '10185',
269
+ 'zip_code_type': 'PO BOX'}]
270
+
271
+ >>> # Use filter_by to filter a list of zip-codes by specific attribute->value pairs.
272
+ >>> pprint(zipcodes.filter_by(city="Old Saybrook"))
273
+ [{'acceptable_cities': [],
274
+ 'active': True,
275
+ 'area_codes': ['860', '959'],
276
+ 'city': 'Old Saybrook',
277
+ 'country': 'US',
278
+ 'county': 'Middlesex County',
279
+ 'lat': '41.2913',
280
+ 'long': '-72.385',
281
+ 'state': 'CT',
282
+ 'timezone': 'America/New_York',
283
+ 'unacceptable_cities': ['Fenwick'],
284
+ 'world_region': 'NA',
285
+ 'zip_code': '06475',
286
+ 'zip_code_type': 'STANDARD'}]
287
+
288
+ >>> # Arbitrary nesting of similar_to and filter_by calls, allowing for great precision while filtering.
289
+ >>> pprint([z['zip_code'] for z in zipcodes.similar_to('2', zips=zipcodes.filter_by(active=True, city='Windsor'))])
290
+ ['23487', '27983', '29856']
291
+
292
+ >>> # Find zipcodes within a radius (miles) of a coordinate.
293
+ >>> pprint([z['zip_code'] for z in zipcodes.filter_by_coordinates(41.3015, -72.3879, 5)])
294
+ ['06371', '06409', '06426', '06442', '06475', '06498']
295
+
296
+ >>> # Have any other ideas? Make a pull request and start contributing today!
297
+ >>> # Made with love by Sean Pianka
298
+ ```
299
+
300
+ ## Repository layout
301
+
302
+ This repository builds both packages from one Rust core:
303
+
304
+ - `crates/zipcodes` — the core library, published to
305
+ [crates.io](https://crates.io/crates/zipcodes).
306
+ - `crates/zipcodes-py` — PyO3 bindings (not published to crates.io).
307
+ - `python/zipcodes` — the thin Python compatibility layer; together with the
308
+ bindings it forms the [PyPI package](https://pypi.org/project/zipcodes/),
309
+ built with [maturin](https://github.com/PyO3/maturin).
310
+