datagovmy-python-sdk 1.0.1__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.
datagovmy/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from datagovmy.datagovmy import DataGovMyClient
2
+
3
+ __all__ = ["DataGovMyClient"]
File without changes
datagovmy/core/api.py ADDED
@@ -0,0 +1,76 @@
1
+ import logging
2
+ from typing import Any, Optional, cast
3
+
4
+ import requests
5
+ from requests.adapters import HTTPAdapter
6
+ from urllib3.util.retry import Retry
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class BaseAPIClient:
12
+ """Generic API client with configurable retry support.
13
+
14
+ Args:
15
+ base_url: Base URL for all requests (e.g. "https://api.example.com").
16
+ headers: Default headers sent with every request.
17
+ retry_strategy: A ``urllib3.util.retry.Retry`` instance that controls
18
+ which status codes trigger retries, how many times, and the backoff.
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ base_url: str,
24
+ headers: Optional[dict[str, str]] = None,
25
+ retry_strategy: Optional[Retry] = None,
26
+ ):
27
+ self.base_url = base_url
28
+ self.session = requests.Session()
29
+ if headers:
30
+ self.session.headers.update(headers)
31
+ if retry_strategy:
32
+ adapter = HTTPAdapter(max_retries=cast(Any, retry_strategy))
33
+ self.session.mount("http://", adapter)
34
+ self.session.mount("https://", adapter)
35
+
36
+ def _build_url(self, path: str) -> str:
37
+ return f"{self.base_url}{path}"
38
+
39
+ def _request(self, method: str, path: str, **kwargs: Any) -> requests.Response:
40
+ url = self._build_url(path)
41
+ logger.debug("Requesting %s %s", method, url)
42
+ response = self.session.request(method, url, **kwargs)
43
+ response.raise_for_status()
44
+ return response
45
+
46
+ def get(
47
+ self,
48
+ path: str,
49
+ params: Optional[dict[str, Any]] = None,
50
+ headers: Optional[dict[str, str]] = None,
51
+ ) -> requests.Response:
52
+ return self._request("GET", path, params=params, headers=headers)
53
+
54
+ def post(
55
+ self,
56
+ path: str,
57
+ json: Optional[Any] = None,
58
+ headers: Optional[dict[str, str]] = None,
59
+ ) -> requests.Response:
60
+ return self._request("POST", path, json=json, headers=headers)
61
+
62
+ def put(
63
+ self,
64
+ path: str,
65
+ json: Optional[Any] = None,
66
+ headers: Optional[dict[str, str]] = None,
67
+ ) -> requests.Response:
68
+ return self._request("PUT", path, json=json, headers=headers)
69
+
70
+ def delete(
71
+ self,
72
+ path: str,
73
+ params: Optional[dict[str, Any]] = None,
74
+ headers: Optional[dict[str, str]] = None,
75
+ ) -> requests.Response:
76
+ return self._request("DELETE", path, params=params, headers=headers)
datagovmy/datagovmy.py ADDED
@@ -0,0 +1,22 @@
1
+ from typing import Optional
2
+
3
+ from datagovmy.service import DataCatalogueClient, OpenDOSMClient
4
+
5
+
6
+ class DataGovMyClient:
7
+ def __init__(self, api_key: Optional[str] = None):
8
+ self.api_key = api_key
9
+ self._data_catalogue: Optional[DataCatalogueClient] = None
10
+ self._opendosm: Optional[OpenDOSMClient] = None
11
+
12
+ @property
13
+ def data_catalogue(self) -> DataCatalogueClient:
14
+ if self._data_catalogue is None:
15
+ self._data_catalogue = DataCatalogueClient(api_key=self.api_key)
16
+ return self._data_catalogue
17
+
18
+ @property
19
+ def opendosm(self) -> OpenDOSMClient:
20
+ if self._opendosm is None:
21
+ self._opendosm = OpenDOSMClient(api_key=self.api_key)
22
+ return self._opendosm
@@ -0,0 +1,4 @@
1
+ from datagovmy.service.data_catalogue import DataCatalogueClient
2
+ from datagovmy.service.open_dosm import OpenDOSMClient
3
+
4
+ __all__ = ["DataCatalogueClient", "OpenDOSMClient"]
@@ -0,0 +1,23 @@
1
+ from typing import Optional
2
+
3
+ from datagovmy.core.api import BaseAPIClient
4
+ from datagovmy.service.environment import get_base_url
5
+
6
+
7
+ class DataCatalogueClient(BaseAPIClient):
8
+ ENDPOINT = "/data-catalogue"
9
+
10
+ def __init__(self, api_key: Optional[str] = None):
11
+ super().__init__(base_url=get_base_url())
12
+ self.api_key = api_key
13
+
14
+ def get_dataset_as_json(self, id: str, **kwargs):
15
+ # kwargs can be used to add additional query parameters for filtering
16
+ # reference: https://developer.data.gov.my/request-query
17
+ endpoint = f"{self.ENDPOINT}?id={id}"
18
+ filters = "&".join(f"{k}={v}" for k, v in kwargs.items())
19
+
20
+ if filters:
21
+ endpoint += f"&{filters}"
22
+
23
+ return self.get(endpoint).json()
@@ -0,0 +1,2 @@
1
+ def get_base_url():
2
+ return "https://api.data.gov.my"
@@ -0,0 +1,6 @@
1
+ class FatalException(Exception):
2
+ pass
3
+
4
+
5
+ class UnknownServiceException(FatalException):
6
+ pass
@@ -0,0 +1,23 @@
1
+ from typing import Optional
2
+
3
+ from datagovmy.core.api import BaseAPIClient
4
+ from datagovmy.service.environment import get_base_url
5
+
6
+
7
+ class OpenDOSMClient(BaseAPIClient):
8
+ ENDPOINT = "/opendosm"
9
+
10
+ def __init__(self, api_key: Optional[str] = None):
11
+ super().__init__(base_url=get_base_url())
12
+ self.api_key = api_key
13
+
14
+ def get_dataset_as_json(self, id: str, **kwargs):
15
+ # kwargs can be used to add additional query parameters for filtering
16
+ # reference: https://developer.data.gov.my/request-query
17
+ endpoint = f"{self.ENDPOINT}?id={id}"
18
+ filters = "&".join(f"{k}={v}" for k, v in kwargs.items())
19
+
20
+ if filters:
21
+ endpoint += f"&{filters}"
22
+
23
+ return self.get(endpoint).json()
@@ -0,0 +1,63 @@
1
+ Metadata-Version: 2.4
2
+ Name: datagovmy-python-sdk
3
+ Version: 1.0.1
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.13
6
+ Requires-Dist: requests
7
+ Description-Content-Type: text/markdown
8
+
9
+ # Data.gov.my Python SDK
10
+
11
+ Unofficial SDK for accessing open source data on https://data.gov.my.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install mydata
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```python
22
+ from datagovmy import DataGovMyClient
23
+
24
+ client = DataGovMyClient()
25
+
26
+ # Fetch a dataset from the national data catalogue
27
+ data = client.data_catalogue.get_dataset_as_json(id="population_malaysia")
28
+
29
+ # Fetch with filters
30
+ data = client.data_catalogue.get_dataset_as_json(
31
+ id="population_malaysia",
32
+ filter="Selangor@location",
33
+ sort="-year",
34
+ limit=10
35
+ )
36
+
37
+ # Fetch DOSM data
38
+ data = client.opendosm.get_dataset_as_json(id="cpi_2d_category")
39
+ ```
40
+
41
+ ## Documentation
42
+
43
+ For detailed usage examples including all supported query filters (filtering, sorting, pagination, date ranges, column selection, and more), see the [Usage Guide](docs/usage.md).
44
+
45
+ ## API Reference
46
+
47
+ This SDK wraps the [data.gov.my Open API](https://developer.data.gov.my/). Dataset IDs can be discovered at:
48
+
49
+ - [data.gov.my Data Catalogue](https://data.gov.my/data-catalogue)
50
+ - [OpenDOSM Data Catalogue](https://open.dosm.gov.my/data-catalogue)
51
+
52
+ ## Rate Limits
53
+
54
+ - Without API key: **4 requests/minute**
55
+ - With API key: **10 requests/minute**
56
+
57
+ ```python
58
+ client = DataGovMyClient(api_key="your-api-key")
59
+ ```
60
+
61
+ ## License
62
+
63
+ MIT
@@ -0,0 +1,12 @@
1
+ datagovmy/__init__.py,sha256=oJ0M_JrIkHoUDTlBbn76AtpyzjafcacVjQFazi7XKic,79
2
+ datagovmy/datagovmy.py,sha256=xWtAliQhHqbY6MvgTq8160acN2_zdxXqZ3OVWPukLQo,739
3
+ datagovmy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ datagovmy/core/api.py,sha256=oHuyGXOl9w0Ahs9eLpZXt48LWmuVAdE0r8LGqHV3McI,2441
5
+ datagovmy/service/__init__.py,sha256=WZwmHeMjr1_uf_O_37facmhL7Rdp89ZPMmEfozHRLGE,173
6
+ datagovmy/service/data_catalogue.py,sha256=hb_cdjPvuQH_J-4YdB5WWawGJVS82mjyyKq41w94T14,754
7
+ datagovmy/service/environment.py,sha256=U5rTbYxoFBx8WdTVygdzO-bVseQCJL3OB0CrMmCp6wE,57
8
+ datagovmy/service/exceptions.py,sha256=CNN8WXJk678minAo2lhYZrzKGz7A6Wk9vePbMUr9l9A,100
9
+ datagovmy/service/open_dosm.py,sha256=pSLU3YgSjVF0ZnmZPJLh3ezzvt8xkB5S6LVKtBPO9Hc,743
10
+ datagovmy_python_sdk-1.0.1.dist-info/METADATA,sha256=gwW9BcS5KOPHv9Z7K5343xRjCT7sIXwhHQTX6kmtnFc,1449
11
+ datagovmy_python_sdk-1.0.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
12
+ datagovmy_python_sdk-1.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any