diff --git a/.github/workflows/arviz_compat.yml b/.github/workflows/arviz_compat.yml deleted file mode 100644 index e12ddba664..0000000000 --- a/.github/workflows/arviz_compat.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: arviz-compatibility - -on: - pull_request: - paths: - - ".github/workflows/*.yml" - - "pymc/**.py" - - "*.py" - - "conda-envs/**" - - "codecov.yml" - - "scripts/*.sh" - push: - branches: [main] - paths: - - ".github/workflows/*.yml" - - "pymc/**.py" - - "*.py" - - "conda-envs/**" - - "codecov.yml" - - "scripts/*.sh" - -jobs: - pytest: - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - floatx: [float64] - test-subset: - - | - pymc/tests/test_parallel_sampling.py - pymc/tests/test_posteriors.py - pymc/tests/test_sampling.py - - - | - pymc/tests/test_data_container.py - pymc/tests/test_idata_conversion.py - pymc/tests/test_missing.py - pymc/tests/test_model.py - pymc/tests/test_shape_handling.py - pymc/tests/test_shared.py - fail-fast: false - runs-on: ${{ matrix.os }} - env: - TEST_SUBSET: ${{ matrix.test-subset }} - AESARA_FLAGS: floatX=${{ matrix.floatx }},gcc__cxxflags='-march=native' - defaults: - run: - shell: bash -l {0} - steps: - - uses: actions/checkout@v2 - - name: Cache conda - uses: actions/cache@v1 - env: - # Increase this value to reset cache if environment-test-py39.yml has not changed - CACHE_NUMBER: 0 - with: - path: ~/conda_pkgs_dir - key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ - hashFiles('conda-envs/environment-test-py39.yml') }} - - name: Cache multiple paths - uses: actions/cache@v2 - env: - # Increase this value to reset cache if requirements.txt has not changed - CACHE_NUMBER: 0 - with: - path: | - ~/.cache/pip - $RUNNER_TOOL_CACHE/Python/* - ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-build-${{ matrix.python-version }}-${{ - hashFiles('requirements.txt') }} - - uses: conda-incubator/setup-miniconda@v2 - with: - miniforge-variant: Mambaforge - miniforge-version: latest - mamba-version: "*" - activate-environment: pymc-test-py39 - channel-priority: strict - environment-file: conda-envs/environment-test-py39.yml - use-mamba: true - use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly! - - name: Install pymc - run: | - conda activate pymc-test-py39 - pip install -e . - python --version - - name: Install latest arviz - run: | - conda activate pymc-test-py39 - pip uninstall arviz -y - pip install git+https://github.com/arviz-devs/arviz - - name: Run tests - run: | - python -m pytest -vv --cov=pymc --cov-report=xml --cov-report term --durations=50 $TEST_SUBSET - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v2 - with: - env_vars: TEST_SUBSET - name: ArviZ compat - ${{ matrix.os }} ${{ matrix.floatx }} - fail_ci_if_error: false diff --git a/.github/workflows/jaxtests.yml b/.github/workflows/jaxtests.yml deleted file mode 100644 index 92f9adc644..0000000000 --- a/.github/workflows/jaxtests.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: jax-sampling - -on: - pull_request: - paths: - - ".github/workflows/*.yml" - - "pymc/**.py" - - "*.py" - - "conda-envs/**" - - "codecov.yml" - - "scripts/*.sh" - push: - branches: [main] - paths: - - ".github/workflows/*.yml" - - "pymc/**.py" - - "*.py" - - "conda-envs/**" - - "codecov.yml" - - "scripts/*.sh" - -jobs: - pytest: - strategy: - matrix: - os: [ubuntu-latest] - floatx: [float64] - test-subset: - - pymc/tests/test_sampling_jax.py - fail-fast: false - runs-on: ${{ matrix.os }} - env: - TEST_SUBSET: ${{ matrix.test-subset }} - AESARA_FLAGS: floatX=${{ matrix.floatx }},gcc__cxxflags='-march=native' - defaults: - run: - shell: bash -l {0} - steps: - - uses: actions/checkout@v2 - - name: Cache conda - uses: actions/cache@v1 - env: - # Increase this value to reset cache if environment-test-py39.yml has not changed - CACHE_NUMBER: 0 - with: - path: ~/conda_pkgs_dir - key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ - hashFiles('conda-envs/environment-test-py39.yml') }} - - name: Cache multiple paths - uses: actions/cache@v2 - env: - # Increase this value to reset cache if requirements.txt has not changed - CACHE_NUMBER: 0 - with: - path: | - ~/.cache/pip - $RUNNER_TOOL_CACHE/Python/* - ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-build-${{ matrix.python-version }}-${{ - hashFiles('requirements.txt') }} - - uses: conda-incubator/setup-miniconda@v2 - with: - miniforge-variant: Mambaforge - miniforge-version: latest - mamba-version: "*" - activate-environment: pymc-test-py39 - channel-priority: strict - environment-file: conda-envs/environment-test-py39.yml - use-mamba: true - use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly! - - name: Install pymc - run: | - conda activate pymc-test-py39 - pip install -e . - python --version - - name: Install jax specific dependencies - run: | - conda activate pymc-test-py39 - pip install "numpyro>=0.8.0" - pip install git+https://github.com/blackjax-devs/blackjax.git@main - - name: Run tests - run: | - python -m pytest -vv --cov=pymc --cov-report=xml --cov-report term --durations=50 $TEST_SUBSET - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v2 - with: - env_vars: TEST_SUBSET - name: JAX tests - ${{ matrix.os }} ${{ matrix.floatx }} - fail_ci_if_error: false diff --git a/.github/workflows/pytest.yml b/.github/workflows/tests.yml similarity index 56% rename from .github/workflows/pytest.yml rename to .github/workflows/tests.yml index cf73135e29..8dc81c7580 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/tests.yml @@ -1,4 +1,4 @@ -name: pytest +name: tests on: pull_request: @@ -19,7 +19,6 @@ on: - "codecov.yml" - "scripts/*.sh" - # Tests are split into multiple jobs to accelerate the CI. # Different jobs should be organized to take approximately the same # time to complete (and not be prohibitely slow). @@ -33,77 +32,48 @@ jobs: ubuntu: strategy: matrix: - os: [ubuntu-18.04] + os: [ubuntu-20.04] floatx: [float32, float64] test-subset: - # How this works: - # 1st block: Only passes --ignore parameters to pytest. - # → pytest will run all test_*.py files that are NOT ignored. - # - # Subsequent blocks: Only pass paths to test files. - # → pytest will run only these files - | - --ignore=pymc/tests/test_distributions_timeseries.py - --ignore=pymc/tests/test_mixture.py - --ignore=pymc/tests/test_model_graph.py - --ignore=pymc/tests/test_modelcontext.py - --ignore=pymc/tests/test_parallel_sampling.py - --ignore=pymc/tests/test_posteriors.py - --ignore=pymc/tests/test_sampling.py - --ignore=pymc/tests/test_profile.py - --ignore=pymc/tests/test_step.py - --ignore=pymc/tests/test_tuning.py - --ignore=pymc/tests/test_transforms.py - --ignore=pymc/tests/test_sampling_jax.py - --ignore=pymc/tests/test_dist_math.py - --ignore=pymc/tests/test_minibatches.py - --ignore=pymc/tests/test_pickling.py - --ignore=pymc/tests/test_updates.py - --ignore=pymc/tests/test_gp.py - --ignore=pymc/tests/test_model.py - --ignore=pymc/tests/test_ode.py - --ignore=pymc/tests/test_posdef_sym.py - --ignore=pymc/tests/test_quadpotential.py - --ignore=pymc/tests/test_shape_handling.py - --ignore=pymc/tests/test_distributions.py - --ignore=pymc/tests/test_distributions_random.py - --ignore=pymc/tests/test_idata_conversion.py - --ignore=pymc/tests/test_smc.py - --ignore=pymc/tests/test_missing.py + pymc/tests/test_util.py + pymc/tests/test_logprob.py + pymc/tests/test_aesaraf.py + pymc/tests/test_math.py + pymc/tests/test_posdef_sym.py + pymc/tests/test_ndarray_backend.py + pymc/tests/test_hmc.py + pymc/tests/test_func_utils.py + pymc/tests/test_shape_handling.py + pymc/tests/test_starting.py + pymc/tests/test_mixture.py - | pymc/tests/test_distributions.py + - | + pymc/tests/test_tuning.py + pymc/tests/test_shared.py + pymc/tests/test_types.py + pymc/tests/test_distributions_moments.py + - | pymc/tests/test_modelcontext.py pymc/tests/test_dist_math.py pymc/tests/test_minibatches.py pymc/tests/test_pickling.py - pymc/tests/test_updates.py pymc/tests/test_transforms.py - pymc/tests/test_smc.py - pymc/tests/test_mixture.py - - - | pymc/tests/test_parallel_sampling.py - pymc/tests/test_sampling.py - pymc/tests/test_tuning.py - pymc/tests/test_posteriors.py - pymc/tests/test_step.py - | - pymc/tests/test_idata_conversion.py pymc/tests/test_distributions_random.py pymc/tests/test_distributions_timeseries.py pymc/tests/test_gp.py pymc/tests/test_model.py pymc/tests/test_model_graph.py pymc/tests/test_ode.py - pymc/tests/test_posdef_sym.py pymc/tests/test_profile.py pymc/tests/test_quadpotential.py - pymc/tests/test_shape_handling.py - pymc/tests/test_missing.py fail-fast: false runs-on: ${{ matrix.os }} @@ -168,27 +138,10 @@ jobs: os: [windows-latest] floatx: [float32, float64] test-subset: - - | - pymc/tests/test_initial_point.py - pymc/tests/test_distributions_random.py - pymc/tests/test_distributions_moments.py - pymc/tests/test_distributions_timeseries.py - pymc/tests/test_variational_inference.py - - | - pymc/tests/test_parallel_sampling.py - pymc/tests/test_sampling.py - pymc/tests/test_tuning.py - pymc/tests/test_shared.py - pymc/tests/test_types.py - - | - pymc/tests/test_gp.py - pymc/tests/test_ode.py - - | - pymc/tests/test_model.py - pymc/tests/test_modelcontext.py - pymc/tests/test_model_graph.py - pymc/tests/test_pickling.py - pymc/tests/test_profile.py + - pymc/tests/test_variational_inference.py pymc/tests/test_initial_point.py + - pymc/tests/test_pickling.py pymc/tests/test_profile.py pymc/tests/test_step.py + - pymc/tests/test_gp.py pymc/tests/test_ode.py pymc/tests/test_smc.py pymc/tests/test_parallel_sampling.py + - pymc/tests/test_sampling.py pymc/tests/test_posteriors.py fail-fast: false runs-on: ${{ matrix.os }} @@ -249,3 +202,142 @@ jobs: env_vars: TEST_SUBSET name: ${{ matrix.os }} ${{ matrix.floatx }} fail_ci_if_error: false + macos: + strategy: + matrix: + os: [macos-latest] + floatx: [float64] + test-subset: + - | + pymc/tests/test_parallel_sampling.py + pymc/tests/test_data_container.py + pymc/tests/test_missing.py + + - | + pymc/tests/test_sampling.py + + - | + pymc/tests/test_idata_conversion.py + pymc/tests/test_updates.py + fail-fast: false + runs-on: ${{ matrix.os }} + env: + TEST_SUBSET: ${{ matrix.test-subset }} + AESARA_FLAGS: floatX=${{ matrix.floatx }},gcc__cxxflags='-march=native' + defaults: + run: + shell: bash -l {0} + steps: + - uses: actions/checkout@v2 + - name: Cache conda + uses: actions/cache@v1 + env: + # Increase this value to reset cache if environment-test-py39.yml has not changed + CACHE_NUMBER: 0 + with: + path: ~/conda_pkgs_dir + key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ + hashFiles('conda-envs/environment-test-py39.yml') }} + - name: Cache multiple paths + uses: actions/cache@v2 + env: + # Increase this value to reset cache if requirements.txt has not changed + CACHE_NUMBER: 0 + with: + path: | + ~/.cache/pip + $RUNNER_TOOL_CACHE/Python/* + ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-build-${{ matrix.python-version }}-${{ + hashFiles('requirements.txt') }} + - uses: conda-incubator/setup-miniconda@v2 + with: + miniforge-variant: Mambaforge + miniforge-version: latest + mamba-version: "*" + activate-environment: pymc-test-py39 + channel-priority: strict + environment-file: conda-envs/environment-test-py39.yml + use-mamba: true + use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly! + - name: Install pymc + run: | + conda activate pymc-test-py39 + pip install -e . + python --version + - name: Run tests + run: | + python -m pytest -vv --cov=pymc --cov-report=xml --cov-report term --durations=50 $TEST_SUBSET + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v2 + with: + env_vars: TEST_SUBSET + name: ${{ matrix.os }} ${{ matrix.floatx }} + fail_ci_if_error: false + jax: + strategy: + matrix: + os: [ubuntu-20.04] + floatx: [float64] + test-subset: + - pymc/tests/test_sampling_jax.py + fail-fast: false + runs-on: ${{ matrix.os }} + env: + TEST_SUBSET: ${{ matrix.test-subset }} + AESARA_FLAGS: floatX=${{ matrix.floatx }},gcc__cxxflags='-march=native' + defaults: + run: + shell: bash -l {0} + steps: + - uses: actions/checkout@v2 + - name: Cache conda + uses: actions/cache@v1 + env: + # Increase this value to reset cache if environment-test-py39.yml has not changed + CACHE_NUMBER: 0 + with: + path: ~/conda_pkgs_dir + key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ + hashFiles('conda-envs/environment-test-py39.yml') }} + - name: Cache multiple paths + uses: actions/cache@v2 + env: + # Increase this value to reset cache if requirements.txt has not changed + CACHE_NUMBER: 0 + with: + path: | + ~/.cache/pip + $RUNNER_TOOL_CACHE/Python/* + ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-build-${{ matrix.python-version }}-${{ + hashFiles('requirements.txt') }} + - uses: conda-incubator/setup-miniconda@v2 + with: + miniforge-variant: Mambaforge + miniforge-version: latest + mamba-version: "*" + activate-environment: pymc-test-py39 + channel-priority: strict + environment-file: conda-envs/environment-test-py39.yml + use-mamba: true + use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly! + - name: Install pymc + run: | + conda activate pymc-test-py39 + pip install -e . + python --version + - name: Install jax specific dependencies + run: | + conda activate pymc-test-py39 + pip install "numpyro>=0.8.0" + pip install git+https://github.com/blackjax-devs/blackjax.git@main + - name: Run tests + run: | + python -m pytest -vv --cov=pymc --cov-report=xml --cov-report term --durations=50 $TEST_SUBSET + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v2 + with: + env_vars: TEST_SUBSET + name: JAX tests - ${{ matrix.os }} ${{ matrix.floatx }} + fail_ci_if_error: false diff --git a/buildosx b/buildosx deleted file mode 100755 index 3fff5a694a..0000000000 --- a/buildosx +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -export CFLAGS="-arch x86_64" -export FFLAGS="-static -ff2c -arch x86_64" -export LDFLAGS="-Wall -undefined dynamic_lookup -bundle -arch x86_64" -rm -rf build -python setupegg.py bdist_egg diff --git a/pymc/tests/test_ode.py b/pymc/tests/test_ode.py index acb0280508..83c36d4990 100644 --- a/pymc/tests/test_ode.py +++ b/pymc/tests/test_ode.py @@ -238,7 +238,6 @@ def system(y, t, p): func=system, t0=0, times=self.times, n_states=1, n_theta=1 ) - @pytest.mark.xfail(condition=(IS_FLOAT32 and IS_WINDOWS), reason="Fails on float32 on Windows") def test_too_many_params(self): with pytest.raises( pm.ShapeError, @@ -246,14 +245,12 @@ def test_too_many_params(self): ): self.ode_model(theta=[1, 1], y0=[0]) - @pytest.mark.xfail(condition=(IS_FLOAT32 and IS_WINDOWS), reason="Fails on float32 on Windows") def test_too_many_y0(self): with pytest.raises( pm.ShapeError, match="Length of y0 is wrong. \\(actual \\(2,\\) != expected \\(1,\\)\\)" ): self.ode_model(theta=[1], y0=[0, 0]) - @pytest.mark.xfail(condition=(IS_FLOAT32 and IS_WINDOWS), reason="Fails on float32 on Windows") def test_too_few_params(self): with pytest.raises( pm.ShapeError, @@ -261,7 +258,6 @@ def test_too_few_params(self): ): self.ode_model(theta=[], y0=[1]) - @pytest.mark.xfail(condition=(IS_FLOAT32 and IS_WINDOWS), reason="Fails on float32 on Windows") def test_too_few_y0(self): with pytest.raises( pm.ShapeError, match="Length of y0 is wrong. \\(actual \\(0,\\) != expected \\(1,\\)\\)" diff --git a/scripts/check_all_tests_are_covered.py b/scripts/check_all_tests_are_covered.py index 6c4b40290d..6d09e5dc80 100644 --- a/scripts/check_all_tests_are_covered.py +++ b/scripts/check_all_tests_are_covered.py @@ -36,7 +36,7 @@ def from_yaml(): """ # First collect the matrix definitions from testing workflows matrices = {} - for wf in ["pytest.yml", "arviz_compat.yml", "jaxtests.yml"]: + for wf in ["tests.yml"]: wfname = wf.strip(".yml") wfdef = yaml.safe_load(open(Path(".github", "workflows", wf))) for jobname, jobdef in wfdef["jobs"].items(): @@ -69,9 +69,29 @@ def from_yaml(): for os_, floatX, subset in itertools.product( matrix["os"], matrix["floatx"], matrix["test-subset"] ): - testfiles = subset.split("\n") + lines = [l for l in subset.split("\n") if l] + if "windows" in os_: + # Windows jobs need \ in line breaks within the test-subset! + # The following checks that these trailing \ are present in + # all items except the last. + nlines = len(lines) + for l, line in enumerate(lines): + if l < nlines - 1 and not line.endswith(" \\"): + raise Exception(f"Missing ' \\' after '{line}' in Windows test-subset.") + elif l == nlines - 1 and line.endswith(" \\"): + raise Exception( + f"Last entry '{line}' in Windows test subset should end WITHOUT ' \\'." + ) + testfiles[l] = line.strip(" \\") + + # Unpack lines with >1 item + testfiles = [] + for line in lines: + testfiles += line.split(" ") + ignored = {item.strip("--ignore=") for item in testfiles if item.startswith("--ignore")} included = {item for item in testfiles if item and not item.startswith("--ignore")} + if ignored and not included: # if no testfile is specified explicitly pytest runs all except the ignored ones included = all_tests - ignored