Skip to content

Deprecate INI configurations and align with pytask v0.3. #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 21, 2023
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
3 changes: 1 addition & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
9 changes: 8 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 6 additions & 3 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ 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
- pre-commit
- pytest-cov
- pytest-xdist
- tox-conda

- pip:
- -e .
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 4 additions & 8 deletions src/pytask_stata/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 1 addition & 1 deletion src/pytask_stata/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
Expand Down
87 changes: 2 additions & 85 deletions src/pytask_stata/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
38 changes: 1 addition & 37 deletions src/pytask_stata/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand All @@ -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

Expand Down
23 changes: 0 additions & 23 deletions tests/test_collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand All @@ -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(),
Expand Down
35 changes: 0 additions & 35 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import pytest
from pytask import main
from pytask_stata.config import _nonnegative_nonzero_integer


@pytest.mark.end_to_end
Expand All @@ -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)
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ conda_channels =
conda-forge
nodefaults
conda_deps =
pytask >=0.2
pytask >=0.3
pytest
pytest-cov
pytest-xdist
Expand Down