Beispiel #1
0
def test_parallel_execution_speedup(tmp_path, parallel_backend):
    source = """
    import pytask
    import time

    @pytask.mark.produces("out_1.txt")
    def task_1(produces):
        time.sleep(5)
        produces.write_text("1")

    @pytask.mark.produces("out_2.txt")
    def task_2(produces):
        time.sleep(5)
        produces.write_text("2")
    """
    tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path})

    assert session.exit_code == 0
    assert session.execution_end - session.execution_start > 10

    tmp_path.joinpath("out_1.txt").unlink()
    tmp_path.joinpath("out_2.txt").unlink()

    session = main({
        "paths": tmp_path,
        "n_workers": 2,
        "parallel_backend": parallel_backend
    })

    assert session.exit_code == 0
    assert session.execution_end - session.execution_start < 10
Beispiel #2
0
def test_multiple_runs_with_persist(tmp_path):
    """Perform multiple consecutive runs and check intermediate outcomes with persist.

    1. The product is missing which should result in a normal execution of the task.
    2. Change the product, check that run is successful and state in database has
       changed.
    3. Run the task another time. Now, the task is skipped successfully.

    """
    source = """
    import pytask

    @pytask.mark.persist
    @pytask.mark.depends_on("in.txt")
    @pytask.mark.produces("out.txt")
    def task_dummy(depends_on, produces):
        produces.write_text(depends_on.read_text())
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))
    tmp_path.joinpath("in.txt").write_text("I'm not the reason you care.")

    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
    assert len(session.execution_reports) == 1
    assert session.execution_reports[0].outcome == TaskOutcome.SUCCESS
    assert session.execution_reports[0].exc_info is None
    assert tmp_path.joinpath("out.txt").exists()

    tmp_path.joinpath("out.txt").write_text("Never again in despair.")

    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
    assert len(session.execution_reports) == 1
    assert session.execution_reports[0].outcome == TaskOutcome.PERSISTENCE
    assert isinstance(session.execution_reports[0].exc_info[1], Persisted)

    with orm.db_session:

        create_database("sqlite",
                        tmp_path.joinpath(".pytask.sqlite3").as_posix(), True,
                        False)
        task_id = tmp_path.joinpath(
            "task_module.py").as_posix() + "::task_dummy"
        node_id = tmp_path.joinpath("out.txt").as_posix()

        state = State[task_id, node_id].state
        assert float(state) == tmp_path.joinpath("out.txt").stat().st_mtime

    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
    assert len(session.execution_reports) == 1
    assert session.execution_reports[0].outcome == TaskOutcome.SKIP_UNCHANGED
    assert isinstance(session.execution_reports[0].exc_info[1],
                      SkippedUnchanged)
Beispiel #3
0
def test_skip_unchanged(tmp_path):
    source = """
    def task_dummy():
        pass
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path})
    assert session.execution_reports[0].outcome == TaskOutcome.SUCCESS

    session = main({"paths": tmp_path})
    assert isinstance(session.execution_reports[0].exc_info[1], SkippedUnchanged)
Beispiel #4
0
def test_duration_is_stored_in_task(tmp_path):
    source = """
    import time
    def task_example(): time.sleep(2)
    """
    tmp_path.joinpath("task_example.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
    assert len(session.tasks) == 1
    task = session.tasks[0]
    duration = task.attributes["duration"]
    assert duration[1] - duration[0] > 2

    with orm.db_session:
        create_database("sqlite",
                        tmp_path.joinpath(".pytask.sqlite3").as_posix(), True,
                        False)

        task_name = tmp_path.joinpath(
            "task_example.py").as_posix() + "::task_example"

        runtime = Runtime[task_name]
        assert runtime.duration > 2
Beispiel #5
0
def test_if_skipif_decorator_is_applied_skipping(tmp_path):
    source = """
    import pytask

    @pytask.mark.skipif(condition=True, reason="bla")
    @pytask.mark.produces("out.txt")
    def task_first():
        assert False

    @pytask.mark.depends_on("out.txt")
    def task_second():
        assert False
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path})
    node = session.collection_reports[0].node
    assert len(node.markers) == 1
    assert node.markers[0].name == "skipif"
    assert node.markers[0].args == ()
    assert node.markers[0].kwargs == {"condition": True, "reason": "bla"}

    assert session.execution_reports[0].outcome == TaskOutcome.SKIP
    assert isinstance(session.execution_reports[0].exc_info[1], Skipped)
    assert session.execution_reports[1].outcome == TaskOutcome.SKIP
    assert isinstance(session.execution_reports[1].exc_info[1], Skipped)
    assert session.execution_reports[0].exc_info[1].args[0] == "bla"
Beispiel #6
0
def test_if_skipif_decorator_is_applied_execute(tmp_path):
    source = """
    import pytask

    @pytask.mark.skipif(False, reason="bla")
    @pytask.mark.produces("out.txt")
    def task_first(produces):
        with open(produces, "w") as f:
            f.write("hello world.")

    @pytask.mark.depends_on("out.txt")
    def task_second():
        pass
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path})
    node = session.collection_reports[0].node

    assert len(node.markers) == 1
    assert node.markers[0].name == "skipif"
    assert node.markers[0].args == (False,)
    assert node.markers[0].kwargs == {"reason": "bla"}
    assert session.execution_reports[0].outcome == TaskOutcome.SUCCESS
    assert session.execution_reports[0].exc_info is None
    assert session.execution_reports[1].outcome == TaskOutcome.SUCCESS
    assert session.execution_reports[1].exc_info is None
