Skip to content

Commit e4168db

Browse files
committed
test: cover default and empty Python templates
The template names are part of the init UX: omitting `template` must produce the useful starter, while users who want a blank object must be able to ask for `empty` explicitly. Exercise both paths through `initModule` and assert the rendered source rather than template-helper internals. In particular, protect the alternate constructor shape: Python reconstructs object state between the constructor and later function calls, so overriding `__init__` with only user-facing inputs makes a rendered module load but fail when a function is invoked. The check also covers the pinned base image, workspace mount, bare empty class, and leaked Go-template placeholders. Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
1 parent 9bbca00 commit e4168db

1 file changed

Lines changed: 44 additions & 1 deletion

File tree

.dagger/modules/e2e/main.dang

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,56 @@ type E2e {
134134
assert(contains(defaultChanges.addedPaths, defaultPath + "/" + generatedMarkerPath) == false, "init should not produce SDK-generated files")
135135
assert(defaultChanges.modifiedPaths.length == 0, "init unexpectedly modified existing files")
136136
assert(defaultChanges.removedPaths.length == 0, "init unexpectedly removed files")
137-
assertContains(defaultChanges.layer.file(defaultPath + "/src/init_default/__init__.py").contents, "class InitDefault:", "minimal template did not render the module type")
137+
assertContains(defaultChanges.layer.file(defaultPath + "/src/init_default/__init__.py").contents, "class InitDefault:", "default template did not render the module type")
138138

139139
assertContains(legacyChanges.layer.file(legacyPath + "/src/init_legacy/main.py").contents, "class InitLegacy:", "legacy template did not render the module type")
140140

141141
null
142142
}
143143

144+
"""
145+
The default template should render a working module that reads source from
146+
the workspace and returns a ready-to-build container. The empty template
147+
should remain available as a bare object class.
148+
"""
149+
pub templateCheck(ws: Workspace!): Void @check {
150+
let defaultPath = outputRoot + "/template-default"
151+
let compatibleDefaultPath = outputRoot + "/template-default-empty-value"
152+
let emptyPath = outputRoot + "/template-empty"
153+
154+
let defaultChanges = pythonSdk.initModule(ws, name: "template-default", path: defaultPath)
155+
let defaultSourcePath = defaultPath + "/src/template_default/__init__.py"
156+
assertAdded(defaultChanges, defaultSourcePath)
157+
assertAdded(defaultChanges, defaultPath + "/pyproject.toml")
158+
let defaultSource = defaultChanges.layer.file(defaultSourcePath).contents
159+
assertContains(defaultSource, "class TemplateDefault:", "default template should render the module class")
160+
assertContains(defaultSource, "@classmethod", "default template should use a reconstructable alternate constructor")
161+
assertContains(defaultSource, "def create(", "default template should expose the alternate constructor")
162+
assertContains(defaultSource, "ws: dagger.Workspace", "default template constructor should receive the workspace")
163+
assertContains(defaultSource, "base_image_address: str = \"alpine:3.21\"", "default template should expose a pinned base image")
164+
assertContains(defaultSource, "return cls(", "default template constructor should return serializable object state")
165+
assertNotContains(defaultSource, "def __init__", "default template should leave state reconstruction to the dataclass initializer")
166+
assertContains(defaultSource, "def container(self) -> dagger.Container:", "default template should expose the container function")
167+
assertContains(defaultSource, ".with_directory(\"/src\", self.source)", "default template should mount the workspace source")
168+
assertNotContains(defaultSource, "{{", "default template placeholders should be fully rendered")
169+
170+
let compatibleDefaultChanges = pythonSdk.initModule(ws, name: "template-default-empty-value", path: compatibleDefaultPath, template: "")
171+
let compatibleDefaultSource = compatibleDefaultChanges.layer.file(compatibleDefaultPath + "/src/template_default_empty_value/__init__.py").contents
172+
assertContains(compatibleDefaultSource, "def container(self) -> dagger.Container:", "an explicitly empty template should retain default-template compatibility")
173+
174+
let emptyChanges = pythonSdk.initModule(ws, name: "template-empty", path: emptyPath, template: "empty")
175+
let emptySourcePath = emptyPath + "/src/template_empty/__init__.py"
176+
assertAdded(emptyChanges, emptySourcePath)
177+
assertAdded(emptyChanges, emptyPath + "/pyproject.toml")
178+
let emptySource = emptyChanges.layer.file(emptySourcePath).contents
179+
assertContains(emptySource, "class TemplateEmpty:", "empty template should render the module class")
180+
assertContains(emptySource, " pass", "empty template should render a bare class")
181+
assertNotContains(emptySource, "def container", "empty template should not include the default behavior")
182+
assertNotContains(emptySource, "{{", "empty template placeholders should be fully rendered")
183+
184+
null
185+
}
186+
144187
"""
145188
Generating an existing module should produce generated files rooted at that
146189
module without touching unrelated paths.

0 commit comments

Comments
 (0)