Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
23 changes: 21 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,31 @@ jobs:
- run: uv run --no-sync ruff format --check
- run: uv run --no-sync ruff check
- run: uv run --no-sync mypy
- run: uv run --no-sync pytest
- run: uv run --no-sync pytest tests/unit

# The real API may block some IP addresses of the GitHub runners (Azure) for their reputation:
# the integration tests run once, in a job that does not fail the workflow.
integration:
name: Integration tests (not blocking)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.2.0
with:
python-version: '3.14'
- run: uv sync --locked
- id: pytest
run: uv run --no-sync pytest tests/integration
continue-on-error: true
env:
# The integration tests are skipped unless these secrets are set.
SHELLRENT_CLIENT_ID: ${{ secrets.SHELLRENT_CLIENT_ID }}
SHELLRENT_CLIENT_SECRET: ${{ secrets.SHELLRENT_CLIENT_SECRET }}
SHELLRENT_API_URL: ${{ vars.SHELLRENT_API_URL }}
- if: steps.pytest.outcome == 'failure'
run: >-
echo "::warning title=Integration tests::The integration tests failed, perhaps because
the API blocks the IP address of the runner: see the log of the pytest step."

lowest-dependencies:
name: Checks (Python 3.11, lowest dependencies)
Expand All @@ -45,7 +64,7 @@ jobs:
- run: uv run --no-sync ruff format --check
- run: uv run --no-sync ruff check
- run: uv run --no-sync mypy
- run: uv run --no-sync pytest
- run: uv run --no-sync pytest tests/unit

generated-code:
name: Generated code is up to date
Expand Down
87 changes: 86 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,90 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.0.0] - 2026-10-16

Functions and models regenerated from the updated specification of the Shellrent API, which renames
paths, parameters and models: see the lists below to update the code written for 0.3.0.

### Added

- `create_prepaid_credit_payment` and `create_one_click_payment` (`payment`), which replace
`pay_orders`, with `PrepaidCreditPaymentCreateRequest` and `OneClickPaymentCreateRequest`.
- `create_server_power_action` (`server`), with `ServerPowerActionRequest`: it replaces
`start_server`, `stop_server`, `reboot_server`, `hard_stop_server` and `hard_reboot_server`.
- `can_reissue_ssl_certificate` and `reissue_ssl_certificate` (`ssl`), which replace
`can_reemit_ssl_certificate` and `reemit_ssl_certificate`.
- `get_pec_mailbox_owner_change` (`pec`) and `list_private_cloud_available_ip_addresses` (`server`).
- `License`, `LicenseResponse` and `LicensePaginatedListResponse`, for both cPanel and Plesk.
- `DomainDetail` and `DomainDetailResponse`, returned by `get_domain`; `DomainNameserver` and
`DomainPremiumPrices`.
- `Hosting.http_version`, `Hosting.file_protection_enabled` and `Hosting.php_settings`
(`HostingPhpSetting`), `DomainAvailability.premium` and `DomainAvailability.premium_prices`,
`ApiErrorMetaType0.errors` (the errors of each field in validation errors).
- Enums for request fields that were `str` or `int`: `DomainDnsRecordRequestType`,
`DomainDnsZoneRequestZoneTtl`, `HostingCronjobCreateRequestRequestProtocol`,
`HostingCronjobCreateRequestHttpRequestMethod`, `HostingHttpVersionUpdateRequestVersion`,
`HostingPhpSettingsUpdateRequestSetting`, `HostingSslCertificateInstallRequestCnType`,
`HostingSslCertificateInstallRequestDestinationType` and `SslCertificateExportRequestFormat`.

### Changed

