iaso-client 1.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.
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.3
2
+ Name: iaso-client
3
+ Version: 1.1.0
4
+ Summary: Python client library for interacting with IASO APIs
5
+ Keywords: iaso,api,client,sdk,python
6
+ Author: abdelrahman meroual
7
+ Author-email: abdelrahman meroual <g62496@etu.he2b.be>
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Requires-Dist: requests>=2.32.0
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+
18
+ # iaso-client
19
+
20
+ `iaso-client` is a Python client library for interacting with IASO APIs.
21
+
22
+ ## Installation
23
+
24
+ From the project root:
25
+
26
+ ```bash
27
+ uv sync
28
+ ```
29
+ ### Configuration
30
+
31
+ 1. Copy .env.sample to .env at the project root, then fill in your credentials:
32
+
33
+ The `IASO_BASE_URL` can't be provided with a trailing slash at the end.
34
+
35
+ ```bash
36
+ IASO_BASE_URL=https://your.iaso-server.com
37
+ IASO_LOGIN=your_login
38
+ IASO_PASSWORD=your_password
39
+ ```
40
+ 2. Create a symlink so Bruno can read the root `.env` file:
41
+ - **Windows** (Run Command Prompt as Administrator):
42
+ ```bash
43
+ cd bruno
44
+ mklink .env ..\.env
45
+ ```
46
+ - **Mac / Linux**:
47
+ ```bash
48
+ cd bruno
49
+ ln -s ../.env .env
50
+ ```
51
+ ### Quickstart
52
+
53
+ ```python
54
+ import os
55
+
56
+ from iaso_client import IasoClient
57
+
58
+ IASO_BASE_URL = os.getenv("IASO_BASE_URL")
59
+ IASO_LOGIN = os.getenv("IASO_LOGIN")
60
+ IASO_PASSWORD = os.getenv("IASO_PASSWORD")
61
+
62
+ client = IasoClient(base_url=IASO_BASE_URL)
63
+ client.login(IASO_LOGIN, IASO_PASSWORD)
64
+ page = client.org_unit_types_list_page(page=1, limit=10, project=975)
65
+ items = client.org_unit_types_list(search="District/Zone de sante - DIST")
66
+
67
+ print(page)
68
+ print(items)
69
+ ```
70
+
71
+ ### Authentication
72
+
73
+ Use login() to authenticate and automatically store the bearer token for subsequent requests.
74
+
75
+ ```python
76
+ client.login("your_login", "your_password")
77
+ ```
78
+
79
+ ### Current typed resources
80
+
81
+ The current typed client API supports:
82
+
83
+ | Resource | Endpoint |
84
+ | --- | --- |
85
+ | Org unit types | `/api/v2/orgunittypes/` |
86
+ | Forms | `/api/forms/` |
87
+ | Form versions | `/api/formversions/` |
88
+ | Instances | `/api/instances/` |
89
+ | Instance files | `/api/instances/attachments/`, `/api/instances/attachments_count/` |
90
+
91
+ Org unit types:
92
+
93
+ client.org_unit_types_list(...)
94
+ client.org_unit_types_list_page(...)
95
+ client.org_unit_types_retrieve(...)
96
+ client.org_unit_types_hierarchy(...)
97
+
98
+ Forms:
99
+
100
+ client.forms_list(...)
101
+ client.forms_list_page(...)
102
+ client.forms_retrieve(...)
103
+
104
+ Form versions:
105
+
106
+ client.form_versions_list(...)
107
+ client.form_versions_list_page(...)
108
+ client.form_versions_retrieve(...)
109
+
110
+ Instances:
111
+
112
+ client.instances_list(...)
113
+ client.instances_list_page(...)
114
+ client.instances_retrieve(...)
115
+
116
+ Instance files:
117
+
118
+ client.instance_files_list(...)
119
+ client.instance_files_list_page(...)
120
+ client.instance_files_count(...)
121
+
122
+ Instances:
123
+
124
+ client.instances_list(...)
125
+ client.instances_list_page(...)
126
+ client.instances_retrieve(...)
127
+
128
+
129
+
130
+ ### Pagination behavior
131
+
132
+ list() fetches and aggregates results across all pages.
133
+ list_page() returns a single paginated response.
134
+
135
+
136
+ ### HTTP request logging
137
+
138
+ You can enable request logging when creating the client:
139
+
140
+ ```python
141
+ import logging
142
+ from iaso_client import IasoClient
143
+
144
+ logging.basicConfig(level=logging.INFO)
145
+
146
+ client = IasoClient(
147
+ base_url="https://your.iaso-server.com",
148
+ enable_logging=True,
149
+ )
150
+ ```
151
+
152
+ Example log output:
153
+
154
+ ```text
155
+ GET https://iaso-staging.bluesquare.org/api/v2/orgunittypes/ -> 200 [143.21 ms]
156
+ ```
157
+
158
+ ### Development
159
+
160
+ Run tests
161
+
162
+ ```bash
163
+ uv run pytest
164
+ ```
165
+
166
+ Run the main script
167
+
168
+ ```bash
169
+ uv run .\examples\main.py
170
+ ```
171
+
172
+ **Setup Pre-commit hooks**
173
+
174
+ 1. To ensure your code is properly formatted and linted before every commit, install the pre-commit hook:
175
+
176
+ ```bash
177
+ uv run pre-commit install
178
+ ```
179
+
180
+ 2. Linting & Formatting (Ruff)
181
+ Format the code (auto-fix styling issues):
182
+
183
+ ```bash
184
+ uv run ruff format .
185
+ ```
186
+
187
+ 3. Check for logic errors and bad practices:
188
+
189
+ ```Bash
190
+ uv run ruff check .
191
+ ```
192
+
193
+ ## Bruno
194
+
195
+ This repository also contains a Bruno collection for manually testing IASO API requests.
196
+
197
+ ### Configure the environment
198
+
199
+ Copy `.env.sample` to `.env` in the `bruno` folder, then fill in your credentials:
200
+
201
+ ```bash
202
+ IASO_BASE_URL=https://your.iaso-server.com
203
+ IASO_LOGIN=your_login
204
+ IASO_PASSWORD=your_password
205
+ ```
206
+
207
+
208
+ ### Run Bruno requests
209
+ 1. Open Bruno.
210
+ 2. In the top-left corner, open the collection and select the `bruno` directory from this repository.
211
+ 3. In the top-right corner, select the `iaso_client` environment for the current collection.
212
+ 4. Before running any protected request, run the `login` request first to authenticate.
213
+ 5. Then select the request you want to run and click `->` to execute it.
@@ -0,0 +1,196 @@
1
+ # iaso-client
2
+
3
+ `iaso-client` is a Python client library for interacting with IASO APIs.
4
+
5
+ ## Installation
6
+
7
+ From the project root:
8
+
9
+ ```bash
10
+ uv sync
11
+ ```
12
+ ### Configuration
13
+
14
+ 1. Copy .env.sample to .env at the project root, then fill in your credentials:
15
+
16
+ The `IASO_BASE_URL` can't be provided with a trailing slash at the end.
17
+
18
+ ```bash
19
+ IASO_BASE_URL=https://your.iaso-server.com
20
+ IASO_LOGIN=your_login
21
+ IASO_PASSWORD=your_password
22
+ ```
23
+ 2. Create a symlink so Bruno can read the root `.env` file:
24
+ - **Windows** (Run Command Prompt as Administrator):
25
+ ```bash
26
+ cd bruno
27
+ mklink .env ..\.env
28
+ ```
29
+ - **Mac / Linux**:
30
+ ```bash
31
+ cd bruno
32
+ ln -s ../.env .env
33
+ ```
34
+ ### Quickstart
35
+
36
+ ```python
37
+ import os
38
+
39
+ from iaso_client import IasoClient
40
+
41
+ IASO_BASE_URL = os.getenv("IASO_BASE_URL")
42
+ IASO_LOGIN = os.getenv("IASO_LOGIN")
43
+ IASO_PASSWORD = os.getenv("IASO_PASSWORD")
44
+
45
+ client = IasoClient(base_url=IASO_BASE_URL)
46
+ client.login(IASO_LOGIN, IASO_PASSWORD)
47
+ page = client.org_unit_types_list_page(page=1, limit=10, project=975)
48
+ items = client.org_unit_types_list(search="District/Zone de sante - DIST")
49
+
50
+ print(page)
51
+ print(items)
52
+ ```
53
+
54
+ ### Authentication
55
+
56
+ Use login() to authenticate and automatically store the bearer token for subsequent requests.
57
+
58
+ ```python
59
+ client.login("your_login", "your_password")
60
+ ```
61
+
62
+ ### Current typed resources
63
+
64
+ The current typed client API supports:
65
+
66
+ | Resource | Endpoint |
67
+ | --- | --- |
68
+ | Org unit types | `/api/v2/orgunittypes/` |
69
+ | Forms | `/api/forms/` |
70
+ | Form versions | `/api/formversions/` |
71
+ | Instances | `/api/instances/` |
72
+ | Instance files | `/api/instances/attachments/`, `/api/instances/attachments_count/` |
73
+
74
+ Org unit types:
75
+
76
+ client.org_unit_types_list(...)
77
+ client.org_unit_types_list_page(...)
78
+ client.org_unit_types_retrieve(...)
79
+ client.org_unit_types_hierarchy(...)
80
+
81
+ Forms:
82
+
83
+ client.forms_list(...)
84
+ client.forms_list_page(...)
85
+ client.forms_retrieve(...)
86
+
87
+ Form versions:
88
+
89
+ client.form_versions_list(...)
90
+ client.form_versions_list_page(...)
91
+ client.form_versions_retrieve(...)
92
+
93
+ Instances:
94
+
95
+ client.instances_list(...)
96
+ client.instances_list_page(...)
97
+ client.instances_retrieve(...)
98
+
99
+ Instance files:
100
+
101
+ client.instance_files_list(...)
102
+ client.instance_files_list_page(...)
103
+ client.instance_files_count(...)
104
+
105
+ Instances:
106
+
107
+ client.instances_list(...)
108
+ client.instances_list_page(...)
109
+ client.instances_retrieve(...)
110
+
111
+
112
+
113
+ ### Pagination behavior
114
+
115
+ list() fetches and aggregates results across all pages.
116
+ list_page() returns a single paginated response.
117
+
118
+
119
+ ### HTTP request logging
120
+
121
+ You can enable request logging when creating the client:
122
+
123
+ ```python
124
+ import logging
125
+ from iaso_client import IasoClient
126
+
127
+ logging.basicConfig(level=logging.INFO)
128
+
129
+ client = IasoClient(
130
+ base_url="https://your.iaso-server.com",
131
+ enable_logging=True,
132
+ )
133
+ ```
134
+
135
+ Example log output:
136
+
137
+ ```text
138
+ GET https://iaso-staging.bluesquare.org/api/v2/orgunittypes/ -> 200 [143.21 ms]
139
+ ```
140
+
141
+ ### Development
142
+
143
+ Run tests
144
+
145
+ ```bash
146
+ uv run pytest
147
+ ```
148
+
149
+ Run the main script
150
+
151
+ ```bash
152
+ uv run .\examples\main.py
153
+ ```
154
+
155
+ **Setup Pre-commit hooks**
156
+
157
+ 1. To ensure your code is properly formatted and linted before every commit, install the pre-commit hook:
158
+
159
+ ```bash
160
+ uv run pre-commit install
161
+ ```
162
+
163
+ 2. Linting & Formatting (Ruff)
164
+ Format the code (auto-fix styling issues):
165
+
166
+ ```bash
167
+ uv run ruff format .
168
+ ```
169
+
170
+ 3. Check for logic errors and bad practices:
171
+
172
+ ```Bash
173
+ uv run ruff check .
174
+ ```
175
+
176
+ ## Bruno
177
+
178
+ This repository also contains a Bruno collection for manually testing IASO API requests.
179
+
180
+ ### Configure the environment
181
+
182
+ Copy `.env.sample` to `.env` in the `bruno` folder, then fill in your credentials:
183
+
184
+ ```bash
185
+ IASO_BASE_URL=https://your.iaso-server.com
186
+ IASO_LOGIN=your_login
187
+ IASO_PASSWORD=your_password
188
+ ```
189
+
190
+
191
+ ### Run Bruno requests
192
+ 1. Open Bruno.
193
+ 2. In the top-left corner, open the collection and select the `bruno` directory from this repository.
194
+ 3. In the top-right corner, select the `iaso_client` environment for the current collection.
195
+ 4. Before running any protected request, run the `login` request first to authenticate.
196
+ 5. Then select the request you want to run and click `->` to execute it.
@@ -0,0 +1,91 @@
1
+ [project]
2
+ name = "iaso-client"
3
+ version = "1.1.0"
4
+ description = "Python client library for interacting with IASO APIs"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "abdelrahman meroual", email = "g62496@etu.he2b.be" }
8
+ ]
9
+ requires-python = ">=3.11"
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Intended Audience :: Developers",
13
+ "Intended Audience :: Science/Research",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.11",
16
+ "Programming Language :: Python :: 3.12",
17
+ ]
18
+ dependencies = [
19
+ "requests>=2.32.0",
20
+
21
+ ]
22
+ keywords = ["iaso", "api", "client", "sdk", "python"]
23
+
24
+ [build-system]
25
+ requires = ["uv_build>=0.10.12,<0.11.0"]
26
+ build-backend = "uv_build"
27
+
28
+ [dependency-groups]
29
+ dev = [
30
+ "pytest>=9.0.2",
31
+ "requests-mock>=1.12.1",
32
+ "python-dotenv>=1.2.2",
33
+ "ruff>=0.15.8",
34
+ "pre-commit>=4.5.1",
35
+ ]
36
+
37
+ [tool.ruff]
38
+ line-length = 88
39
+ target-version = "py311"
40
+
41
+ [tool.ruff.lint]
42
+ select = ["ALL"]
43
+
44
+ ignore = [
45
+ # Official recommendation from Ruff to avoid conflicts
46
+ "W191", # tab-indentation
47
+ "E111", # indentation-with-invalid-multiple
48
+ "E114", # indentation-with-invalid-multiple-comment
49
+ "E117", # over-indented
50
+ "D206", # docstring-tab-indentation
51
+ "D300", # triple-single-quotes
52
+ "Q000", # bad-quotes-inline-string
53
+ "Q001", # bad-quotes-multiline-string
54
+ "Q002", # bad-quotes-docstring
55
+ "Q003", # avoidable-escaped-quote
56
+ "Q004", # unnecessary-escaped-quote
57
+ "COM812", # missing-trailing-comma
58
+ "COM819", # prohibited-trailing-comma
59
+ "ISC001", # single-line-implicit-string-concatenation
60
+ "ISC002", # multi-line-implicit-string-concatenation
61
+
62
+ "D203", # incorrect-blank-line-before-class conflict with D211
63
+ "D213", # multi-line-summary-first-line conflict with D212
64
+
65
+
66
+ # We don't need documentation every time
67
+ "D103", # undocumented-public-function
68
+ "D100", # undocumented-public-module
69
+ "D101", # undocumented-public-class
70
+ "D102", # undocumented-public-method
71
+ "D104", # undocumented-public-package
72
+ "D107", # undocumented-public-init
73
+
74
+ "ANN401", # any-type
75
+
76
+ ]
77
+
78
+ [tool.ruff.lint.per-file-ignores]
79
+ "tests/*.py" = [
80
+ "S101", # assert
81
+ "S105", # hardcoded-password-string
82
+ "SLF001", # private-member-access
83
+ "PLR2004", # magic-value-comparison
84
+ ]
85
+ "examples/main.py" =[
86
+ "T201" # print
87
+ ]
88
+
89
+ [tool.ruff.format]
90
+ quote-style = "double"
91
+ indent-style = "space"
@@ -0,0 +1,5 @@
1
+ from .client import IasoClient
2
+
3
+ __all__ = [
4
+ "IasoClient",
5
+ ]
@@ -0,0 +1,95 @@
1
+ from .exceptions import IasoValidationError
2
+ from .pagination import Pagination
3
+ from .params import QueryParams
4
+ from .transport import IasoTransportClient
5
+
6
+
7
+ class BaseResource:
8
+ def __init__(self, transport: IasoTransportClient, base_path: str) -> None:
9
+ self.transport = transport
10
+ self.base_path = base_path
11
+
12
+ def _build_params(
13
+ self,
14
+ *,
15
+ pagination: Pagination | None = None,
16
+ filters: QueryParams | None = None,
17
+ ) -> dict[str, object] | None:
18
+ params: dict[str, object] = {}
19
+
20
+ if pagination is not None:
21
+ params.update(pagination.to_params())
22
+
23
+ if filters is not None:
24
+ params.update(filters.to_params())
25
+
26
+ return params or None
27
+
28
+ def _get(
29
+ self,
30
+ path: str = "",
31
+ *,
32
+ pagination: Pagination | None = None,
33
+ filters: QueryParams | None = None,
34
+ ) -> object:
35
+ params = self._build_params(pagination=pagination, filters=filters)
36
+
37
+ try:
38
+ return self.transport.get(f"{self.base_path}{path}", params=params)
39
+
40
+ except IasoValidationError as exc:
41
+ if (
42
+ params
43
+ and "fields" in params
44
+ and exc.payload
45
+ and "fields" in exc.payload
46
+ ):
47
+ fields_value = params["fields"]
48
+ if isinstance(fields_value, list):
49
+ fields_value = ", ".join(str(field) for field in fields_value)
50
+ msg = (
51
+ f"Check value for 'fields': {fields_value}. "
52
+ "Please check the available list values and in Swagger UI: "
53
+ f"{self.transport.base_url}/swagger-ui/"
54
+ )
55
+ raise IasoValidationError(
56
+ msg,
57
+ status_code=exc.status_code,
58
+ payload=exc.payload,
59
+ ) from exc
60
+ raise
61
+
62
+ def _fetch_all_pages(
63
+ self,
64
+ path: str = "",
65
+ *,
66
+ filters: QueryParams | None = None,
67
+ limit: int = 10,
68
+ ) -> list[dict[str, object]]:
69
+ """Fetch all paginated responses and return them as a list."""
70
+ if limit < 1:
71
+ msg = "'limit' must be greater than 0."
72
+ raise ValueError(msg)
73
+
74
+ page = 1
75
+ all_pages = []
76
+
77
+ while True:
78
+ response = self._get(
79
+ path,
80
+ pagination=Pagination(page=page, limit=limit),
81
+ filters=filters,
82
+ )
83
+
84
+ if not isinstance(response, dict):
85
+ msg = "Expected a paginated dict response."
86
+ raise TypeError(msg)
87
+
88
+ all_pages.append(response)
89
+
90
+ if not response.get("has_next"):
91
+ break
92
+
93
+ page += 1
94
+
95
+ return all_pages