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
54 changes: 37 additions & 17 deletions .dagger/modules/e2e/main.dang
Original file line number Diff line number Diff line change
Expand Up @@ -940,8 +940,8 @@ type E2e {
let ws = withScope(scope, tomlGenerateModulePath, "toml-generate-app")
let pyprojectPath = tomlGenerateModulePath + "/pyproject.toml"
let pyproject = ws.file("/" + pyprojectPath).contents
let onFloor = pyproject.replace("requires-python = \">=3.14\"", "requires-python = \">=3.12\"")
let belowFloor = pyproject.replace("requires-python = \">=3.14\"", "requires-python = \">=3.11\"")
let onFloor = pyproject.replace("requires-python = \">=3.14\"", "requires-python = \">=3.11\"")
let belowFloor = pyproject.replace("requires-python = \">=3.14\"", "requires-python = \">=3.10\"")
assert(belowFloor != pyproject, "the fixture asks for no Python to lower")

let floor = pythonSdk.mod(ws.withNewFile("/" + pyprojectPath, onFloor), path: tomlGenerateModulePath).generate
Expand All @@ -951,8 +951,8 @@ type E2e {
err: Error => err.message
}
assertContainsAll(older, [
"the module at " + tomlGenerateModulePath + ": this Python SDK needs Python 3.12 or later",
"requires-python = \">=3.11\" asks for Python 3.11. Ask for Python 3.12 or later",
"the module at " + tomlGenerateModulePath + ": this Python SDK needs Python 3.11 or later",
"requires-python = \">=3.10\" asks for Python 3.10. Ask for Python 3.11 or later",
"pin the last release of this SDK that runs on it: dagger module install github.com/dagger/python-sdk@v1.2.0",
"then run dagger generate again",
])
Expand All @@ -961,24 +961,24 @@ type E2e {
let onOwnImage = pythonSdk.mod(ws.withNewFile("/" + pyprojectPath, ownImage), path: tomlGenerateModulePath).generate
assertAdded(onOwnImage, tomlGenerateModulePath + "/" + sdkMemberFile)

let pinned = ws.withNewFile("/" + tomlGenerateModulePath + "/.python-version", "3.11\n")
let pinned = ws.withNewFile("/" + tomlGenerateModulePath + "/.python-version", "3.10\n")
let pinRefused = pythonSdk.mod(pinned, path: tomlGenerateModulePath).generated.cwd rescue {
err: Error => err.message
}
assertContains(pinRefused, "this Python SDK needs Python 3.12 or later, and .python-version pins Python 3.11. Set it to Python 3.12 or later", "a module pinned to Python 3.11 was generated")
assertContains(pinRefused, "this Python SDK needs Python 3.11 or later, and .python-version pins Python 3.10. Set it to Python 3.11 or later", "a module pinned to Python 3.10 was generated")

let initScope = outputRoot + "/python-floor-init"
let initRefused = pythonSdk(template: "empty", pythonVersion: "3.11")
let initRefused = pythonSdk(template: "empty", pythonVersion: "3.10")
.generateScope(scope.withNewDirectory("/" + initScope, directory).withWorkdir(initScope), isModule: true, name: "python-floor-init", clients: [])
.cwd rescue {
err: Error => err.message
}
assertContains(initRefused, "asks for Python 3.11", "a new module asking for Python 3.11 was initialized")
assertContains(initRefused, "asks for Python 3.10", "a new module asking for Python 3.10 was initialized")

let setRefused = pythonSdk.mod(ws, path: tomlGenerateModulePath).config.set(pythonVersion: "3.11").after.file(pyprojectPath).contents rescue {
let setRefused = pythonSdk.mod(ws, path: tomlGenerateModulePath).config.set(pythonVersion: "3.10").after.file(pyprojectPath).contents rescue {
err: Error => err.message
}
assertContains(setRefused, "asks for Python 3.11", "config set wrote Python 3.11")
assertContains(setRefused, "asks for Python 3.10", "config set wrote Python 3.10")

null
}
Expand Down Expand Up @@ -1462,8 +1462,8 @@ type E2e {
assert(release.trimSpace != "", "the generated module did not run")

let floorPath = ".dagger/modules/sdk-floor"
let onFloor = cli(initialized, ["module", "init", "python", "--auto-apply", "--name", "sdk-floor", "--path", floorPath, "--python-version", "3.12"])
.withExec(["grep", "-q", ">=3.12", floorPath + "/pyproject.toml"])
let onFloor = cli(initialized, ["module", "init", "python", "--auto-apply", "--name", "sdk-floor", "--path", floorPath, "--python-version", "3.11"])
.withExec(["grep", "-q", ">=3.11", floorPath + "/pyproject.toml"])
let floorRelease = cli(onFloor, ["-m", floorPath, "call", "container", "file", "--path", "/etc/alpine-release", "contents"])
.stdout
assert(floorRelease.trimSpace != "", "the default template did not run on the Python floor")
Expand Down Expand Up @@ -1543,18 +1543,32 @@ type E2e {
}
assertContains(direct, want, "a module generated directly with targetVersion " + setting + " was not refused the same way: " + direct)
}
[target, target.trimPrefix("v"), target + "+0123abcd", "", floor].each { setting =>
[target, target.trimPrefix("v"), target + "+0123abcd", "", floor, floor.trimPrefix("v"), floor + "+0123abcd"].each { setting =>
assert(pythonSdk.targetRefusal("module \"m\"", setting) == "", "the targeted release was refused as \"" + setting + "\": " + pythonSdk.targetRefusal("module \"m\"", setting))
}

# The target is a v1.0.0 prerelease below beta.100. Identifiers compare as
# numbers, so beta.100 is later than it and beta.9 is below the floor,
# where text order would say the opposite.
let later = [target + ".1", target.split("-")[0] ?? "", "v1.0.0-beta.100", "1.0.0-beta.100", "v1.0.0-beta.100+0123abcd"]
later.each { setting =>
let said = pythonSdk.targetRefusal("module \"m\"", setting)
assertContains(said, "pins targetVersion " + pythonSdk.targetVersionOf(setting) + ", which is later than " + target, "targetVersion " + setting + " was not refused as later than the targeted release: " + said)
}
["v1.0.0-beta.9", "1.0.0-beta.9"].each { setting =>
let said = pythonSdk.targetRefusal("module \"m\"", setting)
assertContains(said, "pins targetVersion v1.0.0-beta.9, which is below " + floor, "targetVersion " + setting + " was not refused as below the floor: " + said)
}
null
}

"""
`dagger module init python --target-version` records the targeted release
in the module's scope settings, and the module runs. A module pinned to the
floor stays pinned when `dagger generate` or `dagger call python-sdk mod
generate` generates it again, also when the pin is recorded in a config
below the workspace root under a key that climbs out of it with `..`.
in the module's scope settings, and the module runs; a release later than
the targeted one is refused. A module pinned to the floor stays pinned
when `dagger generate` or `dagger call python-sdk mod generate` generates
it again, also when the pin is recorded in a config below the workspace
root under a key that climbs out of it with `..`.
"""
pub targetVersionCliCheck(ws: Workspace!): Void @check {
let path = ".dagger/modules/target-cli"
Expand All @@ -1567,6 +1581,12 @@ type E2e {
let ran = cli(initialized, ["-m", path, "call", "container", "file", "--path", "/etc/alpine-release", "contents"]).stdout
assert(ran.trimSpace != "", "the module did not run")

let later = target + ".1"
let refused = playground(ws)
.withExec(["dagger", "module", "init", "python", "--auto-apply", "--name", "target-cli-later", "--path", ".dagger/modules/target-cli-later", "--target-version", later], experimentalPrivilegedNesting: true, expect: ReturnType.FAILURE)
.stderr
assertContains(refused, "module \"target-cli-later\" pins targetVersion " + later + ", which is later than " + target, "dagger module init accepted a targetVersion later than the targeted release: " + refused)

let pinnedPath = ".dagger/modules/target-cli-pinned"
let pinned = cli(playground(ws), ["module", "init", "python", "--auto-apply", "--name", "target-cli-pinned", "--path", pinnedPath, "--target-version", "v" + floorVersion])
let pinnedRan = cli(pinned, ["-m", pinnedPath, "call", "container", "file", "--path", "/etc/alpine-release", "contents"]).stdout
Expand Down
2 changes: 1 addition & 1 deletion .dagger/modules/engine-e2e/dagger-module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ engineVersion = "v1.0.0-0"

[[dependencies]]
name = "target-engine-dev"
source = "github.com/dagger/dagger/.dagger/modules/engine-dev@f0a3d728cf7012e0954f772b5dc5c8471648afaa"
source = "github.com/dagger/dagger/.dagger/modules/engine-dev@b32e84b60b99b68e836408d4318f0818982ea86d"
6 changes: 3 additions & 3 deletions .dagger/modules/engine-e2e/main.dang
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ type EngineE2e {
let belowFloorCommit: String! = "0da36c8da9cb6a682c7d27eca9bd2c125de5ed09"

"""
Commit of v1.0.0-beta.23, the release this SDK targets. Move it, and
Commit of v1.0.0-beta.24, the release this SDK targets. Move it, and
targetRelease, with engineTarget in python-sdk.dang.
"""
let targetCommit: String! = "f0a3d728cf7012e0954f772b5dc5c8471648afaa"
let targetCommit: String! = "b32e84b60b99b68e836408d4318f0818982ea86d"

let targetRelease: String! = "v1.0.0-beta.23"
let targetRelease: String! = "v1.0.0-beta.24"

let assert(condition: Boolean!, message: String!): Void {
if (condition == false) {
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ dagger check --engine=image://registry.dagger.io/engine:v1.0.0-beta.18 \
```

Two `engine-e2e` checks run the target checks on the engine of the release this
SDK targets, v1.0.0-beta.23, built from its commit. Only that release serves a
SDK targets, v1.0.0-beta.24, built from its commit. Only that release serves a
module or a session the view of the release it announces, so the floor cannot
prove it. `floor-coverage-check` does not count these checks:

Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# python-sdk

> [!NOTE]
>
> By default, this version of `dagger.io/sdk/python` targets Dagger engine
> `v1.0.0-beta.24`. See
> [The engine release a module targets](#the-engine-release-a-module-targets).

A Dagger module for managing Dagger modules that use the Python SDK.

SDK-specific module authoring (scaffolding new modules, language build config,
Expand Down Expand Up @@ -99,7 +105,7 @@ resolves to the runtime built into the engine (`dagger/dagger`'s

## The engine release a module targets

Each release of this SDK targets one engine release, `v1.0.0-beta.23` today.
Each release of this SDK targets one engine release, `v1.0.0-beta.24` today.
That release, or the one the setting below pins, is what the SDK generates
for and announces:

Expand Down Expand Up @@ -340,7 +346,7 @@ are persisted on the scope:
```sh
dagger module init python --name my-module --template empty
dagger module init python --name my-module --legacy-runtime
dagger module init python --name my-module --target-version v1.0.0-beta.23
dagger module init python --name my-module --target-version v1.0.0-beta.24
dagger module init python --name my-module \
--python-version 3.13 \
--use-uv=false \
Expand Down
5 changes: 3 additions & 2 deletions dagger.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
["","oci-sha",["docker.io/library/busybox:1.38.0"],"sha256:fd7dc98638c8e305f4dc34e979f1c0fdfdcaeb0fbf8fcff77ae834b6da3d7e6e"]
["","oci-sha",["docker.io/library/golang:1.25-alpine"],"sha256:1ae0735f00daffa3aaf1363a5184c0d2dc55c78e3db4ec70241cdac97bf84b59"]
["","oci-sha",["docker.io/library/golang:1.26-alpine"],"sha256:ce864e7223ac17b1775e6fd0b4c0db580c2eb50e7953a427916379e4b92a1628"]
["","oci-sha",["docker.io/library/golang:1.27-alpine"],"sha256:d200d2dd76b03a99b52651fd1325aff7dcd35422c35c01bac56571b0507f3deb"]
["","oci-sha",["docker.io/tonistiigi/xx:1.2.1"],"sha256:8879a398dedf0aadaacfbd332b29ff2f84bc39ae6d4e9c0a1109db27ac5ba012"]
["","oci-sha",["ghcr.io/astral-sh/uv:python3.12-alpine"],"sha256:a57a1dd942a83dc96d338f7479be4b4cbca018c476eae7e6f3f1d3603e90aaf8"]
["","oci-sha",["ghcr.io/astral-sh/uv:python3.11-alpine"],"sha256:50c205a1d4c3625cec60ee88750e2cd33937699d69a63b3b024f98a18a310190"]
["","oci-sha",["ghcr.io/astral-sh/uv:python3.14-alpine"],"sha256:513b826406ed7efc2604acdf4935266e020283ce17e2ea96509cd4f1a68b9f1a"]
["","oci-sha",["ghcr.io/astral-sh/uv:python3.15-alpine"],"sha256:53c26a742bed4fa993487ff88da17b232c74869b5aabeebfdef786602547dba6"]
["","oci-sha",["registry.dagger.io/engine:v1.0.0-beta.18"],"sha256:bdba5a56b1286e38244ad060c21fb4a5db6d30abc0077d79677f7450c737ae48"]
["","oci-sha",["registry.dagger.io/engine:v1.0.0-beta.23"],"sha256:a5a79c5b3775519be4be61da6507709699c9b31ae7620be0e43d76e5c557871f"]
["","oci-sha",["registry.dagger.io/engine:v1.0.0-beta.24"],"sha256:3ad2b0b80942bb5044e57c1765710a5fab0b913557b6ab7d7f4e81700ac4da35"]
["","vanity-url",["https://dagger.io/linux/alpine"],"https://github.com/dagger/alpine"]
["","vanity-url",["https://dagger.io/sdk/helpers"],"https://github.com/dagger/sdk-helpers"]
2 changes: 1 addition & 1 deletion helpers/pyproject/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

// pythonFloor is the oldest Python the SDK runs on. A test holds it to the
// requires-python of sdk/pyproject.toml.
const pythonFloor = "3.12"
const pythonFloor = "3.11"

// lastReleaseBelowPythonFloor is the last release of this SDK, whose floor
// was lastReleasePythonFloor. A refusal offers it only to a Python that
Expand Down
33 changes: 17 additions & 16 deletions helpers/pyproject/python_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@ func TestPythonFloorIsTheSDKs(t *testing.T) {

func TestBelowPythonFloor(t *testing.T) {
for v, want := range map[string]bool{
"3.11": true,
"3.11.9": true,
"3.10": true,
"3.10.9": true,
"2.7": true,
"2": true,
"3.12.0rc1": true,
"3.12rc1": true,
"3.12.dev0": true,
"3.11.0rc1": true,
"3.11rc1": true,
"3.11.dev0": true,
"3.11": false,
"3.11.0": false,
"3.11.1rc1": false,
"3.12": false,
"3.12.0": false,
"3.12.1rc1": false,
"3.13.0b2": false,
"3": false,
"4": false,
Expand Down Expand Up @@ -64,27 +65,27 @@ func TestPythonRefusal(t *testing.T) {
files map[string]string
want string
}{
"floor": {map[string]string{"pyproject.toml": project(">=3.12")}, ""},
"floor": {map[string]string{"pyproject.toml": project(">=3.11")}, ""},
"newer": {map[string]string{"pyproject.toml": project(">=3.14")}, ""},
"older floor": {map[string]string{"pyproject.toml": project(">=3.11")}, `this Python SDK needs Python 3.12 or later, and requires-python = ">=3.11" asks for Python 3.11. Ask for Python 3.12 or later, or pin the last release of this SDK that runs on it: dagger module install github.com/dagger/python-sdk@v1.2.0`},
"older floor": {map[string]string{"pyproject.toml": project(">=3.10")}, `this Python SDK needs Python 3.11 or later, and requires-python = ">=3.10" asks for Python 3.10. Ask for Python 3.11 or later, or pin the last release of this SDK that runs on it: dagger module install github.com/dagger/python-sdk@v1.2.0`},
"older range": {map[string]string{"pyproject.toml": project(">=3.10,<4")}, "asks for Python 3.10."},
"older exact": {map[string]string{"pyproject.toml": project("==3.11.4")}, "asks for Python 3.11.4."},
"older exact": {map[string]string{"pyproject.toml": project("==3.10.4")}, "asks for Python 3.10.4."},
"another major": {map[string]string{"pyproject.toml": project(">=2.7")}, "asks for Python 2.7."},
"older major only": {map[string]string{"pyproject.toml": project(">=2")}, "asks for Python 2."},
"range the runtime ignores": {map[string]string{"pyproject.toml": project("~=3.11")}, ""},
"range the runtime ignores": {map[string]string{"pyproject.toml": project("~=3.10")}, ""},
"no requires-python": {map[string]string{"pyproject.toml": "[project]\nname = \"app\"\n"}, ""},
"no pyproject.toml": {map[string]string{}, ""},
"older pin": {
map[string]string{".python-version": "3.11.9\n", "pyproject.toml": project(">=3.14")},
"this Python SDK needs Python 3.12 or later, and .python-version pins Python 3.11.9. Set it to Python 3.12 or later, or pin the last release",
map[string]string{".python-version": "3.10.9\n", "pyproject.toml": project(">=3.14")},
"this Python SDK needs Python 3.11 or later, and .python-version pins Python 3.10.9. Set it to Python 3.11 or later, or pin the last release",
},
"pin over requires-python": {map[string]string{".python-version": "3.13\n", "pyproject.toml": project(">=3.10")}, ""},
"base image over requires-python": {
map[string]string{"pyproject.toml": project(">=3.10") + "\n[tool.dagger]\nbase-image = \"python:3.14-slim\"\n"},
"",
},
"base image over pin": {
map[string]string{".python-version": "3.11\n", "pyproject.toml": "[tool.dagger]\nbase-image = \"python:3.14-slim\"\n"},
map[string]string{".python-version": "3.10\n", "pyproject.toml": "[tool.dagger]\nbase-image = \"python:3.14-slim\"\n"},
"",
},
"unreadable pin": {map[string]string{".python-version": "pypy3.10\n"}, ""},
Expand All @@ -102,7 +103,7 @@ func TestPythonRefusal(t *testing.T) {
}

func TestPythonRefusalOffersTheLastReleaseOnlyWhereItRuns(t *testing.T) {
for requires, offered := range map[string]bool{">=3.11": true, ">=3.10": true, ">=3.9": false, ">=2.7": false} {
for requires, offered := range map[string]bool{">=3.10": true, ">=3.9": false, ">=2.7": false} {
got, err := pythonRefusal(moduleDir(t, map[string]string{"pyproject.toml": "[project]\nrequires-python = \"" + requires + "\"\n"}))
if err != nil {
t.Fatal(err)
Expand All @@ -115,7 +116,7 @@ func TestPythonRefusalOffersTheLastReleaseOnlyWhereItRuns(t *testing.T) {

func TestRunPythonRefusalTakesADirectory(t *testing.T) {
dir := moduleDir(t, map[string]string{"pyproject.toml": "[project]\nrequires-python = \">=3.10\"\n"})
if got := printed(t, "python-refusal", dir); !strings.Contains(got, "needs Python 3.12 or later") {
if got := printed(t, "python-refusal", dir); !strings.Contains(got, "needs Python 3.11 or later") {
t.Errorf("got %q", got)
}
}
2 changes: 1 addition & 1 deletion python-sdk.dang
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ type PythonSdk {
bumped with each SDK release. Core is read from the running engine in that
release's view, and the generated entrypoint and the library announce it.
"""
let engineTarget: String! = "v1.0.0-beta.23"
let engineTarget: String! = "v1.0.0-beta.24"

"""
The last release of this SDK that runs on an engine below engineFloor.
Expand Down
2 changes: 1 addition & 1 deletion sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The Dagger Python SDK contains everything you need to develop CI/CD pipelines in

## Requirements

- Python 3.12 or later
- Python 3.11 or later
- [Docker](https://docs.docker.com/engine/install/), or another OCI-compatible container runtime

A compatible version of the [Dagger CLI](https://docs.dagger.io/cli) is automatically downloaded and run by the SDK for you, although it’s possible to manage it manually.
Expand Down
2 changes: 1 addition & 1 deletion sdk/codegen/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "codegen"
version = "0.0.0"
description = "Codegen for the Python SDK"
requires-python = ">=3.12"
requires-python = ">=3.11"
dependencies = ["graphql-core>=3.2.3,<3.3"]

[build-system]
Expand Down
3 changes: 2 additions & 1 deletion sdk/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
Expand All @@ -24,7 +25,7 @@ classifiers = [
"Operating System :: OS Independent",
"Typing :: Typed",
]
requires-python = ">=3.12"
requires-python = ">=3.11"
dependencies = [
"anyio>=3.6.2",
"cattrs>=25.1.0",
Expand Down
2 changes: 1 addition & 1 deletion sdk/ruff.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
src = ["src", "tests"]
target-version = "py312"
target-version = "py311"

[format]
docstring-code-format = true
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/dagger/_engine/_version.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion sdk/src/dagger/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import enum
import typing
from typing import override

from typing_extensions import override

if typing.TYPE_CHECKING:
from dagger.client._core import Context
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/dagger/mod/_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
cast,
get_type_hints,
overload,
override,
)

from cattrs.preconf.json import JsonConverter, make_converter
from typing_extensions import override

from dagger.mod._arguments import Parameter
from dagger.mod._exceptions import (
Expand Down
2 changes: 1 addition & 1 deletion sdk/tests/mod/golden/main.dang
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

type Entrypoint implements ModuleEntrypoint {
let moduleName: String! = "main"
let clientVersion: String! = "v1.0.0-beta.23"
let clientVersion: String! = "v1.0.0-beta.24"

pub sources(workspace: Workspace!): Directory! {
directory
Expand Down
Loading