unitysvc-py 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.
Files changed (87) hide show
  1. unitysvc_py-0.1.0/LICENSE +21 -0
  2. unitysvc_py-0.1.0/PKG-INFO +200 -0
  3. unitysvc_py-0.1.0/README.md +160 -0
  4. unitysvc_py-0.1.0/pyproject.toml +90 -0
  5. unitysvc_py-0.1.0/setup.cfg +4 -0
  6. unitysvc_py-0.1.0/src/unitysvc_py/__init__.py +68 -0
  7. unitysvc_py-0.1.0/src/unitysvc_py/_generated/__init__.py +8 -0
  8. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/__init__.py +1 -0
  9. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_aliases/__init__.py +1 -0
  10. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_aliases/customer_aliases_create_alias.py +241 -0
  11. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_aliases/customer_aliases_delete_alias.py +221 -0
  12. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_aliases/customer_aliases_get_alias.py +217 -0
  13. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_aliases/customer_aliases_list_aliases.py +273 -0
  14. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_aliases/customer_aliases_set_alias_routing.py +237 -0
  15. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_aliases/customer_aliases_update_alias.py +251 -0
  16. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_recurrent_requests/__init__.py +1 -0
  17. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_recurrent_requests/customer_recurrent_requests_create_recurrent_request.py +241 -0
  18. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_recurrent_requests/customer_recurrent_requests_get_recurrent_request_detail.py +225 -0
  19. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_recurrent_requests/customer_recurrent_requests_list_recurrent_requests.py +315 -0
  20. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_recurrent_requests/customer_recurrent_requests_remove_recurrent_request.py +221 -0
  21. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_recurrent_requests/customer_recurrent_requests_trigger_recurrent_request.py +237 -0
  22. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_recurrent_requests/customer_recurrent_requests_update_recurrent_request.py +255 -0
  23. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_secrets/__init__.py +1 -0
  24. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_secrets/customer_secrets_check_secret_exists.py +236 -0
  25. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_secrets/customer_secrets_create_secret.py +261 -0
  26. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_secrets/customer_secrets_delete_secret.py +241 -0
  27. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_secrets/customer_secrets_get_secret.py +233 -0
  28. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_secrets/customer_secrets_list_secrets.py +254 -0
  29. unitysvc_py-0.1.0/src/unitysvc_py/_generated/api/customer_secrets/customer_secrets_update_secret.py +259 -0
  30. unitysvc_py-0.1.0/src/unitysvc_py/_generated/client.py +263 -0
  31. unitysvc_py-0.1.0/src/unitysvc_py/_generated/errors.py +14 -0
  32. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/__init__.py +59 -0
  33. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/http_validation_error.py +94 -0
  34. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/message.py +71 -0
  35. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_create.py +242 -0
  36. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_create_body_template_type_0.py +62 -0
  37. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_create_request_headers_type_0.py +62 -0
  38. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_public.py +337 -0
  39. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_public_body_template_type_0.py +62 -0
  40. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_public_schedule_type_0.py +62 -0
  41. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_public_state_type_0.py +62 -0
  42. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_status_enum.py +10 -0
  43. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_update.py +250 -0
  44. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_update_body_template_type_0.py +62 -0
  45. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_update_request_headers_type_0.py +62 -0
  46. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_request_update_schedule_type_0.py +62 -0
  47. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/recurrent_requests_public.py +98 -0
  48. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/secret_create.py +82 -0
  49. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/secret_exists_response.py +80 -0
  50. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/secret_owner_type_enum.py +10 -0
  51. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/secret_public.py +176 -0
  52. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/secret_update.py +74 -0
  53. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/secrets_public.py +98 -0
  54. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/service_alias_create.py +173 -0
  55. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/service_alias_create_routing_key_override_type_0.py +62 -0
  56. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/service_alias_update.py +207 -0
  57. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/service_alias_update_request_routing_key_type_0.py +62 -0
  58. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/service_alias_update_routing_key_override_type_0.py +62 -0
  59. unitysvc_py-0.1.0/src/unitysvc_py/_generated/models/validation_error.py +102 -0
  60. unitysvc_py-0.1.0/src/unitysvc_py/_generated/types.py +53 -0
  61. unitysvc_py-0.1.0/src/unitysvc_py/_http.py +57 -0
  62. unitysvc_py-0.1.0/src/unitysvc_py/aclient.py +152 -0
  63. unitysvc_py-0.1.0/src/unitysvc_py/cli.py +87 -0
  64. unitysvc_py-0.1.0/src/unitysvc_py/client.py +186 -0
  65. unitysvc_py-0.1.0/src/unitysvc_py/commands/__init__.py +5 -0
  66. unitysvc_py-0.1.0/src/unitysvc_py/commands/_helpers.py +104 -0
  67. unitysvc_py-0.1.0/src/unitysvc_py/commands/aliases.py +109 -0
  68. unitysvc_py-0.1.0/src/unitysvc_py/commands/recurrent_requests.py +127 -0
  69. unitysvc_py-0.1.0/src/unitysvc_py/commands/secrets.py +159 -0
  70. unitysvc_py-0.1.0/src/unitysvc_py/exceptions.py +120 -0
  71. unitysvc_py-0.1.0/src/unitysvc_py/py.typed +0 -0
  72. unitysvc_py-0.1.0/src/unitysvc_py/resources/__init__.py +8 -0
  73. unitysvc_py-0.1.0/src/unitysvc_py/resources/aaliases.py +104 -0
  74. unitysvc_py-0.1.0/src/unitysvc_py/resources/aliases.py +128 -0
  75. unitysvc_py-0.1.0/src/unitysvc_py/resources/arecurrent_requests.py +131 -0
  76. unitysvc_py-0.1.0/src/unitysvc_py/resources/asecrets.py +103 -0
  77. unitysvc_py-0.1.0/src/unitysvc_py/resources/recurrent_requests.py +150 -0
  78. unitysvc_py-0.1.0/src/unitysvc_py/resources/secrets.py +122 -0
  79. unitysvc_py-0.1.0/src/unitysvc_py.egg-info/PKG-INFO +200 -0
  80. unitysvc_py-0.1.0/src/unitysvc_py.egg-info/SOURCES.txt +85 -0
  81. unitysvc_py-0.1.0/src/unitysvc_py.egg-info/dependency_links.txt +1 -0
  82. unitysvc_py-0.1.0/src/unitysvc_py.egg-info/entry_points.txt +2 -0
  83. unitysvc_py-0.1.0/src/unitysvc_py.egg-info/requires.txt +25 -0
  84. unitysvc_py-0.1.0/src/unitysvc_py.egg-info/top_level.txt +1 -0
  85. unitysvc_py-0.1.0/tests/test_cli.py +52 -0
  86. unitysvc_py-0.1.0/tests/test_client.py +86 -0
  87. unitysvc_py-0.1.0/tests/test_http.py +57 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026, Bo Peng
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,200 @@
1
+ Metadata-Version: 2.4
2
+ Name: unitysvc-py
3
+ Version: 0.1.0
4
+ Summary: Customer-facing Python SDK and `usvc` CLI for UnitySVC
5
+ Author-email: Bo Peng <bo.peng@unitysvc.com>
6
+ Maintainer-email: Bo Peng <bo.peng@unitysvc.com>
7
+ License-Expression: MIT
8
+ Project-URL: bugs, https://github.com/unitysvc/unitysvc-py/issues
9
+ Project-URL: homepage, https://github.com/unitysvc/unitysvc-py
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Typing :: Typed
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: typer
18
+ Requires-Dist: rich
19
+ Requires-Dist: httpx>=0.24
20
+ Requires-Dist: attrs>=23.0
21
+ Requires-Dist: python-dateutil>=2.8
22
+ Provides-Extra: test
23
+ Requires-Dist: coverage; extra == "test"
24
+ Requires-Dist: pytest; extra == "test"
25
+ Requires-Dist: pytest-asyncio; extra == "test"
26
+ Requires-Dist: ruff; extra == "test"
27
+ Requires-Dist: mypy; extra == "test"
28
+ Requires-Dist: respx; extra == "test"
29
+ Provides-Extra: dev
30
+ Requires-Dist: coverage; extra == "dev"
31
+ Requires-Dist: pytest; extra == "dev"
32
+ Requires-Dist: ruff; extra == "dev"
33
+ Requires-Dist: ipdb; extra == "dev"
34
+ Provides-Extra: docs
35
+ Requires-Dist: mkdocs; extra == "docs"
36
+ Requires-Dist: mkdocs-material; extra == "docs"
37
+ Requires-Dist: mkdocs-autorefs; extra == "docs"
38
+ Requires-Dist: pymdown-extensions; extra == "docs"
39
+ Dynamic: license-file
40
+
41
+ # unitysvc-py
42
+
43
+ Customer-facing Python SDK and `usvc` CLI for [UnitySVC](https://unitysvc.com/).
44
+
45
+ This package is a thin, typed facade over the UnitySVC customer API.
46
+ It exposes:
47
+
48
+ - A sync [`Client`](#programmatic-usage) and async `AsyncClient` for
49
+ the customer-tagged backend endpoints.
50
+ - The `usvc` CLI for managing the same resources from the terminal.
51
+
52
+ > **Status:** early scaffolding. The customer API currently exposes
53
+ > only a handful of endpoints (aliases, recurrent requests, secrets);
54
+ > the SDK tracks those today and will grow as the backend adds more.
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ pip install unitysvc-py
60
+ ```
61
+
62
+ ## Programmatic usage
63
+
64
+ ```python
65
+ from unitysvc_py import Client
66
+
67
+ client = Client(api_key="svcpass_...") # or Client.from_env()
68
+
69
+ # List and set secrets
70
+ secrets = client.secrets.list()
71
+ for s in secrets.data:
72
+ print(s.name, s.id)
73
+
74
+ client.secrets.create({"name": "openai-key", "value": "sk-..."})
75
+ ```
76
+
77
+ ### Configuration
78
+
79
+ The SDK is configured via a small set of environment variables. Only
80
+ `UNITYSVC_API_KEY` is required; everything else has a sensible
81
+ default.
82
+
83
+ | Variable | Purpose | Default |
84
+ |--------------------------|---------------------------------------------|----------------------------------------------|
85
+ | `UNITYSVC_API_KEY` | Customer API key (`svcpass_...`) | (required) |
86
+ | `UNITYSVC_API_URL` | Control-plane API base URL | `https://api.staging.unitysvc.com/v1` |
87
+ | `UNITYSVC_API_BASE_URL` | HTTP API gateway base URL (inference) | (unset) |
88
+ | `UNITYSVC_S3_BASE_URL` | S3-compatible gateway base URL | (unset) |
89
+ | `UNITYSVC_SMTP_BASE_URL` | SMTP gateway base URL | (unset) |
90
+
91
+ The customer context is encoded entirely in the API key, so no
92
+ separate `customer_id` argument is required.
93
+
94
+ `UNITYSVC_API_URL` is what the SDK itself uses for control-plane
95
+ calls. The `*_BASE_URL` variables are exposed on `Client` as
96
+ `client.api_base_url`, `client.s3_base_url`, `client.smtp_base_url`
97
+ for downstream inference/storage/email SDKs to pick up — the SDK
98
+ itself doesn't talk to them directly.
99
+
100
+ ### Async client
101
+
102
+ ```python
103
+ import asyncio
104
+ from unitysvc_py import AsyncClient
105
+
106
+ async def main():
107
+ async with AsyncClient(api_key="svcpass_...") as client:
108
+ secrets = await client.secrets.list()
109
+ for s in secrets.data:
110
+ print(s.name)
111
+
112
+ asyncio.run(main())
113
+ ```
114
+
115
+ ### Errors
116
+
117
+ All errors are subclasses of `unitysvc_py.UnitysvcSDKError`:
118
+
119
+ ```python
120
+ from unitysvc_py import (
121
+ UnitysvcSDKError,
122
+ AuthenticationError, # 401
123
+ PermissionError, # 403
124
+ NotFoundError, # 404
125
+ ValidationError, # 400, 422
126
+ ConflictError, # 409
127
+ RateLimitError, # 429
128
+ ServerError, # 5xx
129
+ APIError, # base for everything above
130
+ )
131
+ ```
132
+
133
+ ## CLI: `usvc`
134
+
135
+ The CLI follows the SDK's configuration — set `UNITYSVC_API_KEY` (and
136
+ optionally `UNITYSVC_API_URL`) and you can run:
137
+
138
+ ```
139
+ usvc env # show which env vars the SDK will pick up
140
+
141
+ # Secrets
142
+ usvc secrets list # list secrets
143
+ usvc secrets set NAME --value V # create or update a secret by name
144
+ usvc secrets delete NAME # delete a secret by name
145
+
146
+ # Service aliases
147
+ usvc aliases list
148
+ usvc aliases show ALIAS_ID
149
+ usvc aliases delete ALIAS_ID
150
+
151
+ # Recurrent requests
152
+ usvc recurrent-requests list
153
+ usvc recurrent-requests show REQUEST_ID
154
+ usvc recurrent-requests trigger REQUEST_ID
155
+ usvc recurrent-requests delete REQUEST_ID
156
+ ```
157
+
158
+ Every command accepts `--api-key` and `--base-url` overrides.
159
+
160
+ ## Layout
161
+
162
+ ```
163
+ src/unitysvc_py/
164
+ ├── client.py # Client (sync) facade
165
+ ├── aclient.py # AsyncClient (async) facade
166
+ ├── exceptions.py # UnitysvcSDKError + status-code subclasses
167
+ ├── _http.py # internal: unwrap generated Response → typed model or APIError
168
+ ├── resources/
169
+ │ ├── secrets.py # client.secrets.*
170
+ │ ├── aliases.py # client.aliases.*
171
+ │ ├── recurrent_requests.py # client.recurrent_requests.*
172
+ │ ├── asecrets.py # async mirror
173
+ │ ├── aaliases.py # async mirror
174
+ │ └── arecurrent_requests.py # async mirror
175
+ ├── _generated/ # openapi-python-client output (do not edit by hand)
176
+ ├── commands/ # Typer command groups for the CLI
177
+ │ ├── _helpers.py # run_async, async_client, model_list, ...
178
+ │ └── secrets.py # `usvc secrets {list,set,delete}`
179
+ └── cli.py # `usvc` Typer entry point
180
+ ```
181
+
182
+ ## Regenerating the API client
183
+
184
+ The low-level client under `src/unitysvc_py/_generated/` is produced
185
+ by [openapi-python-client] from a copy of the backend OpenAPI spec at
186
+ `openapi.json`. To regenerate after a backend change:
187
+
188
+ ```bash
189
+ # Requires a sibling checkout of unitysvc/unitysvc
190
+ ./scripts/generate_client.sh
191
+ ```
192
+
193
+ The script reads `../unitysvc/backend/generated/customer_api.json` by
194
+ default; pass an explicit spec path as the first argument to override.
195
+
196
+ [openapi-python-client]: https://github.com/openapi-generators/openapi-python-client
197
+
198
+ ## License
199
+
200
+ MIT
@@ -0,0 +1,160 @@
1
+ # unitysvc-py
2
+
3
+ Customer-facing Python SDK and `usvc` CLI for [UnitySVC](https://unitysvc.com/).
4
+
5
+ This package is a thin, typed facade over the UnitySVC customer API.
6
+ It exposes:
7
+
8
+ - A sync [`Client`](#programmatic-usage) and async `AsyncClient` for
9
+ the customer-tagged backend endpoints.
10
+ - The `usvc` CLI for managing the same resources from the terminal.
11
+
12
+ > **Status:** early scaffolding. The customer API currently exposes
13
+ > only a handful of endpoints (aliases, recurrent requests, secrets);
14
+ > the SDK tracks those today and will grow as the backend adds more.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install unitysvc-py
20
+ ```
21
+
22
+ ## Programmatic usage
23
+
24
+ ```python
25
+ from unitysvc_py import Client
26
+
27
+ client = Client(api_key="svcpass_...") # or Client.from_env()
28
+
29
+ # List and set secrets
30
+ secrets = client.secrets.list()
31
+ for s in secrets.data:
32
+ print(s.name, s.id)
33
+
34
+ client.secrets.create({"name": "openai-key", "value": "sk-..."})
35
+ ```
36
+
37
+ ### Configuration
38
+
39
+ The SDK is configured via a small set of environment variables. Only
40
+ `UNITYSVC_API_KEY` is required; everything else has a sensible
41
+ default.
42
+
43
+ | Variable | Purpose | Default |
44
+ |--------------------------|---------------------------------------------|----------------------------------------------|
45
+ | `UNITYSVC_API_KEY` | Customer API key (`svcpass_...`) | (required) |
46
+ | `UNITYSVC_API_URL` | Control-plane API base URL | `https://api.staging.unitysvc.com/v1` |
47
+ | `UNITYSVC_API_BASE_URL` | HTTP API gateway base URL (inference) | (unset) |
48
+ | `UNITYSVC_S3_BASE_URL` | S3-compatible gateway base URL | (unset) |
49
+ | `UNITYSVC_SMTP_BASE_URL` | SMTP gateway base URL | (unset) |
50
+
51
+ The customer context is encoded entirely in the API key, so no
52
+ separate `customer_id` argument is required.
53
+
54
+ `UNITYSVC_API_URL` is what the SDK itself uses for control-plane
55
+ calls. The `*_BASE_URL` variables are exposed on `Client` as
56
+ `client.api_base_url`, `client.s3_base_url`, `client.smtp_base_url`
57
+ for downstream inference/storage/email SDKs to pick up — the SDK
58
+ itself doesn't talk to them directly.
59
+
60
+ ### Async client
61
+
62
+ ```python
63
+ import asyncio
64
+ from unitysvc_py import AsyncClient
65
+
66
+ async def main():
67
+ async with AsyncClient(api_key="svcpass_...") as client:
68
+ secrets = await client.secrets.list()
69
+ for s in secrets.data:
70
+ print(s.name)
71
+
72
+ asyncio.run(main())
73
+ ```
74
+
75
+ ### Errors
76
+
77
+ All errors are subclasses of `unitysvc_py.UnitysvcSDKError`:
78
+
79
+ ```python
80
+ from unitysvc_py import (
81
+ UnitysvcSDKError,
82
+ AuthenticationError, # 401
83
+ PermissionError, # 403
84
+ NotFoundError, # 404
85
+ ValidationError, # 400, 422
86
+ ConflictError, # 409
87
+ RateLimitError, # 429
88
+ ServerError, # 5xx
89
+ APIError, # base for everything above
90
+ )
91
+ ```
92
+
93
+ ## CLI: `usvc`
94
+
95
+ The CLI follows the SDK's configuration — set `UNITYSVC_API_KEY` (and
96
+ optionally `UNITYSVC_API_URL`) and you can run:
97
+
98
+ ```
99
+ usvc env # show which env vars the SDK will pick up
100
+
101
+ # Secrets
102
+ usvc secrets list # list secrets
103
+ usvc secrets set NAME --value V # create or update a secret by name
104
+ usvc secrets delete NAME # delete a secret by name
105
+
106
+ # Service aliases
107
+ usvc aliases list
108
+ usvc aliases show ALIAS_ID
109
+ usvc aliases delete ALIAS_ID
110
+
111
+ # Recurrent requests
112
+ usvc recurrent-requests list
113
+ usvc recurrent-requests show REQUEST_ID
114
+ usvc recurrent-requests trigger REQUEST_ID
115
+ usvc recurrent-requests delete REQUEST_ID
116
+ ```
117
+
118
+ Every command accepts `--api-key` and `--base-url` overrides.
119
+
120
+ ## Layout
121
+
122
+ ```
123
+ src/unitysvc_py/
124
+ ├── client.py # Client (sync) facade
125
+ ├── aclient.py # AsyncClient (async) facade
126
+ ├── exceptions.py # UnitysvcSDKError + status-code subclasses
127
+ ├── _http.py # internal: unwrap generated Response → typed model or APIError
128
+ ├── resources/
129
+ │ ├── secrets.py # client.secrets.*
130
+ │ ├── aliases.py # client.aliases.*
131
+ │ ├── recurrent_requests.py # client.recurrent_requests.*
132
+ │ ├── asecrets.py # async mirror
133
+ │ ├── aaliases.py # async mirror
134
+ │ └── arecurrent_requests.py # async mirror
135
+ ├── _generated/ # openapi-python-client output (do not edit by hand)
136
+ ├── commands/ # Typer command groups for the CLI
137
+ │ ├── _helpers.py # run_async, async_client, model_list, ...
138
+ │ └── secrets.py # `usvc secrets {list,set,delete}`
139
+ └── cli.py # `usvc` Typer entry point
140
+ ```
141
+
142
+ ## Regenerating the API client
143
+
144
+ The low-level client under `src/unitysvc_py/_generated/` is produced
145
+ by [openapi-python-client] from a copy of the backend OpenAPI spec at
146
+ `openapi.json`. To regenerate after a backend change:
147
+
148
+ ```bash
149
+ # Requires a sibling checkout of unitysvc/unitysvc
150
+ ./scripts/generate_client.sh
151
+ ```
152
+
153
+ The script reads `../unitysvc/backend/generated/customer_api.json` by
154
+ default; pass an explicit spec path as the first argument to override.
155
+
156
+ [openapi-python-client]: https://github.com/openapi-generators/openapi-python-client
157
+
158
+ ## License
159
+
160
+ MIT
@@ -0,0 +1,90 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "unitysvc-py"
7
+ version = "0.1.0"
8
+ description = "Customer-facing Python SDK and `usvc` CLI for UnitySVC"
9
+ readme = "README.md"
10
+ authors = [{ name = "Bo Peng", email = "bo.peng@unitysvc.com" }]
11
+ maintainers = [{ name = "Bo Peng", email = "bo.peng@unitysvc.com" }]
12
+ license = "MIT"
13
+ classifiers = [
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3 :: Only",
16
+ "Operating System :: OS Independent",
17
+ "Typing :: Typed",
18
+ ]
19
+ dependencies = [
20
+ "typer",
21
+ "rich",
22
+ "httpx>=0.24",
23
+ "attrs>=23.0",
24
+ "python-dateutil>=2.8",
25
+ ]
26
+ requires-python = ">= 3.11"
27
+
28
+ [project.optional-dependencies]
29
+ test = [
30
+ "coverage",
31
+ "pytest",
32
+ "pytest-asyncio",
33
+ "ruff",
34
+ "mypy",
35
+ "respx",
36
+ ]
37
+ dev = [
38
+ "coverage",
39
+ "pytest",
40
+ "ruff",
41
+ "ipdb",
42
+ ]
43
+ docs = [
44
+ "mkdocs",
45
+ "mkdocs-material",
46
+ "mkdocs-autorefs",
47
+ "pymdown-extensions",
48
+ ]
49
+
50
+ [project.urls]
51
+ bugs = "https://github.com/unitysvc/unitysvc-py/issues"
52
+ homepage = "https://github.com/unitysvc/unitysvc-py"
53
+
54
+ [project.scripts]
55
+ usvc = "unitysvc_py.cli:app"
56
+
57
+ [tool.ruff]
58
+ line-length = 120
59
+ # openapi-python-client produces its own idiosyncratic formatting.
60
+ # Excluding keeps regenerations byte-stable — no post-processing
61
+ # step, no drift between the spec and the committed client.
62
+ extend-exclude = ["src/unitysvc_py/_generated"]
63
+
64
+ [tool.ruff.lint]
65
+ select = [
66
+ "E", # pycodestyle errors
67
+ "W", # pycodestyle warnings
68
+ "F", # Pyflakes
69
+ "I", # isort
70
+ "B", # flake8-bugbear
71
+ "UP", # pyupgrade
72
+ ]
73
+ ignore = [
74
+ "B008", # Typer pattern uses function calls in argument defaults
75
+ "B904",
76
+ ]
77
+
78
+ [tool.mypy]
79
+ ignore_missing_imports = true
80
+ warn_unused_ignores = false
81
+ disable_error_code = ["import-untyped"]
82
+
83
+ [tool.setuptools]
84
+ include-package-data = true
85
+
86
+ [tool.setuptools.package-data]
87
+ unitysvc_py = ["py.typed"]
88
+
89
+ [tool.pytest.ini_options]
90
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,68 @@
1
+ """UnitySVC Python SDK — customer-facing tools for UnitySVC.
2
+
3
+ This package provides:
4
+
5
+ - The :class:`Client` / :class:`AsyncClient` HTTP SDK targeting the
6
+ customer-tagged ``/v1/customer/*`` endpoints (aliases, recurrent
7
+ requests, secrets).
8
+ - The ``usvc`` CLI for managing the same resources from the terminal.
9
+
10
+ Quick start::
11
+
12
+ from unitysvc_py import Client
13
+
14
+ client = Client(api_key="svcpass_...")
15
+ secrets = client.secrets.list()
16
+
17
+ The customer context is encoded entirely in the API key, so no
18
+ separate ``customer_id`` is required. The default base URL points at
19
+ the staging environment; override with the ``base_url`` constructor
20
+ argument or the ``UNITYSVC_API_URL`` env var.
21
+ """
22
+
23
+ from .aclient import AsyncClient
24
+ from .client import (
25
+ DEFAULT_API_URL,
26
+ ENV_API_BASE_URL,
27
+ ENV_API_KEY,
28
+ ENV_API_URL,
29
+ ENV_S3_BASE_URL,
30
+ ENV_SMTP_BASE_URL,
31
+ Client,
32
+ )
33
+ from .exceptions import (
34
+ APIError,
35
+ AuthenticationError,
36
+ ConflictError,
37
+ NotFoundError,
38
+ PermissionError,
39
+ RateLimitError,
40
+ ServerError,
41
+ UnitysvcSDKError,
42
+ ValidationError,
43
+ )
44
+
45
+ __author__ = """Bo Peng"""
46
+ __email__ = "bo.peng@unitysvc.com"
47
+
48
+ __all__ = [
49
+ # Client
50
+ "Client",
51
+ "AsyncClient",
52
+ "DEFAULT_API_URL",
53
+ "ENV_API_KEY",
54
+ "ENV_API_URL",
55
+ "ENV_API_BASE_URL",
56
+ "ENV_S3_BASE_URL",
57
+ "ENV_SMTP_BASE_URL",
58
+ # Exceptions
59
+ "UnitysvcSDKError",
60
+ "APIError",
61
+ "AuthenticationError",
62
+ "PermissionError",
63
+ "NotFoundError",
64
+ "ValidationError",
65
+ "ConflictError",
66
+ "RateLimitError",
67
+ "ServerError",
68
+ ]
@@ -0,0 +1,8 @@
1
+
2
+ """ A client library for accessing UnitySVC Customer API """
3
+ from .client import AuthenticatedClient, Client
4
+
5
+ __all__ = (
6
+ "AuthenticatedClient",
7
+ "Client",
8
+ )
@@ -0,0 +1 @@
1
+ """ Contains methods for accessing the API """
@@ -0,0 +1 @@
1
+ """ Contains endpoint functions for accessing the API """