py-nusantara 0.1.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.
Files changed (55) hide show
  1. py_nusantara-0.1.0/PKG-INFO +211 -0
  2. py_nusantara-0.1.0/README.md +196 -0
  3. py_nusantara-0.1.0/pyproject.toml +26 -0
  4. py_nusantara-0.1.0/src/py_nusantara/__init__.py +336 -0
  5. py_nusantara-0.1.0/src/py_nusantara/cache.py +106 -0
  6. py_nusantara-0.1.0/src/py_nusantara/config.py +149 -0
  7. py_nusantara-0.1.0/src/py_nusantara/data/districts.csv.gz +0 -0
  8. py_nusantara-0.1.0/src/py_nusantara/data/provinces.csv.gz +0 -0
  9. py_nusantara-0.1.0/src/py_nusantara/data/regencies.csv.gz +0 -0
  10. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_11.csv.gz +0 -0
  11. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_12.csv.gz +0 -0
  12. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_13.csv.gz +0 -0
  13. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_14.csv.gz +0 -0
  14. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_15.csv.gz +0 -0
  15. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_16.csv.gz +0 -0
  16. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_17.csv.gz +0 -0
  17. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_18.csv.gz +0 -0
  18. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_19.csv.gz +0 -0
  19. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_21.csv.gz +0 -0
  20. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_31.csv.gz +0 -0
  21. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_32.csv.gz +0 -0
  22. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_33.csv.gz +0 -0
  23. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_34.csv.gz +0 -0
  24. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_35.csv.gz +0 -0
  25. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_36.csv.gz +0 -0
  26. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_51.csv.gz +0 -0
  27. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_52.csv.gz +0 -0
  28. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_53.csv.gz +0 -0
  29. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_61.csv.gz +0 -0
  30. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_62.csv.gz +0 -0
  31. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_63.csv.gz +0 -0
  32. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_64.csv.gz +0 -0
  33. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_65.csv.gz +0 -0
  34. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_71.csv.gz +0 -0
  35. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_72.csv.gz +0 -0
  36. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_73.csv.gz +0 -0
  37. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_74.csv.gz +0 -0
  38. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_75.csv.gz +0 -0
  39. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_76.csv.gz +0 -0
  40. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_81.csv.gz +0 -0
  41. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_82.csv.gz +0 -0
  42. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_91.csv.gz +0 -0
  43. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_92.csv.gz +0 -0
  44. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_93.csv.gz +0 -0
  45. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_94.csv.gz +0 -0
  46. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_95.csv.gz +0 -0
  47. py_nusantara-0.1.0/src/py_nusantara/data/villages/villages_96.csv.gz +0 -0
  48. py_nusantara-0.1.0/src/py_nusantara/db.py +406 -0
  49. py_nusantara-0.1.0/src/py_nusantara/downloader.py +237 -0
  50. py_nusantara-0.1.0/src/py_nusantara/exceptions.py +18 -0
  51. py_nusantara-0.1.0/src/py_nusantara/manifest.py +81 -0
  52. py_nusantara-0.1.0/src/py_nusantara/py.typed +0 -0
  53. py_nusantara-0.1.0/src/py_nusantara/reader.py +150 -0
  54. py_nusantara-0.1.0/src/py_nusantara/records.py +159 -0
  55. py_nusantara-0.1.0/src/py_nusantara/search.py +74 -0
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.3
2
+ Name: py-nusantara
3
+ Version: 0.1.0
4
+ Summary: A customizable, enterprise-ready Python package for Indonesia's administrative regions database.
5
+ Author: Gede Widiantara
6
+ Author-email: Gede Widiantara <gdwidi13@gmail.com>
7
+ Requires-Dist: pandas>=2.0.0 ; extra == 'pandas'
8
+ Requires-Dist: redis>=5.0.0 ; extra == 'redis'
9
+ Requires-Dist: sqlalchemy>=2.0.0 ; extra == 'sqlalchemy'
10
+ Requires-Python: >=3.12
11
+ Provides-Extra: pandas
12
+ Provides-Extra: redis
13
+ Provides-Extra: sqlalchemy
14
+ Description-Content-Type: text/markdown
15
+
16
+ # Python Nusantara (py-nusantara)
17
+
18
+ A highly customizable, enterprise-ready, and developer-friendly Python package for Indonesia's administrative regions database (Provinces, Regencies, Districts, and Villages). Compiled according to **Kepmendagri No 300.2.2-2138 Year 2025**.
19
+
20
+ Designed for both backend backend integrations (with SQLAlchemy) and **data science environments** (Jupyter Notebooks, Google Colab) with direct, database-free access.
21
+
22
+ ---
23
+
24
+ ## ⚡ Key Features
25
+
26
+ * **Zero-DB Mode**: Load, query, and search regions directly from memory using gzipped CSV datasets—no database connection required.
27
+ * **On-Demand Boundaries (GIS)**: Keep the package size tiny. High-resolution geographic boundary coordinates (polygons/multipolygons) are downloaded only when you ask for them.
28
+ * **Data Science Ready**: Convert records directly to Pandas or Polars DataFrames using simple helpers (e.g. `provinces_df()`).
29
+ * **Complete Schema Freedom**: Custom table names and column renames matching your corporate schema guidelines.
30
+ * **Dynamic Property Accessors**: Intercepts attribute calls to logically mapped names (e.g. access `province.name` even if configured as `nama_provinsi` in your database).
31
+ * **Pluggable Caching**: Built-in TTL caching (InMemoryCache) with optional Redis support to minimize file parsing or database query overhead.
32
+ * **Low-Memory Seeder**: Streams datasets and seeds databases in bulk chunks (e.g., SQLite, PostgreSQL, MySQL, SQL Server) using SQLAlchemy.
33
+
34
+ ---
35
+
36
+ ## 📦 Installation
37
+
38
+ Install the package via `pip` or `uv`:
39
+
40
+ ```bash
41
+ # Core package (Database-free direct queries only)
42
+ uv add py-nusantara
43
+
44
+ # For Pandas Dataframe exports
45
+ uv add py-nusantara --optional pandas
46
+
47
+ # For SQL databases (SQLAlchemy models and seeding)
48
+ uv add py-nusantara --optional sqlalchemy
49
+
50
+ # For Redis query caching
51
+ uv add py-nusantara --optional redis
52
+
53
+ # Install everything
54
+ uv add py-nusantara --optional pandas --optional sqlalchemy --optional redis
55
+ ```
56
+
57
+ ---
58
+
59
+ ## 🗺️ Direct Data Access (Jupyter / Google Colab)
60
+
61
+ No database is required to browse, query, and traverse administrative records.
62
+
63
+ ```python
64
+ import py_nusantara as nus
65
+
66
+ # 1. Fetch all Provinces
67
+ provinces = nus.provinces() # returns list of ProvinceRecord
68
+ print(f"Total Provinces: {len(provinces)}")
69
+
70
+ # 2. Get specific Province by ID
71
+ province = nus.find_province("11") # Aceh
72
+ print(f"Capital: {province.capital}")
73
+
74
+ # 3. Traverse relations (Province -> Regencies -> Districts -> Villages)
75
+ regencies = province.regencies
76
+ first_regency = regencies[0]
77
+ print(f"Regency Name: {first_regency.name}")
78
+
79
+ districts = first_regency.districts
80
+ first_district = districts[0]
81
+
82
+ villages = first_district.villages
83
+ if villages:
84
+ first_village = villages[0]
85
+ print(f"Village: {first_village.name} (Postal: {first_village.postal_code})")
86
+
87
+ # 4. Search regions dynamically across all levels
88
+ results = nus.search("Bakongan")
89
+ # Returns: {"provinces": [], "regencies": [], "districts": [...], "villages": [...]}
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 📊 Pandas Data Science Integration
95
+
96
+ Export regions straight into Pandas DataFrames for quick data manipulation or visualization.
97
+
98
+ ```python
99
+ import py_nusantara as nus
100
+
101
+ # Convert provinces to Pandas DataFrame
102
+ df_provinces = nus.provinces_df()
103
+
104
+ # Get regencies as DataFrame
105
+ df_regencies = nus.regencies_df(province_id="11")
106
+ ```
107
+
108
+ ---
109
+
110
+ ## 🌐 On-Demand Geographic Boundaries (GIS)
111
+
112
+ By default, boundary coordinate data is excluded to keep the package lightweight. When needed, they can be downloaded and cached locally.
113
+
114
+ ```python
115
+ import py_nusantara as nus
116
+
117
+ # 1. Enable boundary columns in configuration
118
+ nus.init({
119
+ "columns": {
120
+ "provinces": {"boundary": {"enabled": True}}
121
+ }
122
+ })
123
+
124
+ # 2. Download and verify boundaries checksums (stored in ~/.cache/py-nusantara/)
125
+ nus.download_boundaries(levels="provinces")
126
+
127
+ # 3. Access coordinates directly in memory or dataframe
128
+ aceh = nus.find_province("11")
129
+ print(aceh.boundary) # Raw JSON coordinate array
130
+
131
+ # 4. Format JSON to WKT (Well-Known Text) for spatial engines
132
+ wkt = nus.json_to_wkt(aceh.boundary)
133
+ print(wkt) # e.g. "POLYGON((95.3 5.5, ...))"
134
+ ```
135
+
136
+ ---
137
+
138
+ ## 🏛️ Database Integration & Seeding (SQLAlchemy)
139
+
140
+ Create tables and bulk seed administrative data into your SQLAlchemy-supported database:
141
+
142
+ ```python
143
+ from sqlalchemy import create_engine
144
+ from sqlalchemy.orm import declarative_base, sessionmaker
145
+ import py_nusantara as nus
146
+
147
+ # 1. Setup SQLAlchemy Connection
148
+ engine = create_engine("sqlite:///nusantara.db")
149
+ Session = sessionmaker(bind=engine)
150
+ session = Session()
151
+
152
+ Base = declarative_base()
153
+
154
+ # 2. Build Models dynamically matching your configuration
155
+ models = nus.build_models(Base, nus.Nusantara().config)
156
+ # Generates ORM classes: models["Province"], models["Regency"], models["District"], models["Village"]
157
+
158
+ # 3. Create tables in Database
159
+ Base.metadata.create_all(engine)
160
+
161
+ # 4. Seed core datasets (Streams gzipped files in chunks under 2MB memory)
162
+ seeder = nus.NusantaraSeeder(session, nus.Nusantara().config, nus.Nusantara().reader)
163
+ seeder.seed()
164
+
165
+ # 5. Seed boundaries (Optional, run download_boundaries first)
166
+ seeder.seed_boundaries(levels=["provinces", "regencies"])
167
+ ```
168
+
169
+ ---
170
+
171
+ ## ⚙️ Configuration
172
+
173
+ Initialize `Nusantara` with custom configuration structures:
174
+
175
+ ```python
176
+ custom_config = {
177
+ "tables": {
178
+ "provinces": "indonesia_provinces", # custom table name
179
+ },
180
+ "columns": {
181
+ "provinces": {
182
+ "name": {"name": "nama_provinsi", "enabled": True}, # renamed
183
+ "timezone": {"enabled": False}, # excluded
184
+ }
185
+ },
186
+ "cache": {
187
+ "enabled": True,
188
+ "ttl": 86400,
189
+ "prefix": "nusantara",
190
+ "redis_url": "redis://localhost:6379/0", # redis caching
191
+ }
192
+ }
193
+
194
+ nus = nus.init(custom_config)
195
+ ```
196
+
197
+ ---
198
+
199
+ ## 🧪 Testing
200
+
201
+ To run the test suite:
202
+
203
+ ```bash
204
+ uv run pytest
205
+ ```
206
+
207
+ ---
208
+
209
+ ## 📄 License
210
+
211
+ The MIT License (MIT). Please see [LICENSE](LICENSE) for more information.
@@ -0,0 +1,196 @@
1
+ # Python Nusantara (py-nusantara)
2
+
3
+ A highly customizable, enterprise-ready, and developer-friendly Python package for Indonesia's administrative regions database (Provinces, Regencies, Districts, and Villages). Compiled according to **Kepmendagri No 300.2.2-2138 Year 2025**.
4
+
5
+ Designed for both backend backend integrations (with SQLAlchemy) and **data science environments** (Jupyter Notebooks, Google Colab) with direct, database-free access.
6
+
7
+ ---
8
+
9
+ ## ⚡ Key Features
10
+
11
+ * **Zero-DB Mode**: Load, query, and search regions directly from memory using gzipped CSV datasets—no database connection required.
12
+ * **On-Demand Boundaries (GIS)**: Keep the package size tiny. High-resolution geographic boundary coordinates (polygons/multipolygons) are downloaded only when you ask for them.
13
+ * **Data Science Ready**: Convert records directly to Pandas or Polars DataFrames using simple helpers (e.g. `provinces_df()`).
14
+ * **Complete Schema Freedom**: Custom table names and column renames matching your corporate schema guidelines.
15
+ * **Dynamic Property Accessors**: Intercepts attribute calls to logically mapped names (e.g. access `province.name` even if configured as `nama_provinsi` in your database).
16
+ * **Pluggable Caching**: Built-in TTL caching (InMemoryCache) with optional Redis support to minimize file parsing or database query overhead.
17
+ * **Low-Memory Seeder**: Streams datasets and seeds databases in bulk chunks (e.g., SQLite, PostgreSQL, MySQL, SQL Server) using SQLAlchemy.
18
+
19
+ ---
20
+
21
+ ## 📦 Installation
22
+
23
+ Install the package via `pip` or `uv`:
24
+
25
+ ```bash
26
+ # Core package (Database-free direct queries only)
27
+ uv add py-nusantara
28
+
29
+ # For Pandas Dataframe exports
30
+ uv add py-nusantara --optional pandas
31
+
32
+ # For SQL databases (SQLAlchemy models and seeding)
33
+ uv add py-nusantara --optional sqlalchemy
34
+
35
+ # For Redis query caching
36
+ uv add py-nusantara --optional redis
37
+
38
+ # Install everything
39
+ uv add py-nusantara --optional pandas --optional sqlalchemy --optional redis
40
+ ```
41
+
42
+ ---
43
+
44
+ ## 🗺️ Direct Data Access (Jupyter / Google Colab)
45
+
46
+ No database is required to browse, query, and traverse administrative records.
47
+
48
+ ```python
49
+ import py_nusantara as nus
50
+
51
+ # 1. Fetch all Provinces
52
+ provinces = nus.provinces() # returns list of ProvinceRecord
53
+ print(f"Total Provinces: {len(provinces)}")
54
+
55
+ # 2. Get specific Province by ID
56
+ province = nus.find_province("11") # Aceh
57
+ print(f"Capital: {province.capital}")
58
+
59
+ # 3. Traverse relations (Province -> Regencies -> Districts -> Villages)
60
+ regencies = province.regencies
61
+ first_regency = regencies[0]
62
+ print(f"Regency Name: {first_regency.name}")
63
+
64
+ districts = first_regency.districts
65
+ first_district = districts[0]
66
+
67
+ villages = first_district.villages
68
+ if villages:
69
+ first_village = villages[0]
70
+ print(f"Village: {first_village.name} (Postal: {first_village.postal_code})")
71
+
72
+ # 4. Search regions dynamically across all levels
73
+ results = nus.search("Bakongan")
74
+ # Returns: {"provinces": [], "regencies": [], "districts": [...], "villages": [...]}
75
+ ```
76
+
77
+ ---
78
+
79
+ ## 📊 Pandas Data Science Integration
80
+
81
+ Export regions straight into Pandas DataFrames for quick data manipulation or visualization.
82
+
83
+ ```python
84
+ import py_nusantara as nus
85
+
86
+ # Convert provinces to Pandas DataFrame
87
+ df_provinces = nus.provinces_df()
88
+
89
+ # Get regencies as DataFrame
90
+ df_regencies = nus.regencies_df(province_id="11")
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 🌐 On-Demand Geographic Boundaries (GIS)
96
+
97
+ By default, boundary coordinate data is excluded to keep the package lightweight. When needed, they can be downloaded and cached locally.
98
+
99
+ ```python
100
+ import py_nusantara as nus
101
+
102
+ # 1. Enable boundary columns in configuration
103
+ nus.init({
104
+ "columns": {
105
+ "provinces": {"boundary": {"enabled": True}}
106
+ }
107
+ })
108
+
109
+ # 2. Download and verify boundaries checksums (stored in ~/.cache/py-nusantara/)
110
+ nus.download_boundaries(levels="provinces")
111
+
112
+ # 3. Access coordinates directly in memory or dataframe
113
+ aceh = nus.find_province("11")
114
+ print(aceh.boundary) # Raw JSON coordinate array
115
+
116
+ # 4. Format JSON to WKT (Well-Known Text) for spatial engines
117
+ wkt = nus.json_to_wkt(aceh.boundary)
118
+ print(wkt) # e.g. "POLYGON((95.3 5.5, ...))"
119
+ ```
120
+
121
+ ---
122
+
123
+ ## 🏛️ Database Integration & Seeding (SQLAlchemy)
124
+
125
+ Create tables and bulk seed administrative data into your SQLAlchemy-supported database:
126
+
127
+ ```python
128
+ from sqlalchemy import create_engine
129
+ from sqlalchemy.orm import declarative_base, sessionmaker
130
+ import py_nusantara as nus
131
+
132
+ # 1. Setup SQLAlchemy Connection
133
+ engine = create_engine("sqlite:///nusantara.db")
134
+ Session = sessionmaker(bind=engine)
135
+ session = Session()
136
+
137
+ Base = declarative_base()
138
+
139
+ # 2. Build Models dynamically matching your configuration
140
+ models = nus.build_models(Base, nus.Nusantara().config)
141
+ # Generates ORM classes: models["Province"], models["Regency"], models["District"], models["Village"]
142
+
143
+ # 3. Create tables in Database
144
+ Base.metadata.create_all(engine)
145
+
146
+ # 4. Seed core datasets (Streams gzipped files in chunks under 2MB memory)
147
+ seeder = nus.NusantaraSeeder(session, nus.Nusantara().config, nus.Nusantara().reader)
148
+ seeder.seed()
149
+
150
+ # 5. Seed boundaries (Optional, run download_boundaries first)
151
+ seeder.seed_boundaries(levels=["provinces", "regencies"])
152
+ ```
153
+
154
+ ---
155
+
156
+ ## ⚙️ Configuration
157
+
158
+ Initialize `Nusantara` with custom configuration structures:
159
+
160
+ ```python
161
+ custom_config = {
162
+ "tables": {
163
+ "provinces": "indonesia_provinces", # custom table name
164
+ },
165
+ "columns": {
166
+ "provinces": {
167
+ "name": {"name": "nama_provinsi", "enabled": True}, # renamed
168
+ "timezone": {"enabled": False}, # excluded
169
+ }
170
+ },
171
+ "cache": {
172
+ "enabled": True,
173
+ "ttl": 86400,
174
+ "prefix": "nusantara",
175
+ "redis_url": "redis://localhost:6379/0", # redis caching
176
+ }
177
+ }
178
+
179
+ nus = nus.init(custom_config)
180
+ ```
181
+
182
+ ---
183
+
184
+ ## 🧪 Testing
185
+
186
+ To run the test suite:
187
+
188
+ ```bash
189
+ uv run pytest
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 📄 License
195
+
196
+ The MIT License (MIT). Please see [LICENSE](LICENSE) for more information.
@@ -0,0 +1,26 @@
1
+ [project]
2
+ name = "py-nusantara"
3
+ version = "0.1.0"
4
+ description = "A customizable, enterprise-ready Python package for Indonesia's administrative regions database."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Gede Widiantara", email = "gdwidi13@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = []
11
+
12
+ [project.optional-dependencies]
13
+ sqlalchemy = ["sqlalchemy>=2.0.0"]
14
+ pandas = ["pandas>=2.0.0"]
15
+ redis = ["redis>=5.0.0"]
16
+
17
+ [dependency-groups]
18
+ dev = [
19
+ "pytest>=8.0.0",
20
+ "sqlalchemy>=2.0.0",
21
+ "pandas>=2.0.0",
22
+ ]
23
+
24
+ [build-system]
25
+ requires = ["uv_build>=0.11.20,<0.12.0"]
26
+ build-backend = "uv_build"