quantaroute-geocoding 1.0.2__py3-none-any.whl → 1.0.4__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.
@@ -5,11 +5,12 @@ A Python library for geocoding addresses to DigiPin codes with both online API
5
5
  and offline processing capabilities.
6
6
  """
7
7
 
8
- __version__ = "1.0.2"
8
+ __version__ = "1.0.4"
9
9
  __author__ = "QuantaRoute"
10
10
  __email__ = "support@quantaroute.com"
11
11
 
12
12
  from .client import QuantaRouteClient
13
+ from .location_lookup import LocationLookupClient
13
14
  from .offline import OfflineProcessor
14
15
  from .csv_processor import CSVProcessor
15
16
  from .exceptions import (
@@ -22,6 +23,7 @@ from .exceptions import (
22
23
 
23
24
  __all__ = [
24
25
  "QuantaRouteClient",
26
+ "LocationLookupClient",
25
27
  "OfflineProcessor",
26
28
  "CSVProcessor",
27
29
  "QuantaRouteError",
@@ -8,14 +8,15 @@ from typing import Optional
8
8
 
9
9
  from .csv_processor import CSVProcessor
10
10
  from .client import QuantaRouteClient
11
+ from .location_lookup import LocationLookupClient
11
12
  from .offline import OfflineProcessor
12
13
  from .exceptions import QuantaRouteError
13
14
 
14
15
 
15
16
  @click.group()
16
- @click.version_option(version="1.0.0")
17
+ @click.version_option(version="2.0.0")
17
18
  def main():
18
- """QuantaRoute Geocoding CLI - Process addresses and coordinates with DigiPin"""
19
+ """QuantaRoute Geocoding CLI - Revolutionary location intelligence with DigiPin and administrative boundaries"""
19
20
  pass
20
21
 
21
22
 
@@ -277,5 +278,140 @@ def single_digipin_to_coords(digipin_code: str, api_key: Optional[str], offline:
277
278
  click.echo(f"Unexpected error: {str(e)}", err=True)
278
279
 
279
280
 
281
+ # 🚀 REVOLUTIONARY LOCATION LOOKUP COMMANDS
282
+
283
+ @main.command()
284
+ @click.argument('latitude', type=float)
285
+ @click.argument('longitude', type=float)
286
+ @click.option('--api-key', envvar='QUANTAROUTE_API_KEY', required=True, help='QuantaRoute API key')
287
+ def location_lookup(latitude: float, longitude: float, api_key: str):
288
+ """🚀 REVOLUTIONARY: Get administrative boundaries from coordinates"""
289
+
290
+ try:
291
+ client = LocationLookupClient(api_key)
292
+ result = client.lookup_coordinates(latitude, longitude)
293
+
294
+ click.echo("🚀 REVOLUTIONARY LOCATION LOOKUP RESULT")
295
+ click.echo("=" * 50)
296
+ click.echo(f"📍 Coordinates: {latitude}, {longitude}")
297
+ click.echo(f"📮 Pincode: {result.get('pincode', 'N/A')}")
298
+ click.echo(f"🏢 Office Name: {result.get('office_name', 'N/A')}")
299
+ click.echo(f"🏛️ Division: {result.get('division', 'N/A')}")
300
+ click.echo(f"🌍 Region: {result.get('region', 'N/A')}")
301
+ click.echo(f"⭕ Circle: {result.get('circle', 'N/A')}")
302
+ click.echo(f"🗺️ DigiPin: {result.get('digipin', 'N/A')}")
303
+
304
+ if result.get('cached'):
305
+ click.echo(f"⚡ Response Time: {result.get('response_time_ms', 0)}ms (cached)")
306
+ else:
307
+ click.echo(f"🔍 Response Time: {result.get('response_time_ms', 0)}ms (database)")
308
+
309
+ click.echo("\n✨ This precision is not available from government services!")
310
+
311
+ except QuantaRouteError as e:
312
+ click.echo(f"❌ Error: {str(e)}", err=True)
313
+ except Exception as e:
314
+ click.echo(f"💥 Unexpected error: {str(e)}", err=True)
315
+
316
+
317
+ @main.command()
318
+ @click.argument('digipin_code')
319
+ @click.option('--api-key', envvar='QUANTAROUTE_API_KEY', required=True, help='QuantaRoute API key')
320
+ def location_from_digipin(digipin_code: str, api_key: str):
321
+ """🚀 REVOLUTIONARY: Get administrative boundaries from DigiPin"""
322
+
323
+ try:
324
+ client = LocationLookupClient(api_key)
325
+ result = client.lookup_digipin(digipin_code)
326
+
327
+ click.echo("🚀 REVOLUTIONARY LOCATION LOOKUP FROM DIGIPIN")
328
+ click.echo("=" * 55)
329
+ click.echo(f"🔢 DigiPin: {digipin_code}")
330
+ click.echo(f"📮 Pincode: {result.get('pincode', 'N/A')}")
331
+ click.echo(f"🏢 Office Name: {result.get('office_name', 'N/A')}")
332
+ click.echo(f"🏛️ Division: {result.get('division', 'N/A')}")
333
+ click.echo(f"🌍 Region: {result.get('region', 'N/A')}")
334
+ click.echo(f"⭕ Circle: {result.get('circle', 'N/A')}")
335
+
336
+ coords = result.get('coordinates', {})
337
+ if coords:
338
+ click.echo(f"📍 Coordinates: {coords.get('latitude', 'N/A')}, {coords.get('longitude', 'N/A')}")
339
+
340
+ if result.get('cached'):
341
+ click.echo(f"⚡ Response Time: {result.get('response_time_ms', 0)}ms (cached)")
342
+ else:
343
+ click.echo(f"🔍 Response Time: {result.get('response_time_ms', 0)}ms (database)")
344
+
345
+ click.echo("\n✨ Administrative boundary precision that governments don't provide!")
346
+
347
+ except QuantaRouteError as e:
348
+ click.echo(f"❌ Error: {str(e)}", err=True)
349
+ except Exception as e:
350
+ click.echo(f"💥 Unexpected error: {str(e)}", err=True)
351
+
352
+
353
+ @main.command()
354
+ @click.option('--api-key', envvar='QUANTAROUTE_API_KEY', required=True, help='QuantaRoute API key')
355
+ def location_stats(api_key: str):
356
+ """📊 Get live statistics about the revolutionary Location Lookup service"""
357
+
358
+ try:
359
+ client = LocationLookupClient(api_key)
360
+ stats = client.get_statistics()
361
+
362
+ click.echo("📊 REVOLUTIONARY LOCATION LOOKUP STATISTICS")
363
+ click.echo("=" * 50)
364
+ click.echo(f"🗺️ Total Boundaries: {stats.get('total_boundaries', 'N/A'):,}")
365
+ click.echo(f"🏛️ Total States: {stats.get('total_states', 'N/A')}")
366
+ click.echo(f"📮 Total Divisions: {stats.get('total_divisions', 'N/A')}")
367
+ click.echo(f"⚡ Cache Size: {stats.get('cache_size', 'N/A')}")
368
+
369
+ performance = stats.get('performance_metrics', {})
370
+ if performance:
371
+ click.echo(f"\n⚡ PERFORMANCE METRICS:")
372
+ click.echo(f" Average Response Time: {performance.get('avg_response_time_ms', 'N/A')}ms")
373
+ click.echo(f" Cache Hit Rate: {performance.get('cache_hit_rate', 'N/A')}%")
374
+ click.echo(f" Total Requests: {performance.get('total_requests', 'N/A'):,}")
375
+
376
+ click.echo("\n🚀 Revolutionary service with 36,000+ postal boundaries!")
377
+ click.echo("✨ Precision that even government services don't provide!")
378
+
379
+ except QuantaRouteError as e:
380
+ click.echo(f"❌ Error: {str(e)}", err=True)
381
+ except Exception as e:
382
+ click.echo(f"💥 Unexpected error: {str(e)}", err=True)
383
+
384
+
385
+ @main.command()
386
+ @click.argument('input_file', type=click.Path(exists=True))
387
+ @click.argument('output_file', type=click.Path())
388
+ @click.option('--api-key', envvar='QUANTAROUTE_API_KEY', required=True, help='QuantaRoute API key')
389
+ @click.option('--latitude-column', default='latitude', help='Name of latitude column')
390
+ @click.option('--longitude-column', default='longitude', help='Name of longitude column')
391
+ @click.option('--batch-size', default=50, help='Batch size for API requests')
392
+ def location_lookup_csv(
393
+ input_file: str,
394
+ output_file: str,
395
+ api_key: str,
396
+ latitude_column: str,
397
+ longitude_column: str,
398
+ batch_size: int
399
+ ):
400
+ """🚀 REVOLUTIONARY: Batch location lookup from CSV coordinates"""
401
+
402
+ try:
403
+ # This would need to be implemented in csv_processor.py
404
+ click.echo("🚀 REVOLUTIONARY BATCH LOCATION LOOKUP")
405
+ click.echo("=" * 45)
406
+ click.echo(f"📁 Input: {input_file}")
407
+ click.echo(f"📁 Output: {output_file}")
408
+ click.echo(f"📊 Batch Size: {batch_size}")
409
+ click.echo("\n⚠️ CSV Location Lookup processing coming soon!")
410
+ click.echo("✨ Will process thousands of coordinates to administrative boundaries!")
411
+
412
+ except Exception as e:
413
+ click.echo(f"💥 Unexpected error: {str(e)}", err=True)
414
+
415
+
280
416
  if __name__ == '__main__':
281
417
  main()
@@ -39,7 +39,7 @@ class QuantaRouteClient:
39
39
  self.session = requests.Session()
40
40
  self.session.headers.update({
41
41
  'x-api-key': api_key,
42
- 'User-Agent': 'quantaroute-geocoding-python/1.0.0',
42
+ 'User-Agent': 'quantaroute-geocoding-python/2.0.0',
43
43
  'Content-Type': 'application/json'
44
44
  })
45
45
 
@@ -310,3 +310,114 @@ class QuantaRouteClient:
310
310
 
311
311
  response = self._make_request('DELETE', f'/v1/digipin/webhooks/{webhook_id}')
312
312
  return response
313
+
314
+ # 🚀 REVOLUTIONARY LOCATION LOOKUP METHODS
315
+
316
+ def lookup_location_from_coordinates(self, latitude: float, longitude: float) -> Dict:
317
+ """
318
+ 🚀 REVOLUTIONARY: Get administrative boundaries from coordinates
319
+
320
+ This is a revolutionary service that provides administrative boundary lookup
321
+ with precision that even government services don't offer.
322
+
323
+ Args:
324
+ latitude: Latitude coordinate
325
+ longitude: Longitude coordinate
326
+
327
+ Returns:
328
+ Dict containing administrative boundary information:
329
+ - pincode: 6-digit postal code
330
+ - office_name: Post office name
331
+ - division: Postal division
332
+ - region: Postal region
333
+ - circle: Postal circle
334
+ - state: State name
335
+ - coordinates: Input coordinates
336
+ - digipin: DigiPin code for the location
337
+ - cached: Whether result was from cache
338
+ - response_time_ms: Response time in milliseconds
339
+ """
340
+ if not isinstance(latitude, (int, float)) or not isinstance(longitude, (int, float)):
341
+ raise ValidationError("Latitude and longitude must be numbers")
342
+
343
+ if not (-90 <= latitude <= 90):
344
+ raise ValidationError("Latitude must be between -90 and 90")
345
+
346
+ if not (-180 <= longitude <= 180):
347
+ raise ValidationError("Longitude must be between -180 and 180")
348
+
349
+ data = {
350
+ 'latitude': float(latitude),
351
+ 'longitude': float(longitude)
352
+ }
353
+
354
+ response = self._make_request('POST', '/v1/location/lookup', data)
355
+ return response.get('data', {})
356
+
357
+ def lookup_location_from_digipin(self, digipin: str) -> Dict:
358
+ """
359
+ 🚀 REVOLUTIONARY: Get administrative boundaries from DigiPin
360
+
361
+ Args:
362
+ digipin: DigiPin code (format: XXX-XXX-XXXX)
363
+
364
+ Returns:
365
+ Dict containing administrative boundary information
366
+ """
367
+ if not digipin or not digipin.strip():
368
+ raise ValidationError("DigiPin is required")
369
+
370
+ # Use the LocationLookupClient for this operation
371
+ from .location_lookup import LocationLookupClient
372
+ location_client = LocationLookupClient(
373
+ api_key=self.api_key,
374
+ base_url=self.base_url,
375
+ timeout=self.timeout,
376
+ max_retries=self.max_retries
377
+ )
378
+
379
+ return location_client.lookup_digipin(digipin)
380
+
381
+ def batch_location_lookup(self, locations: List[Dict]) -> Dict:
382
+ """
383
+ 🚀 REVOLUTIONARY: Batch lookup for multiple locations
384
+
385
+ Args:
386
+ locations: List of location dictionaries, each containing either:
387
+ - {'latitude': float, 'longitude': float}
388
+ - {'digipin': str}
389
+
390
+ Returns:
391
+ Dict containing batch processing results with administrative boundaries
392
+ """
393
+ if not locations or not isinstance(locations, list):
394
+ raise ValidationError("Locations must be a non-empty list")
395
+
396
+ if len(locations) > 100:
397
+ raise ValidationError("Maximum 100 locations allowed per batch")
398
+
399
+ # Use the LocationLookupClient for this operation
400
+ from .location_lookup import LocationLookupClient
401
+ location_client = LocationLookupClient(
402
+ api_key=self.api_key,
403
+ base_url=self.base_url,
404
+ timeout=self.timeout,
405
+ max_retries=self.max_retries
406
+ )
407
+
408
+ return location_client.batch_lookup(locations)
409
+
410
+ def get_location_statistics(self) -> Dict:
411
+ """
412
+ 📊 Get live statistics about the revolutionary Location Lookup service
413
+
414
+ Returns:
415
+ Dict containing:
416
+ - total_boundaries: Total number of postal boundaries (36,000+)
417
+ - total_states: Number of states covered
418
+ - total_divisions: Number of postal divisions
419
+ - cache_size: Current cache size
420
+ - performance_metrics: Response time statistics
421
+ """
422
+ response = self._make_request('GET', '/v1/location/stats')
423
+ return response.get('data', {})
@@ -0,0 +1,293 @@
1
+ """
2
+ Revolutionary Location Lookup Client
3
+
4
+ Provides administrative boundary lookup capabilities - a service that even
5
+ the government doesn't provide at this level of precision and accessibility.
6
+ """
7
+
8
+ import requests
9
+ import time
10
+ from typing import Dict, List, Optional, Union
11
+ from .exceptions import APIError, RateLimitError, AuthenticationError, ValidationError
12
+
13
+
14
+ class LocationLookupClient:
15
+ """
16
+ Revolutionary Location Lookup Client
17
+
18
+ Get administrative boundaries (state, division, locality, pincode) from
19
+ coordinates or DigiPin codes. Access to 36,000+ postal boundaries across India.
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ api_key: str,
25
+ base_url: str = "https://api.quantaroute.com",
26
+ timeout: int = 30,
27
+ max_retries: int = 3
28
+ ):
29
+ """
30
+ Initialize the Location Lookup client
31
+
32
+ Args:
33
+ api_key: Your QuantaRoute API key
34
+ base_url: Base URL for the API (default: https://api.quantaroute.com)
35
+ timeout: Request timeout in seconds (default: 30)
36
+ max_retries: Maximum number of retries for failed requests (default: 3)
37
+ """
38
+ self.api_key = api_key
39
+ self.base_url = base_url.rstrip('/')
40
+ self.timeout = timeout
41
+ self.max_retries = max_retries
42
+ self.session = requests.Session()
43
+ self.session.headers.update({
44
+ 'x-api-key': api_key,
45
+ 'User-Agent': 'quantaroute-geocoding-python/2.0.0',
46
+ 'Content-Type': 'application/json'
47
+ })
48
+
49
+ def _make_request(
50
+ self,
51
+ method: str,
52
+ endpoint: str,
53
+ data: Optional[Dict] = None,
54
+ params: Optional[Dict] = None
55
+ ) -> Dict:
56
+ """Make HTTP request with retry logic"""
57
+ url = f"{self.base_url}{endpoint}"
58
+
59
+ for attempt in range(self.max_retries + 1):
60
+ try:
61
+ if method.upper() == 'GET':
62
+ response = self.session.get(url, params=params, timeout=self.timeout)
63
+ else:
64
+ response = self.session.post(url, json=data, params=params, timeout=self.timeout)
65
+
66
+ # Handle rate limiting
67
+ if response.status_code == 429:
68
+ retry_after = int(response.headers.get('Retry-After', 60))
69
+ if attempt < self.max_retries:
70
+ time.sleep(retry_after)
71
+ continue
72
+ raise RateLimitError(
73
+ "Rate limit exceeded",
74
+ retry_after=retry_after
75
+ )
76
+
77
+ # Handle authentication errors
78
+ if response.status_code == 401:
79
+ raise AuthenticationError()
80
+
81
+ # Handle other client/server errors
82
+ if not response.ok:
83
+ try:
84
+ error_data = response.json()
85
+ message = error_data.get('message', f'HTTP {response.status_code}')
86
+ error_code = error_data.get('code')
87
+ except:
88
+ message = f'HTTP {response.status_code}: {response.text}'
89
+ error_code = None
90
+
91
+ raise APIError(message, response.status_code, error_code)
92
+
93
+ return response.json()
94
+
95
+ except requests.exceptions.RequestException as e:
96
+ if attempt < self.max_retries:
97
+ time.sleep(2 ** attempt) # Exponential backoff
98
+ continue
99
+ raise APIError(f"Request failed: {str(e)}")
100
+
101
+ raise APIError("Max retries exceeded")
102
+
103
+ def lookup_coordinates(self, latitude: float, longitude: float) -> Dict:
104
+ """
105
+ 🚀 REVOLUTIONARY: Get administrative boundaries from coordinates
106
+
107
+ Args:
108
+ latitude: Latitude coordinate
109
+ longitude: Longitude coordinate
110
+
111
+ Returns:
112
+ Dict containing administrative boundary information:
113
+ - pincode: 6-digit postal code
114
+ - office_name: Post office name
115
+ - division: Postal division
116
+ - region: Postal region
117
+ - circle: Postal circle
118
+ - state: State name
119
+ - coordinates: Input coordinates
120
+ - digipin: DigiPin code for the location
121
+ - cached: Whether result was from cache
122
+ - response_time_ms: Response time in milliseconds
123
+ """
124
+ if not isinstance(latitude, (int, float)) or not isinstance(longitude, (int, float)):
125
+ raise ValidationError("Latitude and longitude must be numbers")
126
+
127
+ if not (-90 <= latitude <= 90):
128
+ raise ValidationError("Latitude must be between -90 and 90")
129
+
130
+ if not (-180 <= longitude <= 180):
131
+ raise ValidationError("Longitude must be between -180 and 180")
132
+
133
+ data = {
134
+ 'latitude': float(latitude),
135
+ 'longitude': float(longitude)
136
+ }
137
+
138
+ response = self._make_request('POST', '/v1/location/lookup', data)
139
+ return response.get('data', {})
140
+
141
+ def lookup_digipin(self, digipin: str) -> Dict:
142
+ """
143
+ 🚀 REVOLUTIONARY: Get administrative boundaries from DigiPin
144
+
145
+ Args:
146
+ digipin: DigiPin code (format: XXX-XXX-XXXX)
147
+
148
+ Returns:
149
+ Dict containing administrative boundary information
150
+ """
151
+ if not digipin or not digipin.strip():
152
+ raise ValidationError("DigiPin is required")
153
+
154
+ # Convert DigiPin to coordinates first, then lookup
155
+ from .offline import OfflineProcessor
156
+ processor = OfflineProcessor()
157
+
158
+ try:
159
+ coords_result = processor.digipin_to_coordinates(digipin)
160
+ if coords_result and 'coordinates' in coords_result:
161
+ coords = coords_result['coordinates']
162
+ lat = coords['latitude']
163
+ lng = coords['longitude']
164
+ return self.lookup_coordinates(lat, lng)
165
+ else:
166
+ raise ValidationError("Invalid DigiPin format")
167
+ except Exception as e:
168
+ raise ValidationError(f"DigiPin conversion failed: {str(e)}")
169
+
170
+ def batch_lookup(self, locations: List[Dict]) -> Dict:
171
+ """
172
+ 🚀 REVOLUTIONARY: Batch lookup for multiple locations
173
+
174
+ Args:
175
+ locations: List of location dictionaries, each containing either:
176
+ - {'latitude': float, 'longitude': float}
177
+ - {'digipin': str}
178
+
179
+ Returns:
180
+ Dict containing batch processing results with administrative boundaries
181
+ """
182
+ if not locations or not isinstance(locations, list):
183
+ raise ValidationError("Locations must be a non-empty list")
184
+
185
+ if len(locations) > 100:
186
+ raise ValidationError("Maximum 100 locations allowed per batch")
187
+
188
+ # Validate and normalize locations
189
+ normalized_locations = []
190
+ for i, loc in enumerate(locations):
191
+ if not isinstance(loc, dict):
192
+ raise ValidationError(f"Location {i+1} must be a dictionary")
193
+
194
+ if 'latitude' in loc and 'longitude' in loc:
195
+ # Coordinate-based lookup
196
+ if not isinstance(loc['latitude'], (int, float)) or not isinstance(loc['longitude'], (int, float)):
197
+ raise ValidationError(f"Location {i+1}: latitude and longitude must be numbers")
198
+ normalized_locations.append({
199
+ 'latitude': float(loc['latitude']),
200
+ 'longitude': float(loc['longitude'])
201
+ })
202
+ elif 'digipin' in loc:
203
+ # DigiPin-based lookup - convert to coordinates
204
+ from .offline import OfflineProcessor
205
+ processor = OfflineProcessor()
206
+ try:
207
+ coords_result = processor.digipin_to_coordinates(loc['digipin'])
208
+ if coords_result and 'coordinates' in coords_result:
209
+ lat, lng = coords_result['coordinates']
210
+ normalized_locations.append({
211
+ 'latitude': lat,
212
+ 'longitude': lng,
213
+ 'original_digipin': loc['digipin']
214
+ })
215
+ else:
216
+ raise ValidationError(f"Location {i+1}: Invalid DigiPin format")
217
+ except Exception as e:
218
+ raise ValidationError(f"Location {i+1}: DigiPin conversion failed: {str(e)}")
219
+ else:
220
+ raise ValidationError(f"Location {i+1} must contain either 'latitude'+'longitude' or 'digipin'")
221
+
222
+ data = {'locations': normalized_locations}
223
+ response = self._make_request('POST', '/v1/location/batch-lookup', data)
224
+ return response.get('data', {})
225
+
226
+ def get_statistics(self) -> Dict:
227
+ """
228
+ 📊 Get live statistics about the Location Lookup service
229
+
230
+ Returns:
231
+ Dict containing:
232
+ - total_boundaries: Total number of postal boundaries
233
+ - total_states: Number of states covered
234
+ - total_divisions: Number of postal divisions
235
+ - cache_size: Current cache size
236
+ - performance_metrics: Response time statistics
237
+ """
238
+ response = self._make_request('GET', '/v1/location/stats')
239
+ return response.get('data', {})
240
+
241
+ def get_coverage_info(self) -> Dict:
242
+ """
243
+ 🌍 Get coverage information about the Location Lookup service
244
+
245
+ Returns:
246
+ Dict containing coverage details and service capabilities
247
+ """
248
+ response = self._make_request('GET', '/v1/location')
249
+ return response
250
+
251
+ def find_nearby_boundaries(
252
+ self,
253
+ latitude: float,
254
+ longitude: float,
255
+ radius_km: float = 5.0,
256
+ limit: int = 10
257
+ ) -> List[Dict]:
258
+ """
259
+ 🎯 Find nearby postal boundaries (experimental feature)
260
+
261
+ Args:
262
+ latitude: Center latitude
263
+ longitude: Center longitude
264
+ radius_km: Search radius in kilometers (default: 5.0)
265
+ limit: Maximum number of results (default: 10, max: 50)
266
+
267
+ Returns:
268
+ List of nearby postal boundaries with distances
269
+ """
270
+ if not isinstance(latitude, (int, float)) or not isinstance(longitude, (int, float)):
271
+ raise ValidationError("Latitude and longitude must be numbers")
272
+
273
+ if not (-90 <= latitude <= 90):
274
+ raise ValidationError("Latitude must be between -90 and 90")
275
+
276
+ if not (-180 <= longitude <= 180):
277
+ raise ValidationError("Longitude must be between -180 and 180")
278
+
279
+ if radius_km <= 0 or radius_km > 100:
280
+ raise ValidationError("Radius must be between 0 and 100 km")
281
+
282
+ if limit > 50:
283
+ limit = 50
284
+
285
+ params = {
286
+ 'lat': latitude,
287
+ 'lng': longitude,
288
+ 'radius': radius_km,
289
+ 'limit': limit
290
+ }
291
+
292
+ response = self._make_request('GET', '/v1/location/nearby', params=params)
293
+ return response.get('data', [])
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantaroute-geocoding
3
- Version: 1.0.2
4
- Summary: Python SDK for QuantaRoute Geocoding API with offline DigiPin processing
3
+ Version: 1.0.4
4
+ Summary: Revolutionary Python SDK for QuantaRoute Geocoding API with Location Lookup and offline DigiPin processing
5
5
  Home-page: https://github.com/quantaroute/quantaroute-geocoding-python
