uptimer-python-sdk 0.4.0__tar.gz → 1.6.0rc0__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 (82) hide show
  1. uptimer_python_sdk-1.6.0rc0/CHANGELOG.md +80 -0
  2. uptimer_python_sdk-1.6.0rc0/PKG-INFO +344 -0
  3. uptimer_python_sdk-1.6.0rc0/README.md +328 -0
  4. uptimer_python_sdk-1.6.0rc0/Taskfile.yml +35 -0
  5. uptimer_python_sdk-1.6.0rc0/examples/01_client_setup.py +21 -0
  6. uptimer_python_sdk-1.6.0rc0/examples/02_list_workspaces.py +10 -0
  7. uptimer_python_sdk-1.6.0rc0/examples/03_list_locations.py +13 -0
  8. uptimer_python_sdk-1.6.0rc0/examples/04_create_website_monitor.py +43 -0
  9. uptimer_python_sdk-1.6.0rc0/examples/05_open_incidents.py +26 -0
  10. uptimer_python_sdk-1.6.0rc0/examples/README.md +33 -0
  11. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/pyproject.toml +8 -3
  12. uptimer_python_sdk-1.6.0rc0/src/uptimer/__init__.py +12 -0
  13. uptimer_python_sdk-1.6.0rc0/src/uptimer/client.py +71 -0
  14. uptimer_python_sdk-1.6.0rc0/src/uptimer/compat.py +58 -0
  15. uptimer_python_sdk-1.6.0rc0/src/uptimer/endpoints/incidents.py +37 -0
  16. uptimer_python_sdk-0.4.0/src/uptimer/endpoints/regions.py → uptimer_python_sdk-1.6.0rc0/src/uptimer/endpoints/locations.py +7 -6
  17. uptimer_python_sdk-1.6.0rc0/src/uptimer/endpoints/subjects.py +154 -0
  18. uptimer_python_sdk-1.6.0rc0/src/uptimer/endpoints/v2.py +41 -0
  19. uptimer_python_sdk-1.6.0rc0/src/uptimer/endpoints/websites.py +116 -0
  20. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/src/uptimer/endpoints/workspaces.py +4 -3
  21. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/src/uptimer/errors.py +18 -0
  22. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/src/uptimer/http.py +12 -1
  23. uptimer_python_sdk-1.6.0rc0/src/uptimer/models/__init__.py +29 -0
  24. uptimer_python_sdk-1.6.0rc0/src/uptimer/models/v2/__init__.py +96 -0
  25. uptimer_python_sdk-1.6.0rc0/src/uptimer/models/v2/deserialize.py +131 -0
  26. uptimer_python_sdk-1.6.0rc0/src/uptimer/models/v2/incident.py +39 -0
  27. uptimer_python_sdk-1.6.0rc0/src/uptimer/models/v2/location.py +16 -0
  28. uptimer_python_sdk-1.6.0rc0/src/uptimer/models/v2/monitor.py +88 -0
  29. uptimer_python_sdk-1.6.0rc0/src/uptimer/models/v2/observation.py +71 -0
  30. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/tests/integrations/conftest.py +2 -3
  31. uptimer_python_sdk-1.6.0rc0/tests/integrations/test_observations.py +143 -0
  32. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/tests/integrations/test_workspaces.py +4 -4
  33. uptimer_python_sdk-1.6.0rc0/tests/test_client.py +114 -0
  34. uptimer_python_sdk-1.6.0rc0/tests/test_integration_v2.py +274 -0
  35. uptimer_python_sdk-1.6.0rc0/tests/test_model_namespace.py +131 -0
  36. uptimer_python_sdk-1.6.0rc0/tests/test_observations_endpoint.py +217 -0
  37. uptimer_python_sdk-1.6.0rc0/tests/test_v2_endpoints.py +134 -0
  38. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/tests/test_workspaces_endpoint.py +2 -2
  39. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/uv.lock +1 -1
  40. uptimer_python_sdk-0.4.0/CHANGELOG.md +0 -25
  41. uptimer_python_sdk-0.4.0/PKG-INFO +0 -203
  42. uptimer_python_sdk-0.4.0/README.md +0 -190
  43. uptimer_python_sdk-0.4.0/Taskfile.yml +0 -54
  44. uptimer_python_sdk-0.4.0/examples/01_client_setup.py +0 -14
  45. uptimer_python_sdk-0.4.0/examples/02_list_workspaces.py +0 -12
  46. uptimer_python_sdk-0.4.0/examples/03_list_regions.py +0 -12
  47. uptimer_python_sdk-0.4.0/examples/04_list_rules.py +0 -13
  48. uptimer_python_sdk-0.4.0/examples/05_get_rule.py +0 -13
  49. uptimer_python_sdk-0.4.0/examples/06_create_rule.py +0 -41
  50. uptimer_python_sdk-0.4.0/examples/07_update_rule.py +0 -37
  51. uptimer_python_sdk-0.4.0/examples/08_delete_rule.py +0 -13
  52. uptimer_python_sdk-0.4.0/examples/README.md +0 -40
  53. uptimer_python_sdk-0.4.0/src/uptimer/__init__.py +0 -3
  54. uptimer_python_sdk-0.4.0/src/uptimer/client.py +0 -26
  55. uptimer_python_sdk-0.4.0/src/uptimer/endpoints/rules.py +0 -75
  56. uptimer_python_sdk-0.4.0/src/uptimer/endpoints/v1.py +0 -17
  57. uptimer_python_sdk-0.4.0/src/uptimer/models/__init__.py +0 -47
  58. uptimer_python_sdk-0.4.0/src/uptimer/models/deserialize.py +0 -121
  59. uptimer_python_sdk-0.4.0/src/uptimer/models/region.py +0 -9
  60. uptimer_python_sdk-0.4.0/src/uptimer/models/rule.py +0 -60
  61. uptimer_python_sdk-0.4.0/tests/test_client.py +0 -37
  62. uptimer_python_sdk-0.4.0/tests/test_regions_endpoint.py +0 -46
  63. uptimer_python_sdk-0.4.0/tests/test_rules_endpoint.py +0 -596
  64. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/.gitignore +0 -0
  65. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/.pre-commit-config.yaml +0 -0
  66. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/.vscode/extensions.json +0 -0
  67. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/.vscode/launch.json +0 -0
  68. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/.vscode/settings.json +0 -0
  69. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/.vscode/tasks.json +0 -0
  70. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/LICENSE +0 -0
  71. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/NOTICE +0 -0
  72. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/examples/__init__.py +0 -0
  73. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/src/uptimer/endpoints/__init__.py +0 -0
  74. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/src/uptimer/endpoints/endpoint.py +0 -0
  75. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/src/uptimer/models/errors.py +0 -0
  76. {uptimer_python_sdk-0.4.0/src/uptimer/models → uptimer_python_sdk-1.6.0rc0/src/uptimer/models/v2}/workspace.py +0 -0
  77. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/src/uptimer/py.typed +0 -0
  78. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/tests/__init__.py +0 -0
  79. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/tests/conftest.py +0 -0
  80. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/tests/integrations/__init__.py +0 -0
  81. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/tests/test_endpoint.py +0 -0
  82. {uptimer_python_sdk-0.4.0 → uptimer_python_sdk-1.6.0rc0}/tools/mypy-diff.sh +0 -0
