cook-build 0.7.3__tar.gz → 0.7.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cook_build-0.7.3/src/cook_build.egg-info → cook_build-0.7.4}/PKG-INFO +1 -1
- {cook_build-0.7.3 → cook_build-0.7.4}/pyproject.toml +2 -1
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/__init__.py +2 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/actions.py +1 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/util.py +44 -0
- {cook_build-0.7.3 → cook_build-0.7.4/src/cook_build.egg-info}/PKG-INFO +1 -1
- cook_build-0.7.4/tests/test_util.py +69 -0
- cook_build-0.7.3/tests/test_util.py +0 -25
- {cook_build-0.7.3 → cook_build-0.7.4}/LICENSE +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/README.md +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/README.rst +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/setup.cfg +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/__main__.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/contexts.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/controller.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/manager.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/task.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/SOURCES.txt +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/dependency_links.txt +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/entry_points.txt +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/requires.txt +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/top_level.txt +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_actions.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_contexts.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_controller.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_examples.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_main.py +0 -0
- {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_manager.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cook-build"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.4"
|
|
4
4
|
description = "A task-centric build system with simple declarative recipes specified in Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "BSD-3-Clause"}
|
|
@@ -37,6 +37,7 @@ Issues = "https://github.com/tillahoffmann/cook-build/issues"
|
|
|
37
37
|
dev = [
|
|
38
38
|
"build>=1.3.0",
|
|
39
39
|
"furo>=2025.9.25",
|
|
40
|
+
"pre-commit>=4.5.1",
|
|
40
41
|
"pyright>=1.1.406",
|
|
41
42
|
"pytest>=8.4.2",
|
|
42
43
|
"pytest-asyncio>=0.24.0",
|
|
@@ -98,3 +98,47 @@ def format_datetime(dt: datetime) -> str:
|
|
|
98
98
|
Format a date-time.
|
|
99
99
|
"""
|
|
100
100
|
return str(dt).rsplit(".", 2)[0]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def dict2args(*positional, flags: dict | None = None, **kwargs) -> list[str]:
|
|
104
|
+
"""
|
|
105
|
+
Convert arguments to command-line argument strings.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
*positional: Positional arguments appended after flags.
|
|
109
|
+
flags: Dictionary for flag names that aren't valid Python identifiers
|
|
110
|
+
(e.g., names containing dashes).
|
|
111
|
+
**kwargs: Keyword arguments converted to flags.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
List of command-line argument strings.
|
|
115
|
+
|
|
116
|
+
Example:
|
|
117
|
+
|
|
118
|
+
.. doctest::
|
|
119
|
+
|
|
120
|
+
>>> from cook.util import dict2args
|
|
121
|
+
>>> dict2args(output="file.txt", verbose=True, count=3)
|
|
122
|
+
['--output=file.txt', '--verbose', '--count=3']
|
|
123
|
+
>>> dict2args("input.txt", "output.txt", verbose=True)
|
|
124
|
+
['--verbose', 'input.txt', 'output.txt']
|
|
125
|
+
>>> dict2args(flags={"dry-run": True, "num-workers": 4})
|
|
126
|
+
['--dry-run', '--num-workers=4']
|
|
127
|
+
>>> dict2args(values=[1, 2, 3])
|
|
128
|
+
['--values=1,2,3']
|
|
129
|
+
"""
|
|
130
|
+
if flags is not None:
|
|
131
|
+
kwargs = flags | kwargs
|
|
132
|
+
args = []
|
|
133
|
+
for key, value in kwargs.items():
|
|
134
|
+
if isinstance(value, bool):
|
|
135
|
+
if value:
|
|
136
|
+
args.append(f"--{key}")
|
|
137
|
+
elif isinstance(value, (list, tuple)):
|
|
138
|
+
if not value:
|
|
139
|
+
raise ValueError(f"empty sequence for argument {key!r}")
|
|
140
|
+
args.append(f"--{key}={','.join(map(str, value))}")
|
|
141
|
+
else:
|
|
142
|
+
args.append(f"--{key}={value}")
|
|
143
|
+
args.extend(str(arg) for arg in positional)
|
|
144
|
+
return args
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
from datetime import datetime, timedelta
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from cook import util
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_evaluate_digest(tmp_wd: Path) -> None:
|
|
11
|
+
fn = tmp_wd / "foo.txt"
|
|
12
|
+
fn.write_text("bar")
|
|
13
|
+
assert util.evaluate_hexdigest(fn) == hashlib.sha1(b"bar").hexdigest()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_format_timedelta() -> None:
|
|
17
|
+
assert (
|
|
18
|
+
util.format_timedelta(timedelta(1, 13, 17, 28, 40, 3, 8)) == "57 days, 3:40:13"
|
|
19
|
+
)
|
|
20
|
+
assert util.format_timedelta(timedelta(microseconds=999)) == "0:00:00.000999"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_format_datetime() -> None:
|
|
24
|
+
assert (
|
|
25
|
+
util.format_datetime(datetime(2023, 7, 25, 13, 7, 9, 777))
|
|
26
|
+
== "2023-07-25 13:07:09"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_dict2args() -> None:
|
|
31
|
+
# Basic string value
|
|
32
|
+
assert util.dict2args(output="file.txt") == ["--output=file.txt"]
|
|
33
|
+
|
|
34
|
+
# Boolean True adds flag, False omits it
|
|
35
|
+
assert util.dict2args(verbose=True) == ["--verbose"]
|
|
36
|
+
assert util.dict2args(verbose=False) == []
|
|
37
|
+
|
|
38
|
+
# Numeric values
|
|
39
|
+
assert util.dict2args(count=3) == ["--count=3"]
|
|
40
|
+
|
|
41
|
+
# Lists/tuples joined with commas
|
|
42
|
+
assert util.dict2args(values=[1, 2, 3]) == ["--values=1,2,3"]
|
|
43
|
+
assert util.dict2args(items=("a", "b")) == ["--items=a,b"]
|
|
44
|
+
|
|
45
|
+
# Multiple arguments preserve order (Python 3.7+)
|
|
46
|
+
result = util.dict2args(output="out.txt", verbose=True, count=5)
|
|
47
|
+
assert result == ["--output=out.txt", "--verbose", "--count=5"]
|
|
48
|
+
|
|
49
|
+
# Positional arguments come after flags
|
|
50
|
+
result = util.dict2args("input.txt", "output.txt", verbose=True)
|
|
51
|
+
assert result == ["--verbose", "input.txt", "output.txt"]
|
|
52
|
+
|
|
53
|
+
# flags parameter for names with dashes or other non-identifier chars
|
|
54
|
+
assert util.dict2args(flags={"dry-run": True}) == ["--dry-run"]
|
|
55
|
+
assert util.dict2args(flags={"num-workers": 4}) == ["--num-workers=4"]
|
|
56
|
+
|
|
57
|
+
# flags and kwargs combined (kwargs take precedence)
|
|
58
|
+
result = util.dict2args(flags={"output": "old.txt"}, output="new.txt")
|
|
59
|
+
assert result == ["--output=new.txt"]
|
|
60
|
+
|
|
61
|
+
# All together: flags, kwargs, and positional
|
|
62
|
+
result = util.dict2args("file.txt", flags={"dry-run": True}, verbose=True)
|
|
63
|
+
assert result == ["--dry-run", "--verbose", "file.txt"]
|
|
64
|
+
|
|
65
|
+
# Empty sequences raise ValueError
|
|
66
|
+
with pytest.raises(ValueError, match="empty sequence"):
|
|
67
|
+
util.dict2args(values=[])
|
|
68
|
+
with pytest.raises(ValueError, match="empty sequence"):
|
|
69
|
+
util.dict2args(items=())
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import hashlib
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
from cook import util
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def test_evaluate_digest(tmp_wd: Path) -> None:
|
|
9
|
-
fn = tmp_wd / "foo.txt"
|
|
10
|
-
fn.write_text("bar")
|
|
11
|
-
assert util.evaluate_hexdigest(fn) == hashlib.sha1(b"bar").hexdigest()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def test_format_timedelta() -> None:
|
|
15
|
-
assert (
|
|
16
|
-
util.format_timedelta(timedelta(1, 13, 17, 28, 40, 3, 8)) == "57 days, 3:40:13"
|
|
17
|
-
)
|
|
18
|
-
assert util.format_timedelta(timedelta(microseconds=999)) == "0:00:00.000999"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def test_format_datetime() -> None:
|
|
22
|
-
assert (
|
|
23
|
-
util.format_datetime(datetime(2023, 7, 25, 13, 7, 9, 777))
|
|
24
|
-
== "2023-07-25 13:07:09"
|
|
25
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|