6
6
  Author: QuantaRoute
7
7
  Author-email: QuantaRoute <support@quantaroute.com>
@@ -10,7 +10,7 @@ Project-URL: Homepage, https://quantaroute.com
10
10
  Project-URL: Documentation, https://api.quantaroute.com/v1/digipin/docs
11
11
  Project-URL: Repository, https://github.com/quantaroute/quantaroute-geocoding-python
12
12
  Project-URL: Bug Tracker, https://github.com/quantaroute/quantaroute-geocoding-python/issues
13
- Keywords: geocoding,digipin,gis,location,india,address,coordinates
13
+ Keywords: geocoding,digipin,gis,location,india,address,coordinates,administrative-boundaries,pincode,postal-lookup,location-intelligence
14
14
  Classifier: Development Status :: 4 - Beta
15
15
  Classifier: Intended Audience :: Developers
16
16
  Classifier: License :: OSI Approved :: MIT License
@@ -44,10 +44,18 @@ Dynamic: requires-python
44
44
 
45
45
  # QuantaRoute Geocoding Python SDK
46
46
 
47
- A comprehensive Python library for geocoding addresses to DigiPin codes with both online API and offline processing capabilities.
47
+ A **revolutionary** Python library for geocoding addresses to DigiPin codes with **groundbreaking Location Lookup API** and offline processing capabilities.
48
48
 