Beispiel #7
0
def test_keyword_option_custom(tmp_path, expr: str, expected_passed: str) -> None:
    tmp_path.joinpath("task_module.py").write_text(
        textwrap.dedent(
            """
            def task_interface():
                pass
            def task_nointer():
                pass
            def task_pass():
                pass
            def task_no_1():
                pass
            def task_no_2():
                pass
            """
        )
    )
    session = main({"paths": tmp_path, "expression": expr})
    assert session.exit_code == ExitCode.OK

    tasks_that_run = [
        report.task.name.rsplit("::")[1]
        for report in session.execution_reports
        if not report.exc_info
    ]
    assert set(tasks_that_run) == set(expected_passed)
Beispiel #8
0
def test_parametrized_execution_of_do_file(tmp_path):
    task_source = """
    import pytask

    @pytask.mark.stata
    @pytask.mark.parametrize("depends_on, produces", [
        ("script_1.do", "0.dta"),
        ("script_2.do", "1.dta"),
    ])
    def task_run_do_file():
        pass
    """
    tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))

    for name, out in [
        ("script_1.do", "0"),
        ("script_2.do", "1"),
    ]:
        do_file = f"""
        sysuse auto, clear
        save {out}
        """
        tmp_path.joinpath(name).write_text(textwrap.dedent(do_file))

    session = main({"paths": tmp_path})

    assert session.exit_code == 0
    assert tmp_path.joinpath("0.dta").exists()
    assert tmp_path.joinpath("1.dta").exists()
Beispiel #9
0
def test_run_do_file(tmp_path):
    task_source = """
    import pytask

    @pytask.mark.stata
    @pytask.mark.depends_on("script.do")
    @pytask.mark.produces("auto.dta")
    def task_run_do_file():
        pass
    """
    tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))

    do_file = """
    sysuse auto, clear
    save auto
    """
    tmp_path.joinpath("script.do").write_text(textwrap.dedent(do_file))

    session = main({"paths": tmp_path, "stata_keep_log": True})

    assert session.exit_code == 0
    assert tmp_path.joinpath("auto.dta").exists()

    if sys.platform == "win32":
        assert tmp_path.joinpath("task_dummy_py_task_run_do_file.log").exists()
    else:
        assert tmp_path.joinpath("script.log").exists()
Beispiel #10
0
def test_if_skipif_decorator_is_applied_any_condition_matches(tmp_path):
    """Any condition of skipif has to be True and only their message is shown."""
    source = """
    import pytask

    @pytask.mark.skipif(condition=False, reason="I am fine")
    @pytask.mark.skipif(condition=True, reason="No, I am not.")
    @pytask.mark.produces("out.txt")
    def task_first():
        assert False

    @pytask.mark.depends_on("out.txt")
    def task_second():
        assert False
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path})
    node = session.collection_reports[0].node
    assert len(node.markers) == 2
    assert node.markers[0].name == "skipif"
    assert node.markers[0].args == ()
    assert node.markers[0].kwargs == {"condition": True, "reason": "No, I am not."}
    assert node.markers[1].name == "skipif"
    assert node.markers[1].args == ()
    assert node.markers[1].kwargs == {"condition": False, "reason": "I am fine"}

    assert session.execution_reports[0].outcome == TaskOutcome.SKIP
    assert isinstance(session.execution_reports[0].exc_info[1], Skipped)
    assert session.execution_reports[1].outcome == TaskOutcome.SKIP
    assert isinstance(session.execution_reports[1].exc_info[1], Skipped)
    assert session.execution_reports[0].exc_info[1].args[0] == "No, I am not."
Beispiel #11
0
def test_collect_same_test_different_ways(tmp_path, path_extension):
    tmp_path.joinpath("task_module.py").write_text("def task_passes(): pass")

    session = main({"paths": tmp_path.joinpath(path_extension)})

    assert session.exit_code == ExitCode.OK
    assert len(session.tasks) == 1
Beispiel #12
0
def test_preserve_input_for_dependencies_and_products(tmp_path, input_type):
    """Input type for dependencies and products is preserved."""
    path = tmp_path.joinpath("in.txt")
    input_ = {0: path.as_posix()} if input_type == "dict" else [path.as_posix()]
    path.touch()

    path = tmp_path.joinpath("out.txt")
    output = {0: path.as_posix()} if input_type == "dict" else [path.as_posix()]

    source = f"""
    import pytask
    from pathlib import Path

    @pytask.mark.depends_on({input_})
    @pytask.mark.produces({output})
    def task_example(depends_on, produces):
        for nodes in [depends_on, produces]:
            assert isinstance(nodes, dict)
            assert len(nodes) == 1
            assert 0 in nodes
        produces[0].touch()
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path})
    assert session.exit_code == ExitCode.OK
