tanzania-postcodes 0.1.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.
@@ -0,0 +1,86 @@
1
+ """tanzania-postcodes: real Tanzania postal codes, sourced directly from
2
+ TCRA's official gazetted National Postcode System (Government Gazette
3
+ Notice No. 240, 22 April 2016) -- not a third-party's compiled version.
4
+
5
+ >>> import tanzania_postcodes as tzpc
6
+ >>> tzpc.lookup("16112")[0].ward
7
+ 'Goba'
8
+ >>> tzpc.search("Goba")[0].postcode
9
+ '16112'
10
+ """
11
+
12
+ import json
13
+ from dataclasses import dataclass
14
+ from pathlib import Path
15
+ from typing import Optional
16
+
17
+ __version__ = "0.1.0"
18
+
19
+ _DATA_PATH = Path(__file__).parent / "data" / "postcodes.json"
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class Postcode:
24
+ """One locality-level record. Multiple localities share the same
25
+ ward-level `postcode` -- that's the actual unit TCRA's system
26
+ identifies, not the individual village/mtaa.
27
+ """
28
+ region: str
29
+ district: Optional[str]
30
+ ward: str
31
+ postcode: str
32
+ locality: Optional[str]
33
+ sub_locality: Optional[str]
34
+ old_postcode: Optional[str] = None
35
+ district_postcode: Optional[str] = None
36
+
37
+
38
+ def _load():
39
+ with open(_DATA_PATH, encoding="utf-8") as f:
40
+ raw = json.load(f)
41
+ return [Postcode(**r) for r in raw]
42
+
43
+
44
+ _RECORDS = None
45
+
46
+
47
+ def _records():
48
+ global _RECORDS
49
+ if _RECORDS is None:
50
+ _RECORDS = _load()
51
+ return _RECORDS
52
+
53
+
54
+ def lookup(postcode: str) -> list[Postcode]:
55
+ """All records sharing this exact postcode (usually several -- one
56
+ ward maps to multiple villages/mtaa)."""
57
+ postcode = postcode.strip()
58
+ return [r for r in _records() if r.postcode == postcode]
59
+
60
+
61
+ def search(query: str) -> list[Postcode]:
62
+ """Case-insensitive substring search across ward, district, region,
63
+ locality, and sub_locality names."""
64
+ q = query.strip().lower()
65
+ if not q:
66
+ return []
67
+ results = []
68
+ for r in _records():
69
+ haystack = " ".join(filter(None, [r.region, r.district, r.ward, r.locality, r.sub_locality])).lower()
70
+ if q in haystack:
71
+ results.append(r)
72
+ return results
73
+
74
+
75
+ def regions() -> list[str]:
76
+ """All 26 regions with postcode data."""
77
+ return sorted({r.region for r in _records()})
78
+
79
+
80
+ def wards(region: Optional[str] = None) -> list[str]:
81
+ """All ward names, optionally filtered to one region."""
82
+ recs = _records() if region is None else [r for r in _records() if r.region.lower() == region.lower()]
83
+ return sorted({r.ward for r in recs})
84
+
85
+
86
+ __all__ = ["Postcode", "lookup", "search", "regions", "wards", "__version__"]