digiwin-iam-sdk 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Digiwin Middleware Team
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,278 @@
1
+ Metadata-Version: 2.4
2
+ Name: digiwin-iam-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Digiwin IAM (Identity and Access Management) System
5
+ Author: Digiwin Middleware Team
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: authentication,dapware,digiwin,iam,identity
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: cryptography>=42.0
20
+ Requires-Dist: httpx>=0.27.0
21
+ Requires-Dist: pydantic>=2.0
22
+ Provides-Extra: dev
23
+ Requires-Dist: build>=1.2; extra == 'dev'
24
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
25
+ Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
26
+ Requires-Dist: pytest>=8.0; extra == 'dev'
27
+ Requires-Dist: ruff>=0.4; extra == 'dev'
28
+ Requires-Dist: twine>=6.0; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # digiwin-iam-sdk
32
+
33
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
34
+
35
+ Python SDK for the Digiwin IAM (Identity and Access Management) system.
36
+
37
+ PyPI distribution name: `digiwin-iam-sdk`
38
+
39
+ Import namespace: `dapware_iam`
40
+
41
+ ## Features
42
+
43
+ - Identity, user, tenant, and org API modules
44
+ - Transparent RSA + AES login handshake
45
+ - Synchronous and asynchronous clients
46
+ - Pydantic-based request and response models
47
+ - Typed exceptions for auth, validation, server, and crypto failures
48
+
49
+ ## Installation
50
+
51
+ Install from PyPI:
52
+
53
+ ```bash
54
+ pip install digiwin-iam-sdk
55
+ ```
56
+
57
+ Install from source for development:
58
+
59
+ ```bash
60
+ pip install -e ".[dev]"
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ### Synchronous client
66
+
67
+ ```python
68
+ from dapware_iam import IAMClient
69
+
70
+ with IAMClient(
71
+ base_url="https://iam-test.digiwincloud.com.cn",
72
+ app_token="your-app-token",
73
+ ) as client:
74
+ user = client.identity.login("your_user_id", "your_password")
75
+ print(user.token)
76
+
77
+ token_info = client.identity.analyze_token()
78
+ print(token_info.user_id)
79
+
80
+ current_user = client.users.get_user(user_id=token_info.user_id)
81
+ tenants = client.tenants.get_tenants()
82
+
83
+ print(current_user.user_id)
84
+ print([tenant.id for tenant in tenants])
85
+
86
+ client.identity.logout()
87
+ ```
88
+
89
+ ### Asynchronous client
90
+
91
+ ```python
92
+ import asyncio
93
+
94
+ from dapware_iam import AsyncIAMClient
95
+
96
+
97
+ async def main() -> None:
98
+ async with AsyncIAMClient(
99
+ base_url="https://iam-test.digiwincloud.com.cn",
100
+ app_token="your-app-token",
101
+ ) as client:
102
+ user = await client.identity.login("your_user_id", "your_password")
103
+ print(user.token)
104
+
105
+ token_info = await client.identity.analyze_token()
106
+ current_user = await client.users.get_user(user_id=token_info.user_id)
107
+ tenants = await client.tenants.get_tenants()
108
+
109
+ print(current_user.user_id)
110
+ print([tenant.id for tenant in tenants])
111
+
112
+ await client.identity.logout()
113
+
114
+
115
+ asyncio.run(main())
116
+ ```
117
+
118
+ ## Tenant-Scoped APIs
119
+
120
+ Some endpoints require a tenant-scoped token. In the environments validated so
121
+ far, the default login token can be used for:
122
+
123
+ - `identity.analyze_token()`
124
+ - `users.get_user(...)`
125
+ - `tenants.get_tenants(...)`
126
+
127
+ The following methods should be treated as tenant-scoped and called only after
128
+ `identity.refresh_token_with_tenant(...)` succeeds:
129
+
130
+ - `tenants.get_current()`
131
+ - `tenants.get_current_simple()`
132
+ - `tenants.get_applications(...)`
133
+ - `orgs.get_cascade()`
134
+ - `orgs.get_org_list(...)`
135
+ - `orgs.get_users_in_org(...)`
136
+ - `orgs.get_users_cascade(...)`
137
+ - `orgs.create_or_update(...)`
138
+ - `orgs.delete(...)`
139
+
140
+ Example:
141
+
142
+ ```python
143
+ with IAMClient(base_url="...", app_token="...") as client:
144
+ client.identity.login("user", "password")
145
+ client.identity.refresh_token_with_tenant(tenant_id="your-tenant")
146
+
147
+ tenant = client.tenants.get_current()
148
+ org_tree = client.orgs.get_cascade()
149
+ ```
150
+
151
+ If the target tenant has not purchased the current application, the backend may
152
+ reject the tenant switch with an authorization error.
153
+
154
+ ## API Overview
155
+
156
+ ### `IAMClient` and `AsyncIAMClient`
157
+
158
+ | Parameter | Type | Default | Description |
159
+ |---|---|---|---|
160
+ | `base_url` | `str` | - | IAM service base URL |
161
+ | `app_token` | `str` | - | `digi-middleware-auth-app` JWT |
162
+ | `timeout` | `float` | `30.0` | Request timeout in seconds |
163
+ | `verify_ssl` | `bool` | `True` | Whether to verify SSL certificates |
164
+ | `extra_headers` | `dict[str, str] \| None` | `None` | Extra headers added to every request |
165
+
166
+ ### `client.identity`
167
+
168
+ | Method | Endpoint | Description |
169
+ |---|---|---|
170
+ | `login(user_id, password, ...)` | `POST /login` | Cloud user login |
171
+ | `login_ad(user_id, password, ...)` | `POST /login` | Digiwin AD login |
172
+ | `login_verification_code(phone, code)` | `POST /login` | SMS code login |
173
+ | `internal_login(tenant_id, user_id, password, ...)` | `POST /internal/login` | Enterprise internal login |
174
+ | `logout(clear_all=False)` | `POST /logout` | Logout |
175
+ | `get_public_key()` | `GET /publickey` | Get the server RSA public key |
176
+ | `get_aes_key(encrypted_key)` | `POST /aeskey` | Exchange AES key |
177
+ | `analyze_token()` | `POST /token/analyze` | Parse the current token |
178
+ | `analyze_token_internal()` | `GET /token/analyze/internal` | Parse token with the internal variant |
179
+ | `get_login_info()` | `POST /login/info` | Get login info for the current token |
180
+ | `refresh_token_with_tenant(...)` | `POST /token/refresh/tenant` | Switch tenant and refresh token |
181
+ | `refresh_user_token()` | `POST /token/refresh/user` | Refresh user token |
182
+ | `create_access_token(...)` | `POST /token/grant/access` | Create an SSO access token |
183
+
184
+ ### `client.users`
185
+
186
+ | Method | Endpoint | Description |
187
+ |---|---|---|
188
+ | `get_user(user_id=None, user_sid=0)` | `POST /api/iam/v2/user` | Query one user |
189
+ | `get_user_list(user_ids)` | `POST /user/list` | Batch query users in the current tenant |
190
+ | `query_users(query_type, ...)` | `POST /user/query` | Query users by org or status |
191
+ | `get_user_simple()` | `GET /user/simple` | Query current-tenant simple users |
192
+ | `check_email_exists(email)` | `POST /user/email/exist` | Check whether email is registered |
193
+ | `check_phone_exists(phone)` | `POST /user/mobilephone/exist` | Check whether phone is registered |
194
+ | `check_user_exists(user_id)` | `POST /user/exists` | Check whether a user exists |
195
+ | `get_user_roles(...)` | `POST /user/role` | Query user roles |
196
+
197
+ ### `client.tenants`
198
+
199
+ | Method | Endpoint | Description |
200
+ |---|---|---|
201
+ | `get_tenants(...)` | `POST /api/iam/v2/tenant` | List the current user's available tenants |
202
+ | `get_current()` | `POST /tenant/current` | Get current tenant detail |
203
+ | `get_simple(tenant_id)` | `POST /tenant/simple` | Get one tenant's simple info |
204
+ | `get_current_simple()` | `GET /tenant/current/simple` | Get current tenant simple info |
205
+ | `query_tenants(keyword)` | `POST /tenant/query` | Search open tenants |
206
+ | `check_user_in_tenant(user_id)` | `GET /tenant/check/userintenant` | Check whether a user exists in the current tenant |
207
+ | `get_applications(...)` | `GET /tenant/application` | Get current tenant applications |
208
+ | `invite_user(...)` | `POST /tenant/user/invite/new` | Invite a user into a tenant |
209
+ | `remove_user(...)` | `POST /tenant/remove/user` | Remove a user from a tenant |
210
+
211
+ ### `client.orgs`
212
+
213
+ | Method | Endpoint | Description |
214
+ |---|---|---|
215
+ | `get_cascade()` | `GET /org/cascade` | Get org tree |
216
+ | `get_org_list(org_sids)` | `POST /org/list` | Batch query orgs by sid |
217
+ | `get_users_in_org(...)` | `POST /org/userinorg` | Query users in one org |
218
+ | `get_users_cascade(...)` | `POST /org/userinorg/cascade` | Query users in an org subtree |
219
+ | `create_or_update(org_info)` | `POST /org/update` | Create or update an org |
220
+ | `delete(org_sid)` | `POST /org/del` | Delete an org |
221
+
222
+ ## Error Handling
223
+
224
+ ```python
225
+ from dapware_iam import AuthenticationError, IAMClient, ServerError
226
+
227
+ with IAMClient(base_url="...", app_token="...") as client:
228
+ try:
229
+ client.identity.login("user", "wrong_password")
230
+ except AuthenticationError as exc:
231
+ print(exc)
232
+ print(exc.status_code)
233
+ print(exc.body)
234
+ except ServerError as exc:
235
+ print(exc)
236
+ ```
237
+
238
+ Exception hierarchy:
239
+
240
+ ```text
241
+ IAMError
242
+ |- AuthenticationError
243
+ |- AuthorizationError
244
+ |- NotFoundError
245
+ |- ValidationError
246
+ |- ServerError
247
+ `- CryptoError
248
+ ```
249
+
250
+ ## Configuration
251
+
252
+ Disable SSL verification only for trusted internal environments that use
253
+ self-signed certificates:
254
+
255
+ ```python
256
+ client = IAMClient(
257
+ base_url="https://internal-iam.company.com",
258
+ app_token="...",
259
+ verify_ssl=False,
260
+ )
261
+ ```
262
+
263
+ ## Development And Release
264
+
265
+ Manual release instructions live in `RELEASING.md`. The short version is:
266
+
267
+ ```bash
268
+ python -m pytest -q
269
+ python -m build
270
+ python -m twine check dist/*
271
+ ```
272
+
273
+ Upload to TestPyPI first, validate the exact built artifacts, then upload the
274
+ same files to PyPI.
275
+
276
+ ## License
277
+
278
+ MIT
@@ -0,0 +1,248 @@
1
+ # digiwin-iam-sdk
2
+
3
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
4
+
5
+ Python SDK for the Digiwin IAM (Identity and Access Management) system.
6
+
7
+ PyPI distribution name: `digiwin-iam-sdk`
8
+
9
+ Import namespace: `dapware_iam`
10
+
11
+ ## Features
12
+
13
+ - Identity, user, tenant, and org API modules
14
+ - Transparent RSA + AES login handshake
15
+ - Synchronous and asynchronous clients
16
+ - Pydantic-based request and response models
17
+ - Typed exceptions for auth, validation, server, and crypto failures
18
+
19
+ ## Installation
20
+
21
+ Install from PyPI:
22
+
23
+ ```bash
24
+ pip install digiwin-iam-sdk
25
+ ```
26
+
27
+ Install from source for development:
28
+
29
+ ```bash
30
+ pip install -e ".[dev]"
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ### Synchronous client
36
+
37
+ ```python
38
+ from dapware_iam import IAMClient
39
+
40
+ with IAMClient(
41
+ base_url="https://iam-test.digiwincloud.com.cn",
42
+ app_token="your-app-token",
43
+ ) as client:
44
+ user = client.identity.login("your_user_id", "your_password")
45
+ print(user.token)
46
+
47
+ token_info = client.identity.analyze_token()
48
+ print(token_info.user_id)
49
+
50
+ current_user = client.users.get_user(user_id=token_info.user_id)
51
+ tenants = client.tenants.get_tenants()
52
+
53
+ print(current_user.user_id)
54
+ print([tenant.id for tenant in tenants])
55
+
56
+ client.identity.logout()
57
+ ```
58
+
59
+ ### Asynchronous client
60
+
61
+ ```python
62
+ import asyncio
63
+
64
+ from dapware_iam import AsyncIAMClient
65
+
66
+
67
+ async def main() -> None:
68
+ async with AsyncIAMClient(
69
+ base_url="https://iam-test.digiwincloud.com.cn",
70
+ app_token="your-app-token",
71
+ ) as client:
72
+ user = await client.identity.login("your_user_id", "your_password")
73
+ print(user.token)
74
+
75
+ token_info = await client.identity.analyze_token()
76
+ current_user = await client.users.get_user(user_id=token_info.user_id)
77
+ tenants = await client.tenants.get_tenants()
78
+
79
+ print(current_user.user_id)
80
+ print([tenant.id for tenant in tenants])
81
+
82
+ await client.identity.logout()
83
+
84
+
85
+ asyncio.run(main())
86
+ ```
87
+
88
+ ## Tenant-Scoped APIs
89
+
90
+ Some endpoints require a tenant-scoped token. In the environments validated so
91
+ far, the default login token can be used for:
92
+
93
+ - `identity.analyze_token()`
94
+ - `users.get_user(...)`
95
+ - `tenants.get_tenants(...)`
96
+
97
+ The following methods should be treated as tenant-scoped and called only after
98
+ `identity.refresh_token_with_tenant(...)` succeeds:
99
+
100
+ - `tenants.get_current()`
101
+ - `tenants.get_current_simple()`
102
+ - `tenants.get_applications(...)`
103
+ - `orgs.get_cascade()`
104
+ - `orgs.get_org_list(...)`
105
+ - `orgs.get_users_in_org(...)`
106
+ - `orgs.get_users_cascade(...)`
107
+ - `orgs.create_or_update(...)`
108
+ - `orgs.delete(...)`
109
+
110
+ Example:
111
+
112
+ ```python
113
+ with IAMClient(base_url="...", app_token="...") as client:
114
+ client.identity.login("user", "password")
115
+ client.identity.refresh_token_with_tenant(tenant_id="your-tenant")
116
+
117
+ tenant = client.tenants.get_current()
118
+ org_tree = client.orgs.get_cascade()
119
+ ```
120
+
121
+ If the target tenant has not purchased the current application, the backend may
122
+ reject the tenant switch with an authorization error.
123
+
124
+ ## API Overview
125
+
126
+ ### `IAMClient` and `AsyncIAMClient`
127
+
128
+ | Parameter | Type | Default | Description |
129
+ |---|---|---|---|
130
+ | `base_url` | `str` | - | IAM service base URL |
131
+ | `app_token` | `str` | - | `digi-middleware-auth-app` JWT |
132
+ | `timeout` | `float` | `30.0` | Request timeout in seconds |
133
+ | `verify_ssl` | `bool` | `True` | Whether to verify SSL certificates |
134
+ | `extra_headers` | `dict[str, str] \| None` | `None` | Extra headers added to every request |
135
+
136
+ ### `client.identity`
137
+
138
+ | Method | Endpoint | Description |
139
+ |---|---|---|
140
+ | `login(user_id, password, ...)` | `POST /login` | Cloud user login |
141
+ | `login_ad(user_id, password, ...)` | `POST /login` | Digiwin AD login |
142
+ | `login_verification_code(phone, code)` | `POST /login` | SMS code login |
143
+ | `internal_login(tenant_id, user_id, password, ...)` | `POST /internal/login` | Enterprise internal login |
144
+ | `logout(clear_all=False)` | `POST /logout` | Logout |
145
+ | `get_public_key()` | `GET /publickey` | Get the server RSA public key |
146
+ | `get_aes_key(encrypted_key)` | `POST /aeskey` | Exchange AES key |
147
+ | `analyze_token()` | `POST /token/analyze` | Parse the current token |
148
+ | `analyze_token_internal()` | `GET /token/analyze/internal` | Parse token with the internal variant |
149
+ | `get_login_info()` | `POST /login/info` | Get login info for the current token |
150
+ | `refresh_token_with_tenant(...)` | `POST /token/refresh/tenant` | Switch tenant and refresh token |
151
+ | `refresh_user_token()` | `POST /token/refresh/user` | Refresh user token |
152
+ | `create_access_token(...)` | `POST /token/grant/access` | Create an SSO access token |
153
+
154
+ ### `client.users`
155
+
156
+ | Method | Endpoint | Description |
157
+ |---|---|---|
158
+ | `get_user(user_id=None, user_sid=0)` | `POST /api/iam/v2/user` | Query one user |
159
+ | `get_user_list(user_ids)` | `POST /user/list` | Batch query users in the current tenant |
160
+ | `query_users(query_type, ...)` | `POST /user/query` | Query users by org or status |
161
+ | `get_user_simple()` | `GET /user/simple` | Query current-tenant simple users |
162
+ | `check_email_exists(email)` | `POST /user/email/exist` | Check whether email is registered |
163
+ | `check_phone_exists(phone)` | `POST /user/mobilephone/exist` | Check whether phone is registered |
164
+ | `check_user_exists(user_id)` | `POST /user/exists` | Check whether a user exists |
165
+ | `get_user_roles(...)` | `POST /user/role` | Query user roles |
166
+
167
+ ### `client.tenants`
168
+
169
+ | Method | Endpoint | Description |
170
+ |---|---|---|
171
+ | `get_tenants(...)` | `POST /api/iam/v2/tenant` | List the current user's available tenants |
172
+ | `get_current()` | `POST /tenant/current` | Get current tenant detail |
173
+ | `get_simple(tenant_id)` | `POST /tenant/simple` | Get one tenant's simple info |
174
+ | `get_current_simple()` | `GET /tenant/current/simple` | Get current tenant simple info |
175
+ | `query_tenants(keyword)` | `POST /tenant/query` | Search open tenants |
176
+ | `check_user_in_tenant(user_id)` | `GET /tenant/check/userintenant` | Check whether a user exists in the current tenant |
177
+ | `get_applications(...)` | `GET /tenant/application` | Get current tenant applications |
178
+ | `invite_user(...)` | `POST /tenant/user/invite/new` | Invite a user into a tenant |
179
+ | `remove_user(...)` | `POST /tenant/remove/user` | Remove a user from a tenant |
180
+
181
+ ### `client.orgs`
182
+
183
+ | Method | Endpoint | Description |
184
+ |---|---|---|
185
+ | `get_cascade()` | `GET /org/cascade` | Get org tree |
186
+ | `get_org_list(org_sids)` | `POST /org/list` | Batch query orgs by sid |
187
+ | `get_users_in_org(...)` | `POST /org/userinorg` | Query users in one org |
188
+ | `get_users_cascade(...)` | `POST /org/userinorg/cascade` | Query users in an org subtree |
189
+ | `create_or_update(org_info)` | `POST /org/update` | Create or update an org |
190
+ | `delete(org_sid)` | `POST /org/del` | Delete an org |
191
+
192
+ ## Error Handling
193
+
194
+ ```python
195
+ from dapware_iam import AuthenticationError, IAMClient, ServerError
196
+
197
+ with IAMClient(base_url="...", app_token="...") as client:
198
+ try:
199
+ client.identity.login("user", "wrong_password")
200
+ except AuthenticationError as exc:
201
+ print(exc)
202
+ print(exc.status_code)
203
+ print(exc.body)
204
+ except ServerError as exc:
205
+ print(exc)
206
+ ```
207
+
208
+ Exception hierarchy:
209
+
210
+ ```text
211
+ IAMError
212
+ |- AuthenticationError
213
+ |- AuthorizationError
214
+ |- NotFoundError
215
+ |- ValidationError
216
+ |- ServerError
217
+ `- CryptoError
218
+ ```
219
+
220
+ ## Configuration
221
+
222
+ Disable SSL verification only for trusted internal environments that use
223
+ self-signed certificates:
224
+
225
+ ```python
226
+ client = IAMClient(
227
+ base_url="https://internal-iam.company.com",
228
+ app_token="...",
229
+ verify_ssl=False,
230
+ )
231
+ ```
232
+
233
+ ## Development And Release
234
+
235
+ Manual release instructions live in `RELEASING.md`. The short version is:
236
+
237
+ ```bash
238
+ python -m pytest -q
239
+ python -m build
240
+ python -m twine check dist/*
241
+ ```
242
+
243
+ Upload to TestPyPI first, validate the exact built artifacts, then upload the
244
+ same files to PyPI.
245
+
246
+ ## License
247
+
248
+ MIT
@@ -0,0 +1,62 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "digiwin-iam-sdk"
7
+ dynamic = ["version"]
8
+ description = "Python SDK for Digiwin IAM (Identity and Access Management) System"
9
+ readme = { file = "README.md", content-type = "text/markdown" }
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ authors = [
14
+ { name = "Digiwin Middleware Team" },
15
+ ]
16
+ keywords = ["iam", "digiwin", "dapware", "identity", "authentication"]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ ]
28
+ dependencies = [
29
+ "httpx>=0.27.0",
30
+ "pydantic>=2.0",
31
+ "cryptography>=42.0",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "build>=1.2",
37
+ "pytest>=8.0",
38
+ "pytest-asyncio>=0.24",
39
+ "pytest-httpx>=0.30",
40
+ "ruff>=0.4",
41
+ "twine>=6.0",
42
+ ]
43
+
44
+ [tool.hatch.version]
45
+ path = "src/dapware_iam/__init__.py"
46
+
47
+ [tool.hatch.build.targets.sdist]
48
+ include = [
49
+ "/src",
50
+ "/README.md",
51
+ "/LICENSE",
52
+ ]
53
+
54
+ [tool.hatch.build.targets.wheel]
55
+ packages = ["src/dapware_iam"]
56
+
57
+ [tool.pytest.ini_options]
58
+ asyncio_mode = "auto"
59
+
60
+ [tool.ruff]
61
+ target-version = "py310"
62
+ line-length = 120
@@ -0,0 +1,43 @@
1
+ """Dapware IAM Python SDK.
2
+
3
+ Provides synchronous and asynchronous Python clients for the Digiwin IAM
4
+ (Identity and Access Management) system.
5
+
6
+ Quick start::
7
+
8
+ from dapware_iam import IAMClient
9
+
10
+ with IAMClient(
11
+ base_url="https://iam-test.digiwincloud.com.cn",
12
+ app_token="your-app-token",
13
+ ) as client:
14
+ user = client.identity.login("user_id", "password")
15
+ print(user.token)
16
+ """
17
+
18
+ from .client import AsyncIAMClient, IAMClient
19
+ from .config import IAMConfig
20
+ from .exceptions import (
21
+ AuthenticationError,
22
+ AuthorizationError,
23
+ CryptoError,
24
+ IAMError,
25
+ NotFoundError,
26
+ ServerError,
27
+ ValidationError,
28
+ )
29
+
30
+ __version__ = "0.1.0"
31
+
32
+ __all__ = [
33
+ "AsyncIAMClient",
34
+ "AuthenticationError",
35
+ "AuthorizationError",
36
+ "CryptoError",
37
+ "IAMClient",
38
+ "IAMConfig",
39
+ "IAMError",
40
+ "NotFoundError",
41
+ "ServerError",
42
+ "ValidationError",
43
+ ]
@@ -0,0 +1,17 @@
1
+ """API sub-package."""
2
+
3
+ from .identity import AsyncIdentityAPI, IdentityAPI
4
+ from .orgs import AsyncOrgsAPI, OrgsAPI
5
+ from .tenants import AsyncTenantsAPI, TenantsAPI
6
+ from .users import AsyncUsersAPI, UsersAPI
7
+
8
+ __all__ = [
9
+ "AsyncIdentityAPI",
10
+ "AsyncOrgsAPI",
11
+ "AsyncTenantsAPI",
12
+ "AsyncUsersAPI",
13
+ "IdentityAPI",
14
+ "OrgsAPI",
15
+ "TenantsAPI",
16
+ "UsersAPI",
17
+ ]