diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93d32ed..1fe7cd5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,10 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.4.0 hooks: - id: check-added-large-files - args: ['--maxkb=25'] + args: + - --maxkb=25 - id: check-case-conflict - id: check-merge-conflict - id: check-vcs-permalinks @@ -13,10 +14,12 @@ repos: - id: fix-byte-order-marker - id: mixed-line-ending - id: no-commit-to-branch - args: [--branch, main] + args: + - --branch + - main - id: trailing-whitespace - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.9.0 + rev: v1.10.0 hooks: - id: python-check-blanket-noqa - id: python-check-mock-methods @@ -24,90 +27,89 @@ repos: - id: python-no-log-warn - id: python-use-type-annotations - id: text-unicode-replacement-char -- repo: https://github.com/asottile/pyupgrade - rev: v2.32.0 - hooks: - - id: pyupgrade - args: [--py37-plus] - repo: https://github.com/asottile/reorder_python_imports - rev: v3.0.1 + rev: v3.9.0 hooks: - id: reorder-python-imports - args: [--py37-plus, --add-import, 'from __future__ import annotations'] + args: + - --py37-plus + - --add-import + - from __future__ import annotations - repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.20.1 + rev: v2.2.0 hooks: - id: setup-cfg-fmt -- repo: https://github.com/myint/docformatter - rev: v1.3.1 +- repo: https://github.com/PyCQA/docformatter + rev: v1.6.0.rc1 hooks: - id: docformatter - args: [--in-place, --wrap-summaries, "88", --wrap-descriptions, "88", --blank] + args: + - --in-place + - --wrap-summaries + - '88' + - --wrap-descriptions + - '88' + - --blank - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 22.12.0 hooks: - id: black -- repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 +- repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.228 + hooks: + - id: ruff +- repo: https://github.com/dosisod/refurb + rev: v1.10.0 hooks: - - id: flake8 - types: [python] - additional_dependencies: [ - flake8-alfred, - flake8-bugbear, - flake8-builtins, - flake8-comprehensions, - flake8-docstrings, - flake8-eradicate, - flake8-print, - flake8-pytest-style, - flake8-todo, - flake8-typing-imports, - flake8-unused-arguments, - pep8-naming, - pydocstyle, - Pygments, - ] + - id: refurb + args: + - --ignore + - FURB126 - repo: https://github.com/econchick/interrogate rev: 1.5.0 hooks: - id: interrogate - args: [-v, --fail-under=40, src, tests] + args: + - -v + - --fail-under=40 + - src + - tests - repo: https://github.com/executablebooks/mdformat - rev: 0.7.14 + rev: 0.7.16 hooks: - id: mdformat - additional_dependencies: [ - mdformat-gfm, - mdformat-black, - ] - args: [--wrap, "88"] -- repo: https://github.com/codespell-project/codespell - rev: v2.1.0 - hooks: + additional_dependencies: + - mdformat-gfm + - mdformat-black + args: + - --wrap + - '88' +- repo: https://github.com/codespell-project/codespell + rev: v2.2.2 + hooks: - id: codespell - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v0.931' + rev: v0.991 hooks: - id: mypy - args: [ - --no-strict-optional, - --ignore-missing-imports, - ] - additional_dependencies: [ - attrs, - click, - types-setuptools - ] + args: + - --no-strict-optional + - --ignore-missing-imports + additional_dependencies: + - attrs + - click + - types-setuptools pass_filenames: false - repo: https://github.com/mgedmin/check-manifest - rev: "0.48" + rev: '0.49' hooks: - id: check-manifest - args: [--no-build-isolation] - additional_dependencies: [setuptools-scm, toml] + args: + - --no-build-isolation + additional_dependencies: + - setuptools-scm + - toml - repo: meta hooks: - id: check-hooks-apply - id: check-useless-excludes - # - id: identity # Prints all files passed to pre-commits. Debugging. diff --git a/CHANGES.md b/CHANGES.md index 325c37f..7d86f66 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ releases are available on [PyPI](https://pypi.org/project/pytask-stata) and ## 0.3.0 - 2023-xx-xx +- {pull}`24` adds ruff and refurb. - {pull}`25` adds docformatter. - {pull}`26` adds Python 3.11 to CI. - {pull}`28` aligns the package with pytask v0.3. diff --git a/pyproject.toml b/pyproject.toml index 35ff30f..f040661 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,3 +22,43 @@ warn_unused_ignores = true module = "tests.*" disallow_untyped_defs = false ignore_errors = true + + +[tool.ruff] +target-version = "py37" +select = ["ALL"] +fix = true +extend-ignore = [ + # Numpy docstyle + "D107", + "D203", + "D212", + "D213", + "D402", + "D413", + "D415", + "D416", + "D417", + # Others. + "D404", # Do not start module docstring with "This". + "RET504", # unnecessary variable assignment before return. + "S101", # raise errors for asserts. + "B905", # strict parameter for zip that was implemented in py310. + "I", # ignore isort + "ANN101", # type annotating self + "ANN102", # type annotating cls + "FBT", # flake8-boolean-trap + "EM", # flake8-errmsg + "ANN401", # flake8-annotate typing.Any + "PD", # pandas-vet + "COM812", # trailing comma missing, but black takes care of that +] + + +[tool.ruff.per-file-ignores] +"tests/*" = ["D", "ANN"] +"__init__.py" = ["D104"] + + +[tool.ruff.pydocstyle] +convention = "numpy" diff --git a/setup.cfg b/setup.cfg index 80e72bb..d955ee9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,10 +15,6 @@ classifiers = Operating System :: OS Independent Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 project_urls = Documentation = https://github.com/pytask-dev/pytask-stata Github = https://github.com/pytask-dev/pytask-stata diff --git a/src/pytask_stata/collect.py b/src/pytask_stata/collect.py index 0621b6a..4c2ae24 100644 --- a/src/pytask_stata/collect.py +++ b/src/pytask_stata/collect.py @@ -63,7 +63,7 @@ def pytask_collect_task( task = Task( base_name=name, path=path, - function=_copy_func(run_stata_script), # type: ignore + function=_copy_func(run_stata_script), # type: ignore[arg-type] depends_on=dependencies, produces=products, markers=markers, @@ -97,20 +97,14 @@ def pytask_collect_task( task.function = stata_function return task - else: - return None + return None def _parse_stata_mark(mark: Mark) -> Mark: """Parse a Stata mark.""" script, options = stata(**mark.kwargs) - parsed_kwargs = {} - for arg_name, value, default in [ # type: ignore - ("script", script, None), - ("options", options, []), - ]: - parsed_kwargs[arg_name] = value if value else default + parsed_kwargs = {"script": script or None, "options": options or []} mark = Mark("stata", (), parsed_kwargs) return mark diff --git a/src/pytask_stata/parametrize.py b/src/pytask_stata/parametrize.py index d2f49bf..3afec0e 100644 --- a/src/pytask_stata/parametrize.py +++ b/src/pytask_stata/parametrize.py @@ -11,6 +11,5 @@ @hookimpl def pytask_parametrize_kwarg_to_marker(obj: Callable[..., Any], kwargs: Any) -> None: """Attach parametrized stata arguments to the function with a marker.""" - if callable(obj): - if "stata" in kwargs: - pytask.mark.stata(**kwargs.pop("stata"))(obj) + if callable(obj) and "stata" in kwargs: + pytask.mark.stata(**kwargs.pop("stata"))(obj) diff --git a/tests/test_collect.py b/tests/test_collect.py index ea5102d..c4c87bc 100644 --- a/tests/test_collect.py +++ b/tests/test_collect.py @@ -8,9 +8,9 @@ from pytask_stata.collect import stata -@pytest.mark.unit +@pytest.mark.unit() @pytest.mark.parametrize( - "args, kwargs, expectation, expected", + ("args", "kwargs", "expectation", "expected"), [ ( (), @@ -32,9 +32,9 @@ def test_stata(args, kwargs, expectation, expected): assert options == expected -@pytest.mark.unit +@pytest.mark.unit() @pytest.mark.parametrize( - "mark, expectation, expected", + ("mark", "expectation", "expected"), [ ( Mark("stata", (), {"script": "script.do"}), diff --git a/tests/test_config.py b/tests/test_config.py index 479db98..95a1121 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -4,7 +4,7 @@ from pytask import main -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_marker_is_configured(tmp_path): session = main({"paths": tmp_path}) diff --git a/tests/test_execute.py b/tests/test_execute.py index 5fb4a1b..5a94850 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -18,9 +18,9 @@ from tests.conftest import needs_stata -@pytest.mark.unit +@pytest.mark.unit() @pytest.mark.parametrize( - "stata, expectation", + ("stata", "expectation"), [(executable, does_not_raise()) for executable in STATA_COMMANDS] + [(None, pytest.raises(RuntimeError, match="Stata is needed"))], ) @@ -42,7 +42,7 @@ def test_pytask_execute_task_setup_raise_error(stata, platform, expectation): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_run_do_file(runner, tmp_path): task_source = """ import pytask @@ -72,7 +72,7 @@ def task_run_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_run_do_file_w_task_decorator(runner, tmp_path): task_source = """ import pytask @@ -102,7 +102,7 @@ def run_do_file(): assert tmp_path.joinpath("script.log").exists() -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_raise_error_if_stata_is_not_found(tmp_path, monkeypatch): task_source = """ import pytask @@ -117,7 +117,7 @@ def task_run_do_file(): # Hide Stata if available. monkeypatch.setattr( - "pytask_stata.config.shutil.which", lambda x: None # noqa: U100 + "pytask_stata.config.shutil.which", lambda x: None # noqa: ARG005 ) session = main({"paths": tmp_path}) @@ -127,7 +127,7 @@ def task_run_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_run_do_file_w_wrong_cmd_option(runner, tmp_path): """Apparently, Stata simply discards wrong cmd options.""" task_source = """ @@ -152,7 +152,7 @@ def task_run_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_run_do_file_by_passing_path(runner, tmp_path): """Replicates example under "Command Line Arguments" in Readme.""" task_source = """ @@ -178,7 +178,7 @@ def task_run_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_run_do_file_fails_with_multiple_marks(runner, tmp_path): task_source = """ import pytask diff --git a/tests/test_normal_execution_w_plugin.py b/tests/test_normal_execution_w_plugin.py index 4bd592e..346d228 100644 --- a/tests/test_normal_execution_w_plugin.py +++ b/tests/test_normal_execution_w_plugin.py @@ -7,7 +7,7 @@ from pytask import cli -@pytest.mark.end_to_end +@pytest.mark.end_to_end() @pytest.mark.parametrize( "dependencies", [[], ["in.txt"], ["in_1.txt", "in_2.txt"]], diff --git a/tests/test_parallel.py b/tests/test_parallel.py index b7044cf..750411e 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -24,7 +24,7 @@ @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_parallel_parametrization_over_source_files_w_parametrize(runner, tmp_path): source = """ import pytask @@ -52,7 +52,7 @@ def task_execute_do_file(): assert result.exit_code == ExitCode.OK duration_normal = time.time() - start - for name in ["1.dta", "2.dta"]: + for name in ("1.dta", "2.dta"): tmp_path.joinpath(name).unlink() start = time.time() @@ -64,7 +64,7 @@ def task_execute_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_parallel_parametrization_over_source_files_w_loop(runner, tmp_path): source = """ import pytask @@ -98,7 +98,7 @@ def task_execute_do_file(): assert result.exit_code == ExitCode.OK duration_normal = time.time() - start - for name in ["1.dta", "2.dta"]: + for name in ("1.dta", "2.dta"): tmp_path.joinpath(name).unlink() start = time.time() @@ -110,7 +110,7 @@ def task_execute_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_parallel_parametrization_over_source_file_w_parametrize(runner, tmp_path): source = """ import pytask @@ -140,7 +140,7 @@ def task_execute_do_file(): assert result.exit_code == ExitCode.OK duration_normal = time.time() - start - for name in ["output_1.dta", "output_2.dta"]: + for name in ("output_1.dta", "output_2.dta"): tmp_path.joinpath(name).unlink() start = time.time() @@ -152,7 +152,7 @@ def task_execute_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_parallel_parametrization_over_source_file_w_loop(runner, tmp_path): source = """ import pytask @@ -180,7 +180,7 @@ def task_execute_do_file(): assert result.exit_code == ExitCode.OK duration_normal = time.time() - start - for name in ["output_1.dta", "output_2.dta"]: + for name in ("output_1.dta", "output_2.dta"): tmp_path.joinpath(name).unlink() start = time.time() diff --git a/tests/test_parametrize.py b/tests/test_parametrize.py index 917f460..9ac0009 100644 --- a/tests/test_parametrize.py +++ b/tests/test_parametrize.py @@ -11,7 +11,7 @@ @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_parametrized_execution_of_do_file_w_parametrize(runner, tmp_path): task_source = """ import pytask @@ -41,7 +41,7 @@ def task_execute_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_parametrized_execution_of_do_file_w_loop(runner, tmp_path): source = """ import pytask @@ -71,7 +71,7 @@ def task_execute_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_parametrize_command_line_options_w_parametrize(runner, tmp_path): task_source = """ import pytask @@ -114,7 +114,7 @@ def task_execute_do_file(): @needs_stata -@pytest.mark.end_to_end +@pytest.mark.end_to_end() def test_parametrize_command_line_options_w_loop(runner, tmp_path): task_source = """ import pytask