|
14 | 14 | from aiida.cmdline.params import arguments, options, types
|
15 | 15 | from aiida.cmdline.params.options.overridable import OverridableOption
|
16 | 16 | from aiida.cmdline.utils import decorators, echo
|
| 17 | +from aiida.cmdline.utils.decorators import with_dbenv |
17 | 18 | from aiida.common.log import LOG_LEVELS, capture_logging
|
18 | 19 |
|
19 | 20 | REPAIR_INSTRUCTIONS = """\
|
@@ -583,98 +584,94 @@ def process_repair(manager, broker, dry_run):
|
583 | 584 | @verdi_process.command('dump')
|
584 | 585 | @arguments.PROCESS()
|
585 | 586 | @options.PATH()
|
| 587 | +@options.DRY_RUN() |
586 | 588 | @options.OVERWRITE()
|
587 |
| -@click.option( |
588 |
| - '--include-inputs/--exclude-inputs', |
589 |
| - default=True, |
590 |
| - show_default=True, |
591 |
| - help='Include the linked input nodes of the `CalculationNode`(s).', |
592 |
| -) |
593 |
| -@click.option( |
594 |
| - '--include-outputs/--exclude-outputs', |
595 |
| - default=False, |
596 |
| - show_default=True, |
597 |
| - help='Include the linked output nodes of the `CalculationNode`(s).', |
598 |
| -) |
599 |
| -@click.option( |
600 |
| - '--include-attributes/--exclude-attributes', |
601 |
| - default=True, |
602 |
| - show_default=True, |
603 |
| - help='Include attributes in the `.aiida_node_metadata.yaml` written for every `ProcessNode`.', |
604 |
| -) |
605 |
| -@click.option( |
606 |
| - '--include-extras/--exclude-extras', |
607 |
| - default=True, |
608 |
| - show_default=True, |
609 |
| - help='Include extras in the `.aiida_node_metadata.yaml` written for every `ProcessNode`.', |
610 |
| -) |
611 |
| -@click.option( |
612 |
| - '-f', |
613 |
| - '--flat', |
614 |
| - is_flag=True, |
615 |
| - default=False, |
616 |
| - show_default=True, |
617 |
| - help='Dump files in a flat directory for every step of the workflow.', |
618 |
| -) |
619 |
| -@click.option( |
620 |
| - '--dump-unsealed', |
621 |
| - is_flag=True, |
622 |
| - default=False, |
623 |
| - show_default=True, |
624 |
| - help='Also allow the dumping of unsealed process nodes.', |
625 |
| -) |
626 |
| -@options.INCREMENTAL() |
| 589 | +@options.INCLUDE_INPUTS() |
| 590 | +@options.INCLUDE_OUTPUTS() |
| 591 | +@options.INCLUDE_ATTRIBUTES() |
| 592 | +@options.INCLUDE_EXTRAS() |
| 593 | +@options.FLAT() |
| 594 | +@options.DUMP_UNSEALED() |
| 595 | +@click.pass_context |
| 596 | +@with_dbenv() |
627 | 597 | def process_dump(
|
| 598 | + ctx, |
628 | 599 | process,
|
629 | 600 | path,
|
| 601 | + dry_run, |
630 | 602 | overwrite,
|
631 | 603 | include_inputs,
|
632 | 604 | include_outputs,
|
633 | 605 | include_attributes,
|
634 | 606 | include_extras,
|
635 | 607 | flat,
|
636 | 608 | dump_unsealed,
|
637 |
| - incremental, |
638 | 609 | ) -> None:
|
639 | 610 | """Dump process input and output files to disk.
|
640 | 611 |
|
641 | 612 | Child calculations/workflows (also called `CalcJob`s/`CalcFunction`s and `WorkChain`s/`WorkFunction`s in AiiDA
|
642 | 613 | jargon) run by the parent workflow are contained in the directory tree as sub-folders and are sorted by their
|
643 |
| - creation time. The directory tree thus mirrors the logical execution of the workflow, which can also be queried by |
| 614 | + creation time. The directory tree thus mirrors the logical execution of the workflow, which can also be queried by |
644 | 615 | running `verdi process status <pk>` on the command line.
|
645 | 616 |
|
646 | 617 | By default, input and output files of each calculation can be found in the corresponding "inputs" and
|
647 | 618 | "outputs" directories (the former also contains the hidden ".aiida" folder with machine-readable job execution
|
648 | 619 | settings). Additional input and output files (depending on the type of calculation) are placed in the "node_inputs"
|
649 | 620 | and "node_outputs", respectively.
|
650 | 621 |
|
651 |
| - Lastly, every folder also contains a hidden, human-readable `.aiida_node_metadata.yaml` file with the relevant AiiDA |
| 622 | + Lastly, every folder also contains a hidden, human-readable `aiida_node_metadata.yaml` file with the relevant AiiDA |
652 | 623 | node data for further inspection.
|
653 | 624 | """
|
| 625 | + import traceback |
| 626 | + from pathlib import Path |
654 | 627 |
|
| 628 | + from aiida.cmdline.utils import echo |
| 629 | + from aiida.tools._dumping.utils import DumpPaths |
655 | 630 | from aiida.tools.archive.exceptions import ExportValidationError
|
656 |
| - from aiida.tools.dumping.processes import ProcessDumper |
657 |
| - |
658 |
| - process_dumper = ProcessDumper( |
659 |
| - include_inputs=include_inputs, |
660 |
| - include_outputs=include_outputs, |
661 |
| - include_attributes=include_attributes, |
662 |
| - include_extras=include_extras, |
663 |
| - overwrite=overwrite, |
664 |
| - flat=flat, |
665 |
| - dump_unsealed=dump_unsealed, |
666 |
| - incremental=incremental, |
| 631 | + |
| 632 | + warning_msg = ( |
| 633 | + 'This is a new feature which is still in its testing phase. ' |
| 634 | + 'If you encounter unexpected behavior or bugs, please report them via Discourse or GitHub.' |
667 | 635 | )
|
| 636 | + echo.echo_warning(warning_msg) |
668 | 637 |
|
| 638 | + # Check for dry_run + overwrite |
| 639 | + if overwrite and dry_run: |
| 640 | + msg = 'Both `dry_run` and `overwrite` set to true. Operation will NOT be performed.' |
| 641 | + echo.echo_warning(msg) |
| 642 | + return |
| 643 | + |
| 644 | + if path is None: |
| 645 | + process_path = DumpPaths.get_default_dump_path(process) |
| 646 | + dump_base_output_path = Path.cwd() / process_path |
| 647 | + msg = f'No output path specified. Using default: `{dump_base_output_path}`' |
| 648 | + echo.echo_report(msg) |
| 649 | + else: |
| 650 | + echo.echo_report(f'Using specified output path: `{path}`') |
| 651 | + dump_base_output_path = Path(path).resolve() |
| 652 | + |
| 653 | + if dry_run: |
| 654 | + echo.echo_success('Dry run completed.') |
| 655 | + return |
| 656 | + |
| 657 | + # Execute dumping |
669 | 658 | try:
|
670 |
| - dump_path = process_dumper.dump(process_node=process, output_path=path) |
671 |
| - except FileExistsError: |
672 |
| - echo.echo_critical( |
673 |
| - 'Dumping directory exists and overwrite is False. Set overwrite to True, or delete directory manually.' |
| 659 | + process.dump( |
| 660 | + output_path=dump_base_output_path, |
| 661 | + dry_run=dry_run, |
| 662 | + overwrite=overwrite, |
| 663 | + include_inputs=include_inputs, |
| 664 | + include_outputs=include_outputs, |
| 665 | + include_attributes=include_attributes, |
| 666 | + include_extras=include_extras, |
| 667 | + flat=flat, |
| 668 | + dump_unsealed=dump_unsealed, |
674 | 669 | )
|
| 670 | + |
| 671 | + msg = f'Raw files for process `{process.pk}` dumped into folder `{dump_base_output_path.name}`.' |
| 672 | + echo.echo_success(msg) |
675 | 673 | except ExportValidationError as e:
|
676 |
| - echo.echo_critical(f'{e!s}') |
| 674 | + echo.echo_critical(f'Data validation error during dump: {e!s}') |
677 | 675 | except Exception as e:
|
678 |
| - echo.echo_critical(f'Unexpected error while dumping {process.__class__.__name__} <{process.pk}>:\n ({e!s}).') |
679 |
| - |
680 |
| - echo.echo_success(f'Raw files for {process.__class__.__name__} <{process.pk}> dumped into folder `{dump_path}`.') |
| 676 | + msg = f'Unexpected error during dump of process {process.pk}:\n ({e!s}).\n' |
| 677 | + echo.echo_critical(msg + traceback.format_exc()) |
0 commit comments