chore: regen API types + 5 DevEx round-3 SDK fixes#23
Merged
Conversation
Generated Pydantic models reject snake_case kwargs because extra='forbid' + validation_alias=camelCase is set without populate_by_name=True. Callers had to write CreateMonitorRequest(frequencySeconds=60, managedBy='API') even though the rest of the SDK is snake_case Python. Patch every model_config block (and the inject_strict_config.py template that emits them) so models accept both frequency_seconds=60 and frequencySeconds=60. Round-3 DevEx fix P1.Bug5. Co-authored-by: Cursor <cursoragent@cursor.com>
Generated unions like CreateAssertionRequest.config (41 members) had
no discriminator, so a typo on operator='eq' (should be 'equals')
emitted 161 validation errors as Pydantic tried every union arm.
Extend inject_strict_config.py with a post-pass that:
1. Identifies classes whose first payload field is a single-member
Literal[...] (the OpenAPI ``type``/``channel_type``/``check_type``
polymorphic-tag pattern), and
2. Rewrites parenthesized union fields whose every member shares
the same tag into Annotated[Union[...], Field(discriminator=...)].
After the patch, the same typo emits 1 error instead of 161, and
``ruff format`` reflows the long Annotated lines so the file stays
formatter-clean. Round-3 DevEx fix P0.Bug4.
Co-authored-by: Cursor <cursoragent@cursor.com>
``python -c 'import devhelm; print(devhelm.__version__)'`` previously
raised ``AttributeError`` because the top-level package didn't define
the attribute. Resolve it from ``importlib.metadata.version("devhelm")``
at import time so a single source of truth (pyproject.toml) flows
through to user code, and add ``"__version__"`` to ``__all__`` for
``from devhelm import *`` consumers. Round-3 DevEx fix P1.Bug14.
Co-authored-by: Cursor <cursoragent@cursor.com>
``client.monitors.list()`` previously took no parameters, forcing users to drop down to ``httpx`` to use the documented ``GET /api/v1/monitors`` filters. Surface ``enabled``, ``type``, ``managed_by``, ``tags``, ``search``, and ``environment_id`` as keyword-only arguments on both ``list()`` and ``list_page()``, projecting snake_case onto the camelCase wire names the API expects. Threaded through ``fetch_all_pages`` and ``fetch_page`` via a new ``extra_params`` keyword so future filter additions land in one place; pagination keys still win in the merge so the iterator's invariants stay intact. Round-3 DevEx fix P1.Bug7. Co-authored-by: Cursor <cursoragent@cursor.com>
The docs-quickstart at https://docs.devhelm.io/sdk/python/quickstart shows ``monitor.currentStatus`` but the field was removed from the DTO and never came back. Pre-existing SDK users hit this on upgrade and are stuck guessing how to recover the live status of a monitor. Inject a class-level docstring banner via ``inject_strict_config.py`` so the note shows up in IDE hovers and survives regeneration. The banner table is keyed by class name so future runtime-affecting upstream changes can land here without bloating the typegen. Restoring ``current_status`` properly is upstream work in mono; tracked separately. Round-3 DevEx fix P1.Bug9 (in-scope half). Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on the auto-regenerated Pydantic types (which pick up the new
MCPandAPIvalues onMonitorManagedBy) with five DevEx round-3 ergonomics fixes that surfaced while exercising the SDK from a fresh laptop.Summary
MCP/APIonMonitorManagedByf8eb9ebpopulate_by_name=True97cbc9fField(discriminator=…)on tagged unions — 161 errors → 119b182fdevhelm.__version__3bcc9f6client.monitors.list(enabled=…, type=…, …)filter kwargs66bec7bMonitorDtonotingcurrentStatusremoval (in-scope half)cc358faDetail
#2 —
populate_by_name=Trueextra='forbid'plusvalidation_alias=camelCaserejected snake_case kwargs, soCreateMonitorRequest(frequency_seconds=60, managed_by='API')raisedValidationError. Patched theinject_strict_config.pytemplate + every generatedmodel_configblock so models accept both spellings now.#3 — Discriminator on tagged unions
A typo on
operator='eq'(should be'equals') inside astatus_codeassertion previously emitted 161 validation errors because Pydantic walked every arm of the 41-member assertion union. Extendedinject_strict_config.pywith a post-pass that detects classes whose first payload field is a single-memberLiteral[…]and wraps qualifying parenthesized unions inAnnotated[Union[…], Field(discriminator=…)]. Applies toCreateAssertionRequest.config,UpdateAssertionRequest.config, alert-channel configs inCreate/Test/UpdateAlertChannelRequest, andMonitorTestRequest.config. Same input now emits 1 error.#4 —
devhelm.__version__python -c "import devhelm; print(devhelm.__version__)"raisedAttributeError. Resolves it fromimportlib.metadata.version("devhelm")at import time (with"unknown"fallback for editable installs) and lists it in__all__. Backed byTestSdkVersionExposedintests/test_client.py.#5 —
client.monitors.list(...)filtersSurfaces every documented
GET /api/v1/monitorsquery param (enabled,type,managed_by,tags,search,environment_id) as keyword-only arguments onMonitors.list()andMonitors.list_page(). Threaded through_pagination.fetch_all_pages/fetch_pagevia a newextra_paramskeyword so future filter additions land in one place. Pagination keys still win in the merge so the iterator's invariants stay intact. Backed byTestMonitorsListFiltersintests/test_client.py.#6 —
currentStatusdeprecation bannerThe docs-quickstart shows
monitor.currentStatus, but that field was removed from the DTO and never came back. Added a class-level docstring banner viainject_strict_config.py(keyed by class name in aCLASS_BANNERStable) so the note shows in IDE hovers and survives regen. Restoringcurrent_statusin the spec is upstream mono work, tracked separately.Verification
Out of scope
pyproject.tomlversion bump — that ships with the next release.current_statustoMonitorDtorequires editingmono; tracked as upstream follow-up.