easylink 0.1.17__tar.gz → 0.1.18__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {easylink-0.1.17 → easylink-0.1.18}/CHANGELOG.rst +4 -0
- {easylink-0.1.17 → easylink-0.1.18}/PKG-INFO +1 -1
- easylink-0.1.18/src/easylink/_version.py +1 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/cli.py +9 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/configuration.py +18 -34
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/devtools/implementation_creator.py +13 -11
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/implementation_metadata.yaml +0 -3
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/pipeline_schema.py +12 -13
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/pipeline_schema_constants/__init__.py +3 -4
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/runner.py +5 -7
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink.egg-info/PKG-INFO +1 -1
- {easylink-0.1.17 → easylink-0.1.18}/tests/e2e/test_easylink_run.py +2 -1
- {easylink-0.1.17 → easylink-0.1.18}/tests/e2e/test_step_types.py +2 -1
- {easylink-0.1.17 → easylink-0.1.18}/tests/integration/test_compositions.py +5 -11
- {easylink-0.1.17 → easylink-0.1.18}/tests/integration/test_snakemake.py +3 -5
- {easylink-0.1.17 → easylink-0.1.18}/tests/integration/test_snakemake_slurm.py +2 -3
- {easylink-0.1.17 → easylink-0.1.18}/tests/integration/test_snakemake_spark.py +2 -3
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/conftest.py +1 -1
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_config.py +24 -6
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_implementation_creator.py +13 -3
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_pipeline.py +1 -1
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_pipeline_graph.py +10 -18
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_pipeline_schema.py +15 -19
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_runner.py +2 -2
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_validations.py +10 -10
- easylink-0.1.17/src/easylink/_version.py +0 -1
- {easylink-0.1.17 → easylink-0.1.18}/.bandit +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/.flake8 +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/.github/CODEOWNERS +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/.github/pull_request_template.md +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/.github/workflows/deploy.yml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/.github/workflows/update_readme.yml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/.gitignore +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/.readthedocs.yml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/CONTRIBUTING.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/Jenkinsfile +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/Makefile +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/README.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/Makefile +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/nitpick-exceptions +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/_static/style.css +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/_templates/layout.html +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/cli.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/configuration.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/graph_components.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/implementation.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/index.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/pipeline.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/pipeline_graph.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/pipeline_schema.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/pipeline_schema_constants/development.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/pipeline_schema_constants/index.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/pipeline_schema_constants/testing.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/rule.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/runner.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/step.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/utilities/aggregator_utils.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/utilities/data_utils.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/utilities/general_utils.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/utilities/index.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/utilities/paths.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/utilities/splitter_utils.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/api_reference/utilities/validation_utils.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/index.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/01_step.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/02_default_implementation.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/03_slots.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/04_data_dependency.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/05_pipeline_schema.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/06_default_input.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/07_cloneable_section.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/08_cloneable_section_expanded.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/09_loopable_section.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/10_loopable_section_expanded.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/11_cloneable_section_splitter.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/12_cloneable_section_splitter_expanded.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/13_autoparallel_section.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/14_choice_section.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/15_choice_section_expanded.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/16_step_hierarchy.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/17_draws.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/18_schema_to_pipeline.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/19_schema_to_pipeline_combined.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/clustering_sub_steps.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/easylink_pipeline_schema.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/images/entity_resolution_sub_steps.drawio.png +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/concepts/pipeline_schema/index.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/conf.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/glossary.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/index.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/cli.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/index.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/DAG-common-pipeline.svg +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/DAG-e2e-pipeline-expanded.svg +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/DAG-e2e-pipeline.svg +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/DAG-r-pyspark.svg +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/environment_slurm.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/getting_started.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/impl-config-pipeline.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/index.rst +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/input_data.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/input_file_1.parquet +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/input_file_2.parquet +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/input_file_3.parquet +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/docs/source/user_guide/tutorials/r_spark_pipeline.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/pyproject.toml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/python_versions.json +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/pytype.cfg +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/setup.cfg +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/setup.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/__about__.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/__init__.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/graph_components.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/images/spark_cluster/Dockerfile +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/images/spark_cluster/README.md +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/implementation.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/pipeline.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/pipeline_graph.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/pipeline_schema_constants/development.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/pipeline_schema_constants/testing.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/rule.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/step.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/README.md +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/build-containers-local.sh +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/build-containers-remote.sh +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/input_data/create_input_files.ipynb +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/input_data/input_file_1.csv +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/input_data/input_file_1.parquet +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/input_data/input_file_2.csv +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/input_data/input_file_2.parquet +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/python_pandas/README.md +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/python_pandas/dummy_step.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/python_pandas/python_pandas.def +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/python_pyspark/README.md +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/python_pyspark/dummy_step.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/python_pyspark/python_pyspark.def +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/r/README.md +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/r/dummy_step.R +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/r/r-image.def +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/dev/test.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/output_dir/dummy_step_1_for_output_dir_example.def +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/output_dir/dummy_step_1_for_output_dir_example.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/output_dir/dummy_step_2_for_output_dir_example.def +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/steps/output_dir/dummy_step_2_for_output_dir_example.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/utilities/__init__.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/utilities/aggregator_utils.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/utilities/data_utils.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/utilities/general_utils.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/utilities/paths.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/utilities/spark.smk +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/utilities/splitter_utils.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink/utilities/validation_utils.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink.egg-info/SOURCES.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink.egg-info/dependency_links.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink.egg-info/entry_points.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink.egg-info/not-zip-safe +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink.egg-info/requires.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/src/easylink.egg-info/top_level.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/__init__.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/conftest.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/common/environment_local.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/common/input_data.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/common/input_data_one_file.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/common/pipeline.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/e2e/environment_slurm.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/e2e/pipeline.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/e2e/pipeline_expanded.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/integration/embarrassingly_parallel/pipeline_hierarchical_step.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/integration/embarrassingly_parallel/pipeline_loop_step.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/integration/embarrassingly_parallel/pipeline_parallel_step.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/integration/environment_spark_slurm.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/integration/pipeline.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/integration/pipeline_output_dir.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/integration/pipeline_output_dir_default.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/integration/pipeline_spark.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/environment_minimum.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/environment_spark_slurm.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_bad_combined_implementations.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_bad_implementation.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_bad_loop_formatting.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_bad_step.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_bad_type_key.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_combine_bad_implementation_names.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_combine_bad_topology.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_combine_two_steps.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_combine_with_extra_node.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_combine_with_iteration.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_combine_with_iteration_cycle.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_combine_with_missing_node.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_combine_with_parallel.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_missing_implementation_name.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_missing_implementations.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_missing_loop_nodes.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_missing_step.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_missing_substeps.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_missing_type_key.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_nested_templated_steps.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_out_of_order.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_spark.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_type_config_mismatch.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/specifications/unit/pipeline_wrong_parallel_split_keys.yaml +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/__init__.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/recipe_strings/python_pandas.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/aggregation_rule.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/checkpoint_rule.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/embarrassingly_parallel_rule.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/implemented_rule_local.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/implemented_rule_slurm.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/pipeline_local.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/pipeline_slurm.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/target_rule.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/rule_strings/validation_rule.txt +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_cli.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_data_utils.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_general_utils.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_graph_components.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_implementation.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_rule.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/tests/unit/test_step.py +0 -0
- {easylink-0.1.17 → easylink-0.1.18}/update_readme.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.18"
|
@@ -91,6 +91,11 @@ SHARED_OPTIONS = [
|
|
91
91
|
default=False,
|
92
92
|
help="Do not save the results in a timestamped sub-directory of ``--output-dir``.",
|
93
93
|
),
|
94
|
+
click.option(
|
95
|
+
"--schema",
|
96
|
+
hidden=True,
|
97
|
+
default="main",
|
98
|
+
),
|
94
99
|
]
|
95
100
|
|
96
101
|
VERBOSE_WITH_DEBUGGER_OPTIONS = [
|
@@ -165,6 +170,7 @@ def run(
|
|
165
170
|
input_data: str,
|
166
171
|
output_dir: str | None,
|
167
172
|
no_timestamp: bool,
|
173
|
+
schema: str,
|
168
174
|
computing_environment: str | None,
|
169
175
|
verbose: int,
|
170
176
|
with_debugger: bool,
|
@@ -190,6 +196,7 @@ def run(
|
|
190
196
|
input_data=input_data,
|
191
197
|
computing_environment=computing_environment,
|
192
198
|
results_dir=results_dir,
|
199
|
+
schema_name=schema,
|
193
200
|
)
|
194
201
|
logger.info("*** FINISHED ***")
|
195
202
|
|
@@ -201,6 +208,7 @@ def generate_dag(
|
|
201
208
|
input_data: str,
|
202
209
|
output_dir: str | None,
|
203
210
|
no_timestamp: bool,
|
211
|
+
schema: str,
|
204
212
|
verbose: int,
|
205
213
|
with_debugger: bool,
|
206
214
|
) -> None:
|
@@ -223,6 +231,7 @@ def generate_dag(
|
|
223
231
|
input_data=input_data,
|
224
232
|
computing_environment=None,
|
225
233
|
results_dir=results_dir,
|
234
|
+
schema_name=schema,
|
226
235
|
)
|
227
236
|
logger.info("*** DAG saved to result directory ***")
|
228
237
|
|
@@ -14,7 +14,7 @@ from typing import Any
|
|
14
14
|
|
15
15
|
from layered_config_tree import LayeredConfigTree
|
16
16
|
|
17
|
-
from easylink.pipeline_schema import
|
17
|
+
from easylink.pipeline_schema import PipelineSchema
|
18
18
|
from easylink.utilities.data_utils import load_yaml
|
19
19
|
from easylink.utilities.general_utils import exit_with_validation_error
|
20
20
|
|
@@ -67,9 +67,8 @@ class Config(LayeredConfigTree):
|
|
67
67
|
A dictionary of all specifications required to run the pipeline. This
|
68
68
|
includes the pipeline, input data, and computing environment specifications,
|
69
69
|
as well as the results directory.
|
70
|
-
|
71
|
-
|
72
|
-
This is primarily used for testing purposes. Defaults to the supported schemas.
|
70
|
+
schema_name
|
71
|
+
The name of the schema to validate the pipeline configuration against.
|
73
72
|
|
74
73
|
Attributes
|
75
74
|
----------
|
@@ -82,22 +81,14 @@ class Config(LayeredConfigTree):
|
|
82
81
|
input_data
|
83
82
|
The input data filepaths.
|
84
83
|
schema
|
85
|
-
The :class:`~easylink.pipeline_schema.PipelineSchema
|
86
|
-
|
87
|
-
|
88
|
-
Notes
|
89
|
-
-----
|
90
|
-
The requested pipeline is checked against a set of supported
|
91
|
-
``PipelineSchemas``. The first schema that successfully validates is assumed
|
92
|
-
to be the correct one and is attached to the ``Config`` object and its
|
93
|
-
:meth:`~easylink.pipeline_schema.PipelineSchema.configure_pipeline`
|
94
|
-
method is called.
|
84
|
+
The :class:`~easylink.pipeline_schema.PipelineSchema`.
|
85
|
+
|
95
86
|
"""
|
96
87
|
|
97
88
|
def __init__(
|
98
89
|
self,
|
99
90
|
config_params: dict[str, Any],
|
100
|
-
|
91
|
+
schema_name: str = "main",
|
101
92
|
) -> None:
|
102
93
|
super().__init__(layers=["initial_data", "default", "user_configured"])
|
103
94
|
self.update(DEFAULT_ENVIRONMENT, layer="default")
|
@@ -108,9 +99,7 @@ class Config(LayeredConfigTree):
|
|
108
99
|
# Set slurm defaults to empty dict instead of None so that we don't get errors
|
109
100
|
# in slurm_resources property
|
110
101
|
self.update({"environment": {"slurm": {}}}, layer="default")
|
111
|
-
|
112
|
-
potential_schemas = [potential_schemas]
|
113
|
-
self.update({"schema": self._get_schema(potential_schemas)}, layer="initial_data")
|
102
|
+
self.update({"schema": self._get_schema(schema_name)}, layer="initial_data")
|
114
103
|
self.schema.configure_pipeline(self.pipeline, self.input_data)
|
115
104
|
self._validate()
|
116
105
|
self.freeze()
|
@@ -173,22 +162,22 @@ class Config(LayeredConfigTree):
|
|
173
162
|
# Setup Methods #
|
174
163
|
#################
|
175
164
|
|
176
|
-
def _get_schema(self,
|
165
|
+
def _get_schema(self, schema_name: str = "main") -> PipelineSchema:
|
177
166
|
"""Returns the first :class:`~easylink.pipeline_schema.PipelineSchema` that validates the requested pipeline.
|
178
167
|
|
179
168
|
Parameters
|
180
169
|
----------
|
181
|
-
|
182
|
-
``
|
170
|
+
schema_name
|
171
|
+
The name of the specific ``PipelineSchema`` to validate the pipeline configuration against.
|
183
172
|
|
184
173
|
Returns
|
185
174
|
-------
|
186
|
-
The
|
175
|
+
The requested ``PipelineSchema`` if it validates the requested pipeline configuration.
|
187
176
|
|
188
177
|
Raises
|
189
178
|
------
|
190
179
|
SystemExit
|
191
|
-
If the pipeline configuration is not valid for
|
180
|
+
If the pipeline configuration is not valid for the requested schema,
|
192
181
|
the program exits with a non-zero code and all validation errors found
|
193
182
|
are logged.
|
194
183
|
|
@@ -197,20 +186,15 @@ class Config(LayeredConfigTree):
|
|
197
186
|
This acts as the pipeline configuration file's validation method since
|
198
187
|
we can only find a matching ``PipelineSchema`` if that file is valid.
|
199
188
|
|
200
|
-
This method returns the *first* ``PipelineSchema`` that validates and does
|
201
|
-
not attempt to check additional ones.
|
202
189
|
"""
|
203
190
|
errors = defaultdict(dict)
|
204
191
|
# Try each schema until one is validated
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
return schema
|
212
|
-
# No schemas were validated
|
213
|
-
exit_with_validation_error(dict(errors))
|
192
|
+
schema = PipelineSchema.get_schema(schema_name)
|
193
|
+
logs = schema.validate_step(self.pipeline, self.input_data)
|
194
|
+
if logs:
|
195
|
+
errors[PIPELINE_ERRORS_KEY][schema.name] = logs
|
196
|
+
exit_with_validation_error(dict(errors))
|
197
|
+
return schema
|
214
198
|
|
215
199
|
def _validate(self) -> None:
|
216
200
|
"""Validates the ``Config``.
|
@@ -19,7 +19,7 @@ from typing import cast
|
|
19
19
|
import yaml
|
20
20
|
from loguru import logger
|
21
21
|
|
22
|
-
from easylink.pipeline_schema_constants import
|
22
|
+
from easylink.pipeline_schema_constants import SCHEMA_PARAMS
|
23
23
|
from easylink.step import (
|
24
24
|
ChoiceStep,
|
25
25
|
EmbarrassinglyParallelStep,
|
@@ -244,17 +244,17 @@ class ImplementationCreator:
|
|
244
244
|
@staticmethod
|
245
245
|
def _extract_output_slot(script_path: Path, step_name: str) -> str:
|
246
246
|
"""Extracts the name of the output slot that this script is implementing."""
|
247
|
-
|
248
|
-
implementable_steps = ImplementationCreator._extract_implementable_steps(
|
247
|
+
schema_name = ImplementationCreator._extract_pipeline_schema_name(script_path)
|
248
|
+
implementable_steps = ImplementationCreator._extract_implementable_steps(schema_name)
|
249
249
|
step_names = [step.name for step in implementable_steps]
|
250
250
|
if step_name not in step_names:
|
251
251
|
raise ValueError(
|
252
|
-
f"'{step_name}' does not exist as an implementable step in the '{
|
252
|
+
f"'{step_name}' does not exist as an implementable step in the '{schema_name}' pipeline schema. "
|
253
253
|
)
|
254
254
|
duplicates = list(set([step for step in step_names if step_names.count(step) > 1]))
|
255
255
|
if duplicates:
|
256
256
|
raise ValueError(
|
257
|
-
f"Multiple implementable steps with the same name found in the '{
|
257
|
+
f"Multiple implementable steps with the same name found in the '{schema_name}' "
|
258
258
|
f"pipeline schema: {duplicates}."
|
259
259
|
)
|
260
260
|
implemented_step = [step for step in implementable_steps if step.name == step_name][0]
|
@@ -266,7 +266,7 @@ class ImplementationCreator:
|
|
266
266
|
return list(implemented_step.output_slots)[0]
|
267
267
|
|
268
268
|
@staticmethod
|
269
|
-
def _extract_implementable_steps(
|
269
|
+
def _extract_implementable_steps(schema_name: str) -> list[Step]:
|
270
270
|
"""Extracts all implementable steps from the pipeline schema.
|
271
271
|
|
272
272
|
This method recursively traverses the pipeline schema specified in the script
|
@@ -296,8 +296,7 @@ class ImplementationCreator:
|
|
296
296
|
implementable_steps.append(node)
|
297
297
|
return
|
298
298
|
|
299
|
-
schema_steps =
|
300
|
-
|
299
|
+
schema_steps, _edges = SCHEMA_PARAMS[schema_name]
|
301
300
|
implementable_steps: list[Step] = []
|
302
301
|
for schema_step in schema_steps:
|
303
302
|
_process_step(schema_step)
|
@@ -305,7 +304,7 @@ class ImplementationCreator:
|
|
305
304
|
return implementable_steps
|
306
305
|
|
307
306
|
@staticmethod
|
308
|
-
def
|
307
|
+
def _extract_pipeline_schema_name(script_path: Path) -> str:
|
309
308
|
"""Extracts the relevant pipeline schema name.
|
310
309
|
|
311
310
|
The expectation is that the output slot's name is specified within the script
|
@@ -316,8 +315,11 @@ class ImplementationCreator:
|
|
316
315
|
|
317
316
|
If no pipeline schema is specified, "main" will be used by default.
|
318
317
|
"""
|
319
|
-
|
320
|
-
|
318
|
+
schema_name_list: list[str] = _extract_metadata("PIPELINE_SCHEMA", script_path)
|
319
|
+
schema_name = "main" if len(schema_name_list) == 0 else schema_name_list[0]
|
320
|
+
if schema_name not in SCHEMA_PARAMS:
|
321
|
+
raise ValueError(f"Pipeline schema '{schema_name}' is not supported.")
|
322
|
+
return schema_name
|
321
323
|
|
322
324
|
@staticmethod
|
323
325
|
def _write_metadata(info: dict[str, dict[str, str]]) -> None:
|
@@ -204,9 +204,6 @@ dummy_step_1_for_output_dir_example_default:
|
|
204
204
|
- step_1_for_output_dir_example
|
205
205
|
image_path: /mnt/team/simulation_science/priv/engineering/er_ecosystem/images/zmbc/dummy_step_1_for_output_dir_example.sif
|
206
206
|
script_cmd: python /dummy_step_1_for_output_dir_example.py
|
207
|
-
# leave outputs out for testing purposes
|
208
|
-
# outputs:
|
209
|
-
# step_1_main_output_directory: output_dir/
|
210
207
|
dummy_step_2_for_output_dir_example:
|
211
208
|
steps:
|
212
209
|
- step_2_for_output_dir_example
|
@@ -14,7 +14,7 @@ from pathlib import Path
|
|
14
14
|
from layered_config_tree import LayeredConfigTree
|
15
15
|
|
16
16
|
from easylink.graph_components import EdgeParams, ImplementationGraph
|
17
|
-
from easylink.pipeline_schema_constants import
|
17
|
+
from easylink.pipeline_schema_constants import SCHEMA_PARAMS
|
18
18
|
from easylink.step import HierarchicalStep, NonLeafConfigurationState, Step
|
19
19
|
|
20
20
|
|
@@ -39,7 +39,7 @@ class PipelineSchema(HierarchicalStep):
|
|
39
39
|
|
40
40
|
Notes
|
41
41
|
-----
|
42
|
-
|
42
|
+
A ``PipelineSchema`` is intended to be constructed by the :meth:`get_schema`
|
43
43
|
class method.
|
44
44
|
|
45
45
|
The ``PipelineSchema`` is a high-level abstraction; it represents the desired
|
@@ -159,22 +159,21 @@ class PipelineSchema(HierarchicalStep):
|
|
159
159
|
)
|
160
160
|
|
161
161
|
@classmethod
|
162
|
-
def
|
162
|
+
def get_schema(cls, name: str = "main") -> list["PipelineSchema"]:
|
163
163
|
"""Gets all allowable ``PipelineSchemas``.
|
164
164
|
|
165
165
|
These ``PipelineSchemas`` represent the fully supported pipelines and are
|
166
166
|
used to validate the user-requested pipeline.
|
167
167
|
|
168
|
+
Parameters
|
169
|
+
----------
|
170
|
+
name
|
171
|
+
The name of the ``PipelineSchema`` to get.
|
172
|
+
|
168
173
|
Returns
|
169
174
|
-------
|
170
|
-
|
175
|
+
The requested ``PipelineSchema``.
|
171
176
|
"""
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
]
|
176
|
-
|
177
|
-
|
178
|
-
PIPELINE_SCHEMAS = PipelineSchema._get_schemas()
|
179
|
-
"""All allowable :class:`PipelineSchemas<PipelineSchema>` to validate the requested
|
180
|
-
pipeline against."""
|
177
|
+
if name not in SCHEMA_PARAMS:
|
178
|
+
raise ValueError(f"Pipeline schema '{name}' is not supported.")
|
179
|
+
return cls(name, *SCHEMA_PARAMS[name])
|
@@ -11,11 +11,10 @@ package defines the nodes and edges required to instantiate such ``PipelineSchem
|
|
11
11
|
|
12
12
|
from easylink.pipeline_schema_constants import development, testing
|
13
13
|
|
14
|
-
|
14
|
+
SCHEMA_PARAMS = {
|
15
|
+
"main": "TODO",
|
16
|
+
# development and testing
|
15
17
|
"development": development.SCHEMA_PARAMS,
|
16
|
-
}
|
17
|
-
|
18
|
-
TESTING_SCHEMA_PARAMS = {
|
19
18
|
"integration": testing.SCHEMA_PARAMS_ONE_STEP,
|
20
19
|
"output_dir": testing.SCHEMA_PARAMS_OUTPUT_DIR,
|
21
20
|
"combine_bad_topology": testing.SCHEMA_PARAMS_BAD_COMBINED_TOPOLOGY,
|
@@ -19,7 +19,6 @@ from snakemake.cli import main as snake_main
|
|
19
19
|
|
20
20
|
from easylink.configuration import Config, load_params_from_specification
|
21
21
|
from easylink.pipeline import Pipeline
|
22
|
-
from easylink.pipeline_schema import PIPELINE_SCHEMAS, PipelineSchema
|
23
22
|
from easylink.utilities.data_utils import (
|
24
23
|
copy_configuration_files_to_results_directory,
|
25
24
|
create_results_directory,
|
@@ -35,8 +34,8 @@ def main(
|
|
35
34
|
input_data: str | Path,
|
36
35
|
computing_environment: str | Path | None,
|
37
36
|
results_dir: str | Path,
|
38
|
-
|
39
|
-
|
37
|
+
schema_name: str = "main",
|
38
|
+
debug: bool = False,
|
40
39
|
) -> None:
|
41
40
|
"""Runs an EasyLink command.
|
42
41
|
|
@@ -60,17 +59,16 @@ def main(
|
|
60
59
|
to run the pipeline on. If None, the pipeline will be run locally.
|
61
60
|
results_dir
|
62
61
|
The directory to write results and incidental files (logs, etc.) to.
|
62
|
+
schema_name
|
63
|
+
The name of the schema to validate the pipeline configuration against.
|
63
64
|
debug
|
64
65
|
If False (the default), will suppress some of the workflow output. This
|
65
66
|
is intended to only be used for testing and development purposes.
|
66
|
-
potential_schemas
|
67
|
-
A list of potential schemas to validate the pipeline configuration against.
|
68
|
-
This is primarily used for testing purposes. Defaults to the supported schemas.
|
69
67
|
"""
|
70
68
|
config_params = load_params_from_specification(
|
71
69
|
pipeline_specification, input_data, computing_environment, results_dir
|
72
70
|
)
|
73
|
-
config = Config(config_params,
|
71
|
+
config = Config(config_params, schema_name)
|
74
72
|
pipeline = Pipeline(config)
|
75
73
|
# After validation is completed, create the results directory
|
76
74
|
create_results_directory(Path(results_dir))
|
@@ -63,7 +63,8 @@ def test_easylink_run(
|
|
63
63
|
f"-i {SPECIFICATIONS_DIR / input_data} "
|
64
64
|
f"-e {SPECIFICATIONS_DIR / computing_environment} "
|
65
65
|
f"-o {str(test_specific_results_dir)} "
|
66
|
-
"--no-timestamp"
|
66
|
+
"--no-timestamp "
|
67
|
+
"--schema development "
|
67
68
|
)
|
68
69
|
subprocess.run(
|
69
70
|
cmd,
|
@@ -57,7 +57,8 @@ def test_step_types(
|
|
57
57
|
f"-i {SPECIFICATIONS_DIR / input_data} "
|
58
58
|
f"-e {SPECIFICATIONS_DIR / computing_environment} "
|
59
59
|
f"-o {str(test_specific_results_dir)} "
|
60
|
-
"--no-timestamp"
|
60
|
+
"--no-timestamp "
|
61
|
+
"--schema development "
|
61
62
|
)
|
62
63
|
subprocess.run(
|
63
64
|
cmd,
|
@@ -6,7 +6,7 @@ import pyarrow.parquet as pq
|
|
6
6
|
import pytest
|
7
7
|
|
8
8
|
from easylink.pipeline_schema import PipelineSchema
|
9
|
-
from easylink.pipeline_schema_constants import
|
9
|
+
from easylink.pipeline_schema_constants import SCHEMA_PARAMS
|
10
10
|
from easylink.runner import main
|
11
11
|
from easylink.utilities.data_utils import load_yaml
|
12
12
|
from tests.conftest import SPECIFICATIONS_DIR
|
@@ -20,11 +20,8 @@ def test_looping_embarrassingly_parallel_step(test_specific_results_dir: Path) -
|
|
20
20
|
pipeline_specification = EP_SPECIFICATIONS_DIR / "pipeline_loop_step.yaml"
|
21
21
|
input_data = COMMON_SPECIFICATIONS_DIR / "input_data.yaml"
|
22
22
|
|
23
|
-
# Load the schema to test against
|
24
|
-
schema = PipelineSchema("looping_ep_step", *TESTING_SCHEMA_PARAMS["looping_ep_step"])
|
25
|
-
|
26
23
|
_run_pipeline_and_confirm_finished(
|
27
|
-
|
24
|
+
"looping_ep_step", test_specific_results_dir, pipeline_specification, input_data
|
28
25
|
)
|
29
26
|
|
30
27
|
intermediate_results_dir = test_specific_results_dir / "intermediate"
|
@@ -137,11 +134,8 @@ def test_embarrassingly_parallel_sections(
|
|
137
134
|
pipeline_specification = EP_SPECIFICATIONS_DIR / pipeline_spec
|
138
135
|
input_data = COMMON_SPECIFICATIONS_DIR / "input_data.yaml"
|
139
136
|
|
140
|
-
# Load the schema to test against
|
141
|
-
schema = PipelineSchema(schema_name, *TESTING_SCHEMA_PARAMS[schema_name])
|
142
|
-
|
143
137
|
_run_pipeline_and_confirm_finished(
|
144
|
-
|
138
|
+
schema_name, test_specific_results_dir, pipeline_specification, input_data
|
145
139
|
)
|
146
140
|
|
147
141
|
intermediate_results_dir = test_specific_results_dir / "intermediate"
|
@@ -185,7 +179,7 @@ def test_embarrassingly_parallel_sections(
|
|
185
179
|
|
186
180
|
|
187
181
|
def _run_pipeline_and_confirm_finished(
|
188
|
-
|
182
|
+
schema_name: str,
|
189
183
|
results_dir: Path,
|
190
184
|
pipeline_specification: Path,
|
191
185
|
input_data: Path,
|
@@ -199,7 +193,7 @@ def _run_pipeline_and_confirm_finished(
|
|
199
193
|
input_data=input_data,
|
200
194
|
computing_environment=computing_environment,
|
201
195
|
results_dir=results_dir,
|
202
|
-
|
196
|
+
schema_name=schema_name,
|
203
197
|
)
|
204
198
|
assert pytest_wrapped_e.value.code == 0
|
205
199
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import pytest
|
3
3
|
|
4
4
|
from easylink.pipeline_schema import PipelineSchema
|
5
|
-
from easylink.pipeline_schema_constants import
|
5
|
+
from easylink.pipeline_schema_constants import SCHEMA_PARAMS
|
6
6
|
from easylink.runner import main
|
7
7
|
from tests.conftest import SPECIFICATIONS_DIR
|
8
8
|
|
@@ -10,8 +10,7 @@ from tests.conftest import SPECIFICATIONS_DIR
|
|
10
10
|
@pytest.mark.slow
|
11
11
|
def test_missing_results(test_specific_results_dir, mocker, caplog):
|
12
12
|
"""Test that the pipeline fails when a step is missing output files."""
|
13
|
-
nodes, edges =
|
14
|
-
mocker.patch("easylink.pipeline_schema.ALLOWED_SCHEMA_PARAMS", TESTING_SCHEMA_PARAMS)
|
13
|
+
nodes, edges = SCHEMA_PARAMS["integration"]
|
15
14
|
mocker.patch(
|
16
15
|
"easylink.configuration.Config._get_schema",
|
17
16
|
return_value=PipelineSchema("integration", nodes=nodes, edges=edges),
|
@@ -39,8 +38,7 @@ def test_missing_results(test_specific_results_dir, mocker, caplog):
|
|
39
38
|
@pytest.mark.parametrize("outputs_specified", [True, False])
|
40
39
|
def test_outputting_a_directory(outputs_specified: bool, test_specific_results_dir, mocker):
|
41
40
|
"""Test that the pipeline fails when a step is missing output files."""
|
42
|
-
nodes, edges =
|
43
|
-
mocker.patch("easylink.pipeline_schema.ALLOWED_SCHEMA_PARAMS", TESTING_SCHEMA_PARAMS)
|
41
|
+
nodes, edges = SCHEMA_PARAMS["output_dir"]
|
44
42
|
mocker.patch(
|
45
43
|
"easylink.configuration.Config._get_schema",
|
46
44
|
return_value=PipelineSchema("output_dir", nodes=nodes, edges=edges),
|
@@ -6,7 +6,7 @@ import pytest
|
|
6
6
|
from pytest_mock import MockerFixture
|
7
7
|
|
8
8
|
from easylink.pipeline_schema import PipelineSchema
|
9
|
-
from easylink.pipeline_schema_constants import
|
9
|
+
from easylink.pipeline_schema_constants import SCHEMA_PARAMS
|
10
10
|
from easylink.runner import main
|
11
11
|
from easylink.utilities.general_utils import is_on_slurm
|
12
12
|
from tests.conftest import SPECIFICATIONS_DIR
|
@@ -21,8 +21,7 @@ def test_slurm(
|
|
21
21
|
test_specific_results_dir: Path, mocker: MockerFixture, caplog: pytest.LogCaptureFixture
|
22
22
|
) -> None:
|
23
23
|
"""Test that the pipeline runs on SLURM with appropriate resources."""
|
24
|
-
nodes, edges =
|
25
|
-
mocker.patch("easylink.pipeline_schema.ALLOWED_SCHEMA_PARAMS", TESTING_SCHEMA_PARAMS)
|
24
|
+
nodes, edges = SCHEMA_PARAMS["integration"]
|
26
25
|
mocker.patch(
|
27
26
|
"easylink.configuration.Config._get_schema",
|
28
27
|
return_value=PipelineSchema("integration", nodes=nodes, edges=edges),
|
@@ -6,7 +6,7 @@ import pytest
|
|
6
6
|
import yaml
|
7
7
|
|
8
8
|
from easylink.pipeline_schema import PipelineSchema
|
9
|
-
from easylink.pipeline_schema_constants import
|
9
|
+
from easylink.pipeline_schema_constants import SCHEMA_PARAMS
|
10
10
|
from easylink.runner import main
|
11
11
|
from easylink.utilities.general_utils import is_on_slurm
|
12
12
|
from tests.conftest import SPECIFICATIONS_DIR
|
@@ -19,8 +19,7 @@ from tests.conftest import SPECIFICATIONS_DIR
|
|
19
19
|
)
|
20
20
|
def test_spark_slurm(test_specific_results_dir, mocker, caplog):
|
21
21
|
"""Test that the pipeline runs spark on SLURM with appropriate resources."""
|
22
|
-
nodes, edges =
|
23
|
-
mocker.patch("easylink.pipeline_schema.ALLOWED_SCHEMA_PARAMS", TESTING_SCHEMA_PARAMS)
|
22
|
+
nodes, edges = SCHEMA_PARAMS["integration"]
|
24
23
|
mocker.patch(
|
25
24
|
"easylink.configuration.Config._get_schema",
|
26
25
|
return_value=PipelineSchema("integration", nodes=nodes, edges=edges),
|
@@ -155,4 +155,4 @@ def default_config_params(default_config_paths) -> dict[str, Path]:
|
|
155
155
|
@pytest.fixture()
|
156
156
|
def default_config(default_config_params) -> Config:
|
157
157
|
"""A good/known Config object"""
|
158
|
-
return Config(default_config_params)
|
158
|
+
return Config(default_config_params, schema_name="development")
|
@@ -12,12 +12,28 @@ from easylink.configuration import (
|
|
12
12
|
_load_computing_environment,
|
13
13
|
_load_input_data_paths,
|
14
14
|
)
|
15
|
-
from easylink.pipeline_schema import
|
15
|
+
from easylink.pipeline_schema import PipelineSchema
|
16
|
+
from easylink.step import NonLeafConfigurationState
|
16
17
|
|
17
18
|
|
18
19
|
def test__get_schema(default_config: Config) -> None:
|
19
20
|
"""Test default config gets "development schema", without errors"""
|
20
|
-
assert
|
21
|
+
# We cannot assert equality of the config's schema object and a different instance
|
22
|
+
# from PipelineSchema.get_schema("development"), so instead just check that
|
23
|
+
# some of the attrs are the same.
|
24
|
+
schema = default_config.schema
|
25
|
+
assert isinstance(schema, PipelineSchema)
|
26
|
+
assert schema.name == schema.step_name == "development"
|
27
|
+
assert schema.config_key == "substeps"
|
28
|
+
assert isinstance(schema.configuration_state, NonLeafConfigurationState)
|
29
|
+
assert [node.name for node in schema.nodes] == [
|
30
|
+
"input_data",
|
31
|
+
"step_1",
|
32
|
+
"step_2",
|
33
|
+
"step_3",
|
34
|
+
"choice_section",
|
35
|
+
"results",
|
36
|
+
]
|
21
37
|
|
22
38
|
|
23
39
|
def test_load_params_from_specification(
|
@@ -121,7 +137,7 @@ def test_required_attributes(mocker, default_config_params, key, value):
|
|
121
137
|
if value:
|
122
138
|
config_params["environment"][key] = value
|
123
139
|
env_dict = {key: value} if value else {}
|
124
|
-
retrieved = Config(config_params).environment[key]
|
140
|
+
retrieved = Config(config_params, "development").environment[key]
|
125
141
|
expected = DEFAULT_ENVIRONMENT["environment"].copy()
|
126
142
|
expected.update(env_dict)
|
127
143
|
assert retrieved == expected[key]
|
@@ -143,7 +159,7 @@ def test_implementation_resource_requests(default_config_params, resource_reques
|
|
143
159
|
config_params = default_config_params
|
144
160
|
if resource_request:
|
145
161
|
config_params["environment"][key] = resource_request
|
146
|
-
config = Config(config_params)
|
162
|
+
config = Config(config_params, "development")
|
147
163
|
env_dict = {key: resource_request.copy()} if resource_request else {}
|
148
164
|
retrieved = config.environment[key].to_dict()
|
149
165
|
expected = DEFAULT_ENVIRONMENT["environment"][key].copy()
|
@@ -191,7 +207,7 @@ def test_spark_requests(default_config_params, spark_request, requires_spark):
|
|
191
207
|
|
192
208
|
if spark_request:
|
193
209
|
config_params["environment"][key] = spark_request
|
194
|
-
retrieved = Config(config_params).environment[key].to_dict()
|
210
|
+
retrieved = Config(config_params, "development").environment[key].to_dict()
|
195
211
|
expected_env_dict = {key: spark_request.copy()} if spark_request else {}
|
196
212
|
expected = LayeredConfigTree(SPARK_DEFAULTS, layers=["initial_data", "user"])
|
197
213
|
if spark_request:
|
@@ -206,6 +222,8 @@ def test_combined_implementations(default_config_params, is_default):
|
|
206
222
|
config_params = default_config_params
|
207
223
|
if not is_default:
|
208
224
|
config_params["pipeline"]["combined_implementations"] = combined_dict
|
209
|
-
combined_implementations = Config(
|
225
|
+
combined_implementations = Config(
|
226
|
+
config_params, "development"
|
227
|
+
).pipeline.combined_implementations
|
210
228
|
expected = {} if is_default else combined_dict
|
211
229
|
assert combined_implementations.to_dict() == expected
|
@@ -30,7 +30,6 @@ MULTIPLE_METADATA = """
|
|
30
30
|
# STEP_NAME: step_1
|
31
31
|
# REQUIREMENTS: pandas==2.1.2 pyarrow pyyaml"""
|
32
32
|
|
33
|
-
|
34
33
|
MULTIPLE_STEPS_METADATA = """
|
35
34
|
# STEP_NAME: step_1, step_2
|
36
35
|
# REQUIREMENTS: pandas==2.1.2 pyarrow pyyaml"""
|
@@ -89,11 +88,22 @@ def test__extract_requirements_raises(tmp_path: Path) -> None:
|
|
89
88
|
(MISSING_METADATA, "main"),
|
90
89
|
],
|
91
90
|
)
|
92
|
-
def
|
91
|
+
def test__extract_pipeline_schema_name(
|
92
|
+
script_content: str, expected: str, tmp_path: Path
|
93
|
+
) -> None:
|
93
94
|
script_path = tmp_path / "foo_step.py"
|
94
95
|
with open(script_path, "w") as file:
|
95
96
|
file.write(script_content)
|
96
|
-
assert ImplementationCreator.
|
97
|
+
assert ImplementationCreator._extract_pipeline_schema_name(script_path) == expected
|
98
|
+
|
99
|
+
|
100
|
+
def test__extract_pipeline_schema_name_raises(tmp_path: Path) -> None:
|
101
|
+
script_path = tmp_path / "foo_step.py"
|
102
|
+
metadata_str = GOOD_METADATA.replace("development", "some-non-existing-schema")
|
103
|
+
with open(script_path, "w") as file:
|
104
|
+
file.write(metadata_str)
|
105
|
+
with pytest.raises(ValueError, match="is not supported"):
|
106
|
+
ImplementationCreator._extract_pipeline_schema_name(script_path)
|
97
107
|
|
98
108
|
|
99
109
|
def test__extract_implementable_steps(tmp_path: Path) -> None:
|
@@ -27,7 +27,7 @@ def test_build_snakefile(
|
|
27
27
|
config_paths["computing_environment"] = f"{test_dir}/spark_environment.yaml"
|
28
28
|
|
29
29
|
config_params = load_params_from_specification(**config_paths)
|
30
|
-
config = Config(config_params)
|
30
|
+
config = Config(config_params, "development")
|
31
31
|
mocker.patch("easylink.implementation.Implementation.validate", return_value={})
|
32
32
|
pipeline = Pipeline(config)
|
33
33
|
create_results_directory(results_dir)
|