Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 3 additions & 25 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,31 +51,9 @@ jobs:
sudo apt-get update
sudo apt-get install graphviz graphviz-dev

# Unit, integration, and end-to-end tests.

- name: Run unit tests and doctests.
shell: bash -l {0}
run: uv run --group test pytest --nbmake -m "unit or (not integration and not end_to_end)" --cov=src --cov=tests --cov-report=xml -n auto

- name: Upload unit test coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v5
with:
flags: unit

- name: Run integration tests.
- name: Run tests, doctests, and notebook tests
shell: bash -l {0}
run: uv run --group test pytest --nbmake -m integration --cov=src --cov=tests --cov-report=xml -n auto
run: uv run --group test pytest --nbmake --cov=src --cov=tests --cov-report=xml -n auto

- name: Upload integration test coverage reports to Codecov with GitHub Action
- name: Upload test coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v5
with:
flags: integration

- name: Run end-to-end tests.
shell: bash -l {0}
run: uv run --group test pytest --nbmake -m end_to_end --cov=src --cov=tests --cov-report=xml -n auto

- name: Upload end_to_end test coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v5
with:
flags: end_to_end
6 changes: 0 additions & 6 deletions tests/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@

import textwrap

import pytest

from pytask import ExitCode
from pytask import cli


@pytest.mark.end_to_end
def test_execution_failed(runner, tmp_path):
source = """
def task_raises():
Expand All @@ -20,13 +17,11 @@ def task_raises():
assert result.exit_code == ExitCode.FAILED


@pytest.mark.end_to_end
def test_configuration_failed(runner, tmp_path):
result = runner.invoke(cli, [tmp_path.joinpath("non_existent_path").as_posix()])
assert result.exit_code == ExitCode.CONFIGURATION_FAILED


@pytest.mark.end_to_end
def test_collection_failed(runner, tmp_path):
source = """
raise Exception
Expand All @@ -37,7 +32,6 @@ def test_collection_failed(runner, tmp_path):
assert result.exit_code == ExitCode.COLLECTION_FAILED


@pytest.mark.end_to_end
def test_building_dag_failed(runner, tmp_path):
source = """
from pathlib import Path
Expand Down
5 changes: 0 additions & 5 deletions tests/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@

import inspect

import pytest

from _pytask.cache import Cache
from _pytask.cache import _make_memoize_key


@pytest.mark.unit
def test_cache():
cache = Cache()

Expand All @@ -32,7 +29,6 @@ def func(a, b):
assert func.cache.cache_info.misses == 1


@pytest.mark.unit
def test_cache_add():
cache = Cache()

Expand All @@ -56,7 +52,6 @@ def func(a):
assert cache.cache_info.misses == 1


@pytest.mark.unit
def test_make_memoize_key():
def func(a, b): # pragma: no cover
return a + b
Expand Down
20 changes: 0 additions & 20 deletions tests/test_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from collections.abc import Generator


@pytest.mark.end_to_end
@pytest.mark.parametrize("show_capture", ["s", "no", "stdout", "stderr", "all"])
def test_show_capture(tmp_path, runner, show_capture):
source = """
Expand Down Expand Up @@ -66,7 +65,6 @@ def task_show_capture():
raise NotImplementedError


