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.
Files changed (28) hide show
  1. {cook_build-0.7.3/src/cook_build.egg-info → cook_build-0.7.4}/PKG-INFO +1 -1
  2. {cook_build-0.7.3 → cook_build-0.7.4}/pyproject.toml +2 -1
  3. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/__init__.py +2 -0
  4. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/actions.py +1 -0
  5. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/util.py +44 -0
  6. {cook_build-0.7.3 → cook_build-0.7.4/src/cook_build.egg-info}/PKG-INFO +1 -1
  7. cook_build-0.7.4/tests/test_util.py +69 -0
  8. cook_build-0.7.3/tests/test_util.py +0 -25
  9. {cook_build-0.7.3 → cook_build-0.7.4}/LICENSE +0 -0
  10. {cook_build-0.7.3 → cook_build-0.7.4}/README.md +0 -0
  11. {cook_build-0.7.3 → cook_build-0.7.4}/README.rst +0 -0
  12. {cook_build-0.7.3 → cook_build-0.7.4}/setup.cfg +0 -0
  13. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/__main__.py +0 -0
  14. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/contexts.py +0 -0
  15. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/controller.py +0 -0
  16. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/manager.py +0 -0
  17. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook/task.py +0 -0
  18. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/SOURCES.txt +0 -0
  19. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/dependency_links.txt +0 -0
  20. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/entry_points.txt +0 -0
  21. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/requires.txt +0 -0
  22. {cook_build-0.7.3 → cook_build-0.7.4}/src/cook_build.egg-info/top_level.txt +0 -0
  23. {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_actions.py +0 -0
  24. {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_contexts.py +0 -0
  25. {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_controller.py +0 -0
  26. {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_examples.py +0 -0
  27. {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_main.py +0 -0
  28. {cook_build-0.7.3 → cook_build-0.7.4}/tests/test_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cook-build
3
- Version: 0.7.3
3
+ Version: 0.7.4
4
4
  Summary: A task-centric build system with simple declarative recipes specified in Python
5
5
  Author: Till Hoffmann
6
6
  License: BSD-3-Clause
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cook-build"
3
- version = "0.7.3"
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",
@@ -1,10 +1,12 @@
1
1
  from .controller import Controller
2
2
  from .manager import Manager, create_task
3
3
  from .task import Task
4
+ from .util import dict2args
4
5
 
5
6
  __all__ = [
6
7
  "Controller",
7
8
  "create_task",
9
+ "dict2args",
8
10
  "Manager",
9
11
  "Task",
10
12
  ]
@@ -174,6 +174,7 @@ class SubprocessAction(Action):
174
174
  else:
175
175
  for arg in args:
176
176
  hasher.update(arg.encode())
177
+ hasher.update(b"\0")
177
178
  return hasher.hexdigest()
178
179
 
179
180
  def __repr__(self) -> str:
@@ -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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cook-build
3
- Version: 0.7.3
3
+ Version: 0.7.4
4
4
  Summary: A task-centric build system with simple declarative recipes specified in Python
5
5
  Author: Till Hoffmann
6
6
  License: BSD-3-Clause
@@ -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