- `unwrap()` returns `None` for a 204 No Content response instead of raising `UnexpectedStatus`:
the specification now documents 204 for the deletions, `cancel_order`, `cancel_purchase`,
`apply_domain_contact_changes`, `revoke_one_click_autorenew` and the payments with nothing to pay.
The generated functions type these responses as `Any` instead of `EmptyResponse`.
- Path parameters renamed: `creditnote_id` → `credit_note_id` (`billing`), `cronjob_id` →
`cron_job_id` (`hosting`), `microsoft365_id` → `microsoft_365_subscription_id` (`license_`),
`topup_id` → `top_up_id` (`get_prepaid_credit_topup`).
- Parameters moved from the path to keyword-only query parameters: `recurrence_id` of
`can_change_purchase_recurrence`, `status` of `can_change_purchase_renew_status`, `domain_name`
of `list_ssl_approver_emails`. `export_ssl_certificate` takes the format in the body
(`SslCertificateExportRequest`) instead of the positional `format_`.
- `create_hosting_database` has no body: the API chooses the name of the database.
- New keyword-only parameters: `one_click_id` and `prepaid_credit` of `can_pay_order`, `page` and
`per_page` of `list_sms_messages` and `list_sms_prices`. The `body` of `upload_file` is required
and `UploadFileBody` has the `file` field.
- Return types: `create_server_network_interface`, `delete_server_network_interface`,
`create_object_storage_bucket_firewall_entry` and `delete_object_storage_bucket_firewall_entry`
return `TaskResponse`; `update_private_cloud_virtual_machine` returns `EmptyResponse` when no
resource changes; `get_hosting_antivirus` returns `HostingAntivirusNullableResponse`.
- The default of `per_page` in the list operations is 20, as in the specification.
- `error` of the success envelopes is `Literal[0]`. The fields that are always null are `Any`:
`meta` of the envelopes that are not paginated lists, `data` of `EmptyResponse` and of `ApiError`.
- The package is classified as `Development Status :: 5 - Production/Stable`.
- Model fields: many fields are now nullable or required as in the API, some request fields are
enums (see Added), `Domain.nameservers` is a list of `DomainNameserver`,
`Payment.provider_data` is `PaymentProviderData | None`, `ObjectStorage.code`,
`ObjectStorageBucket.code` and `ObjectStorageIamUser.code` are `int | None`,
`ObjectStorageBucket.creation_date` is a date, `ApiUpload.upload_date` a datetime, the `tlsa_*`
fields of `HostingDnsRecord` are `int | None`, `Creditnote.creditnote_year` is `int | None`.

### Removed

- `pay_orders` and `OrderPayRequest`: use `create_prepaid_credit_payment` or
`create_one_click_payment`.
- `start_server`, `stop_server`, `reboot_server`, `hard_stop_server` and `hard_reboot_server`: use
`create_server_power_action`. `start_server_first_backup` and `create_hosting_catch_all` (use
`update_hosting_catch_all`, which creates or replaces it).
- Secure Mail: `buy_secure_mail`, `buy_secure_mail_for_google_workspace`,
`buy_secure_mail_for_microsoft_365`, `list_secure_mails`, `get_secure_mail`,
`get_secure_mail_statistics`, `list_secure_mail_mailboxes`, `upgrade_secure_mail_quantity`,
`downgrade_secure_mail_quantity`, the `Securemail*` and `BuyServiceSecuremail*` models and
`Purchase.securemail_id`.
- `can_reemit_ssl_certificate`, `reemit_ssl_certificate` and `SslCertificateCanReemit*`.
- Models renamed: `CpanelLicense*` and `PleskLicense*` → `License*`, `DomainResponse` →
`DomainDetailResponse`, `HostingEmailBlocList*` → `HostingEmailBlockList*`,
`PaymentProviderDataType0` → `PaymentProviderData`, `GetHostingAntivirusResponse200` →
`HostingAntivirusNullableResponse`. Also removed: the `*ResponseMetaType0` models of the `meta`
that is always null (such as `PaymentResponseMetaType0`), `EmptyResponseDataType0`,
`ApiErrorDataType0`, `HostingDatabaseCreateRequest`, `PayOrdersResponse200`,
`BuyServiceObjectStorageRequestConfigurationTbSize` (`tb_size` is an `int`).
- Fields no longer in the API: `Domain.dnssec_enabled`, the `ns_*_ip` of
`DomainDnsNameserversChangeRequest`, `HostingSubdomainCreateRequest.subdomain`,
`Microsoft365DomainAvailable.microsoft_uuid`, `ObjectStorageIamUser.firewall_policy`,
`OneClick.one_click_preference`, `PecOwnerChange.person_id_accept` and `person_id_reject`,
`ServerBackup.backup_path` and `backup_path_parent`.

