Skip to content

Commit 06b021e

Browse files
authored
Merge pull request #1 from eunomie/python-customization
Add native Python SDK configuration (python version, uv, base image)
2 parents aad6453 + 81e56c0 commit 06b021e

20 files changed

Lines changed: 756 additions & 5 deletions

File tree

.dagger/lock

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[["version","1"]]
2-
["","git.head",["https://github.com/dagger/sdk-sdk"],"d6ab6406586e6b3853b8936b2b3a96bba2554071","float"]
2+
["","container.from",["docker.io/library/golang:1.25-alpine","linux/arm64"],"sha256:8d22e29d960bc50cd025d93d5b7c7d220b1ee9aa7a239b3c8f55a57e987e8d45","pin"]
3+
["","git.head",["https://github.com/dagger/sdk-sdk"],"09da9576688ec4b495ae4a9443a4719da86ed25e","float"]

.dagger/modules/e2e/fixtures/config/.dagger-python-sdk-skip-generate

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "config-app",
3+
"engineVersion": "latest",
4+
"sdk": {
5+
"source": "python"
6+
}
7+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[project]
2+
name = "config-app"
3+
version = "0.1.0"
4+
requires-python = ">=3.14"
5+
dependencies = ["dagger-io"]
6+
7+
[build-system]
8+
requires = ["uv_build>=0.8.4,<0.9.0"]
9+
build-backend = "uv_build"
10+
11+
[tool.uv.sources]
12+
dagger-io = { path = "sdk", editable = true }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import dagger
2+
from dagger import object_type
3+
4+
5+
@object_type
6+
class ConfigApp:
7+
source: dagger.Directory
8+
9+
def __init__(self, ws: dagger.Workspace):
10+
self.source = ws.directory("/")
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "config-configured",
3+
"engineVersion": "latest",
4+
"sdk": {
5+
"source": "python"
6+
}
7+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[project]
2+
name = "config-configured"
3+
version = "0.1.0"
4+
requires-python = ">=3.12"
5+
dependencies = ["dagger-io"]
6+
7+
[build-system]
8+
requires = ["uv_build>=0.8.4,<0.9.0"]
9+
build-backend = "uv_build"
10+
11+
[tool.dagger]
12+
use-uv = false
13+
base-image = "python:3.12-slim"
14+
15+
[tool.uv.sources]
16+
dagger-io = { path = "sdk", editable = true }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import dagger
2+
from dagger import object_type
3+
4+
5+
@object_type
6+
class ConfigConfigured:
7+
source: dagger.Directory
8+
9+
def __init__(self, ws: dagger.Workspace):
10+
self.source = ws.directory("/")

