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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/dedalus-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand All @@ -43,10 +43,10 @@ jobs:
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/dedalus-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand All @@ -61,7 +61,7 @@ jobs:
github.repository == 'stainless-sdks/dedalus-python' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setOutput('github_token', await core.getIDToken());

Expand All @@ -81,10 +81,10 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/dedalus-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.10.2'

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
id-token: write

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
with:
version: '0.9.13'

Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.2.0"
".": "0.3.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 29
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/dedalus-labs%2Fdedalus-018f649c40452f64a7454d2841a410297ef931793d4f6dbfebab541b060a2b21.yml
openapi_spec_hash: 7fd462f39c9dcf835904c06fea51ef46
config_hash: 816359ffd81767484efabdc39744bf77
configured_endpoints: 32
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/dedalus-labs/dedalus-8618662d24c795caf31ecb2b62c603c5cb1002386003f3a40854664da766eef4.yml
openapi_spec_hash: 4dd9388612970bff30995d2a4f53fa59
config_hash: 1459e41df47cbb91484141371c74dba9
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## 0.3.0 (2026-05-12)

Full Changelog: [v0.2.0...v0.3.0](https://github.com/dedalus-labs/dedalus-python/compare/v0.2.0...v0.3.0)

### Features

* **api:** add orgs usage endpoints, autosleep to machines, remove if_match parameters ([3ecc5f7](https://github.com/dedalus-labs/dedalus-python/commit/3ecc5f71350a236eeb38b6ca1116146378ea7f20))
* **internal/types:** support eagerly validating pydantic iterators ([d2686f3](https://github.com/dedalus-labs/dedalus-python/commit/d2686f3ea4d92a9b4c1ab211f62483dd2cdfc712))
* support setting headers via env ([31654ea](https://github.com/dedalus-labs/dedalus-python/commit/31654ea7dba81fd19b0c334846eb4bf988035224))


### Bug Fixes

* **client:** add missing f-string prefix in file type error message ([aa1c869](https://github.com/dedalus-labs/dedalus-python/commit/aa1c869547ee96d99910ac50f0962c02812cf844))
* use correct field name format for multipart file arrays ([09bc433](https://github.com/dedalus-labs/dedalus-python/commit/09bc4338396af1f0a28df189bd026ce052554532))


### Chores

* **internal:** reformat pyproject.toml ([6a4934a](https://github.com/dedalus-labs/dedalus-python/commit/6a4934a311b675e0b59dfe5e1d521e2d9405b62f))
* remove custom code ([e296321](https://github.com/dedalus-labs/dedalus-python/commit/e2963215b941cf1f14c44215f4c5ba8427ea00d4))

## 0.2.0 (2026-04-22)

Full Changelog: [v0.1.0...v0.2.0](https://github.com/dedalus-labs/dedalus-python/compare/v0.1.0...v0.2.0)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ from dedalus_sdk import Dedalus
client = Dedalus()

stream = client.machines.watch(
machine_id="machine_id",
machine_id="dm-3",
)
for machine in stream:
print(machine.machine_id)
Expand All @@ -142,7 +142,7 @@ from dedalus_sdk import AsyncDedalus
client = AsyncDedalus()

stream = await client.machines.watch(
machine_id="machine_id",
machine_id="dm-3",
)
async for machine in stream:
print(machine.machine_id)
Expand Down
22 changes: 22 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
# Orgs

## Usage

Types:

```python
from dedalus_sdk.types.orgs import (
MachineStorageUsage,
MachineStorageUsageEvidence,
MachineUsage,
MachineUsageEvidence,
OrgUsage,
)
```

Methods:

- <code title="get /v1/orgs/{org_id}/usage">client.orgs.usage.<a href="./src/dedalus_sdk/resources/orgs/usage.py">retrieve</a>(\*, org_id, \*\*<a href="src/dedalus_sdk/types/orgs/usage_retrieve_params.py">params</a>) -> <a href="./src/dedalus_sdk/types/orgs/org_usage.py">OrgUsage</a></code>
- <code title="get /v1/orgs/{org_id}/usage/storage/machines">client.orgs.usage.<a href="./src/dedalus_sdk/resources/orgs/usage.py">get_machine_storage_usage</a>(\*, org_id, \*\*<a href="src/dedalus_sdk/types/orgs/usage_get_machine_storage_usage_params.py">params</a>) -> <a href="./src/dedalus_sdk/types/orgs/machine_storage_usage.py">MachineStorageUsage</a></code>
- <code title="get /v1/orgs/{org_id}/usage/machines">client.orgs.usage.<a href="./src/dedalus_sdk/resources/orgs/usage.py">get_machine_usage</a>(\*, org_id, \*\*<a href="src/dedalus_sdk/types/orgs/usage_get_machine_usage_params.py">params</a>) -> <a href="./src/dedalus_sdk/types/orgs/machine_usage.py">MachineUsage</a></code>

# Machines

Types:
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "dedalus-sdk"
version = "0.2.0"
version = "0.3.0"
description = "The official Python library for the Dedalus API"
dynamic = ["readme"]
license = "MIT"
Expand Down Expand Up @@ -155,7 +155,7 @@ show_error_codes = true
#
# We also exclude our `tests` as mypy doesn't always infer
# types correctly and Pyright will still catch any type errors.
exclude = ['src/dedalus_sdk/_files.py', '_dev/.*.py', 'tests/.*']
exclude = ["src/dedalus_sdk/_files.py", "_dev/.*.py", "tests/.*"]

strict_equality = true
implicit_reexport = true
Expand Down
63 changes: 61 additions & 2 deletions src/dedalus_sdk/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
RequestOptions,
not_given,
)
from ._utils import is_given, get_async_library
from ._utils import (
is_given,
is_mapping_t,
get_async_library,
)
from ._compat import cached_property
from ._models import SecurityOptions
from ._version import __version__
Expand All @@ -33,7 +37,8 @@
)

if TYPE_CHECKING:
from .resources import machines
from .resources import orgs, machines
from .resources.orgs.orgs import OrgsResource, AsyncOrgsResource
from .resources.machines.machines import MachinesResource, AsyncMachinesResource

__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Dedalus", "AsyncDedalus", "Client", "AsyncClient"]
Expand Down Expand Up @@ -105,6 +110,15 @@ def __init__(
if base_url is None:
base_url = f"https://dcs.dedaluslabs.ai"

custom_headers_env = os.environ.get("DEDALUS_CUSTOM_HEADERS")
if custom_headers_env is not None:
parsed: dict[str, str] = {}
for line in custom_headers_env.split("\n"):
colon = line.find(":")
if colon >= 0:
parsed[line[:colon].strip()] = line[colon + 1 :].strip()
default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})}

super().__init__(
version=__version__,
base_url=base_url,
Expand All @@ -120,6 +134,12 @@ def __init__(

self._default_stream_cls = Stream

@cached_property
def orgs(self) -> OrgsResource:
from .resources.orgs import OrgsResource

return OrgsResource(self)

@cached_property
def machines(self) -> MachinesResource:
from .resources.machines import MachinesResource
Expand Down Expand Up @@ -339,6 +359,15 @@ def __init__(
if base_url is None:
base_url = f"https://dcs.dedaluslabs.ai"

custom_headers_env = os.environ.get("DEDALUS_CUSTOM_HEADERS")
if custom_headers_env is not None:
parsed: dict[str, str] = {}
for line in custom_headers_env.split("\n"):
colon = line.find(":")
if colon >= 0:
parsed[line[:colon].strip()] = line[colon + 1 :].strip()
default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})}

super().__init__(
version=__version__,
base_url=base_url,
Expand All @@ -354,6 +383,12 @@ def __init__(

self._default_stream_cls = AsyncStream

@cached_property
def orgs(self) -> AsyncOrgsResource:
from .resources.orgs import AsyncOrgsResource

return AsyncOrgsResource(self)

@cached_property
def machines(self) -> AsyncMachinesResource:
from .resources.machines import AsyncMachinesResource
Expand Down Expand Up @@ -513,6 +548,12 @@ class DedalusWithRawResponse:
def __init__(self, client: Dedalus) -> None:
self._client = client

@cached_property
def orgs(self) -> orgs.OrgsResourceWithRawResponse:
from .resources.orgs import OrgsResourceWithRawResponse

return OrgsResourceWithRawResponse(self._client.orgs)

@cached_property
def machines(self) -> machines.MachinesResourceWithRawResponse:
from .resources.machines import MachinesResourceWithRawResponse
Expand All @@ -526,6 +567,12 @@ class AsyncDedalusWithRawResponse:
def __init__(self, client: AsyncDedalus) -> None:
self._client = client

@cached_property
def orgs(self) -> orgs.AsyncOrgsResourceWithRawResponse:
from .resources.orgs import AsyncOrgsResourceWithRawResponse

return AsyncOrgsResourceWithRawResponse(self._client.orgs)

@cached_property
def machines(self) -> machines.AsyncMachinesResourceWithRawResponse:
from .resources.machines import AsyncMachinesResourceWithRawResponse
Expand All @@ -539,6 +586,12 @@ class DedalusWithStreamedResponse:
def __init__(self, client: Dedalus) -> None:
self._client = client

@cached_property
def orgs(self) -> orgs.OrgsResourceWithStreamingResponse:
from .resources.orgs import OrgsResourceWithStreamingResponse

return OrgsResourceWithStreamingResponse(self._client.orgs)

@cached_property
def machines(self) -> machines.MachinesResourceWithStreamingResponse:
from .resources.machines import MachinesResourceWithStreamingResponse
Expand All @@ -552,6 +605,12 @@ class AsyncDedalusWithStreamedResponse:
def __init__(self, client: AsyncDedalus) -> None:
self._client = client

@cached_property
def orgs(self) -> orgs.AsyncOrgsResourceWithStreamingResponse:
from .resources.orgs import AsyncOrgsResourceWithStreamingResponse

return AsyncOrgsResourceWithStreamingResponse(self._client.orgs)

@cached_property
def machines(self) -> machines.AsyncMachinesResourceWithStreamingResponse:
from .resources.machines import AsyncMachinesResourceWithStreamingResponse
Expand Down
2 changes: 1 addition & 1 deletion src/dedalus_sdk/_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles
elif is_sequence_t(files):
files = [(key, await _async_transform_file(file)) for key, file in files]
else:
raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence")
raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence")

return files

Expand Down
Loading
Loading