49
- ## Features
49
+ ## 🚀 Revolutionary Features
50
50
 
51
+ ### 🎯 **NEW: Location Lookup API** - *Service that even government doesn't provide!*
52
+ - 🗺️ **Administrative Boundary Lookup**: Get state, division, locality, pincode from coordinates
53
+ - 📍 **36,000+ Postal Boundaries**: Complete coverage across India
54
+ - ⚡ **Sub-100ms Response**: Cached responses with database fallback
55
+ - 🎯 **Government-Level Precision**: Accuracy that official services don't offer
56
+ - 🔄 **Batch Processing**: Up to 100 locations per request
57
+
58
+ ### 🌟 **Core Features**
51
59
  - 🌐 **Online API Integration**: Full access to QuantaRoute Geocoding API
52
60
  - 🔌 **Offline Processing**: Process coordinates ↔ DigiPin without internet
53
61
  - 📊 **CSV Bulk Processing**: Handle large datasets efficiently
@@ -70,14 +78,39 @@ pip install digipin
70
78
 
71
79
  ## Quick Start
72
80
 
73
- ### Online API Usage
81
+ ### 🚀 **NEW: Revolutionary Location Lookup API**
74
82
 
75
83
  ```python
76
- from quantaroute_geocoding import QuantaRouteClient
84
+ from quantaroute_geocoding import QuantaRouteClient, LocationLookupClient
77
85
 
78
86
  # Initialize client
79
87
  client = QuantaRouteClient(api_key="your-api-key")
80
88
 
89
+ # 🚀 REVOLUTIONARY: Get administrative boundaries from coordinates
90
+ result = client.lookup_location_from_coordinates(28.6139, 77.2090)
91
+ print(f"Pincode: {result['pincode']}") # 110001
92
+ print(f"Office: {result['office_name']}") # New Delhi GPO
93
+ print(f"Division: {result['division']}") # New Delhi GPO
94
+ print(f"Circle: {result['circle']}") # Delhi
95
+ print(f"DigiPin: {result['digipin']}") # 39J-438-TJC7
96
+ print(f"Response Time: {result['response_time_ms']}ms") # <100ms
97
+
98
+ # 🚀 REVOLUTIONARY: Get boundaries from DigiPin
99
+ result = client.lookup_location_from_digipin("39J-438-TJC7")
100
+ print(f"Pincode: {result['administrative_info']['pincode']}")
101
+ print(f"State: {result['administrative_info']['state']}")
102
+ print(f"Division: {result['administrative_info']['division']}")
103
+ print(f"Locality: {result['administrative_info']['locality']}")
104
+
105
+ # 📊 Get live statistics (36,000+ boundaries)
106
+ stats = client.get_location_statistics()
107
+ print(f"Total Boundaries: {stats['total_boundaries']:,}")
108
+ print(f"Total States: {stats['total_states']}")
109
+ ```
110
+
111
+ ### 🌟 **Traditional Geocoding API**
112
+
113
+ ```python
81
114
  # Geocode an address
82
115
  result = client.geocode("India Gate, New Delhi, India")
83
116
  print(f"DigiPin: {result['digipin']}")
@@ -141,9 +174,25 @@ result = processor_offline.process_coordinates_to_digipin_csv(
141
174
 
142
175
  ## Command Line Interface
143
176
 
144
- The package includes a powerful CLI for batch processing:
177
+ The package includes a **revolutionary** CLI with Location Lookup capabilities:
145
178
 
146
- ### Geocode addresses from CSV
179
+ ### 🚀 **NEW: Revolutionary Location Lookup Commands**
180
+
181
+ ```bash
182
+ # Get administrative boundaries from coordinates
183
+ quantaroute-geocode location-lookup 28.6139 77.2090 --api-key your-key
184
+
185
+ # Get boundaries from DigiPin
186
+ quantaroute-geocode location-from-digipin "39J-438-TJC7" --api-key your-key
187
+
188
+ # Get live statistics (36,000+ boundaries)
189
+ quantaroute-geocode location-stats --api-key your-key
190
+
191
+ # Batch location lookup from CSV (coming soon)
192
+ quantaroute-geocode location-lookup-csv coordinates.csv boundaries.csv --api-key your-key
193
+ ```
194
+
195
+ ### 🌟 **Traditional Geocoding Commands**
147
196
 
148
197
  ```bash