.dagger/modules/e2e/main.dang

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ type E2e {
1111
let skipModulePath: String! = fixtureRoot + "/skip/app"
1212
let generateModulePath: String! = fixtureRoot + "/generate/app"
1313
let depsModulePath: String! = fixtureRoot + "/deps/app"
14+
let configModulePath: String! = fixtureRoot + "/config/app"
15+
let configuredModulePath: String! = fixtureRoot + "/config/configured"
1416

1517
let generatedMarkerPath: String! = "sdk/src/dagger/client/gen.py"
1618
let generatedMarkerContents: String! = "Code generated by dagger."
@@ -222,4 +224,74 @@ type E2e {
222224

223225
null
224226
}
227+
228+
"""
229+
config.get should reflect pyproject.toml and report unset values as null
230+
rather than guessing, and config.set should edit only pyproject.toml.
231+
"""
232+
pub configCheck(ws: Workspace!): Void @check {
233+
let app = pythonSdk.mod(ws, path: configModulePath).config
234+
let configured = pythonSdk.mod(ws, path: configuredModulePath).config
235+
236+
let appValues = app.get
237+
assert(appValues.pythonVersion == "3.14", "default pythonVersion should read 3.14")
238+
assert(appValues.useUv == null, "useUv should be reported as unset, not guessed")
239+
assert(appValues.baseImage == null, "baseImage should be reported as unset")
240+
241+
let configuredValues = configured.get
242+
assert(configuredValues.pythonVersion == "3.12", "configured pythonVersion should read 3.12")
243+
assert(configuredValues.useUv == false, "configured useUv should read false")
244+
assert(configuredValues.baseImage == "python:3.12-slim", "configured baseImage should read the override")
245+
246+
let pyproj = configModulePath + "/pyproject.toml"
247+
248+
let py = app.set(pythonVersion: "3.13")
249+
assert(contains(py.modifiedPaths, pyproj), "set should modify pyproject.toml")
250+
assert(py.modifiedPaths.length == 1, "set modified more than pyproject.toml")
251+
assert(py.addedPaths.length == 0, "set should not add files")
252+
assertContains(py.after.file(pyproj).contents, ">=3.13", "set did not write the new python version")
253+
assertContains(py.after.file(pyproj).contents, "dagger-io", "set dropped unrelated keys")
254+
255+
let multi = app.set(pythonVersion: "3.13", useUv: false, baseImage: "python:3.13-slim")
256+
assert(multi.modifiedPaths.length == 1, "multi-value set modified more than pyproject.toml")
257+
assert(multi.addedPaths.length == 0, "multi-value set should not add files")
258+
assertContains(multi.after.file(pyproj).contents, ">=3.13", "multi-value set did not write python version")
259+
assertContains(multi.after.file(pyproj).contents, "use-uv = false", "multi-value set did not write use-uv")
260+
assertContains(multi.after.file(pyproj).contents, "python:3.13-slim", "multi-value set did not write base image")
261+
262+
let configuredPyproj = configuredModulePath + "/pyproject.toml"
263+
let partial = configured.set(pythonVersion: "3.13")
264+
assertContains(partial.after.file(configuredPyproj).contents, ">=3.13", "partial set did not update python version")
265+
assertContains(partial.after.file(configuredPyproj).contents, "use-uv = false", "omitting useUv should leave it untouched")
266+
assertContains(partial.after.file(configuredPyproj).contents, "python:3.12-slim", "omitting baseImage should leave it untouched")
267+
268+
null
269+
}
270+
271+
"""
272+
Init flags should write configuration into the generated pyproject.toml, and
273+
defaults should leave it unconfigured.
274+
"""
275+
pub initConfigCheck(ws: Workspace!): Void @check {
276+
let configuredPath = outputRoot + "/init-configured"
277+
let defaultPath = outputRoot + "/init-config-default"
278+
279+
let configured = pythonSdk.init(ws, name: "init-configured", path: configuredPath, pythonVersion: "3.13", useUv: false, baseImage: "python:3.13-slim")
280+
let pyproj = configuredPath + "/pyproject.toml"
281+
assertAdded(configured, pyproj)
282+
assert(configured.modifiedPaths.length == 0, "configured init should not modify existing files")
283+
assert(configured.removedPaths.length == 0, "configured init should not remove files")
284+
assertContains(configured.layer.file(pyproj).contents, ">=3.13", "init --python-version not written")
285+
assertContains(configured.layer.file(pyproj).contents, "use-uv = false", "init --use-uv=false not written")
286+
assertContains(configured.layer.file(pyproj).contents, "python:3.13-slim", "init --base-image not written")
287+
assertContains(configured.layer.file(pyproj).contents, "dagger-io", "init config dropped template data")
288+
289+
let default = pythonSdk.init(ws, name: "init-config-default", path: defaultPath)
290+
let defaultPyproj = defaultPath + "/pyproject.toml"
291+
assertContains(default.layer.file(defaultPyproj).contents, ">=3.14", "default init should keep the template python version")
292+
assertNotContains(default.layer.file(defaultPyproj).contents, "use-uv", "default init should not write use-uv")
293+
assertNotContains(default.layer.file(defaultPyproj).contents, "[tool.dagger]", "default init should not write a [tool.dagger] table")
294+
295+
null
296+
}
225297
}

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,47 @@ dagger call python-sdk init --name my-module --template legacy
4545
`init` only seeds template files. Run `mod ... generate` to produce the
4646
generated SDK.
4747

48+
### Configure a module at creation
49+
50+
`init` accepts configuration flags written into the module's `pyproject.toml`:
51+
52+
```sh
53+
dagger call python-sdk init --name my-module \
54+
--python-version 3.13 \
55+
--use-uv=false \
56+
--base-image python:3.13-slim
57+
```
58+
59+
All three are optional. By default the template's Python version is used, uv is
60+
enabled, and no base image override is written.
61+
62+
## Configure an existing module
63+
64+
Read the current configuration. Settings that are not explicitly written to
65+
`pyproject.toml` are reported as `null` rather than guessed:
66+
67+
```sh
68+
dagger call python-sdk mod --path my-module config get
69+
```
70+
71+
Select a single value:
72+
73+
```sh
74+
dagger call python-sdk mod --path my-module config get python-version
75+
dagger call python-sdk mod --path my-module config get use-uv
76+
dagger call python-sdk mod --path my-module config get base-image
77+
```
78+
79+
Change one or more values at once (prints a diff to confirm before writing).
80+
Each flag is optional; omitting one leaves that setting untouched:
81+
82+
```sh
83+
dagger call python-sdk mod --path my-module config set \
84+
--python-version 3.13 \
85+
--use-uv=false \
86+
--base-image python:3.13-slim
87+
```
88+
4889
## Generate SDK files
4990

5091
For a single module:

0 commit comments

Comments
 (0)