Beispiel #13
0
def test_ignore_default_paths(tmp_path, ignored_folder):
    folder = ignored_folder.split("/*")[0]
    tmp_path.joinpath(folder).mkdir()
    tmp_path.joinpath(folder, "task_module.py").write_text("def task_d(): pass")

    session = main({"paths": tmp_path})
    assert session.exit_code == ExitCode.OK
    assert len(session.tasks) == 0
Beispiel #14
0
def test_marker_names_toml(tmp_path, marker_name):
    toml = f"""
    [tool.pytask.ini_options.markers]
    markers = ['{marker_name}']
    """
    tmp_path.joinpath("pyproject.toml").write_text(textwrap.dedent(toml))
    session = main({"paths": tmp_path, "markers": True})
    assert session.exit_code == ExitCode.CONFIGURATION_FAILED
Beispiel #15
0
def test_ignore_paths(tmp_path, config_path, ignore, new_line):
    tmp_path.joinpath("task_module.py").write_text("def task_example(): pass")
    entry = f"ignore =\n\t{ignore}" if new_line else f"ignore = {ignore}"
    config = f"[pytask]\n{entry}" if ignore else "[pytask]"
    tmp_path.joinpath(config_path).write_text(config)

    session = main({"paths": tmp_path})
    assert session.exit_code == ExitCode.OK
    assert len(session.tasks) == 0 if ignore else len(session.tasks) == 1
Beispiel #16
0
def test_marker_names(tmp_path, marker_name, config_name):
    ini = f"""
    [pytask]
    markers =
        {marker_name}
    """
    tmp_path.joinpath(config_name).write_text(textwrap.dedent(ini))
    session = main({"paths": tmp_path, "markers": True})
    assert session.exit_code == ExitCode.CONFIGURATION_FAILED
Beispiel #17
0
def test_ignore_paths_toml(tmp_path, ignore, new_line):
    tmp_path.joinpath("task_module.py").write_text("def task_example(): pass")
    entry = f"ignore = ['{ignore}']" if new_line else f"ignore = '{ignore}'"
    config = (
        f"[tool.pytask.ini_options]\n{entry}" if ignore else "[tool.pytask.ini_options]"
    )
    tmp_path.joinpath("pyproject.toml").write_text(config)

    session = main({"paths": tmp_path})
    assert session.exit_code == ExitCode.OK
    assert len(session.tasks) == 0 if ignore else len(session.tasks) == 1
Beispiel #18
0
def test_execution_stops_after_n_failures(tmp_path, n_failures):
    source = """
    def task_1(): raise Exception
    def task_2(): raise Exception
    def task_3(): raise Exception
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path, "max_failures": n_failures})

    assert len(session.tasks) == 3
    assert len(session.execution_reports) == n_failures
Beispiel #19
0
def test_collect_files_w_custom_file_name_pattern_toml(
        tmp_path, task_files, pattern, expected_collected_tasks):
    tmp_path.joinpath("pyproject.toml").write_text(
        f"[tool.pytask.ini_options]\ntask_files = {pattern}")

    for file in task_files:
        tmp_path.joinpath(file).write_text("def task_example(): pass")

    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
    assert len(session.tasks) == expected_collected_tasks
Beispiel #20
0
def test_skip_unchanged_w_dependencies_and_products(tmp_path):
    source = """
    import pytask

    @pytask.mark.depends_on("in.txt")
    @pytask.mark.produces("out.txt")
    def task_dummy(depends_on, produces):
        produces.write_text(depends_on.read_text())
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))
    tmp_path.joinpath("in.txt").write_text("Original content of in.txt.")

    session = main({"paths": tmp_path})

    assert session.execution_reports[0].outcome == TaskOutcome.SUCCESS
    assert tmp_path.joinpath("out.txt").read_text() == "Original content of in.txt."

    session = main({"paths": tmp_path})

    assert session.execution_reports[0].outcome == TaskOutcome.SKIP_UNCHANGED
    assert isinstance(session.execution_reports[0].exc_info[1], SkippedUnchanged)
    assert tmp_path.joinpath("out.txt").read_text() == "Original content of in.txt."
