Skip to content

Commit 23d8e0d

Browse files
authored
Deprecate INI configurations and align with pytask v0.3. (#33)
1 parent 7f6152d commit 23d8e0d

File tree

10 files changed

+34
-103
lines changed

10 files changed

+34
-103
lines changed

CHANGES.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@ chronological order. Releases follow [semantic versioning](https://semver.org/)
55
releases are available on [PyPI](https://pypi.org/project/pytask-r) and
66
[Anaconda.org](https://anaconda.org/conda-forge/pytask-r).
77

8-
## 0.2.0 - 2022-xx-xx
8+
## 0.3.0 - 2023-xx-xx
9+
10+
- {pull}`33` deprecates INI configurations and aligns the plugin with pytask v0.3.
11+
12+
## 0.2.0 - 2022-04-16
913

1014
- {pull}`24` removes an unnecessary hook implementation.
15+
- {pull}`26` implements the new interface for v0.2.
1116

1217
## 0.1.1 - 2022-02-08
1318

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![image](https://img.shields.io/conda/vn/conda-forge/pytask-r.svg)](https://anaconda.org/conda-forge/pytask-r)
66
[![image](https://img.shields.io/conda/pn/conda-forge/pytask-r.svg)](https://anaconda.org/conda-forge/pytask-r)
77
[![PyPI - License](https://img.shields.io/pypi/l/pytask-r)](https://pypi.org/project/pytask-r)
8-
[![image](https://img.shields.io/github/workflow/status/pytask-dev/pytask-r/main/main)](https://github.com/pytask-dev/pytask-r/actions?query=branch%3Amain)
8+
[![image](https://img.shields.io/github/actions/workflow/status/pytask-dev/pytask-r/main.yml?branch=main)](https://github.com/pytask-dev/pytask-r/actions?query=branch%3Amain)
99
[![image](https://codecov.io/gh/pytask-dev/pytask-r/branch/main/graph/badge.svg)](https://codecov.io/gh/pytask-dev/pytask-r)
1010
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/pytask-dev/pytask-r/main.svg)](https://results.pre-commit.ci/latest/github/pytask-dev/pytask-r/main)
1111
[![image](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

environment.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ dependencies:
1616
- conda-verify
1717

1818
# Package dependencies
19-
- pytask >=0.2
20-
- pytask-parallel >=0.2
19+
- pytask >=0.3
20+
- pytask-parallel >=0.3
2121

2222
- r-base >4
2323
- r-jsonlite

setup.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ packages = find:
2727
install_requires =
2828
click
2929
pybaum>=0.1.1
30-
pytask>=0.2
30+
pytask>=0.3
3131
python_requires = >=3.7
3232
include_package_data = True
3333
package_dir = =src

src/pytask_r/collect.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from pytask import produces
1515
from pytask import remove_marks
1616
from pytask import Task
17-
from pytask_r.serialization import SERIALIZER
17+
from pytask_r.serialization import SERIALIZERS
1818
from pytask_r.shared import r
1919

2020

@@ -101,9 +101,9 @@ def _parse_r_mark(mark, default_options, default_serializer, default_suffix):
101101

102102
if (
103103
isinstance(parsed_kwargs["serializer"], str)
104-
and parsed_kwargs["serializer"] in SERIALIZER
104+
and parsed_kwargs["serializer"] in SERIALIZERS
105105
):
106-
proposed_suffix = SERIALIZER[parsed_kwargs["serializer"]]["suffix"]
106+
proposed_suffix = SERIALIZERS[parsed_kwargs["serializer"]]["suffix"]
107107
else:
108108
proposed_suffix = default_suffix
109109
parsed_kwargs["suffix"] = suffix if suffix else proposed_suffix

src/pytask_r/config.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,28 @@
22
from __future__ import annotations
33

44
from pytask import hookimpl
5+
from pytask_r.serialization import SERIALIZERS
56

67

78
@hookimpl
8-
def pytask_parse_config(config, config_from_file):
9+
def pytask_parse_config(config):
910
"""Register the r marker."""
1011
config["markers"]["r"] = "Tasks which are executed with Rscript."
11-
config["r_serializer"] = config_from_file.get("r_serializer", "json")
12-
config["r_suffix"] = config_from_file.get("r_suffix", "")
13-
config["r_options"] = _parse_value_or_whitespace_option(
14-
config_from_file.get("r_options")
15-
)
12+
config["r_serializer"] = config.get("r_serializer", "json")
13+
if config["r_serializer"] not in SERIALIZERS:
14+
raise ValueError(
15+
f"'r_serializer' is {config['r_serializer']} and not one of "
16+
f"{list(SERIALIZERS)}."
17+
)
18+
config["r_suffix"] = config.get("r_suffix", "")
19+
config["r_options"] = _parse_value_or_whitespace_option(config.get("r_options"))
1620

1721

1822
def _parse_value_or_whitespace_option(value: str | None) -> None | str | list[str]:
1923
"""Parse option which can hold a single value or values separated by new lines."""
20-
if value in ["none", "None", None, ""]:
24+
if value is None:
2125
return None
2226
elif isinstance(value, list):
2327
return list(map(str, value))
24-
elif isinstance(value, str):
25-
return [v.strip() for v in value.split(" ") if v.strip()]
2628
else:
27-
raise ValueError(f"Input {value!r} is neither a 'str' nor 'None'.")
29+
raise ValueError(f"'r_options' is {value} and not a list.")

src/pytask_r/serialization.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@
1212
_HIDDEN_FOLDER = ".pytask"
1313

1414

15-
SERIALIZER = {"json": {"serializer": json.dumps, "suffix": ".json"}}
15+
SERIALIZERS = {"json": {"serializer": json.dumps, "suffix": ".json"}}
1616

1717

1818
try:
1919
import yaml
2020
except ImportError: # pragma: no cover
2121
pass
2222
else:
23-
SERIALIZER["yaml"] = {"serializer": yaml.dump, "suffix": ".yaml"}
24-
SERIALIZER["yml"] = {"serializer": yaml.dump, "suffix": ".yml"}
23+
SERIALIZERS["yaml"] = {"serializer": yaml.dump, "suffix": ".yaml"}
24+
SERIALIZERS["yml"] = {"serializer": yaml.dump, "suffix": ".yml"}
2525

2626

2727
def create_path_to_serialized(task: Task, suffix: str) -> Path:
@@ -56,8 +56,8 @@ def serialize_keyword_arguments(
5656
) -> None:
5757
if callable(serializer):
5858
serializer_func = serializer
59-
elif isinstance(serializer, str) and serializer in SERIALIZER:
60-
serializer_func = SERIALIZER[serializer]["serializer"]
59+
elif isinstance(serializer, str) and serializer in SERIALIZERS:
60+
serializer_func = SERIALIZERS[serializer]["serializer"]
6161
else:
6262
raise ValueError(f"Serializer {serializer!r} is not known.")
6363

src/pytask_r/shared.py

-38
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,7 @@
66
from typing import Sequence
77

88

9-
_ERROR_MSG = """The old syntax for @pytask.mark.r was suddenly deprecated starting \
10-
with pytask-r v0.2 to provide a better user experience. Thank you for your \
11-
understanding!
12-
13-
It is recommended to upgrade to the new syntax, so you enjoy all the benefits of v0.2 \
14-
of pytask and pytask-r which is among others access to 'depends_on' and 'produces', \
15-
and other kwargs inside the R script.
16-
17-
You can find a manual here: \
18-
https://github.com/pytask-dev/pytask-r/blob/v0.2.0/README.md
19-
20-
Upgrading can be as easy as rewriting your current task from
21-
22-
@pytask.mark.r(["--option", "path_to_dependency.txt"])
23-
@pytask.mark.depends_on("script.R")
24-
@pytask.mark.produces("out.csv")
25-
def task_r():
26-
...
27-
28-
to
29-
30-
@pytask.mark.r(script="script.r", options="--option")
31-
@pytask.mark.depends_on("path_to_dependency.txt")
32-
@pytask.mark.produces("out.csv")
33-
def task_r():
34-
...
35-
36-
You can also fix the version of pytask and pytask-r to <0.2, so you do not have to \
37-
to upgrade. At the same time, you will not enjoy the improvements released with \
38-
version v0.2 of pytask and pytask-r.
39-
40-
"""
41-
42-
439
def r(
44-
*args,
4510
script: str | Path = None,
4611
options: str | Iterable[str] | None = None,
4712
serializer: str | Callable[..., str] | str | None = None,
@@ -70,9 +35,6 @@ def r(
7035
``".json"``.
7136
7237
"""
73-
if args or script is None:
74-
raise RuntimeError(_ERROR_MSG)
75-
7638
options = [] if options is None else list(map(str, _to_list(options)))
7739
return script, options, serializer, suffix
7840

tests/test_collect.py

+2-40
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,13 @@
66
from pytask import Mark
77
from pytask_r.collect import _parse_r_mark
88
from pytask_r.collect import r
9-
from pytask_r.serialization import SERIALIZER
9+
from pytask_r.serialization import SERIALIZERS
1010

1111

1212
@pytest.mark.unit
1313
@pytest.mark.parametrize(
1414
"args, kwargs, expectation, expected",
1515
[
16-
((), {}, pytest.raises(RuntimeError, match="The old syntax"), None),
17-
(
18-
("-o"),
19-
{"script": "script.r"},
20-
pytest.raises(RuntimeError, match="The old syntax"),
21-
None,
22-
),
23-
(
24-
(),
25-
{"options": ("-o")},
26-
pytest.raises(RuntimeError, match="The old syntax"),
27-
None,
28-
),
2916
(
3017
(),
3118
{
@@ -60,31 +47,6 @@ def test_r(args, kwargs, expectation, expected):
6047
@pytest.mark.parametrize(
6148
"mark, default_options, default_serializer, default_suffix, expectation, expected",
6249
[
63-
(
64-
Mark("r", (), {}),
65-
[],
66-
None,
67-
".json",
68-
pytest.raises(RuntimeError, match="The old syntax for @pytask.mark.r"),
69-
Mark(
70-
"r",
71-
(),
72-
{
73-
"script": None,
74-
"options": [],
75-
"serializer": None,
76-
"suffix": ".json",
77-
},
78-
),
79-
),
80-
(
81-
Mark("r", ("-o"), {}),
82-
[],
83-
None,
84-
".json",
85-
pytest.raises(RuntimeError, match="The old syntax for @pytask.mark.r"),
86-
None,
87-
),
8850
(
8951
Mark("r", (), {"script": "script.r"}),
9052
[],
@@ -122,7 +84,7 @@ def test_r(args, kwargs, expectation, expected):
12284
"script": "script.r",
12385
"options": [],
12486
"serializer": "json",
125-
"suffix": SERIALIZER["json"]["suffix"],
87+
"suffix": SERIALIZERS["json"]["suffix"],
12688
},
12789
),
12890
),

tox.ini

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ basepython = python
99

1010
[testenv:pytest]
1111
conda_deps =
12-
pytask >=0.1.0
13-
pytask-parallel >=0.1.0
12+
pytask >=0.3
13+
pytask-parallel >=0.3
1414
pybaum >=0.1.1
1515

1616
# Optional dependencies.

0 commit comments

Comments
 (0)