|
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