diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8165d18..93d32ed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: args: [--branch, main] - id: trailing-whitespace - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.9.0 # Use the ref you want to point at + rev: v1.9.0 hooks: - id: python-check-blanket-noqa - id: python-check-mock-methods @@ -100,7 +100,6 @@ repos: types-setuptools ] pass_filenames: false - language_version: "3.9" - repo: https://github.com/mgedmin/check-manifest rev: "0.48" hooks: diff --git a/CHANGES.md b/CHANGES.md index 016fbe0..325c37f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,10 +5,17 @@ chronological order. Releases follow [semantic versioning](https://semver.org/) releases are available on [PyPI](https://pypi.org/project/pytask-stata) and [Anaconda.org](https://anaconda.org/conda-forge/pytask-stata). -## 0.2.0 - 2022-xx-xx +## 0.3.0 - 2023-xx-xx + +- {pull}`25` adds docformatter. +- {pull}`26` adds Python 3.11 to CI. +- {pull}`28` aligns the package with pytask v0.3. + +## 0.2.0 - 2022-04-16 - {pull}`18` adds typing to the package. - {pull}`20` removes an unnecessary hook implementation. +- {pull}`22` aligns the package with pytask v0.2. ## 0.1.2 - 2022-02-08 diff --git a/README.md b/README.md index c7a558a..81eca38 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![image](https://img.shields.io/conda/vn/conda-forge/pytask-stata.svg)](https://anaconda.org/conda-forge/pytask-stata) [![image](https://img.shields.io/conda/pn/conda-forge/pytask-stata.svg)](https://anaconda.org/conda-forge/pytask-stata) [![PyPI - License](https://img.shields.io/pypi/l/pytask-stata)](https://pypi.org/project/pytask-stata) -[![image](https://img.shields.io/github/workflow/status/pytask-dev/pytask-stata/main/main)](https://github.com/pytask-dev/pytask-stata/actions?query=branch%3Amain) +[![image](https://img.shields.io/github/actions/workflow/status/pytask-dev/pytask-stata/main.yml?branch=main)](https://github.com/pytask-dev/pytask-stata/actions?query=branch%3Amain) [![image](https://codecov.io/gh/pytask-dev/pytask-stata/branch/main/graph/badge.svg)](https://codecov.io/gh/pytask-dev/pytask-stata) [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pytask-dev/pytask-stata/main.svg)](https://results.pre-commit.ci/latest/github/pytask-dev/pytask-stata/main) [![image](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) diff --git a/environment.yml b/environment.yml index 4605ad1..2296d45 100644 --- a/environment.yml +++ b/environment.yml @@ -5,14 +5,14 @@ channels: - nodefaults dependencies: - - python >3.7 + - python >=3.7 - pip - setuptools_scm - toml # Package dependencies - - pytask >=0.2 - - pytask-parallel >=0.2 + - pytask >=0.3 + - pytask-parallel >=0.3 # Misc - black @@ -20,3 +20,6 @@ dependencies: - pytest-cov - pytest-xdist - tox-conda + + - pip: + - -e . diff --git a/setup.cfg b/setup.cfg index f8932a9..80e72bb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,7 +29,7 @@ project_urls = packages = find: install_requires = click - pytask>=0.2 + pytask>=0.3 python_requires = >=3.7 include_package_data = True package_dir = =src diff --git a/src/pytask_stata/cli.py b/src/pytask_stata/cli.py index 3695031..8cb2667 100644 --- a/src/pytask_stata/cli.py +++ b/src/pytask_stata/cli.py @@ -11,21 +11,17 @@ def pytask_extend_command_line_interface(cli: click.Group) -> None: additional_parameters = [ click.Option( ["--stata-keep-log"], - help=( - "Do not remove the log files produced while running do-files. " - "[default: False]" - ), + help="Do not remove the log files produced while running do-files.", is_flag=True, - default=None, ), click.Option( ["--stata-check-log-lines"], help=( "Number of lines of the log file to consider when searching for " - "non-zero exit codes. [default: 10]" + "non-zero exit codes." ), - type=int, - default=None, + type=click.IntRange(min=1), + default=10, ), ] cli.commands["build"].params.extend(additional_parameters) diff --git a/src/pytask_stata/collect.py b/src/pytask_stata/collect.py index 74fa2c5..0621b6a 100644 --- a/src/pytask_stata/collect.py +++ b/src/pytask_stata/collect.py @@ -102,7 +102,7 @@ def pytask_collect_task( def _parse_stata_mark(mark: Mark) -> Mark: - """Parse a Julia mark.""" + """Parse a Stata mark.""" script, options = stata(**mark.kwargs) parsed_kwargs = {} diff --git a/src/pytask_stata/config.py b/src/pytask_stata/config.py index b779250..0634e07 100644 --- a/src/pytask_stata/config.py +++ b/src/pytask_stata/config.py @@ -4,102 +4,19 @@ import shutil import sys from typing import Any -from typing import Callable from pytask import hookimpl from pytask_stata.shared import STATA_COMMANDS @hookimpl -def pytask_parse_config( - config: dict[str, Any], - config_from_cli: dict[str, Any], - config_from_file: dict[str, Any], -) -> None: +def pytask_parse_config(config: dict[str, Any]) -> None: """Register the r marker.""" config["markers"]["stata"] = "Tasks which are executed with Stata." config["platform"] = sys.platform - if config_from_file.get("stata"): - config["stata"] = config_from_file["stata"] - else: + if not config.get("stata"): config["stata"] = next( (executable for executable in STATA_COMMANDS if shutil.which(executable)), None, ) - - config["stata_keep_log"] = _get_first_non_none_value( - config_from_cli, - config_from_file, - key="stata_keep_log", - callback=_convert_truthy_or_falsy_to_bool, - default=False, - ) - - config["stata_check_log_lines"] = _get_first_non_none_value( - config_from_cli, - config_from_file, - key="stata_check_log_lines", - callback=_nonnegative_nonzero_integer, - default=10, - ) - - -def _nonnegative_nonzero_integer(x: Any) -> int: - """Check for nonnegative and nonzero integer.""" - if x is not None: - try: - x = int(x) - except ValueError: - raise ValueError( - "'stata_check_log_lines' must be a nonzero and nonnegative integer, " - f"but it is '{x}'." - ) - - if x <= 0: - raise ValueError("'stata_check_log_lines' must be greater than zero.") - - return x - - -def _get_first_non_none_value( - *configs: dict[str, Any], - key: str, - default: Any | None = None, - callback: Callable[..., Any] | None = None, -) -> Any: - """Get the first non-None value for a key from a list of dictionaries. - - This function allows to prioritize information from many configurations by changing - the order of the inputs while also providing a default. - - Examples - -------- - >>> _get_first_non_none_value({"a": None}, {"a": 1}, key="a") - 1 - >>> _get_first_non_none_value({"a": None}, {"a": None}, key="a", default="default") - 'default' - >>> _get_first_non_none_value({}, {}, key="a", default="default") - 'default' - >>> _get_first_non_none_value({"a": None}, {"a": "b"}, key="a") - 'b' - - """ - callback = (lambda x: x) if callback is None else callback # noqa: E731 - processed_values = (callback(config.get(key)) for config in configs) - return next((value for value in processed_values if value is not None), default) - - -def _convert_truthy_or_falsy_to_bool(x: bool | str | None) -> bool: - """Convert truthy or falsy value in .ini to Python boolean.""" - if x in [True, "True", "true", "1"]: - out = True - elif x in [False, "False", "false", "0"]: - out = False - elif x in [None, "None", "none"]: - out = None - else: - raise ValueError( - f"Input {x!r} is neither truthy (True, true, 1) or falsy (False, false, 0)." - ) - return out diff --git a/src/pytask_stata/shared.py b/src/pytask_stata/shared.py index e9f985a..c63d829 100644 --- a/src/pytask_stata/shared.py +++ b/src/pytask_stata/shared.py @@ -38,41 +38,8 @@ STATA_COMMANDS = [] -_ERROR_MSG = """The old syntax for @pytask.mark.stata was suddenly deprecated starting \ -with pytask-stata v0.2 to provide a better user experience. Thank you for your \ -understanding! - -It is recommended to upgrade to the new syntax, so you enjoy all the benefits of v0.2 \ -of pytask and pytask-stata. - -You can find a manual here: \ -https://github.com/pytask-dev/pytask-stata/blob/v0.2.0/README.md - -Upgrading can be as easy as rewriting your current task from - - @pytask.mark.stata(["--option", "path_to_dependency.txt"]) - @pytask.mark.depends_on("script.do") - @pytask.mark.produces("out.csv") - def task_r(): - ... - -to - - @pytask.mark.stata(script="script.do", options="--option") - @pytask.mark.depends_on("path_to_dependency.txt") - @pytask.mark.produces("out.csv") - def task_r(): - ... - -You can also fix the version of pytask and pytask-stata to <0.2, so you do not have to \ -to upgrade. At the same time, you will not enjoy the improvements released with \ -version v0.2 of pytask and pytask-stata. - -""" - - def stata( - *args: Any, + *, script: str | Path | None = None, options: str | Iterable[str] | None = None, ) -> tuple[str | Path | None, str | Iterable[str] | None]: @@ -84,9 +51,6 @@ def stata( One or multiple command line options passed to Stata. """ - if args or script is None: - raise RuntimeError(_ERROR_MSG) - options = [] if options is None else list(map(str, _to_list(options))) return script, options diff --git a/tests/test_collect.py b/tests/test_collect.py index 304ae51..ea5102d 100644 --- a/tests/test_collect.py +++ b/tests/test_collect.py @@ -12,19 +12,6 @@ @pytest.mark.parametrize( "args, kwargs, expectation, expected", [ - ((), {}, pytest.raises(RuntimeError, match="The old syntax"), None), - ( - ("-o"), - {"script": "script.do"}, - pytest.raises(RuntimeError, match="The old syntax"), - None, - ), - ( - (), - {"options": ("-o")}, - pytest.raises(RuntimeError, match="The old syntax"), - None, - ), ( (), {"script": "script.do", "options": "--option"}, @@ -49,16 +36,6 @@ def test_stata(args, kwargs, expectation, expected): @pytest.mark.parametrize( "mark, expectation, expected", [ - ( - Mark("stata", (), {}), - pytest.raises(RuntimeError, match="The old syntax for @pytask.mark.stata"), - Mark("stata", (), {"script": None, "options": []}), - ), - ( - Mark("stata", ("-o"), {}), - pytest.raises(RuntimeError, match="The old syntax for @pytask.mark.stata"), - None, - ), ( Mark("stata", (), {"script": "script.do"}), does_not_raise(), diff --git a/tests/test_config.py b/tests/test_config.py index 19d9be7..479db98 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,7 +2,6 @@ import pytest from pytask import main -from pytask_stata.config import _nonnegative_nonzero_integer @pytest.mark.end_to_end @@ -11,37 +10,3 @@ def test_marker_is_configured(tmp_path): assert "stata" in session.config assert "stata" in session.config["markers"] - - -@pytest.mark.unit -@pytest.mark.parametrize("x, expected", [(None, None), (1, 1), ("1", 1), (1.5, 1)]) -def test_nonnegative_nonzero_integer(x, expected): - assert _nonnegative_nonzero_integer(x) == expected - - -@pytest.mark.unit -@pytest.mark.parametrize( - "x, expectation", - [ - ( - -1, - pytest.raises(ValueError, match="'stata_check_log_lines' must be greater"), - ), - ( - "-1", - pytest.raises(ValueError, match="'stata_check_log_lines' must be greater"), - ), - (0, pytest.raises(ValueError, match="'stata_check_log_lines' must be greater")), - ( - "0", - pytest.raises(ValueError, match="'stata_check_log_lines' must be greater"), - ), - ( - "1.5", - pytest.raises(ValueError, match="'stata_check_log_lines' must be a"), - ), - ], -) -def test_nonnegative_nonzero_integer_raises_error(x, expectation): - with expectation: - _nonnegative_nonzero_integer(x) diff --git a/tox.ini b/tox.ini index da168af..341a53c 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ conda_channels = conda-forge nodefaults conda_deps = - pytask >=0.2 + pytask >=0.3 pytest pytest-cov pytest-xdist