@pytest.mark.end_to_end
@pytest.mark.parametrize("show_capture", ["no", "stdout", "stderr", "all"])
@pytest.mark.xfail(
sys.platform == "win32",
Expand Down Expand Up @@ -114,7 +112,6 @@ def task_show_capture():
raise NotImplementedError


@pytest.mark.end_to_end
@pytest.mark.xfail(
sys.platform == "win32",
reason="from pytask ... cannot be found",
Expand Down Expand Up @@ -173,7 +170,6 @@ def TeeStdCapture( # noqa: N802
)


@pytest.mark.end_to_end
class TestCaptureManager:
@pytest.mark.parametrize(
"method", [CaptureMethod.NO, CaptureMethod.SYS, CaptureMethod.FD]
Expand Down Expand Up @@ -218,7 +214,6 @@ def test_init_capturing(self):
capouter.stop_capturing()


@pytest.mark.end_to_end
@pytest.mark.parametrize("method", ["fd", "sys"])
def test_capturing_unicode(tmp_path, runner, method):
obj = "'b\u00f6y'"
Expand All @@ -239,7 +234,6 @@ def task_unicode():
assert result.exit_code == ExitCode.OK


@pytest.mark.end_to_end
@pytest.mark.parametrize("method", ["fd", "sys"])
@pytest.mark.skipif(sys.platform == "win32", reason="Fails on Windows.")
def test_capturing_unicode_with_build(tmp_path, method):
Expand All @@ -266,7 +260,6 @@ def task_unicode():
assert "1 Succeeded" in result.stdout


@pytest.mark.end_to_end
@pytest.mark.parametrize("method", ["fd", "sys"])
def test_capturing_bytes_in_utf8_encoding(tmp_path, runner, method):
source = """
Expand All @@ -283,7 +276,6 @@ def task_unicode():
assert result.exit_code == ExitCode.OK


@pytest.mark.end_to_end
@pytest.mark.xfail(strict=True, reason="pytask cannot capture during collection.")
def test_collect_capturing(tmp_path, runner):
source = """
Expand All @@ -305,7 +297,6 @@ def test_collect_capturing(tmp_path, runner):
assert content in result.output


@pytest.mark.end_to_end
def test_capturing_outerr(tmp_path, runner):
source = """
import sys
Expand Down Expand Up @@ -341,7 +332,6 @@ def task_capturing_error():
assert content in result.output


@pytest.mark.end_to_end
def test_capture_badoutput_issue412(tmp_path, runner):
source = """
import os
Expand All @@ -363,7 +353,6 @@ def task_func():
assert content in result.output


@pytest.mark.unit
class TestCaptureIO:
def test_text(self):
f = capture.CaptureIO()
Expand All @@ -389,7 +378,6 @@ def test_write_bytes_to_buffer(self):
assert f.getvalue() == "foo\r\n"


@pytest.mark.unit
class TestTeeCaptureIO(TestCaptureIO):
def test_text(self):
sio = io.StringIO()
Expand All @@ -409,7 +397,6 @@ def test_unicode_and_str_mixture(self):
pytest.raises(TypeError, f.write, b"hello")


@pytest.mark.integration
def test_dontreadfrominput():
from _pytest.capture import DontReadFromInput

Expand All @@ -424,7 +411,6 @@ def test_dontreadfrominput():
f.close() # just for completeness


@pytest.mark.unit
def test_captureresult() -> None:
cr = CaptureResult("out", "err")
assert len(cr) == 2
Expand Down Expand Up @@ -482,7 +468,6 @@ def lsof_check():
assert len2 < len1 + 3, out2


@pytest.mark.unit
class TestFDCapture:
def test_simple(self, tmpfile):
fd = tmpfile.fileno()
Expand Down Expand Up @@ -589,7 +574,6 @@ def saved_fd(fd):
os.close(new_fd)


@pytest.mark.unit
class TestStdCapture:
captureclass = staticmethod(StdCapture)

Expand Down Expand Up @@ -708,7 +692,6 @@ def test_stdin_nulled_by_default(self):
pytest.raises(OSError, sys.stdin.read)


@pytest.mark.unit
class TestTeeStdCapture(TestStdCapture):
captureclass = staticmethod(TeeStdCapture)

Expand All @@ -725,7 +708,6 @@ def test_capturing_error_recursive(self):
assert out2 == "cap2\n"


@pytest.mark.unit
class TestStdCaptureFD(TestStdCapture):
captureclass = staticmethod(StdCaptureFD)

Expand Down Expand Up @@ -767,7 +749,6 @@ def test_many(self, capfd): # noqa: ARG002
cap.stop_capturing()


@pytest.mark.unit
class TestStdCaptureFDinvalidFD:
@pytest.mark.skipif(
sys.platform == "darwin" and sys.version_info[:2] == (3, 9),
Expand Down Expand Up @@ -851,7 +832,6 @@ def test_fdcapture_invalid_fd_without_fd_reuse(self, tmp_path):
os.write(2, b"done")


@pytest.mark.unit
def test__get_multicapture() -> None:
assert isinstance(_get_multicapture(CaptureMethod.NO), MultiCapture)
pytest.raises(ValueError, _get_multicapture, "unknown").match(
Expand Down
17 changes: 0 additions & 17 deletions tests/test_clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ def task_write_text(path=Path("in_tracked.txt"), produces=Path("out.txt")):
return tmp_path


@pytest.mark.end_to_end
def test_clean_database_ignored(project, runner):
with enter_directory(project):
result = runner.invoke(cli, ["build"])
Expand All @@ -70,7 +69,6 @@ def test_clean_database_ignored(project, runner):
assert "pytask.sqlite3" not in text_without_linebreaks


@pytest.mark.end_to_end
def test_clean_with_auto_collect(project, runner):
with enter_directory(project):
result = runner.invoke(cli, ["clean"])
Expand All @@ -82,7 +80,6 @@ def test_clean_with_auto_collect(project, runner):
assert "to_be_deleted_file_2.txt" in text_without_linebreaks


@pytest.mark.end_to_end
@pytest.mark.parametrize("flag", ["-e", "--exclude"])
@pytest.mark.parametrize("pattern", ["*_1.txt", "to_be_deleted_file_[1]*"])
def test_clean_with_excluded_file(project, runner, flag, pattern):
Expand All @@ -94,7 +91,6 @@ def test_clean_with_excluded_file(project, runner, flag, pattern):
assert "to_be_deleted_file_2.txt" in text_without_linebreaks


@pytest.mark.end_to_end
@pytest.mark.parametrize("flag", ["-e", "--exclude"])
@pytest.mark.parametrize("pattern", ["*_1.txt", "to_be_deleted_file_[1]*"])
def test_clean_with_excluded_file_via_config(project, runner, flag, pattern):
Expand All @@ -111,7 +107,6 @@ def test_clean_with_excluded_file_via_config(project, runner, flag, pattern):
assert "pyproject.toml" in text_without_linebreaks


@pytest.mark.end_to_end
@pytest.mark.parametrize("flag", ["-e", "--exclude"])
def test_clean_with_excluded_directory(project, runner, flag):
result = runner.invoke(
Expand All @@ -123,15 +118,13 @@ def test_clean_with_excluded_directory(project, runner, flag):
assert "deleted_file_1.txt" in result.output.replace("\n", "")


@pytest.mark.end_to_end
def test_clean_with_nothing_to_remove(tmp_path, runner):
result = runner.invoke(cli, ["clean", "--exclude", "*", tmp_path.as_posix()])

assert result.exit_code == ExitCode.OK
assert "There are no files and directories which can be deleted." in result.output


@pytest.mark.end_to_end
def test_clean_dry_run(project, runner):
result = runner.invoke(cli, ["clean", project.as_posix()])

Expand All @@ -146,7 +139,6 @@ def test_clean_dry_run(project, runner):
).exists()


@pytest.mark.end_to_end
def test_clean_dry_run_w_directories(project, runner):
result = runner.invoke(cli, ["clean", "-d", project.as_posix()])

Expand All @@ -158,7 +150,6 @@ def test_clean_dry_run_w_directories(project, runner):
assert "to_be_deleted_folder_1" in text_without_linebreaks


@pytest.mark.end_to_end
def test_clean_force(project, runner):
result = runner.invoke(cli, ["clean", "--mode", "force", project.as_posix()])

Expand All @@ -173,7 +164,6 @@ def test_clean_force(project, runner):
).exists()


@pytest.mark.end_to_end
def test_clean_force_w_directories(project, runner):
result = runner.invoke(cli, ["clean", "-d", "--mode", "force", project.as_posix()])

Expand All @@ -185,7 +175,6 @@ def test_clean_force_w_directories(project, runner):
assert "to_be_deleted_folder_1" in text_without_linebreaks


@pytest.mark.end_to_end
def test_clean_interactive(project, runner):
result = runner.invoke(
cli,
Expand All @@ -204,7 +193,6 @@ def test_clean_interactive(project, runner):
).exists()


@pytest.mark.end_to_end
def test_clean_interactive_w_directories(project, runner):
result = runner.invoke(
cli,
Expand All @@ -222,15 +210,13 @@ def test_clean_interactive_w_directories(project, runner):
assert not project.joinpath("to_be_deleted_folder_1").exists()


@pytest.mark.end_to_end
def test_configuration_failed(runner, tmp_path):
result = runner.invoke(
cli, ["clean", tmp_path.joinpath("non_existent_path").as_posix()]
)
assert result.exit_code == ExitCode.CONFIGURATION_FAILED


@pytest.mark.end_to_end
def test_collection_failed(runner, tmp_path):
source = """
raise Exception
Expand All @@ -241,7 +227,6 @@ def test_collection_failed(runner, tmp_path):
assert result.exit_code == ExitCode.COLLECTION_FAILED


@pytest.mark.end_to_end
def test_dont_remove_files_tracked_by_git(runner, git_project):
result = runner.invoke(cli, ["clean", git_project.as_posix()])

Expand All @@ -251,7 +236,6 @@ def test_dont_remove_files_tracked_by_git(runner, git_project):
assert ".git" not in result.output


@pytest.mark.end_to_end
def test_clean_git_files_if_git_is_not_installed(monkeypatch, runner, git_project):
monkeypatch.setattr(
"_pytask.clean.is_git_installed",
Expand All @@ -266,7 +250,6 @@ def test_clean_git_files_if_git_is_not_installed(monkeypatch, runner, git_projec
assert ".git" not in result.output


@pytest.mark.end_to_end
def test_clean_git_files_if_git_is_installed_but_git_root_is_not_found(
monkeypatch, runner, git_project
):
Expand Down
Loading