@@ -100,7 +100,14 @@ def test_python_node_id_is_collision_free(tmp_path):
100100 assert left_id != right_id
101101
102102
103- def test_collection_fails_for_ambiguous_lockfile_ids (runner , tmp_path ):
103+ @pytest .mark .parametrize (
104+ "args" ,
105+ [
106+ pytest .param (lambda path : [path .as_posix ()], id = "build" ),
107+ pytest .param (lambda path : ["collect" , path .as_posix ()], id = "collect" ),
108+ ],
109+ )
110+ def test_collection_fails_for_ambiguous_lockfile_ids (runner , tmp_path , args ):
104111 source = """
105112 from dataclasses import dataclass, field
106113 from pathlib import Path
@@ -131,6 +138,63 @@ def task_example(
131138 """
132139 tmp_path .joinpath ("task_module.py" ).write_text (textwrap .dedent (source ))
133140
141+ result = runner .invoke (cli , args (tmp_path ))
142+
143+ assert result .exit_code == ExitCode .COLLECTION_FAILED
144+ assert "Ambiguous lockfile ids detected" in result .output
145+ assert "lockfile id 'dup'" in result .output
146+
147+
148+ def test_markers_command_ignores_invalid_lockfile (runner , tmp_path ):
149+ tmp_path .joinpath ("pytask.lock" ).write_text ("{not toml" )
150+
151+ result = runner .invoke (cli , ["markers" , tmp_path .as_posix ()])
152+
153+ assert result .exit_code == ExitCode .OK
154+ assert "persist" in result .output
155+
156+
157+ def test_collection_fails_for_ambiguous_lockfile_ids_with_missing_product_state (
158+ runner , tmp_path
159+ ):
160+ source = """
161+ from dataclasses import dataclass, field
162+ from pathlib import Path
163+ from typing import Annotated, Any
164+
165+ from pytask import Product
166+
167+ @dataclass
168+ class CustomNode:
169+ name: str
170+ filepath: Path
171+ signature: str
172+ attributes: dict[Any, Any] = field(default_factory=dict)
173+
174+ def state(self):
175+ if not self.filepath.exists():
176+ return None
177+ return self.filepath.read_text()
178+
179+ def load(self, is_product=False):
180+ return self if is_product else self.filepath.read_text()
181+
182+ def save(self, value):
183+ self.filepath.write_text(value)
184+
185+ def task_example(
186+ dependency=CustomNode(
187+ name="dup", filepath=Path("in.txt"), signature="signature-a"
188+ ),
189+ product: Annotated[CustomNode, Product] = CustomNode(
190+ name="dup", filepath=Path("out.txt"), signature="signature-b"
191+ ),
192+ ):
193+ product.save(dependency.upper())
194+ """
195+ tmp_path .joinpath ("task_module.py" ).write_text (textwrap .dedent (source ))
196+ tmp_path .joinpath ("in.txt" ).write_text ("hello" )
197+
134198 result = runner .invoke (cli , [tmp_path .as_posix ()])
135199
136200 assert result .exit_code == ExitCode .COLLECTION_FAILED
0 commit comments