Beispiel #21
0
def test_keyword_option_wrong_arguments(
    tmp_path, capsys, option: str, expr: str, expected_error: str
) -> None:
    tmp_path.joinpath("task_module.py").write_text(
        textwrap.dedent("def task_func(arg): pass")
    )
    session = main({"paths": tmp_path, option: expr})
    assert session.exit_code == ExitCode.RESOLVING_DEPENDENCIES_FAILED

    captured = capsys.readouterr()
    assert expected_error in captured.out.replace(
        "\n", " "
    ) or expected_error in captured.out.replace("\n", "")
Beispiel #22
0
def test_parse_markers_toml(tmp_path):
    toml = """
    [tool.pytask.ini_options.markers]
    a1 = "this is a webtest marker"
    a2 = "this is a smoke marker"
    """
    tmp_path.joinpath("pyproject.toml").write_text(textwrap.dedent(toml))

    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
    assert "a1" in session.config["markers"]
    assert "a2" in session.config["markers"]
Beispiel #23
0
def test_collect_files_w_custom_file_name_pattern(tmp_path, config_name,
                                                  task_files, pattern,
                                                  expected_collected_tasks):
    tmp_path.joinpath(config_name).write_text(
        f"[pytask]\ntask_files = {pattern}")

    for file in task_files:
        tmp_path.joinpath(file).write_text("def task_example(): pass")

    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
    assert len(session.tasks) == expected_collected_tasks
Beispiel #24
0
def test_parametrize_with_single_dict(tmp_path):
    source = """
    import pytask

    @pytask.mark.parametrize('i', [{"a": 1}, {"a": 1.0}])
    def task_write_numbers_to_file(i):
        assert i["a"] == 1
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))

    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
Beispiel #25
0
def test_raise_error_if_parametrization_produces_non_unique_tasks(tmp_path):
    tmp_path.joinpath("task_module.py").write_text(
        textwrap.dedent("""
            import pytask

            @pytask.mark.parametrize('i', [0, 0])
            def task_func(i):
                pass
            """))
    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.COLLECTION_FAILED
    assert isinstance(session.collection_reports[0].exc_info[1], ValueError)
Beispiel #26
0
def test_raise_error_for_irregular_ids(tmp_path, ids):
    tmp_path.joinpath("task_module.py").write_text(
        textwrap.dedent(f"""
            import pytask

            @pytask.mark.parametrize('i', range(2), ids={ids})
            def task_func():
                pass
            """))
    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.COLLECTION_FAILED
    assert isinstance(session.collection_reports[0].exc_info[1], ValueError)
Beispiel #27
0
def test_debug_pytask(capsys, tmp_path):
    session = main({"paths": tmp_path, "debug_pytask": True})

    assert session.exit_code == ExitCode.OK

    captured = capsys.readouterr()

    # The first hooks which will be displayed.
    assert "pytask_post_parse [hook]" in captured.out
    assert "finish pytask_post_parse --> [] [hook]" in captured.out
    # The last hooks which will be displayed.
    assert "finish pytask_execute_log_end --> [True] [hook]" in captured.out
    assert "finish pytask_execute --> None [hook]" in captured.out
Beispiel #28
0
def test_pass_config_to_cli_toml(tmp_path):
    config = """
    [tool.pytask.ini_options]
    markers = {"elton" = "Can you feel the love tonight?"}
    """
    tmp_path.joinpath("pyproject.toml").write_text(textwrap.dedent(config))

    session = main({
        "config": tmp_path.joinpath("pyproject.toml"),
        "paths": tmp_path
    })

    assert session.exit_code == ExitCode.OK
    assert "elton" in session.config["markers"]
Beispiel #29
0
def test_raise_error_if_function_does_not_use_parametrized_arguments(tmp_path):
    source = """
    import pytask

    @pytask.mark.parametrize('i', range(2))
    def task_func():
        pass
    """
    tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source))
    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.FAILED
    assert isinstance(session.execution_reports[0].exc_info[1], TypeError)
    assert isinstance(session.execution_reports[1].exc_info[1], TypeError)
Beispiel #30
0
def test_parametrize_w_ids(tmp_path, arg_values, ids):
    tmp_path.joinpath("task_module.py").write_text(
        textwrap.dedent(f"""
            import pytask

            @pytask.mark.parametrize('i', {arg_values}, ids={ids})
            def task_func(i):
                pass
            """))
    session = main({"paths": tmp_path})

    assert session.exit_code == ExitCode.OK
    for task, id_ in zip(session.tasks, ids):
        assert id_ in task.name