## [0.3.0] - 2026-10-01

### Added
Expand Down Expand Up @@ -73,7 +157,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`invalid_client` or, for its rate limit, `rate_limited`.
- The `shellrent` command, with `shellrent api` and `shellrent token`.

[Unreleased]: https://github.com/shellrent/shellrent-sdk-python/compare/v0.3.0...HEAD
[Unreleased]: https://github.com/shellrent/shellrent-sdk-python/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/shellrent/shellrent-sdk-python/compare/v0.3.0...v1.0.0
[0.3.0]: https://github.com/shellrent/shellrent-sdk-python/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/shellrent/shellrent-sdk-python/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/shellrent/shellrent-sdk-python/releases/tag/v0.1.0
7 changes: 5 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ da `spec/openapi.yaml`; a mano solo autenticazione, creazione del client, CLI, t
chiave della CA non è conservata: per rifarli crea una nuova CA e aggiorna `CA_HASH_NAME`.
- `tests/integration` chiama l'API reale solo con `SHELLRENT_CLIENT_ID` e `SHELLRENT_CLIENT_SECRET` (e
opzionalmente `SHELLRENT_API_URL`); `test_errors.py` richiede lo scope `purchases:read`.
- La CI esegue ruff, mypy e pytest su Python 3.11-3.14, gli stessi controlli su 3.11 con le dipendenze minime
(`uv sync --resolution lowest-direct`) e `bin/generate`, fallendo se il codice rigenerato è diverso.
- La CI esegue ruff, mypy e i test unitari su Python 3.11-3.14, gli stessi controlli su 3.11 con le dipendenze
minime (`uv sync --resolution lowest-direct`) e `bin/generate`, fallendo se il codice rigenerato è diverso.
- I test di integrazione girano una sola volta (Python 3.14) nel job `Integration tests (not blocking)`: l'API
può bloccare alcuni IP dei runner GitHub (Azure) per la reputazione, quindi un fallimento lascia il workflow
verde con un warning nel riepilogo della run. Se falliscono spesso, verificali a mano con le credenziali.

## Vincoli

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ As with httpx, the requests follow the proxy and certificate settings of the env
`sync()` and `asyncio()` return the error responses documented in the specification as `ApiError`,
the error envelope, so you would check the type of every result. `unwrap()` does that for you: it
takes the result of `sync_detailed()` or `asyncio_detailed()`, returns the parsed body of a 2xx
response and raises `ApiException` for the documented errors.
response (`None` for 204 No Content, such as most deletions) and raises `ApiException` for the
documented errors.

```python
import httpx
Expand Down Expand Up @@ -238,12 +239,12 @@ shellrent api GET /api/v3/purchases | jq '.data[] | {purchase_id, name: .purchas
shellrent api GET '/api/v3/purchases?page=2&per_page=50' | jq -r '.data[].purchase_id'

# JSON body: as text, from a file with @, from stdin with -
shellrent api POST /api/v3/orders/pay --data '{"order_ids": [123], "use_prepaid_credit": true}'
shellrent api POST /api/v3/orders/pay --data @order.json
jq -n '{order_ids: [123], use_prepaid_credit: true}' | shellrent api POST /api/v3/orders/pay --data -
shellrent api POST /api/v3/payments/prepaid-credit --data '{"order_ids": [123]}'
shellrent api POST /api/v3/payments/prepaid-credit --data @order.json
jq -n '{order_ids: [123]}' | shellrent api POST /api/v3/payments/prepaid-credit --data -

# Files are written as they are
shellrent api GET /api/v3/invoices/456/download/pdf > invoice.pdf
shellrent api GET /api/v3/invoices/456/pdf > invoice.pdf

# An access token for other tools
curl -H "Authorization: Bearer $(shellrent token)" https://api.shellrent.com/api/v3/purchases
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ authors = [{ name = "Shellrent S.r.l." }]
requires-python = ">=3.11"
keywords = ["shellrent", "api", "sdk", "client", "hosting", "domains", "openapi"]
classifiers = [
"Development Status :: 4 - Beta",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
Expand Down
Loading
Loading