diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e25ca9bb5..5a43cbecc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,53 +1,73 @@ name: Testing on: push: - branches: [main, develop] + branches: + - main + - develop pull_request: - branches: [main, develop] + branches: + - main + - develop schedule: - cron: 0 0 * * MON jobs: build: - runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.11', '3.13'] - optional: [false] + os: + - ubuntu-latest + - windows-latest + python-version: + - '3.11' + - '3.13' + optional: + - true include: - python-version: '3.11' - optional: true + optional: false + os: ubuntu-latest + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 + uses: conda-incubator/setup-miniconda@v3 with: + miniconda-version: latest + auto-update-conda: true python-version: ${{ matrix.python-version }} - - name: Install dependencies + auto-activate: true + activate-environment: h2integrate + - name: Install base dependencies + shell: bash -el {0} env: SKLEARN_ALLOW_DEPRECATED_SKLEARN_PACKAGE_INSTALL: true run: | - sudo apt-get update && sudo apt-get install -y libglpk-dev glpk-utils coinor-cbc + conda install -y -c conda-forge glpk coin-or-cbc>=2.10.12 python -m pip install --upgrade pip - if [ "${{ matrix.optional }}" = "true" ]; then - pip install ".[develop]" - else - pip install ".[develop]" - fi + pip install ".[develop]" + - if: ${{ matrix.optional }} + name: Install optional dependencies + shell: bash -el {0} + run: | + conda install -y -c conda-forge wisdem + pip install ".[extras]" - name: Create env file run: | touch .env - name: Run unit tests - run: | - pytest . -m unit --cov=h2integrate --cov-report=xml:unit-coverage.xml + shell: bash -el {0} + run: pytest . -m unit --cov=h2integrate --cov-report=lcov:./unit-coverage.lcov - name: Run regression tests - run: | - pytest . -m regression --cov=h2integrate --cov-report=xml:regression-coverage.xml + shell: bash -el {0} + run: pytest . -m regression --cov=h2integrate --cov-report=lcov:./regression-coverage.lcov - name: Run integration tests - run: | - pytest . -m integration --cov=h2integrate --cov-report=xml:integration-coverage.xml - - name: Upload unit coverage to - uses: codecov/codecov-action@v5 + shell: bash -el {0} + run: pytest . -m integration --cov=h2integrate --cov-report=lcov:./integration-coverage.lcov + - name: Upload test coverage + uses: coverallsapp/github-action@v2 + if: contains( matrix.os, 'ubuntu') && contains( matrix.python-version, '3.13') with: - token: ${{ secrets.CODECOV_TOKEN }} - files: unit-coverage.xml, regression-coverage.xml, integration-coverage.xml - flags: unit,regression,integration + github-token: ${{ secrets.COVERALLS_REPO_TOKEN }} + files: ./unit-coverage.lcov, ./regression-coverage.lcov, ./integration-coverage.lcov + flag-name: unit,regression,integration + fail-on-error: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e7e62e9e..c2302b3b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## Unreleased + +- Bumps the `coin-or-cbc` dependency to at least 2.10.12 to enable easy Windows compatibility. [PR 590](https://github.com/NatLabRockies/H2Integrate/pull/590) +- Uses the optional installation parameter `extras` to combine all analysis extras, and remove them + from the `develop` options. [PR 590](https://github.com/NatLabRockies/H2Integrate/pull/590) +- Tests reliant on the `gis` optional dependencies are no longer run when the extra dependencies are not installed + similar to the ard tests. [PR 590](https://github.com/NatLabRockies/H2Integrate/pull/590) +- Updates the testing infrastructure to use function-scoped fixtures unless there is a specific need for sharing + data between functions in a module. [PR 590](https://github.com/NatLabRockies/H2Integrate/pull/590) + ## 0.7.1 [March 13, 2026] ### Updates @@ -26,6 +36,7 @@ - Fixed a bug in the discrete variable instantiation within the iron processing stack that caused a failure with OpenMDAO v3.43 [PR 595](https://github.com/NatLabRockies/H2Integrate/pull/595) - Fixed a bug in model setup where transporters were added to the system at the end of the system instead after their source [PR 591](https://github.com/NatLabRockies/H2Integrate/pull/591) - Fixed a bug in example 1 (steel) where a cable was included between the combiner to steel, but steel uses an internal grid connection [PR 591](https://github.com/NatLabRockies/H2Integrate/pull/591) +- Introduced a keyword arg to `post_process` to allow users to choose if results are printed to the console. [PR 597](https://github.com/NatLabRockies/H2Integrate/pull/597) ## 0.7 [March 3, 2026] diff --git a/README.md b/README.md index 060082d98..ce4604603 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ pip install h2integrate 1. Using Git, navigate to a local target directory and clone repository: ```bash - git clone https://github.com/NREL/H2Integrate.git + git clone https://github.com/NatLabRockies/H2Integrate.git ``` 2. Navigate to `H2Integrate` @@ -141,7 +141,8 @@ environment for development work. - Use one of the extra flags as needed: - `gis`: adds the iron mapping tools. - `ard`: adds the Ard-based wind models. - - `develop`: adds developer and documentation tools, plus optional analysis modifiers `gis` and `ard`. + - `extras`: installs all extra analysis tool dependencies, e.g., `ard` or `gis`. + - `develop`: adds developer and documentation tools. - `examples`: allows you to use the Jupyter Notebooks and all examples (includes `ard` and `gis`). - `all` simplifies adding all the dependencies. @@ -176,17 +177,9 @@ pip install -e ".[all]" 4. Install H2Integrate and its dependencies: ```bash - conda install -y -c conda-forge glpk - ``` - - Note: Unix users should install Cbc via: - - ```bash - conda install -y -c conda-forge coin-or-cbc=2.10.8 + conda install -y -c conda-forge glpk coin-or-cbc>=2.10.12 ``` - Windows users will have to manually install Cbc: https://github.com/coin-or/Cbc. - - If you want to just use H2Integrate: ```bash diff --git a/docs/getting_started/install.md b/docs/getting_started/install.md index a65b34c3f..4e9c1c8d9 100644 --- a/docs/getting_started/install.md +++ b/docs/getting_started/install.md @@ -75,7 +75,8 @@ environment for development work. - Use one of the extra flags as needed: - `gis`: adds the iron mapping tools. - `ard`: adds the Ard-based wind models. - - `develop`: adds developer and documentation tools, plus optional analysis modifiers `gis` and `ard`. + - `extras`: installs all extra analysis tool dependencies, e.g., `ard` or `gis`. + - `develop`: adds developer and documentation tools. - `examples`: allows you to use the Jupyter Notebooks and all examples (includes `ard` and `gis`). - `all` simplifies adding all the dependencies. @@ -110,19 +111,9 @@ pip install -e ".[all]" 4. Install H2Integrate and its dependencies: ```bash - conda install -y -c conda-forge glpk + conda install -y -c conda-forge glpk coin-or-cbc>=2.10.12 ``` - ````{note} - Unix users should install Cbc via: - - ```bash - conda install -y -c conda-forge coin-or-cbc=2.10.8 - ``` - - Windows users should install Cbc manually according to https://github.com/coin-or/Cbc. - ```` - - If you want to just use H2Integrate: ```bash diff --git a/docs/user_guide/figures/example_26_iron_map.png b/docs/user_guide/figures/example_26_iron_map.png deleted file mode 100644 index ee528ab32..000000000 Binary files a/docs/user_guide/figures/example_26_iron_map.png and /dev/null differ diff --git a/environment.yml b/environment.yml index 3899c89f9..5ca9dbed3 100644 --- a/environment.yml +++ b/environment.yml @@ -3,7 +3,7 @@ channels: [conda-forge, defaults] dependencies: - python=3.11 - glpk - # - coin-or-cbc=2.10.8 # NOTE: uncomment if on Unix + - coin-or-cbc>=2.10.12 # - wisdem # NOTE: uncomment if installing with Ard - pip - pip: [.] diff --git a/examples/test/conftest.py b/examples/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/examples/test/conftest.py +++ b/examples/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/examples/test/test_all_examples.py b/examples/test/test_all_examples.py index efe524ee6..72c043f9c 100644 --- a/examples/test/test_all_examples.py +++ b/examples/test/test_all_examples.py @@ -1,5 +1,4 @@ import os -import shutil import importlib from pathlib import Path @@ -8,7 +7,7 @@ import pytest import openmdao.api as om -from h2integrate import ROOT_DIR, EXAMPLE_DIR +from h2integrate import ROOT_DIR from h2integrate.core.file_utils import load_yaml from h2integrate.core.h2integrate_model import H2IntegrateModel @@ -16,18 +15,6 @@ ROOT = Path(__file__).parents[1] -@pytest.fixture(scope="function") -def temp_copy_of_example(temp_dir, example_folder, resource_example_folder): - original = EXAMPLE_DIR / example_folder - shutil.copytree(original, temp_dir / example_folder, dirs_exist_ok=True) - if resource_example_folder is not None: - secondary = EXAMPLE_DIR / resource_example_folder - shutil.copytree(secondary, temp_dir / resource_example_folder, dirs_exist_ok=True) - os.chdir(temp_dir / example_folder) - yield temp_dir / example_folder - os.chdir(Path(__file__).parent) - - # docs fencepost start: DO NOT REMOVE @pytest.mark.integration @pytest.mark.parametrize("example_folder,resource_example_folder", [("01_onshore_steel_mn", None)]) @@ -1937,6 +1924,7 @@ def test_24_solar_battery_grid_example(subtests, temp_copy_of_example): @pytest.mark.integration @pytest.mark.parametrize("example_folder,resource_example_folder", [("28_iron_map", None)]) +@pytest.mark.skipif(importlib.util.find_spec("geopandas") is None, reason="`gis` not installed") def test_28_iron_map_example(subtests, temp_copy_of_example): import geopandas as gpd import matplotlib diff --git a/h2integrate/control/test/conftest.py b/h2integrate/control/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/control/test/conftest.py +++ b/h2integrate/control/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/ammonia/test/conftest.py b/h2integrate/converters/ammonia/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/ammonia/test/conftest.py +++ b/h2integrate/converters/ammonia/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/co2/marine/test/conftest.py b/h2integrate/converters/co2/marine/test/conftest.py index 7dc54f763..4a4191a52 100644 --- a/h2integrate/converters/co2/marine/test/conftest.py +++ b/h2integrate/converters/co2/marine/test/conftest.py @@ -2,7 +2,11 @@ import pytest -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) has_mcm = importlib.util.find_spec("mcm") is not None @@ -23,7 +27,7 @@ def plant_config(): # docs fencepost start: DO NOT REMOVE -@pytest.fixture(scope="module") +@pytest.fixture(scope="function") def driver_config(temp_dir): # noqa: F811 driver_config = { "general": { diff --git a/h2integrate/converters/grid/test/conftest.py b/h2integrate/converters/grid/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/grid/test/conftest.py +++ b/h2integrate/converters/grid/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/hopp/test/conftest.py b/h2integrate/converters/hopp/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/hopp/test/conftest.py +++ b/h2integrate/converters/hopp/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/hydrogen/geologic/test/conftest.py b/h2integrate/converters/hydrogen/geologic/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/hydrogen/geologic/test/conftest.py +++ b/h2integrate/converters/hydrogen/geologic/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/hydrogen/test/conftest.py b/h2integrate/converters/hydrogen/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/hydrogen/test/conftest.py +++ b/h2integrate/converters/hydrogen/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/iron/test/conftest.py b/h2integrate/converters/iron/test/conftest.py index 107ff3d86..50afd8132 100644 --- a/h2integrate/converters/iron/test/conftest.py +++ b/h2integrate/converters/iron/test/conftest.py @@ -3,7 +3,11 @@ from h2integrate import EXAMPLE_DIR from h2integrate.core.inputs.validation import load_driver_yaml -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) @fixture diff --git a/h2integrate/converters/methanol/test/conftest.py b/h2integrate/converters/methanol/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/methanol/test/conftest.py +++ b/h2integrate/converters/methanol/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/natural_gas/test/conftest.py b/h2integrate/converters/natural_gas/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/natural_gas/test/conftest.py +++ b/h2integrate/converters/natural_gas/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/nitrogen/test/conftest.py b/h2integrate/converters/nitrogen/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/nitrogen/test/conftest.py +++ b/h2integrate/converters/nitrogen/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/solar/test/conftest.py b/h2integrate/converters/solar/test/conftest.py index fe767140b..2a0ca26e7 100644 --- a/h2integrate/converters/solar/test/conftest.py +++ b/h2integrate/converters/solar/test/conftest.py @@ -2,7 +2,11 @@ from h2integrate import EXAMPLE_DIR -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) @pytest.fixture diff --git a/h2integrate/converters/steel/test/conftest.py b/h2integrate/converters/steel/test/conftest.py index 934d70cd2..7471ef3b1 100644 --- a/h2integrate/converters/steel/test/conftest.py +++ b/h2integrate/converters/steel/test/conftest.py @@ -3,7 +3,11 @@ from h2integrate import EXAMPLE_DIR from h2integrate.core.inputs.validation import load_driver_yaml -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) @pytest.fixture diff --git a/h2integrate/converters/test/conftest.py b/h2integrate/converters/test/conftest.py index aec692e38..a4763a760 100644 --- a/h2integrate/converters/test/conftest.py +++ b/h2integrate/converters/test/conftest.py @@ -4,7 +4,11 @@ import os -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/converters/water/desal/test/conftest.py b/h2integrate/converters/water/desal/test/conftest.py index aec692e38..a4763a760 100644 --- a/h2integrate/converters/water/desal/test/conftest.py +++ b/h2integrate/converters/water/desal/test/conftest.py @@ -4,7 +4,11 @@ import os -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/converters/water_power/test/conftest.py b/h2integrate/converters/water_power/test/conftest.py index aec692e38..a4763a760 100644 --- a/h2integrate/converters/water_power/test/conftest.py +++ b/h2integrate/converters/water_power/test/conftest.py @@ -4,7 +4,11 @@ import os -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/converters/wind/layout/test/conftest.py b/h2integrate/converters/wind/layout/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/wind/layout/test/conftest.py +++ b/h2integrate/converters/wind/layout/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/converters/wind/test/conftest.py b/h2integrate/converters/wind/test/conftest.py index 3c9a44d85..81f4ba75b 100644 --- a/h2integrate/converters/wind/test/conftest.py +++ b/h2integrate/converters/wind/test/conftest.py @@ -3,7 +3,11 @@ import pytest from hopp import TEST_ENV_VAR -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/converters/wind/tools/test/conftest.py b/h2integrate/converters/wind/tools/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/converters/wind/tools/test/conftest.py +++ b/h2integrate/converters/wind/tools/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/core/test/conftest.py b/h2integrate/core/test/conftest.py index 144c38689..378efd555 100644 --- a/h2integrate/core/test/conftest.py +++ b/h2integrate/core/test/conftest.py @@ -6,7 +6,13 @@ from h2integrate import EXAMPLE_DIR -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_dir_module, + temp_copy_of_example, + pytest_collection_modifyitems, + temp_copy_of_example_module_scope, +) def pytest_sessionstart(session): diff --git a/h2integrate/core/test/test_recorder.py b/h2integrate/core/test/test_recorder.py index 316a25f80..504e18fb0 100644 --- a/h2integrate/core/test/test_recorder.py +++ b/h2integrate/core/test/test_recorder.py @@ -1,8 +1,5 @@ -import os - import pytest -from h2integrate import EXAMPLE_DIR from h2integrate.core.h2integrate_model import H2IntegrateModel from h2integrate.core.inputs.validation import load_driver_yaml @@ -13,23 +10,21 @@ @pytest.mark.unit -def test_output_folder_creation_first_run(temp_dir, subtests): - # Test that the sql file is written to the output folder - # with the specified name - - # change to example dir - os.chdir(EXAMPLE_DIR / "05_wind_h2_opt") +@pytest.mark.parametrize("example_folder,resource_example_folder", [("05_wind_h2_opt", None)]) +def test_output_folder_creation_first_run(temp_copy_of_example_module_scope, subtests): + """Test that the sql file is written to the output folder with the specified name.""" # initialize H2I using non-optimization config - input_file = EXAMPLE_DIR / "05_wind_h2_opt" / "wind_plant_electrolyzer0.yaml" + example_folder = temp_copy_of_example_module_scope + input_file = example_folder / "wind_plant_electrolyzer0.yaml" h2i = H2IntegrateModel(input_file) # load driver config for optimization run - driver_config = load_driver_yaml(EXAMPLE_DIR / "05_wind_h2_opt" / "driver_config.yaml") + driver_config = load_driver_yaml(example_folder / "driver_config.yaml") # update driver config params with test variables filename_initial = TEST_RECORDER_OUTPUT_FILE0 - driver_config["general"]["folder_output"] = temp_dir + output_folder = example_folder / driver_config["general"]["folder_output"] driver_config["recorder"]["file"] = filename_initial driver_config["driver"]["optimization"]["max_iter"] = 5 # to prevent tests taking too long @@ -40,10 +35,8 @@ def test_output_folder_creation_first_run(temp_dir, subtests): h2i.create_driver_model() # check if output folder and output files exist - output_folder_exists = (EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir).exists() - output_file_exists_prerun = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_initial - ).exists() + output_folder_exists = output_folder.exists() + output_file_exists_prerun = (output_folder / filename_initial).exists() with subtests.test("Run 0: output folder exists"): assert output_folder_exists is True @@ -54,32 +47,31 @@ def test_output_folder_creation_first_run(temp_dir, subtests): h2i.run() # check that recorder file was created - output_file_exists_postrun = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_initial - ).exists() + output_file_exists_postrun = (output_folder / filename_initial).exists() with subtests.test("Run 0: recorder output file exists after run"): assert output_file_exists_postrun is True @pytest.mark.unit -def test_output_new_recorder_filename_second_run(temp_dir, subtests): - # Test that the sql file is written to the output folder - # with the specified base name and an appended 0 - # change to example dir - os.chdir(EXAMPLE_DIR / "05_wind_h2_opt") +@pytest.mark.parametrize("example_folder,resource_example_folder", [("05_wind_h2_opt", None)]) +def test_output_new_recorder_filename_second_run(temp_copy_of_example_module_scope, subtests): + """Test that the sql file is written to the output folder with the specified base name and + an appended 0. + """ # initialize H2I using non-optimization config - input_file = EXAMPLE_DIR / "05_wind_h2_opt" / "wind_plant_electrolyzer0.yaml" + example_folder = temp_copy_of_example_module_scope + input_file = example_folder / "wind_plant_electrolyzer0.yaml" h2i = H2IntegrateModel(input_file) # load driver config for optimization run - driver_config = load_driver_yaml(EXAMPLE_DIR / "05_wind_h2_opt" / "driver_config.yaml") + driver_config = load_driver_yaml(example_folder / "driver_config.yaml") # update driver config params with test variables filename_initial = TEST_RECORDER_OUTPUT_FILE0 filename_expected = TEST_RECORDER_OUTPUT_FILE1 - driver_config["general"]["folder_output"] = temp_dir + output_folder = example_folder / driver_config["general"]["folder_output"] driver_config["recorder"]["file"] = filename_initial driver_config["driver"]["optimization"]["max_iter"] = 5 # to prevent tests taking too long @@ -90,43 +82,34 @@ def test_output_new_recorder_filename_second_run(temp_dir, subtests): h2i.create_driver_model() # check if output folder and output files exist - output_folder_exists = (EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir).exists() - output_file_exists_prerun = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_initial - ).exists() - with subtests.test("Run 1: output folder exists"): - assert output_folder_exists is True + assert output_folder.exists() with subtests.test("Run 1: initial recorder output file exists"): - assert output_file_exists_prerun is True + assert (output_folder / filename_initial).exists() # run the model h2i.run() # check that the new recorder file was created - new_output_file_exists = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_expected - ).exists() with subtests.test("Run 1: new recorder output file was made"): - assert new_output_file_exists is True + assert (output_folder / filename_expected).exists() @pytest.mark.unit -def test_output_new_recorder_overwrite_first_run(temp_dir, subtests): - # change to example dir - os.chdir(EXAMPLE_DIR / "05_wind_h2_opt") - +@pytest.mark.parametrize("example_folder,resource_example_folder", [("05_wind_h2_opt", None)]) +def test_output_new_recorder_overwrite_first_run(temp_copy_of_example_module_scope, subtests): # initialize H2I using non-optimization config - input_file = EXAMPLE_DIR / "05_wind_h2_opt" / "wind_plant_electrolyzer0.yaml" + example_folder = temp_copy_of_example_module_scope + input_file = example_folder / "wind_plant_electrolyzer0.yaml" h2i = H2IntegrateModel(input_file) # load driver config for optimization run - driver_config = load_driver_yaml(EXAMPLE_DIR / "05_wind_h2_opt" / "driver_config.yaml") + driver_config = load_driver_yaml(example_folder / "driver_config.yaml") # update driver config params with test variables filename_initial = TEST_RECORDER_OUTPUT_FILE0 filename_exists_if_failed = TEST_RECORDER_OUTPUT_FILE2 - driver_config["general"]["folder_output"] = temp_dir + output_folder = example_folder / driver_config["general"]["folder_output"] driver_config["recorder"]["file"] = filename_initial # specify that we want the previous file overwritten rather @@ -141,44 +124,35 @@ def test_output_new_recorder_overwrite_first_run(temp_dir, subtests): h2i.create_driver_model() # check if output folder and output files exist - output_folder_exists = (EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir).exists() - output_file_exists_prerun = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_initial - ).exists() - with subtests.test("Run 2: output folder exists"): - assert output_folder_exists is True + assert output_folder.exists() with subtests.test("Run 2: initial recorder output file exists"): - assert output_file_exists_prerun is True + assert (output_folder / filename_initial).exists() # run the model h2i.run() # check that recorder file was overwritten - new_output_file_exists = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_exists_if_failed - ).exists() with subtests.test("Run 2: initial output file was overwritten"): - assert new_output_file_exists is False + assert not (output_folder / filename_exists_if_failed).exists() @pytest.mark.unit -def test_output_new_recorder_filename_third_run(temp_dir, subtests): - # change to example dir - os.chdir(EXAMPLE_DIR / "05_wind_h2_opt") - +@pytest.mark.parametrize("example_folder,resource_example_folder", [("05_wind_h2_opt", None)]) +def test_output_new_recorder_filename_third_run(temp_copy_of_example_module_scope, subtests): # initialize H2I using non-optimization config - input_file = EXAMPLE_DIR / "05_wind_h2_opt" / "wind_plant_electrolyzer0.yaml" + example_folder = temp_copy_of_example_module_scope + input_file = example_folder / "wind_plant_electrolyzer0.yaml" h2i = H2IntegrateModel(input_file) # load driver config for optimization run - driver_config = load_driver_yaml(EXAMPLE_DIR / "05_wind_h2_opt" / "driver_config.yaml") + driver_config = load_driver_yaml(example_folder / "driver_config.yaml") # update driver config params with test variables filename_initial = TEST_RECORDER_OUTPUT_FILE0 filename_second = TEST_RECORDER_OUTPUT_FILE1 filename_expected = TEST_RECORDER_OUTPUT_FILE2 - driver_config["general"]["folder_output"] = temp_dir + output_folder = example_folder / driver_config["general"]["folder_output"] driver_config["recorder"]["file"] = filename_initial driver_config["driver"]["optimization"]["max_iter"] = 5 # to prevent tests taking too long @@ -189,26 +163,16 @@ def test_output_new_recorder_filename_third_run(temp_dir, subtests): h2i.create_driver_model() # check if output folder and output files exist - output_folder_exists = (EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir).exists() - output_file_exists_prerun = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_initial - ).exists() - run1_output_file_exists_prerun = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_second - ).exists() with subtests.test("Run 3: output folder exists"): - assert output_folder_exists is True + assert output_folder.exists() with subtests.test("Run 3: initial recorder output file exists"): - assert output_file_exists_prerun is True + assert (output_folder / filename_initial).exists() with subtests.test("Run 3: second recorder output file exists"): - assert run1_output_file_exists_prerun is True + assert (output_folder / filename_second).exists() # run the model h2i.run() # check that the new recorder file was created - new_output_file_exists = ( - EXAMPLE_DIR / "05_wind_h2_opt" / temp_dir / filename_expected - ).exists() with subtests.test("Run 3: new recorder output file was made"): - assert new_output_file_exists is True + assert (output_folder / filename_expected).exists() diff --git a/h2integrate/finances/test/conftest.py b/h2integrate/finances/test/conftest.py index aec692e38..a4763a760 100644 --- a/h2integrate/finances/test/conftest.py +++ b/h2integrate/finances/test/conftest.py @@ -4,7 +4,11 @@ import os -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/postprocess/test/conftest.py b/h2integrate/postprocess/test/conftest.py index 8d49ffb3d..fa8f250cf 100644 --- a/h2integrate/postprocess/test/conftest.py +++ b/h2integrate/postprocess/test/conftest.py @@ -1 +1,5 @@ -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/postprocess/test/test_mapping_tools.py b/h2integrate/postprocess/test/test_mapping_tools.py index 285e411b2..8da878ac7 100644 --- a/h2integrate/postprocess/test/test_mapping_tools.py +++ b/h2integrate/postprocess/test/test_mapping_tools.py @@ -1,15 +1,21 @@ import numpy as np import pandas as pd import pytest -import geopandas as gpd from shapely.geometry import Polygon -from h2integrate.postprocess.mapping import ( - auto_colorbar_limits, - validate_gdfs_are_same_crs, - auto_detect_lat_long_columns, - calculate_geodataframe_total_bounds, -) + +gis_extras = True +try: + import geopandas as gpd + + from h2integrate.postprocess.mapping import ( + auto_colorbar_limits, + validate_gdfs_are_same_crs, + auto_detect_lat_long_columns, + calculate_geodataframe_total_bounds, + ) +except ModuleNotFoundError: + gis_extras = False # Define geometries to be used in testing of GeoDataFrames @@ -32,6 +38,7 @@ @pytest.mark.unit +@pytest.mark.skipif(not gis_extras, reason="`gis` dependencies not installed") def test_calculate_geodataframe_total_bounds(subtests): with subtests.test("Check invalid argument type"): expected_msg = "Must provide at least one GeoDataFrame." @@ -98,6 +105,7 @@ def test_calculate_geodataframe_total_bounds(subtests): @pytest.mark.unit +@pytest.mark.skipif(not gis_extras, reason="`gis` dependencies not installed") def test_auto_detect_lat_long_columns(subtests): test_good_results_df1 = pd.DataFrame(columns=["index", "latitude", "longitude"]) test_good_results_df2 = pd.DataFrame(columns=["index", "lat", "long"]) @@ -163,6 +171,7 @@ def test_auto_detect_lat_long_columns(subtests): @pytest.mark.unit +@pytest.mark.skipif(not gis_extras, reason="`gis` dependencies not installed") def test_validate_gdfs_are_same_crs(subtests): gdf_1 = gpd.GeoDataFrame( data={"index": [0], "test1": ["larger_square"], "test2": [larger_square_coords]}, @@ -211,6 +220,7 @@ def test_validate_gdfs_are_same_crs(subtests): @pytest.mark.unit +@pytest.mark.skipif(not gis_extras, reason="`gis` dependencies not installed") def test_auto_colorbar_limits(subtests): with subtests.test("Test good value input types"): vmin, vmax = auto_colorbar_limits(values=pd.Series([0.62, 0.75, 0.93])) diff --git a/h2integrate/postprocess/test/test_sql_timeseries_to_csv.py b/h2integrate/postprocess/test/test_sql_timeseries_to_csv.py index dae722dc5..1b0a521fb 100644 --- a/h2integrate/postprocess/test/test_sql_timeseries_to_csv.py +++ b/h2integrate/postprocess/test/test_sql_timeseries_to_csv.py @@ -1,27 +1,27 @@ -import os from pathlib import Path import numpy as np import pytest from pytest import fixture -from h2integrate import EXAMPLE_DIR from h2integrate.core.h2integrate_model import H2IntegrateModel from h2integrate.core.inputs.validation import load_yaml, load_tech_yaml, load_driver_yaml from h2integrate.postprocess.sql_timeseries_to_csv import save_case_timeseries_as_csv @fixture -def configuration(temp_dir): - config = load_yaml(EXAMPLE_DIR / "02_texas_ammonia" / "02_texas_ammonia.yaml") +def configuration(temp_copy_of_example): + example_folder = temp_copy_of_example + config = load_yaml(example_folder / "02_texas_ammonia.yaml") - driver_config = load_driver_yaml(EXAMPLE_DIR / "02_texas_ammonia" / "driver_config.yaml") - driver_config["general"]["folder_output"] = str(temp_dir) + driver_config = load_driver_yaml(example_folder / "driver_config.yaml") + output_folder = example_folder / driver_config["general"]["folder_output"] + driver_config["general"]["folder_output"] = str(output_folder) config["driver_config"] = driver_config - tech_config = load_tech_yaml(EXAMPLE_DIR / "02_texas_ammonia" / "tech_config.yaml") + tech_config = load_tech_yaml(example_folder / "tech_config.yaml") tech_config["technologies"]["wind"]["model_inputs"]["performance_parameters"]["cache_dir"] = ( - str(temp_dir) + str(output_folder) ) config["technology_config"] = tech_config return config @@ -30,11 +30,13 @@ def configuration(temp_dir): @fixture def run_example_02_sql_fpath(configuration): # check if case file exists, if so, return the filepath - sql_fpath = EXAMPLE_DIR / "02_texas_ammonia" / "outputs" / "cases.sql" + output_folder = ( + Path(configuration["driver_config"]["general"]["folder_output"]).resolve().parent + ) + sql_fpath = output_folder / "cases.sql" if sql_fpath.exists(): return sql_fpath else: - os.chdir(EXAMPLE_DIR / "02_texas_ammonia") # Create a H2Integrate model h2i = H2IntegrateModel(configuration) @@ -50,6 +52,7 @@ def run_example_02_sql_fpath(configuration): @pytest.mark.unit +@pytest.mark.parametrize("example_folder,resource_example_folder", [("02_texas_ammonia", None)]) def test_save_csv_all_results(subtests, configuration, run_example_02_sql_fpath): expected_csv_fpath = ( Path(configuration["driver_config"]["general"]["folder_output"]) / "cases_Case-1.csv" @@ -67,6 +70,7 @@ def test_save_csv_all_results(subtests, configuration, run_example_02_sql_fpath) @pytest.mark.unit +@pytest.mark.parametrize("example_folder,resource_example_folder", [("02_texas_ammonia", None)]) def test_make_df_from_varname_list(subtests, run_example_02_sql_fpath): vars_to_save = [ "electrolyzer.hydrogen_out", @@ -91,6 +95,7 @@ def test_make_df_from_varname_list(subtests, run_example_02_sql_fpath): @pytest.mark.unit +@pytest.mark.parametrize("example_folder,resource_example_folder", [("02_texas_ammonia", None)]) def test_make_df_from_varname_unit_dict(subtests, run_example_02_sql_fpath): vars_units_to_save = { "ammonia.hydrogen_in": "kg/h", @@ -116,6 +121,7 @@ def test_make_df_from_varname_unit_dict(subtests, run_example_02_sql_fpath): @pytest.mark.unit +@pytest.mark.parametrize("example_folder,resource_example_folder", [("02_texas_ammonia", None)]) def test_alternative_column_names(subtests, run_example_02_sql_fpath): vars_to_save = { "electrolyzer.hydrogen_out": {"alternative_name": "Electrolyzer Hydrogen Output"}, diff --git a/h2integrate/postprocess/test/test_sql_to_csv.py b/h2integrate/postprocess/test/test_sql_to_csv.py index 3fde7ae2e..19fb3a773 100644 --- a/h2integrate/postprocess/test/test_sql_to_csv.py +++ b/h2integrate/postprocess/test/test_sql_to_csv.py @@ -27,7 +27,7 @@ EXAMPLE_19_DIR = EXAMPLE_DIR / "19_simple_dispatch" -@fixture +@fixture(scope="function") def configuration(temp_dir): """Load and patch the example-19 configuration so outputs go to a temp dir.""" config = load_yaml(EXAMPLE_19_DIR / "wind_battery_dispatch.yaml") diff --git a/h2integrate/preprocess/test/conftest.py b/h2integrate/preprocess/test/conftest.py index aec692e38..a4763a760 100644 --- a/h2integrate/preprocess/test/conftest.py +++ b/h2integrate/preprocess/test/conftest.py @@ -4,7 +4,11 @@ import os -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/resource/solar/test/conftest.py b/h2integrate/resource/solar/test/conftest.py index fb3a637e2..b8bb99aee 100644 --- a/h2integrate/resource/solar/test/conftest.py +++ b/h2integrate/resource/solar/test/conftest.py @@ -5,4 +5,8 @@ pytest_sessionfinish, ) -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/resource/test/conftest.py b/h2integrate/resource/test/conftest.py index 204de72db..5cd0ab0ea 100644 --- a/h2integrate/resource/test/conftest.py +++ b/h2integrate/resource/test/conftest.py @@ -4,7 +4,11 @@ from h2integrate.resource.utilities.nlr_developer_api_keys import set_nlr_key_dot_env -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) # docs fencepost start: DO NOT REMOVE diff --git a/h2integrate/resource/utilities/test/conftest.py b/h2integrate/resource/utilities/test/conftest.py index 6a746b5c5..a7b6c2f5e 100644 --- a/h2integrate/resource/utilities/test/conftest.py +++ b/h2integrate/resource/utilities/test/conftest.py @@ -2,7 +2,11 @@ from hopp import TEST_ENV_VAR -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/resource/wind/test/conftest.py b/h2integrate/resource/wind/test/conftest.py index fb3a637e2..b8bb99aee 100644 --- a/h2integrate/resource/wind/test/conftest.py +++ b/h2integrate/resource/wind/test/conftest.py @@ -5,4 +5,8 @@ pytest_sessionfinish, ) -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/storage/battery/test/conftest.py b/h2integrate/storage/battery/test/conftest.py index 1003a1f0a..349aa222a 100644 --- a/h2integrate/storage/battery/test/conftest.py +++ b/h2integrate/storage/battery/test/conftest.py @@ -1,3 +1,7 @@ from h2integrate.storage.test.conftest import plant_config # noqa: F401 -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) diff --git a/h2integrate/storage/hydrogen/test/conftest.py b/h2integrate/storage/hydrogen/test/conftest.py index abdb88bca..1600cde57 100644 --- a/h2integrate/storage/hydrogen/test/conftest.py +++ b/h2integrate/storage/hydrogen/test/conftest.py @@ -6,7 +6,11 @@ from h2integrate.storage.test.conftest import plant_config # noqa: F401 -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/storage/test/conftest.py b/h2integrate/storage/test/conftest.py index 3ae271aaf..be1f5dacd 100644 --- a/h2integrate/storage/test/conftest.py +++ b/h2integrate/storage/test/conftest.py @@ -6,7 +6,11 @@ import pytest -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/test/conftest.py b/h2integrate/test/conftest.py index aec692e38..a4763a760 100644 --- a/h2integrate/test/conftest.py +++ b/h2integrate/test/conftest.py @@ -4,7 +4,11 @@ import os -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/tools/test/conftest.py b/h2integrate/tools/test/conftest.py index aec692e38..a4763a760 100644 --- a/h2integrate/tools/test/conftest.py +++ b/h2integrate/tools/test/conftest.py @@ -4,7 +4,11 @@ import os -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/h2integrate/transporters/test/conftest.py b/h2integrate/transporters/test/conftest.py index aec692e38..a4763a760 100644 --- a/h2integrate/transporters/test/conftest.py +++ b/h2integrate/transporters/test/conftest.py @@ -4,7 +4,11 @@ import os -from test.conftest import temp_dir, pytest_collection_modifyitems # noqa: F401 +from test.conftest import ( # noqa: F401 + temp_dir, + temp_copy_of_example, + pytest_collection_modifyitems, +) def pytest_sessionstart(session): diff --git a/pyproject.toml b/pyproject.toml index d6f57d0fb..43ccb299a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,7 +100,6 @@ develop = [ "pytest-cov", "ruff", "sphinxcontrib-napoleon", - "h2integrate[gis,ard]", "yamlfix" ] examples = [ @@ -112,7 +111,8 @@ gis = [ "contextily" ] ard = ["ard-nrel"] -all = ["h2integrate[develop,examples]"] +extras = ["h2integrate[gis,ard]"] +all = ["h2integrate[develop,extras,examples]"] [tool.setuptools] include-package-data = true diff --git a/test/conftest.py b/test/conftest.py index cb066cfce..da20dd743 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -4,9 +4,11 @@ import os import shutil +from pathlib import Path import pytest +from h2integrate import EXAMPLE_DIR from h2integrate.resource.utilities.nlr_developer_api_keys import set_nlr_key_dot_env @@ -67,9 +69,41 @@ def pytest_collection_modifyitems(config, items): raise pytest.UsageError(msg) -@pytest.fixture(scope="module") +@pytest.fixture(scope="function") def temp_dir(tmp_path_factory): """Temp directory for YAML outputs.""" temp_dir = tmp_path_factory.mktemp("temp_dir") yield temp_dir shutil.rmtree(str(temp_dir)) + + +@pytest.fixture(scope="module") +def temp_dir_module(tmp_path_factory): + """Temp directory for YAML outputs.""" + temp_dir = tmp_path_factory.mktemp("temp_dir") + yield temp_dir + shutil.rmtree(str(temp_dir)) + + +@pytest.fixture(scope="function") +def temp_copy_of_example(temp_dir, example_folder, resource_example_folder): + original = EXAMPLE_DIR / example_folder + shutil.copytree(original, temp_dir / example_folder, dirs_exist_ok=True) + if resource_example_folder is not None: + secondary = EXAMPLE_DIR / resource_example_folder + shutil.copytree(secondary, temp_dir / resource_example_folder, dirs_exist_ok=True) + os.chdir(temp_dir / example_folder) + yield temp_dir / example_folder + os.chdir(Path(__file__).parent) + + +@pytest.fixture(scope="function") +def temp_copy_of_example_module_scope(temp_dir_module, example_folder, resource_example_folder): + original = EXAMPLE_DIR / example_folder + shutil.copytree(original, temp_dir_module / example_folder, dirs_exist_ok=True) + if resource_example_folder is not None: + secondary = EXAMPLE_DIR / resource_example_folder + shutil.copytree(secondary, temp_dir_module / resource_example_folder, dirs_exist_ok=True) + os.chdir(temp_dir_module / example_folder) + yield temp_dir_module / example_folder + os.chdir(Path(__file__).parent)