30
30
from _pytask .mark_utils import has_mark
31
31
from _pytask .node_protocols import PNode
32
32
from _pytask .node_protocols import PPathNode
33
+ from _pytask .node_protocols import PProvisionalNode
33
34
from _pytask .node_protocols import PTask
35
+ from _pytask .nodes import DirectoryNode
34
36
from _pytask .nodes import PathNode
35
37
from _pytask .nodes import PythonNode
36
38
from _pytask .nodes import Task
@@ -299,6 +301,8 @@ def pytask_collect_task(
299
301
raise ValueError (msg )
300
302
301
303
path_nodes = Path .cwd () if path is None else path .parent
304
+
305
+ # Collect dependencies and products.
302
306
dependencies = parse_dependencies_from_task_function (
303
307
session , path , name , path_nodes , obj
304
308
)
@@ -309,6 +313,9 @@ def pytask_collect_task(
309
313
markers = get_all_marks (obj )
310
314
collection_id = obj .pytask_meta ._id if hasattr (obj , "pytask_meta" ) else None
311
315
after = obj .pytask_meta .after if hasattr (obj , "pytask_meta" ) else []
316
+ is_generator = (
317
+ obj .pytask_meta .is_generator if hasattr (obj , "pytask_meta" ) else False
318
+ )
312
319
313
320
# Get the underlying function to avoid having different states of the function,
314
321
# e.g. due to pytask_meta, in different layers of the wrapping.
@@ -321,7 +328,11 @@ def pytask_collect_task(
321
328
depends_on = dependencies ,
322
329
produces = products ,
323
330
markers = markers ,
324
- attributes = {"collection_id" : collection_id , "after" : after },
331
+ attributes = {
332
+ "collection_id" : collection_id ,
333
+ "after" : after ,
334
+ "is_generator" : is_generator ,
335
+ },
325
336
)
326
337
return Task (
327
338
base_name = name ,
@@ -330,41 +341,25 @@ def pytask_collect_task(
330
341
depends_on = dependencies ,
331
342
produces = products ,
332
343
markers = markers ,
333
- attributes = {"collection_id" : collection_id , "after" : after },
344
+ attributes = {
345
+ "collection_id" : collection_id ,
346
+ "after" : after ,
347
+ "is_generator" : is_generator ,
348
+ },
334
349
)
335
350
if isinstance (obj , PTask ):
336
351
return obj
337
352
return None
338
353
339
354
340
- _TEMPLATE_ERROR : str = """\
341
- The provided path of the dependency/product is
342
-
343
- {}
344
-
345
- , but the path of the file on disk is
346
-
347
- {}
348
-
349
- Case-sensitive file systems would raise an error because the upper and lower case \
350
- format of the paths does not match.
351
-
352
- Please, align the names to ensure reproducibility on case-sensitive file systems \
353
- (often Linux or macOS) or disable this error with 'check_casing_of_paths = false' in \
354
- the pyproject.toml file.
355
-
356
- Hint: If parts of the path preceding your project directory are not properly \
357
- formatted, check whether you need to call `.resolve()` on `SRC`, `BLD` or other paths \
358
- created from the `__file__` attribute of a module.
359
- """
360
-
361
-
362
355
_TEMPLATE_ERROR_DIRECTORY : str = """\
363
356
The path '{path}' points to a directory, although only files are allowed."""
364
357
365
358
366
359
@hookimpl (trylast = True )
367
- def pytask_collect_node (session : Session , path : Path , node_info : NodeInfo ) -> PNode : # noqa: C901, PLR0912
360
+ def pytask_collect_node ( # noqa: C901, PLR0912
361
+ session : Session , path : Path , node_info : NodeInfo
362
+ ) -> PNode | PProvisionalNode :
368
363
"""Collect a node of a task as a :class:`pytask.PNode`.
369
364
370
365
Strings are assumed to be paths. This might be a strict assumption, but since this
@@ -384,6 +379,21 @@ def pytask_collect_node(session: Session, path: Path, node_info: NodeInfo) -> PN
384
379
"""
385
380
node = node_info .value
386
381
382
+ if isinstance (node , DirectoryNode ):
383
+ if node .root_dir is None :
384
+ node .root_dir = path
385
+ if (
386
+ not node .name
387
+ or node .name == node .root_dir .joinpath (node .pattern ).as_posix ()
388
+ ):
389
+ short_root_dir = shorten_path (
390
+ node .root_dir , session .config ["paths" ] or (session .config ["root" ],)
391
+ )
392
+ node .name = Path (short_root_dir , node .pattern ).as_posix ()
393
+
394
+ if isinstance (node , PProvisionalNode ):
395
+ return node
396
+
387
397
if isinstance (node , PythonNode ):
388
398
node .node_info = node_info
389
399
if not node .name :
@@ -418,9 +428,11 @@ def pytask_collect_node(session: Session, path: Path, node_info: NodeInfo) -> PN
418
428
raise ValueError (_TEMPLATE_ERROR_DIRECTORY .format (path = node .path ))
419
429
420
430
if isinstance (node , PNode ):
431
+ if not node .name :
432
+ node .name = create_name_of_python_node (node_info )
421
433
return node
422
434
423
- if isinstance (node , UPath ):
435
+ if isinstance (node , UPath ): # pragma: no cover
424
436
if not node .protocol :
425
437
node = Path (node )
426
438
else :
@@ -459,6 +471,28 @@ def pytask_collect_node(session: Session, path: Path, node_info: NodeInfo) -> PN
459
471
return PythonNode (value = node , name = node_name , node_info = node_info )
460
472
461
473
474
+ _TEMPLATE_ERROR : str = """\
475
+ The provided path of the dependency/product is
476
+
477
+ {}
478
+
479
+ , but the path of the file on disk is
480
+
481
+ {}
482
+
483
+ Case-sensitive file systems would raise an error because the upper and lower case \
484
+ format of the paths does not match.
485
+
486
+ Please, align the names to ensure reproducibility on case-sensitive file systems \
487
+ (often Linux or macOS) or disable this error with 'check_casing_of_paths = false' in \
488
+ your pytask configuration file.
489
+
490
+ Hint: If parts of the path preceding your project directory are not properly \
491
+ formatted, check whether you need to call `.resolve()` on `SRC`, `BLD` or other paths \
492
+ created from the `__file__` attribute of a module.
493
+ """
494
+
495
+
462
496
def _raise_error_if_casing_of_path_is_wrong (
463
497
path : Path , check_casing_of_paths : bool
464
498
) -> None :
0 commit comments