@@ -0,0 +1,80 @@
1
+ ## 1.6.0-rc.0 (2026-08-30)
2
+
3
+ ### Feat
4
+
5
+ - **api**: post custom observations via client.v2 subjects/signals
6
+
7
+ ## 1.5.0 (2026-08-20)
8
+
9
+ ### BREAKING CHANGE
10
+
11
+ - Targets Uptimer **API v2 only**. The `client.v1` namespace, its models and its
12
+ kinds are gone. Code written against 0.4.x keeps working **against the
13
+ server** — API v1 is unchanged and supported — but must pin
14
+ `uptimer-python-sdk<1`.
15
+ - The version now tracks the uptimer release it targets, so this is 1.5.0 rather
16
+ than 1.0.0: 1.5.x speaks to uptimer 1.5.0 and later. Patch numbers stay
17
+ independent (product Decision 0013).
18
+
19
+ ### Feat
20
+
21
+ - `client.v2.workspaces`, `client.v2.locations`, `client.v2.incidents` and
22
+ `client.v2.monitoring.websites` replace the v1 namespace. The API version stays
23
+ visible in the SDK, as it was in 0.4.x — there are no root-level aliases.
24
+ - **Types are versioned too:** import them from `uptimer.models.v2`
25
+ (`Location`, `Incident`, `Workspace`, the website-monitor classes, the
26
+ `AGREEMENT_*` / `STATUS_*` constants and the `from_api*` helpers). They are no
27
+ longer exported from `uptimer.models`, and there are no flat aliases. The
28
+ deserialization exceptions stay on `uptimer.models`, being
29
+ version-independent.
30
+ - `client.v2.incidents` reads **open** incidents, with the same five status words
31
+ the Uptimer screens use — `problem`, `pending`, `recovering`, `no_data`, `ok`.
32
+ `pending` means failing but inside the confirm hold: nobody has been notified
33
+ yet.
34
+ - Website monitors carry `agreement` (`any`, `majority`, `all`) — how many
35
+ locations must report a problem before the monitor does. Omitting it on update
36
+ keeps the stored value.
37
+ - `client.check_compatibility()` refuses a server that predates API v2 with a
38
+ message naming the fix, instead of a bare 404 on the first call.
39
+
40
+ ### Migration
41
+
42
+ | 0.4.x | 1.5.0 |
43
+ |---|---|
44
+ | `client.v1.workspaces` | `client.v2.workspaces` |
45
+ | `client.v1.regions` | `client.v2.locations` |
46
+ | `client.v1.rules` | `client.v2.monitoring.websites` |
47
+ | `Region` | `Location` |
48
+ | `Rule` / `CreateRuleRequest` | `WebsiteMonitor` / `CreateWebsiteMonitorRequest` |
49
+ | `regions=[...]` | `locations=[...]` |
50
+ | — | `agreement=...`, `client.v2.incidents` |
51
+ | `from uptimer.models import …` | `from uptimer.models.v2 import …` |
52
+
53
+ `client.version()` and the compatibility helpers are unchanged and stay on the
54
+ client itself: `/version` is a shared global endpoint, not a versioned one.
55
+
56
+ ## 0.4.0 (2026-07-15)
57
+
58
+ ### Feat
59
+
60
+ - assign regions (by name) when creating or updating a rule via `rules.create`/`rules.update`; rules now expose a `regions` field
61
+
62
+ ## 0.3.0 (2025-08-19)
63
+
64
+ ### Feat
65
+
66
+ - self-hosted client now requires a base_url, added cloud client, updated docs
67
+
68
+ ## 0.2.0 (2025-08-10)
69
+
70
+ ### Feat
71
+
72
+ - create/update/delete rule methods.
73
+ - added method to get all rules
74
+ - added regions and get rule API
75
+ - added getting workspace list
76
+ - add Cursor IDE configuration for testing and development
77
+
78
+ ### Fix
79
+
80
+ - fixed dependencies in pyproject.toml
@@ -0,0 +1,344 @@
1
+ Metadata-Version: 2.5
2
+ Name: uptimer-python-sdk
3
+ Version: 1.6.0rc0
4
+ Summary: A Python SDK for hosted and self-hosted Uptimer
5
+ Project-URL: Homepage, https://myuptime.info
6
+ Project-URL: Documentation, https://uptimer.myuptime.info/latest/reference/python-sdk/
7
+ Project-URL: Repository, https://github.com/myuptime-info/uptimer-python-sdk
8
+ Project-URL: Changelog, https://myuptime.info/product-updates
9
+ Author-email: Roman Zadoev <zadoev@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ License-File: NOTICE
13
+ Requires-Python: >=3.9
14
+ Requires-Dist: httpx>=0.28.1
15
+ Description-Content-Type: text/markdown
16
+
17
+ # Uptimer Python SDK
18
+
19
+ A Python SDK for hosted and self-hosted Uptimer.
20
+
21
+ * [Hosted Uptimer](https://myuptime.info)
22
+ * [Self-hosted documentation](https://uptimer.myuptime.info)
23
+ * [PyPI package](https://pypi.org/project/uptimer-python-sdk/)
24
+ * [Uptimer resources](https://myuptime.info/resources)
25
+ * [Product updates](https://myuptime.info/product-updates)
26
+
27
+ ## License
28
+
29
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
30
+
31
+ For third-party license information, see the [NOTICE](NOTICE) file.
32
+
33
+ ## Installation
34
+
35
+ ```shell
36
+ pip install uptimer-python-sdk
37
+ ```
38
+
39
+ or
40
+ ```shell
41
+ uv add uptimer-python-sdk
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ ### Create client
47
+
48
+ #### self-hosted
49
+
50
+ ```python
51
+ from uptimer.client import UptimerClient
52
+ client = UptimerClient(
53
+ api_key="your-api-key-here",
54
+ base_url="http://127.0.0.1:2517/api", # or your custom base URL
55
+ )
56
+ ```
57
+
58
+ #### cloud
59
+ ```python
60
+ from uptimer.client import UptimerCloudClient
61
+ client = UptimerCloudClient(
62
+ api_key="your-api-key-here",
63
+ )
64
+ ```
65
+
66
+ ### Basic example
67
+
68
+ ```python
69
+ from uptimer.client import UptimerClient
70
+ from uptimer.errors import (
71
+ DefaultUptimerApiError,
72
+ IncompatibleServerError,
73
+ UptimerError,
74
+ UptimerInvalidHttpCodeError,
75
+ )
76
+ from uptimer.models.v2 import (
77
+ AGREEMENT_MAJORITY,
78
+ CreateWebsiteMonitorRequest,
79
+ UpdateWebsiteMonitorRequest,
80
+ WebsiteMonitorRequest,
81
+ WebsiteMonitorResponse,
82
+ WebsiteMonitorResponseBody,
83
+ )
84
+
85
+ client = UptimerClient(
86
+ api_key="your-api-key-here",
87
+ base_url="http://127.0.0.1:2517/api", # or your custom base URL
88
+ )
89
+
90
+ # Optional: fail fast with a message that names the fix, rather than a 404 on
91
+ # the first real call.
92
+ print("server:", client.check_compatibility())
93
+
94
+ workspace = client.v2.workspaces.all()[0]
95
+ locations = [location.name for location in client.v2.locations.all()]
96
+
97
+ monitor = client.v2.monitoring.websites.create(
98
+ CreateWebsiteMonitorRequest(
99
+ name="Checkout API",
100
+ interval=60, # seconds between probes
101
+ workspace_id=workspace.id,
102
+ request=WebsiteMonitorRequest(
103
+ url="https://checkout.example/health",
104
+ method="GET", # one of GET, POST, PATCH, OPTIONS
105
+ content_type="application/json",
106
+ data="",
107
+ ),
108
+ response=WebsiteMonitorResponse(
109
+ statuses=[200, 201], # any of these means the site is up
110
+ body=WebsiteMonitorResponseBody(content="ok"), # expected substring
111
+ ),
112
+ locations=locations,
113
+ # How many locations must report a problem before this monitor does:
114
+ # "any", "majority" or "all". Omit to keep the server default.
115
+ agreement=AGREEMENT_MAJORITY,
116
+ ),
117
+ )
118
+
119
+ monitor = client.v2.monitoring.websites.update(
120
+ monitor.id,
121
+ UpdateWebsiteMonitorRequest(
122
+ name="Checkout API",
123
+ interval=120,
124
+ request=WebsiteMonitorRequest(url="https://checkout.example/health", method="GET"),
125
+ response=WebsiteMonitorResponse(statuses=[200]),
126
+ locations=locations,
127
+ # Omitting agreement here keeps the stored one.
128
+ ),
129
+ )
130
+
131
+ # What is wrong right now. Only open incidents come back.
132
+ for incident in client.v2.incidents.all(workspace.id):
133
+ print(incident.monitor_name, incident.status, incident.locations.failing)
134
+
135
+ try:
136
+ client.v2.monitoring.websites.delete(monitor.id)
137
+ except DefaultUptimerApiError as e:
138
+ # error responses from the uptimer server
139
+ print(
140
+ e.message, # user message
141
+ e.code, # error id
142
+ e.error_type, # class of error
143
+ e.details, # detailed message for a developer
144
+ )
145
+ except IncompatibleServerError as e:
146
+ # the server does not provide API v2 — see Migrating from 0.4.x below
147
+ print(e)
148
+ except UptimerInvalidHttpCodeError as e:
149
+ # the uptimer api always returns 200; anything else is a transport error.
150
+ # a 404 really is "no such URL", not "no object with that id".
151
+ print(e.url, e.status_code)
152
+ except UptimerError: # base error, if you need one
153
+ raise
154
+ ```
155
+
156
+ ### Reporting your own observations
157
+
158
+ Uptimer probes websites itself. For anything else — a cron job, a queue worker,
159
+ a nightly export — you add a **custom signal** to a subject in the Uptimer UI
160
+ and report to it yourself.
161
+
162
+ Requires Uptimer 1.6.0 or later, and a **custom heartbeat or event** signal. The
163
+ platform HTTP signal of a website monitor is written by Uptimer's own probe and
164
+ refuses posted observations.
165
+
166
+ ```python
167
+ from uptimer.client import UptimerClient
168
+ from uptimer.models.v2 import (
169
+ OBSERVATION_STATUS_OK,
170
+ OBSERVATION_STATUS_PROBLEM,
171
+ CreateObservationRequest,
172
+ )
173
+
174
+ client = UptimerClient(
175
+ api_key="your-api-key-here",
176
+ base_url="http://127.0.0.1:2517/api",
177
+ )
178
+
179
+ # The two slugs are the address: the subject, and the signal within it. Both
180
+ # are shown on the signal's page in the Uptimer UI.
181
+ observations = client.v2.subjects("checkout-api").signals("worker-pulse").observations
182
+
183
+ # A heartbeat: "I ran, and I am fine."
184
+ stored = observations.create(CreateObservationRequest(status=OBSERVATION_STATUS_OK))
185
+
186
+ # Everything except status is optional.
187
+ stored = observations.create(
188
+ CreateObservationRequest(
189
+ status=OBSERVATION_STATUS_PROBLEM,
190
+ observed_at="2026-08-30T12:00:00Z", # RFC 3339; omit to mean "now"
191
+ value=0.0, # optional numeric reading
192
+ error="queue backlog over threshold",
193
+ labels={"instance": "worker-3", "env": "prod"},
194
+ ),
195
+ )
196
+
197
+ print(stored.accepted, stored.reject_reason)
198
+ ```
199
+
200
+ `accepted` reports **acceptance, not health**: it says Uptimer stored the
201
+ observation and may evaluate it, not that anything is wrong or fine. Whether an
202
+ observation raises an incident is decided by a *rule* that selects the signal.
203
+
204
+ An observation Uptimer keeps but will not evaluate — one stamped too far in the
205
+ future, say — comes back with `accepted=False` and a `reject_reason` such as
206
+ `clock_skew`. It is **returned, not raised**: it was received. An exception
207
+ means nothing was stored.
208
+
209
+ Retries are safe. An observation is identified by its signal, its `observed_at`
210
+ and its labels, so re-sending the same one replaces it rather than counting
211
+ twice.
212
+
213
+ ### Incident status
214
+
215
+ `client.v2.incidents.all()` returns only **open** incidents. `status` carries the
216
+ same words the Uptimer screens show, so a client and the UI cannot disagree:
217
+
218
+ | status | meaning |
219
+ |---|---|
220
+ | `problem` | confirmed, and notifications have gone out |
221
+ | `pending` | failing, but inside the confirm hold — **nobody has been notified yet** |
222
+ | `recovering` | reporting ok again while the incident is still open |
223
+ | `no_data` | nothing usable arrived; a silent location counts toward the agreement |
224
+ | `ok` | healthy |
225
+
226
+ `locations.failing` / `.unknown` / `.ok` is the evidence the verdict was taken
227
+ from. A location that has never reported stays in `unknown` — that is a real
228
+ state, not a missing one.
229
+
230
+ ### Migrating from 0.4.x
231
+
232
+ **1.5.0 targets API v2 only.** Your existing 0.4.x code keeps working against
233
+ the server — API v1 is unchanged and supported — but it must stay on the 0.4.x
234
+ SDK. Pin `uptimer-python-sdk<1` if you are not ready to move.
235
+
236
+ What changed:
237
+
238
+ | 0.4.x (API v1) | 1.5.0 (API v2) |
239
+ |---|---|
240
+ | `client.v1.workspaces` | `client.v2.workspaces` |
241
+ | `client.v1.regions` | `client.v2.locations` |
242
+ | `client.v1.rules` | `client.v2.monitoring.websites` |
243
+ | `Region` | `Location` |
244
+ | `Rule`, `CreateRuleRequest` | `WebsiteMonitor`, `CreateWebsiteMonitorRequest` |
245
+ | `regions=[...]` | `locations=[...]` |
246
+ | — | `agreement="any"|"majority"|"all"` |
247
+ | — | `client.v2.incidents` |
248
+ | `from uptimer.models import …` | `from uptimer.models.v2 import …` |
249
+
250
+ **The version namespace stays, and now covers the types too.** As in 0.4.x,
251
+ resources sit under the API version that serves them — `client.v1.*` becomes
252
+ `client.v2.*`, not a bare `client.*` — and the models follow: import them from
253
+ `uptimer.models.v2`, not from `uptimer.models`. The HTTP API is versioned by
254
+ path, so the SDK shows the same thing rather than hiding it. There are no
255
+ root-level aliases for either surface, so a stale flat import fails loudly
256
+ instead of silently binding to the wrong thing.
257
+
258
+ The deserialization exceptions (`ModelError`, `TypeMismatchError`, …) stay on
259
+ `uptimer.models`: the same error is raised whichever API version produced the
260
+ payload, so versioning them would say something untrue.
261
+
262
+ Why `monitoring.websites` rather than `monitors`: website monitoring is a
263
+ built-in template, not the general model. Keeping the bare name free lets other
264
+ monitor types arrive later without renaming this one.
265
+
266
+ `client.version()`, `client.check_compatibility()` and
267
+ `client.ensure_compatible()` are unchanged and stay on the client itself —
268
+ `/version` is a shared global endpoint, not a versioned one, so it works against
269
+ any server, including one too old for the rest of this SDK.
270
+
271
+ **Why 1.5.0 and not 1.0.0:** the SDK's major.minor tracks the uptimer release it
272
+ targets, so the version is the compatibility statement — 1.5.x speaks to uptimer
273
+ 1.5.0 and later. Patch numbers are independent, so an SDK fix can ship without a
274
+ server release.
275
+
276
+ Also, check out the [examples directory](https://github.com/myuptime-info/uptimer-python-sdk/tree/main/examples).
277
+
278
+ ### Development Setup
279
+
280
+ 1. Clone the repository:
281
+
282
+ ```bash
283
+ git clone <repository-url>
284
+ cd uptimer-python-sdk
285
+ ```
286
+
287
+ 2. Install dependencies:
288
+
289
+ ```bash
290
+ uv sync --dev
291
+ # for integration tests
292
+ uv run playwright install chromium
293
+ ```
294
+
295
+ 3. Run tests:
296
+
297
+ ```bash
298
+ uv run pytest
299
+ # integration
300
+ docker pull ghcr.io/myuptime-info/uptimer:1.3.0
301
+ docker run -p 2517:2517 ghcr.io/myuptime-info/uptimer:1.3.0
302
+ UPTIMER_URL=http://localhost:2517 uv run --integration
303
+ ```
304
+
305
+ 4. Run linting:
306
+
307
+ ```bash
308
+ uv run ruff check .
309
+ uv run mypy src
310
+ ```
311
+
312
+ 5. Format code:
313
+
314
+ ```bash
315
+ uv run ruff format .
316
+ ```
317
+
318
+ 6. Run pre-commit hooks:
319
+
320
+ ```bash
321
+ uv run pre-commit run --all-files
322
+ ```
323
+
324
+ ## Third-Party Licenses
325
+
326
+ This project uses the following third-party libraries:
327
+
328
+ ### Production Dependencies
329
+
330
+ - **httpx** (BSD 3-Clause License) - HTTP client for Python
331
+
332
+ ### Development Dependencies
333
+
334
+ - **mypy** (Apache 2.0 License) - Static type checker
335
+ - **playwright** (Apache 2.0 License) - Browser automation
336
+ - **pre-commit** (MIT License) - Git hooks framework
337
+ - **pytest** (MIT License) - Testing framework
338
+ - **pytest-cov** (MIT License) - Coverage plugin for pytest
339
+ - **pytest-httpx** (MIT License) - HTTPX plugin for pytest
340
+ - **pytest-playwright** (MIT License) - Playwright plugin for pytest
341
+ - **responses** (Apache 2.0 License) - Mock library for requests
342
+ - **ruff** (MIT License) - Fast Python linter and formatter
343
+
344
+ All third-party licenses are compatible with the MIT License used by this project. Note that the BSD 3-Clause License (used by httpx) includes an additional restriction prohibiting the use of the copyright holder's name for endorsement without permission.