149
198
  # Using API
@@ -215,6 +264,77 @@ digipin
215
264
  39J-49J-4867
216
265
  ```
217
266
 
267
+ ## 🚀 Revolutionary Location Lookup API
268
+
269
+ ### Dedicated Location Lookup Client
270
+
271
+ ```python
272
+ from quantaroute_geocoding import LocationLookupClient
273
+
274
+ # Initialize dedicated location client
275
+ location_client = LocationLookupClient(api_key="your-api-key")
276
+
277
+ # Single coordinate lookup
278
+ result = location_client.lookup_coordinates(28.6139, 77.2090)
279
+ print(f"📮 Pincode: {result['pincode']}")
280
+ print(f"🏢 Office: {result['office_name']}")
281
+ print(f"🏛️ Division: {result['division']}")
282
+ print(f"⚡ Response Time: {result['response_time_ms']}ms")
283
+
284
+ # DigiPin to boundaries
285
+ result = location_client.lookup_digipin("39J-438-TJC7")
286
+ print(f"Administrative boundaries: {result}")
287
+
288
+ # Batch processing (up to 100 locations)
289
+ locations = [
290
+ {"latitude": 28.6139, "longitude": 77.2090},
291
+ {"latitude": 19.0760, "longitude": 72.8777},
292
+ {"digipin": "39J-438-TJC7"}
293
+ ]
294
+ results = location_client.batch_lookup(locations)
295
+ print(f"Processed {len(results['results'])} locations")
296
+
297
+ # Live statistics
298
+ stats = location_client.get_statistics()
299
+ print(f"🗺️ Total Boundaries: {stats['total_boundaries']:,}")
300
+ print(f"⚡ Cache Size: {stats['cache_size']}")
301
+
302
+ # Coverage information
303
+ coverage = location_client.get_coverage_info()
304
+ print(f"Service capabilities: {coverage}")
305
+ ```
306
+
307
+ ### Location Lookup Output Format
308
+
309
+ ```json
310
+ {
311
+ "pincode": "110001",
312
+ "office_name": "New Delhi GPO",
313
+ "division": "New Delhi GPO",
314
+ "region": "",
315
+ "circle": "Delhi",
316
+ "coordinates": {
317
+ "latitude": 28.6139,
318
+ "longitude": 77.2090
319
+ },
320
+ "digipin": "39J-438-TJC7",
321
+ "cached": true,
322
+ "response_time_ms": 45
323
+ }
324
+ ```
325
+
326
+ ### Why This is Revolutionary
327
+
328
+ 🎯 **Government-Level Precision**: Access to administrative boundaries that even government APIs don't provide at this level of detail and accessibility.
329
+
330
+ 📍 **36,000+ Boundaries**: Complete coverage of Indian postal boundaries with sub-district level precision.
331
+
332
+ ⚡ **Performance**: Sub-100ms cached responses, <500ms database queries.
333
+
334
+ 🔄 **Batch Processing**: Process up to 100 locations in a single API call.
335
+
336
+ ✨ **Unique Value**: The only service providing this level of administrative boundary lookup precision for India.
337
+
218
338
  ## Advanced Features
219
339
 
220
340
  ### Webhook Management
@@ -332,17 +452,51 @@ except APIError as e:
332
452
 
333
453
  ## API Limits
334
454
 
455
+ ### Traditional Geocoding API
456
+
335
457
  | Tier | Requests/Minute | Monthly Limit | Batch Size |
336
458
  |------|----------------|---------------|------------|
337
459
  | Free | 10 | 1,000 | 50 |
338
460
  | Paid | 100 | 10,000 | 100 |
339
461
  | Enterprise | 1,000 | Unlimited | 100 |
340
462
 
463
+ ### 🚀 Revolutionary Location Lookup API
464
+
465
+ | Tier | Requests/Minute | Monthly Limit | Batch Size | Boundaries |
466
+ |------|----------------|---------------|------------|------------|
467
+ | Free | 20 | 2,000 | 50 | 36,000+ |
468
+ | Paid | 200 | 20,000 | 100 | 36,000+ |
469
+ | Enterprise | 2,000 | Unlimited | 100 | 36,000+ |
470
+
471
+ **Performance Guarantees:**
472
+ - ⚡ Cached responses: <100ms
473
+ - 🔍 Database queries: <500ms
474
+ - 📊 Batch processing: <50ms per location
475
+ - 🎯 99.9% uptime SLA (Enterprise)
476
+
341
477
  ## Support
342
478
 
343
479
  - 📧 Email: support@quantaroute.com
344
480
  - 🌐 Website: https://quantaroute.com
345
- - 📖 API Documentation: https://api.quantaroute.com/v1/digipin/docs
481
+ - 📖 Traditional API Docs: https://api.quantaroute.com/v1/digipin/docs
482
+ - 🚀 **NEW: Location Lookup API**: https://api.quantaroute.com/v1/location
483
+ - 📊 **Live Statistics**: https://api.quantaroute.com/v1/location/stats
484
+
485
+ ### 🚀 What Makes This Revolutionary?
486
+
487
+ **QuantaRoute's Location Lookup API is the first and only service to provide:**
488
+
489
+ ✨ **Government-Level Precision**: Administrative boundary data that even government APIs don't provide at this level of detail and accessibility.
490
+
491
+ 📍 **Complete Coverage**: 36,000+ postal boundaries across India with sub-district precision.
492
+
493
+ ⚡ **Blazing Performance**: Sub-100ms cached responses, guaranteed <500ms database queries.
494
+
495
+ 🎯 **Unique Value Proposition**: The only service providing this level of administrative boundary lookup precision for India.
496
+
497
+ 🔄 **Developer-Friendly**: Simple APIs, comprehensive SDKs, and excellent documentation.
498
+
499
+ **Ready to revolutionize your location intelligence applications?**
346
500
 
347
501
  ## License
348
502
 
@@ -0,0 +1,13 @@
1
+ quantaroute_geocoding/__init__.py,sha256=MKBlkAnJYv5BCGMAJ9TfpCAElhGY8Ie6lQCFT2A8qx4,766
2
+ quantaroute_geocoding/cli.py,sha256=2vJRef_4dP-4iCs3BWmNDACxMV628X4q2pos4S5UfIY,16835
3
+ quantaroute_geocoding/client.py,sha256=47sirSJMek9dGeybm6-62RoLx1SBfYlJuqDqZfgQcF8,14935
4
+ quantaroute_geocoding/csv_processor.py,sha256=tmbtE1bQzi2TnKgxOGIQ-H6MWirh-cuG4RRErcCdfco,16096
5
+ quantaroute_geocoding/exceptions.py,sha256=rAkj8K5-AUf31kV8UlmNxQ5IN0m4CIL2qnI6ALas5Ys,1173
6
+ quantaroute_geocoding/location_lookup.py,sha256=kMUceiQF6sUG_nmyH9UyXDO07xtyNZyPNsinsuv7TYg,11490
7
+ quantaroute_geocoding/offline.py,sha256=HymAwPNp01oHifQrXZ5Qj8EVn7EwoeqxjczJxbMNuXE,9711
8
+ quantaroute_geocoding-1.0.4.dist-info/licenses/LICENSE,sha256=QY7Uoe-MPRTjfyyDM3HOnqtuSqbzyPLATiriEaQ9u90,1068
9
+ quantaroute_geocoding-1.0.4.dist-info/METADATA,sha256=ehVSo01AtkdHv00pLMsxZ5qr5zXqLXJKd55UDjS0ypk,15504
10
+ quantaroute_geocoding-1.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ quantaroute_geocoding-1.0.4.dist-info/entry_points.txt,sha256=cniijgPLz_Pb6Fiti6aOxaJp1BB_bv60ZOL_oitGCx8,71
12
+ quantaroute_geocoding-1.0.4.dist-info/top_level.txt,sha256=_cyyFLwSH1wYB1HNs_LcZIDQRo1CnvoEsdnKz-cBCr4,22
13
+ quantaroute_geocoding-1.0.4.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- quantaroute_geocoding/__init__.py,sha256=lvtwtmpxPcgW050HFy-n5ReuYN1QsDmadn8sPsjXVQE,688
2
- quantaroute_geocoding/cli.py,sha256=kfVoKtBNC_jeAeqMeKRN5kxpwNEcPhnekTyLwZJFRw0,10626
3
- quantaroute_geocoding/client.py,sha256=y6aAr5Ka1nlu2epw6rXxiJ8WQpOTAO7O-ef2Ww6EYtY,10644
4
- quantaroute_geocoding/csv_processor.py,sha256=tmbtE1bQzi2TnKgxOGIQ-H6MWirh-cuG4RRErcCdfco,16096
5
- quantaroute_geocoding/exceptions.py,sha256=rAkj8K5-AUf31kV8UlmNxQ5IN0m4CIL2qnI6ALas5Ys,1173
6
- quantaroute_geocoding/offline.py,sha256=HymAwPNp01oHifQrXZ5Qj8EVn7EwoeqxjczJxbMNuXE,9711
7
- quantaroute_geocoding-1.0.2.dist-info/licenses/LICENSE,sha256=QY7Uoe-MPRTjfyyDM3HOnqtuSqbzyPLATiriEaQ9u90,1068
8
- quantaroute_geocoding-1.0.2.dist-info/METADATA,sha256=lcu-ynNWxk1I6D-ok_Rbv2fyKtlHGhp-1qMdbvNOUMw,9545
9
- quantaroute_geocoding-1.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
- quantaroute_geocoding-1.0.2.dist-info/entry_points.txt,sha256=cniijgPLz_Pb6Fiti6aOxaJp1BB_bv60ZOL_oitGCx8,71
11
- quantaroute_geocoding-1.0.2.dist-info/top_level.txt,sha256=_cyyFLwSH1wYB1HNs_LcZIDQRo1CnvoEsdnKz-cBCr4,22
12
- quantaroute_geocoding-1.0.2.dist-info/RECORD,,