gstaccelerator 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,20 @@
1
+ from .client import GSTAccelerator
2
+ from .exceptions import (
3
+ GSTAcceleratorError, AuthenticationError, RateLimitError,
4
+ NotFoundError, ValidationError, ServerError
5
+ )
6
+ from .models import HSNResult, GSTINResult, TaxRates, ApplicableRate
7
+
8
+ __all__ = [
9
+ "GSTAccelerator",
10
+ "GSTAcceleratorError",
11
+ "AuthenticationError",
12
+ "RateLimitError",
13
+ "NotFoundError",
14
+ "ValidationError",
15
+ "ServerError",
16
+ "HSNResult",
17
+ "GSTINResult",
18
+ "TaxRates",
19
+ "ApplicableRate"
20
+ ]
@@ -0,0 +1,147 @@
1
+ import httpx
2
+ import time
3
+ from typing import List, Dict, Optional, Any
4
+ from .exceptions import (
5
+ GSTAcceleratorError, AuthenticationError, RateLimitError,
6
+ NotFoundError, ValidationError, ServerError
7
+ )
8
+
9
+ class _BaseClient:
10
+ def __init__(self, client: httpx.Client):
11
+ self._client = client
12
+
13
+ def _request(self, method: str, path: str, **kwargs) -> Any:
14
+ max_retries = self._client._gsta_max_retries
15
+ retry_delay = self._client._gsta_retry_delay
16
+
17
+ for attempt in range(max_retries + 1):
18
+ try:
19
+ response = self._client.request(method, path, **kwargs)
20
+
21
+ if response.status_code < 400:
22
+ return response.json() if response.content else {}
23
+
24
+ resp_json = response.json() if response.content else {}
25
+
26
+ if response.status_code == 401:
27
+ raise AuthenticationError("Authentication failed", 401, resp_json)
28
+ elif response.status_code == 404:
29
+ raise NotFoundError("Resource not found", 404, resp_json)
30
+ elif response.status_code in (400, 422):
31
+ raise ValidationError("Validation error", response.status_code, resp_json)
32
+ elif response.status_code == 429:
33
+ if attempt < max_retries:
34
+ retry_after = response.headers.get("Retry-After")
35
+ sleep_time = float(retry_after) if retry_after else retry_delay * (2 ** attempt)
36
+ time.sleep(sleep_time)
37
+ continue
38
+ raise RateLimitError("Rate limit exceeded", 429, resp_json)
39
+ elif response.status_code >= 500:
40
+ if attempt < max_retries:
41
+ time.sleep(retry_delay * (2 ** attempt))
42
+ continue
43
+ raise ServerError(f"Server error: {response.status_code}", response.status_code, resp_json)
44
+
45
+ response.raise_for_status()
46
+
47
+ except httpx.RequestError as e:
48
+ if attempt < max_retries:
49
+ time.sleep(retry_delay * (2 ** attempt))
50
+ continue
51
+ raise GSTAcceleratorError(f"Request failed: {str(e)}")
52
+
53
+ return {}
54
+
55
+ class HSNClient(_BaseClient):
56
+ def get(self, code: str) -> dict:
57
+ return self._request("GET", f"/api/v1/hsn/{code}")
58
+
59
+ class SACClient(_BaseClient):
60
+ def get(self, code: str) -> dict:
61
+ return self._request("GET", f"/api/v1/sac/{code}")
62
+
63
+ class GSTINClient(_BaseClient):
64
+ def validate(self, gstin: str) -> dict:
65
+ return self._request("GET", f"/api/v1/gstin/{gstin}/validate")
66
+
67
+ def state(self, gstin: str) -> dict:
68
+ return self._request("GET", f"/api/v1/gstin/{gstin}/state")
69
+
70
+ def pan(self, gstin: str) -> dict:
71
+ return self._request("GET", f"/api/v1/gstin/{gstin}/pan")
72
+
73
+ class GSTAccelerator:
74
+ def __init__(
75
+ self,
76
+ api_key: str = "",
77
+ base_url: str = "https://gstaccelerator.in",
78
+ timeout: int = 30,
79
+ max_retries: int = 3,
80
+ retry_delay: float = 1.0
81
+ ):
82
+ from importlib.metadata import version, PackageNotFoundError
83
+ try:
84
+ pkg_version = version("gstaccelerator")
85
+ except PackageNotFoundError:
86
+ pkg_version = "0.1.0"
87
+
88
+ headers = {
89
+ "User-Agent": f"gstaccelerator-python/{pkg_version}",
90
+ "Content-Type": "application/json"
91
+ }
92
+ if api_key:
93
+ headers["Authorization"] = f"Bearer {api_key}"
94
+
95
+ self._client = httpx.Client(
96
+ base_url=base_url,
97
+ timeout=timeout,
98
+ headers=headers
99
+ )
100
+ self._client._gsta_max_retries = max_retries
101
+ self._client._gsta_retry_delay = retry_delay
102
+
103
+ self.hsn = HSNClient(self._client)
104
+ self.sac = SACClient(self._client)
105
+ self.gstin = GSTINClient(self._client)
106
+
107
+ def lookup(
108
+ self,
109
+ description: str,
110
+ supply_type: Optional[str] = None,
111
+ branded: Optional[bool] = None,
112
+ sale_value_inr: Optional[float] = None,
113
+ state_of_supply: Optional[str] = None
114
+ ) -> List[Dict]:
115
+ payload = {"description": description}
116
+ if supply_type is not None: payload["supply_type"] = supply_type
117
+ if branded is not None: payload["branded"] = branded
118
+ if sale_value_inr is not None: payload["sale_value_inr"] = sale_value_inr
119
+ if state_of_supply is not None: payload["state_of_supply"] = state_of_supply
120
+
121
+ base = _BaseClient(self._client)
122
+ return base._request("POST", "/api/v1/lookup", json=payload)
123
+
124
+ def autocomplete(self, query: str) -> List[str]:
125
+ base = _BaseClient(self._client)
126
+ return base._request("GET", "/api/v1/autocomplete", params={"q": query})
127
+
128
+ def bulk(self, descriptions: List[str]) -> List[List[Dict]]:
129
+ base = _BaseClient(self._client)
130
+ return base._request("POST", "/api/v1/bulk", json={"descriptions": descriptions})
131
+
132
+ def health(self) -> dict:
133
+ base = _BaseClient(self._client)
134
+ return base._request("GET", "/api/v1/health")
135
+
136
+ def meta(self) -> dict:
137
+ base = _BaseClient(self._client)
138
+ return base._request("GET", "/api/v1/meta")
139
+
140
+ def close(self):
141
+ self._client.close()
142
+
143
+ def __enter__(self):
144
+ return self
145
+
146
+ def __exit__(self, exc_type, exc_val, exc_tb):
147
+ self.close()
@@ -0,0 +1,14 @@
1
+ from typing import Optional, Dict, Any
2
+
3
+ class GSTAcceleratorError(Exception):
4
+ def __init__(self, message: str, status_code: Optional[int] = None, response_body: Optional[Dict[str, Any]] = None):
5
+ super().__init__(message)
6
+ self.message = message
7
+ self.status_code = status_code
8
+ self.response_body = response_body or {}
9
+
10
+ class AuthenticationError(GSTAcceleratorError): pass
11
+ class RateLimitError(GSTAcceleratorError): pass
12
+ class NotFoundError(GSTAcceleratorError): pass
13
+ class ValidationError(GSTAcceleratorError): pass
14
+ class ServerError(GSTAcceleratorError): pass
@@ -0,0 +1,37 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ @dataclass
5
+ class TaxRates:
6
+ igst: float
7
+ cgst: float
8
+ sgst: float
9
+ cess: float
10
+
11
+ @dataclass
12
+ class ApplicableRate:
13
+ intrastate: str
14
+ interstate: str
15
+
16
+ @dataclass
17
+ class HSNResult:
18
+ hsn_code: str
19
+ description: str
20
+ tax_rates: TaxRates
21
+ applicable_rate: ApplicableRate
22
+ notification_ref: str
23
+ confidence: float
24
+ needs_review: bool
25
+ condition_applied: Optional[str] = None
26
+ condition_warning: Optional[str] = None
27
+ last_updated: Optional[str] = None
28
+
29
+ @dataclass
30
+ class GSTINResult:
31
+ valid: bool
32
+ gstin: str
33
+ state_code: Optional[str] = None
34
+ state_name: Optional[str] = None
35
+ pan: Optional[str] = None
36
+ entity_type_code: Optional[str] = None
37
+ error_reason: Optional[str] = None
@@ -0,0 +1,66 @@
1
+ Metadata-Version: 2.4
2
+ Name: gstaccelerator
3
+ Version: 0.1.0
4
+ Summary: Python client for the GST Accelerator API — India GST HSN/SAC lookup, GSTIN validation, condition resolver
5
+ Project-URL: Homepage, https://gstaccelerator.in
6
+ Project-URL: Documentation, https://gstaccelerator.in/docs
7
+ Project-URL: Repository, https://github.com/thedivine1/gst-hsn-api
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: httpx>=0.24.0
12
+ Dynamic: license-file
13
+
14
+ # GST Accelerator Python Client
15
+
16
+ Python client for the GST Accelerator API — India GST HSN/SAC lookup, GSTIN validation, and condition resolver.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install gstaccelerator
22
+ ```
23
+
24
+ ## Quickstart
25
+
26
+ ```python
27
+ from gstaccelerator import GSTAccelerator
28
+
29
+ gst = GSTAccelerator(api_key="your_api_key_here")
30
+ result = gst.hsn.get("84151010")
31
+ print(result)
32
+ ```
33
+
34
+ ## Method Reference
35
+
36
+ | Resource | Method | Description |
37
+ |---|---|---|
38
+ | `gst.hsn` | `get(code: str)` | HSN lookup |
39
+ | `gst.sac` | `get(code: str)` | SAC lookup |
40
+ | `gst` | `lookup(description: str, ...)` | Description search |
41
+ | `gst` | `autocomplete(query: str)` | Autocomplete |
42
+ | `gst` | `bulk(descriptions: list[str])` | Bulk lookup |
43
+ | `gst.gstin` | `validate(gstin: str)` | GSTIN validation |
44
+ | `gst.gstin` | `state(gstin: str)` | Get state info for GSTIN |
45
+ | `gst.gstin` | `pan(gstin: str)` | Get PAN info for GSTIN |
46
+ | `gst` | `health()` | Health check |
47
+ | `gst` | `meta()` | Meta data |
48
+
49
+ ## Exception Handling
50
+
51
+ ```python
52
+ from gstaccelerator import GSTAccelerator, RateLimitError, AuthenticationError
53
+
54
+ gst = GSTAccelerator(api_key="your_api_key_here")
55
+
56
+ try:
57
+ result = gst.hsn.get("84151010")
58
+ except AuthenticationError as e:
59
+ print(f"Auth failed: {e.message}")
60
+ except RateLimitError as e:
61
+ print(f"Rate limited: {e.message}")
62
+ ```
63
+
64
+ ## Full Documentation
65
+
66
+ For full documentation, visit: https://gstaccelerator.in/docs
@@ -0,0 +1,9 @@
1
+ gstaccelerator/__init__.py,sha256=X7YPPH0X-GdzkjADzgX3Vs4_wR62tgmfGCjt9oLW-rs,491
2
+ gstaccelerator/client.py,sha256=FnXip3Ba26GsFLeFtFSDh98PAU6ryDTNlvbsBabycaA,5631
3
+ gstaccelerator/exceptions.py,sha256=6IECs08CWvLVh1ntU8F1Bguk918xF7CiiEtbVE4WaHE,595
4
+ gstaccelerator/models.py,sha256=ISOuDFnz4y107ryVlUysfVtm0eK95_pPkmz2SCg45SQ,802
5
+ gstaccelerator-0.1.0.dist-info/licenses/LICENSE,sha256=1NtrO7G-Zs_RDmKygBVvd17SvVJe0FWY6kjW-kgcm2A,1072
6
+ gstaccelerator-0.1.0.dist-info/METADATA,sha256=k8zDluzk9JzNriQZAxECzsxoej5u9DGw6x6SwFsEutc,1963
7
+ gstaccelerator-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
8
+ gstaccelerator-0.1.0.dist-info/top_level.txt,sha256=LRD--2m7tsUj_UBSYDZzFzmrRnujZo2Tf5at0tybje4,15
9
+ gstaccelerator-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GST Accelerator
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ gstaccelerator