PyProd 0.3.0__tar.gz → 0.5.0__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 (59) hide show
  1. {pyprod-0.3.0 → pyprod-0.5.0}/.gitignore +3 -1
  2. {pyprod-0.3.0 → pyprod-0.5.0}/PKG-INFO +13 -6
  3. {pyprod-0.3.0 → pyprod-0.5.0}/README.rst +11 -5
  4. pyprod-0.5.0/docs/commandline.rst +23 -0
  5. {pyprod-0.3.0 → pyprod-0.5.0}/docs/conf.py +1 -1
  6. {pyprod-0.3.0 → pyprod-0.5.0}/docs/index.rst +32 -2
  7. {pyprod-0.3.0 → pyprod-0.5.0}/docs/prodfile.rst +84 -34
  8. pyprod-0.5.0/docs/releasenotes.rst +22 -0
  9. {pyprod-0.3.0 → pyprod-0.5.0}/pyproject.toml +8 -2
  10. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/build-c/Makefile +1 -1
  11. pyprod-0.3.0/sample/build-c/PRODFILE.py → pyprod-0.5.0/samples/build-c/Prodfile.py +6 -3
  12. pyprod-0.3.0/sample/generate-doc/PRODFILE.py → pyprod-0.5.0/samples/generate-doc/Prodfile.py +5 -2
  13. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/md-to-pdf/Prodfile.py +7 -1
  14. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/s3files/Prodfile.py +7 -3
  15. pyprod-0.5.0/src/pyprod/__init__.py +1 -0
  16. {pyprod-0.3.0 → pyprod-0.5.0}/src/pyprod/main.py +28 -8
  17. {pyprod-0.3.0 → pyprod-0.5.0}/src/pyprod/prod.py +248 -135
  18. {pyprod-0.3.0 → pyprod-0.5.0}/src/pyprod/utils.py +5 -3
  19. {pyprod-0.3.0 → pyprod-0.5.0}/src/pyprod/venv.py +13 -4
  20. pyprod-0.5.0/tests/conftest.py +11 -0
  21. pyprod-0.5.0/tests/test_prod.py +344 -0
  22. {pyprod-0.3.0 → pyprod-0.5.0}/tests/test_prodfuncs.py +35 -3
  23. {pyprod-0.3.0 → pyprod-0.5.0}/tests/test_rule.py +23 -41
  24. pyprod-0.5.0/tests/utils.py +13 -0
  25. pyprod-0.3.0/.python-version +0 -1
  26. pyprod-0.3.0/.readthedocs.yaml +0 -20
  27. pyprod-0.3.0/docs/commandline.rst +0 -20
  28. pyprod-0.3.0/docs/releasenotes.rst +0 -9
  29. pyprod-0.3.0/sample/generate-doc/.gitignore +0 -2
  30. pyprod-0.3.0/tests/__init__.py +0 -0
  31. pyprod-0.3.0/tests/conftest.py +0 -3
  32. pyprod-0.3.0/tests/test_prod.py +0 -217
  33. pyprod-0.3.0/uv.lock +0 -723
  34. {pyprod-0.3.0 → pyprod-0.5.0}/.github/workflows/publish.yml +0 -0
  35. {pyprod-0.3.0 → pyprod-0.5.0}/.github/workflows/test.yml +0 -0
  36. {pyprod-0.3.0 → pyprod-0.5.0}/LICENSE +0 -0
  37. {pyprod-0.3.0 → pyprod-0.5.0}/docs/Makefile +0 -0
  38. {pyprod-0.3.0 → pyprod-0.5.0}/docs/make.bat +0 -0
  39. {pyprod-0.3.0 → pyprod-0.5.0}/docs/pyprod2.png +0 -0
  40. {pyprod-0.3.0 → pyprod-0.5.0}/docs/quickstart.rst +0 -0
  41. {pyprod-0.3.0 → pyprod-0.5.0}/docs/requirements.txt +0 -0
  42. {pyprod-0.3.0 → pyprod-0.5.0}/pyprod.webp +0 -0
  43. {pyprod-0.3.0 → pyprod-0.5.0}/pyprod2.png +0 -0
  44. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/build-c/hello.c +0 -0
  45. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/build-c/hello.h +0 -0
  46. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/build-c/main.c +0 -0
  47. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/generate-doc/a.txt +0 -0
  48. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/generate-doc/b.txt +0 -0
  49. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/generate-doc/c.txt +0 -0
  50. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/generate-doc/inc1.txt +0 -0
  51. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/generate-doc/inc2.txt +0 -0
  52. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/md-to-pdf/doc.md +0 -0
  53. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/md-to-pdf/md_to_html.py +0 -0
  54. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/md-to-pdf/template.html +0 -0
  55. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/s3files/S3TEST.txt +0 -0
  56. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/tutorial-1/Prodfile.py +0 -0
  57. {pyprod-0.3.0/sample → pyprod-0.5.0/samples}/tutorial-2/Prodfile.py +0 -0
  58. {pyprod-0.3.0 → pyprod-0.5.0}/src/pyprod/__main__.py +0 -0
  59. {pyprod-0.3.0/src/pyprod → pyprod-0.5.0/tests}/__init__.py +0 -0
@@ -1,3 +1,5 @@
1
+ .*
2
+ !.github
1
3
  # Byte-compiled / optimized / DLL files
2
4
  __pycache__/
3
5
  *.py[cod]
@@ -98,7 +100,7 @@ ipython_config.py
98
100
  # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
101
  # This is especially recommended for binary packages to ensure reproducibility, and is more
100
102
  # commonly ignored for libraries.
101
- #uv.lock
103
+ uv.lock
102
104
 
103
105
  # poetry
104
106
  # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyProd
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: PyProd: More Makeable than Make
5
5
  Project-URL: Homepage, https://github.com/atsuoishimoto/pyprod
6
6
  Project-URL: Documentation, https://pyprod.readthedocs.io/en/latest/
@@ -12,12 +12,13 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Topic :: Software Development :: Build Tools
14
14
  Requires-Python: >=3.10
15
+ Requires-Dist: python-dateutil
15
16
  Description-Content-Type: text/x-rst
16
17
 
17
18
  PyProd - More Makeable than Make
18
19
  =================================
19
20
 
20
- PyProd is a Python script that can be used as an alternative to Makefile. By leveraging Python's versatility, it enables you to define build rules and dependencies programmatically, allowing for dynamic configurations, integration with existing Python libraries, and custom build logic not easily achievable with traditional Makefiles. For detailed documentation, please refer to the `official documentation <https://pyprod.readthedocs.io/en/latest/>`_.
21
+ PyProd is a Python script that can be used as an alternative to Makefile. By leveraging Python's versatility, it enables you to define build rules and dependencies programmatically, allowing for dynamic configurations, integration with existing Python libraries, and custom build logic not easily achievable with traditional Makefiles. For detailed documentation, please refer to the `official documentation <https://pyprod.readthedocs.io/en/stable/>`_.
21
22
 
22
23
 
23
24
  Features
@@ -42,22 +43,26 @@ With PyProd, a traditional Makefile for C can be expressed as a Python script li
42
43
  .. code-block:: python
43
44
 
44
45
  CC = "gcc"
45
- CFLAGS = "-I."
46
+ CFLAGS = "-c -I."
46
47
  DEPS = "hello.h"
47
48
  OBJS = "hello.o main.o".split()
49
+ EXE = "hello.exe"
48
50
 
49
51
  @rule("%.o", depends=("%.c", DEPS))
50
52
  def compile(target, src, *deps):
51
- run(CC, "-c -o", target, src, CFLAGS)
53
+ run(CC, "-o", target, src, CFLAGS)
52
54
 
53
- @rule("hello.exe", depends=OBJS)
55
+ @rule(EXE, depends=OBJS)
54
56
  def link(target, *objs):
55
57
  run(CC, "-o", target, objs)
56
58
 
59
+ @task
57
60
  def clean():
58
61
  run("rm -f", OBJS, "hello.exe")
59
62
 
60
- all = "hello.exe"
63
+ @task
64
+ def rebuild():
65
+ build(clean, EXE)
61
66
 
62
67
 
63
68
  To run the build script, simply execute:
@@ -67,6 +72,8 @@ To run the build script, simply execute:
67
72
  $ cd project
68
73
  $ pyprod
69
74
 
75
+ Other examples can be found in the `samples <https://github.com/atsuoishimoto/pyprod/tree/main/samples>`_ directory.
76
+
70
77
  License
71
78
  -------
72
79
  PyProd is licensed under the MIT License. See the `LICENSE <LICENSE>`_ file for more details.
@@ -1,7 +1,7 @@
1
1
  PyProd - More Makeable than Make
2
2
  =================================
3
3
 
4
- PyProd is a Python script that can be used as an alternative to Makefile. By leveraging Python's versatility, it enables you to define build rules and dependencies programmatically, allowing for dynamic configurations, integration with existing Python libraries, and custom build logic not easily achievable with traditional Makefiles. For detailed documentation, please refer to the `official documentation <https://pyprod.readthedocs.io/en/latest/>`_.
4
+ PyProd is a Python script that can be used as an alternative to Makefile. By leveraging Python's versatility, it enables you to define build rules and dependencies programmatically, allowing for dynamic configurations, integration with existing Python libraries, and custom build logic not easily achievable with traditional Makefiles. For detailed documentation, please refer to the `official documentation <https://pyprod.readthedocs.io/en/stable/>`_.
5
5
 
6
6
 
7
7
  Features
@@ -26,22 +26,26 @@ With PyProd, a traditional Makefile for C can be expressed as a Python script li
26
26
  .. code-block:: python
27
27
 
28
28
  CC = "gcc"
29
- CFLAGS = "-I."
29
+ CFLAGS = "-c -I."
30
30
  DEPS = "hello.h"
31
31
  OBJS = "hello.o main.o".split()
32
+ EXE = "hello.exe"
32
33
 
33
34
  @rule("%.o", depends=("%.c", DEPS))
34
35
  def compile(target, src, *deps):
35
- run(CC, "-c -o", target, src, CFLAGS)
36
+ run(CC, "-o", target, src, CFLAGS)
36
37
 
37
- @rule("hello.exe", depends=OBJS)
38
+ @rule(EXE, depends=OBJS)
38
39
  def link(target, *objs):
39
40
  run(CC, "-o", target, objs)
40
41
 
42
+ @task
41
43
  def clean():
42
44
  run("rm -f", OBJS, "hello.exe")
43
45
 
44
- all = "hello.exe"
46
+ @task
47
+ def rebuild():
48
+ build(clean, EXE)
45
49
 
46
50
 
47
51
  To run the build script, simply execute:
@@ -51,6 +55,8 @@ To run the build script, simply execute:
51
55
  $ cd project
52
56
  $ pyprod
53
57
 
58
+ Other examples can be found in the `samples <https://github.com/atsuoishimoto/pyprod/tree/main/samples>`_ directory.
59
+
54
60
  License
55
61
  -------
56
62
  PyProd is licensed under the MIT License. See the `LICENSE <LICENSE>`_ file for more details.
@@ -0,0 +1,23 @@
1
+
2
+ .. _commandline:
3
+
4
+ Command line options
5
+ ------------------------
6
+
7
+
8
+ usage: pyprod [-h] [-C DIRECTORY] [-f FILE] [-j JOB] [-r] [-g] [-v] [targets ...]
9
+
10
+ PyProd - More makable than make
11
+
12
+ positional arguments:
13
+ targets Build targets
14
+
15
+ options:
16
+ -h, --help show this help message and exit
17
+ -C, --directory DIRECTORY
18
+ Change to DIRECTORY before performing any operations
19
+ -f, --file FILE Use FILE as the Prodfile (default: 'Prodfile.py')
20
+ -j, --job JOB Allow up to N jobs to run simultaneously (default: 1)
21
+ -r, --rebuild Rebuild all
22
+ -g, --use-git Get file timestamps from Git
23
+ -v Increase verbosity level (default: 0)
@@ -7,7 +7,7 @@
7
7
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8
8
 
9
9
  project = "PyProd"
10
- copyright = "2024, Atsuo Ishimoto"
10
+ copyright = "2024-2025, Atsuo Ishimoto"
11
11
  author = "Atsuo Ishimoto"
12
12
 
13
13
  # -- General configuration ---------------------------------------------------
@@ -1,17 +1,47 @@
1
1
  PyProd - More Makeable than Make
2
2
  ============================================
3
-
4
3
  PyProd is a Python script that can be used as an alternative to Makefile. By leveraging Python's versatility, it enables you to define build rules and dependencies programmatically, allowing for dynamic configurations, integration with existing Python libraries, and custom build logic not easily achievable with traditional Makefiles.
5
4
 
6
5
  Features
7
6
  --------
8
-
9
7
  - Define build rules in Python: Use Python functions to create clear and concise build logic.
10
8
  - Specify dependencies for each rule: Automatically track and resolve dependencies between files, such as source files and headers.
11
9
  - Easily extendable with custom Python functions: Integrate custom logic for specialized tasks, like code linting or deployment.
12
10
  - Manages virtual environments: Automatically create and manage virtual environments for each project, ensuring a clean and isolated build environment.
13
11
 
14
12
 
13
+ Example
14
+ -------
15
+ With PyProd, a traditional Makefile for C can be expressed as a Python script like this:
16
+
17
+ .. code-block:: python
18
+
19
+ CC = "gcc"
20
+ CFLAGS = "-c -I."
21
+ DEPS = "hello.h"
22
+ OBJS = "hello.o main.o".split()
23
+ EXE = "hello.exe"
24
+
25
+ @rule("%.o", depends=("%.c", DEPS))
26
+ def compile(target, src, *deps):
27
+ run(CC, "-o", target, src, CFLAGS)
28
+
29
+ @rule(EXE, depends=OBJS)
30
+ def link(target, *objs):
31
+ run(CC, "-o", target, objs)
32
+
33
+ @task
34
+ def clean():
35
+ run("rm -f", OBJS, "hello.exe")
36
+
37
+ @task
38
+ def rebuild():
39
+ build(clean, EXE)
40
+
41
+
42
+
43
+ Other examples can be found in the `samples <https://github.com/atsuoishimoto/pyprod/tree/main/samples>`_ directory.
44
+
15
45
  Table of Contents
16
46
  --------------------
17
47
 
@@ -10,12 +10,12 @@ Rule definition
10
10
 
11
11
  A rule is defined using the ``@rule`` decorator, which takes the target file as an argument. The target file is the output of the rule, and the function that follows the decorator is the build logic that generates the target file.
12
12
 
13
- .. py:function:: @rule(target, pattern=None, depends=(), uses=())
13
+ .. py:function:: @rule(targets, pattern=None, *, depends=(), uses=())
14
14
 
15
15
  Defines rule to build target files.
16
16
 
17
- :param target: The target file or files to be generated by the rule. Wildcards can be used in filenames, and exactly one % must be included in the filename.
18
- :type target: str | Path|list[str | Path]
17
+ :param targets: The target file or files to be generated by the rule. Wildcards can be used in filenames, and exactly one % must be included in the filename.
18
+ :type target: str | Path | list[str | Path]
19
19
 
20
20
  :param pattern: Specify the pattern used to extract the stem of the target filename.
21
21
 
@@ -85,8 +85,8 @@ The rule decorator can also be used as a standalone function without being tied
85
85
 
86
86
  .. code-block:: python
87
87
 
88
- rule(target=("file1", "file2"), depends="inc1")
89
- rule(target=("file3", "file4"), uses="inc2")
88
+ rule(targets=("file1", "file2"), depends="inc1")
89
+ rule(targets=("file3", "file4"), uses="inc2")
90
90
 
91
91
 
92
92
 
@@ -97,12 +97,12 @@ Checker definition
97
97
  PyProd provides default checkers for common file types for files and directories. For non-file targets requiring specialized checks, you can define a custom checker to determine whether a build is needed.
98
98
  A checker is defined using the ``@check`` decorator, which takes the target file as an argument.
99
99
 
100
- .. py:function:: @check(target)
100
+ .. py:function:: @check(targets)
101
101
 
102
102
  Defines a checker to get last modified time of the target.
103
103
 
104
- :param target: The target file to be checked. Wildcards can be used.
105
- :type target: str | Path
104
+ :param targets: The target file or files to be checked. Wildcards can be used.
105
+ :type target: str | Path | list[str | Path]
106
106
 
107
107
  :return: Last modified time of the file if the target exists. Returns false or raise FileNotFoundError if the target does not exist.
108
108
  :rtype: false|float|datetime.datetime
@@ -137,6 +137,37 @@ For example, a checker to retrieve the last modified timestamp of a file on Amaz
137
137
  return
138
138
  raise
139
139
 
140
+ Task definition
141
+ ^^^^^^^^^^^^^^^^^^
142
+
143
+ A task is similar to a rule but does not have a target and is always executed when it is depended upon.
144
+
145
+ .. py:function:: @task(*, name=None, uses=(), default=False)
146
+
147
+ Defines a task to be executed.
148
+
149
+ :param name: The name of the task. Defaults to the function name.
150
+ :type name: str
151
+
152
+ :param uses: Specify the dependencies of the target file.
153
+ :type uses: str | Path | list[str | Path]
154
+
155
+ :param default: If True, this task will be executed when no target is specified in the command-line arguments.
156
+
157
+ .. code-block:: python
158
+
159
+ @task(depends=("file1", "file2"))
160
+ def my_task(*files):
161
+ print("Task executed", files)
162
+
163
+
164
+ `@task` can be used without any arguments if no dependencies are specified.
165
+
166
+ .. code-block:: python
167
+
168
+ @task
169
+ def my_task(*files):
170
+ print("Task executed", files)
140
171
 
141
172
 
142
173
 
@@ -148,18 +179,31 @@ In addition to the ``@rule`` and ``@check`` decorators, PyProd provides several
148
179
  The following built-ins are available:
149
180
 
150
181
 
182
+ .. py:function:: build(*deps)
183
+
184
+ Schedule dependencies. The specified deps are built sequentially after the current build completes.
185
+
186
+ :param deps: name of dependencies to be built.
187
+
188
+ Example:
189
+
190
+ .. code-block:: python
191
+
192
+ @task
193
+ def rebuild():
194
+ build(clean, EXE)
195
+
151
196
  .. py:function:: pip(*args)
152
197
 
153
198
  Install Python packages. It creates a virtual environment if one does not already exist and installs the specified packages.
154
199
 
155
200
  :param args: Arguments to pass to the pip install command.
156
- :type target: str
157
201
 
158
- Example:
202
+ Example:
159
203
 
160
- .. code-block:: python
204
+ .. code-block:: python
161
205
 
162
- pip("numpy", "pandas")
206
+ pip("numpy", "pandas")
163
207
 
164
208
  .. _run:
165
209
 
@@ -196,14 +240,14 @@ Example:
196
240
  .. code-block:: python
197
241
 
198
242
  run(["echo", "Hello, World!"]) # list style args
199
- run(["echo Hello, World"]) # Shell style args
200
- run(["echo", "Hello,", "World"]) # Shell style args (automactic concatenation)
243
+ run("echo Hello, World") # Shell style args
244
+ run("echo", "Hello,", "World") # Shell style args (automactic concatenation)
201
245
  run("echo", ["hello", ["world"]]) # Shell style args (automactic flattening)
202
246
 
203
247
  files = run("ls", stdout=True).stdout # Capture output
204
248
 
205
249
 
206
- .. py:function:: def capture(*args, echo=True, cwd=None, check=True, text=True, shell=None)
250
+ .. py:function:: capture(*args, echo=True, cwd=None, check=True, text=True, shell=None)
207
251
 
208
252
  Execute a command and capture the output. This function is a wrapper around
209
253
  :ref:`run <run>`.
@@ -211,10 +255,10 @@ Example:
211
255
  :param args: Command and arguments to execute. If first argument is a list, the first element is the command and the rest are arguments. Sequences specified for args are automatically flattened.
212
256
  :type args: str | Path | list[str | Path]
213
257
 
214
- :echo: Print the command before executing it (default ``True``).
258
+ :param echo: Print the command before executing it (default ``True``).
215
259
  :type echo: bool
216
260
 
217
- :cwd: Change the current working directory before executing the command.
261
+ :param cwd: Change the current working directory before executing the command.
218
262
  :type shell: str | Path | None
219
263
 
220
264
  :param check: Raise an exception if the command returns a non-zero exit code (default ``True``).
@@ -235,7 +279,7 @@ Example:
235
279
  msg = capture("echo Hello, World!")
236
280
 
237
281
 
238
- .. py:function:: read(filename):
282
+ .. py:function:: read(filename)
239
283
 
240
284
  Read the contents of a file.
241
285
 
@@ -245,7 +289,7 @@ Example:
245
289
  :return: The contents of the file.
246
290
  :rtype: str
247
291
 
248
- .. py:function:: write(filename, txt, append=False):
292
+ .. py:function:: write(filename, txt, append=False)
249
293
 
250
294
  Write text to a file.
251
295
 
@@ -258,7 +302,7 @@ Example:
258
302
  :param append: Append to the file instead of overwriting it (default ``False``).
259
303
  :type append: bool
260
304
 
261
- .. py:function:: makedirs(path):
305
+ .. py:function:: makedirs(path)
262
306
 
263
307
  Create a directory along with any necessary parent directories if they do not already exist. This function wraps `os.makedirs() <https://docs.python.org/3/library/os.html#os.makedirs>`_ with the ``exists_ok`` parameter set to ``True``.
264
308
 
@@ -285,27 +329,34 @@ Example:
285
329
 
286
330
  SRCFILES = glob("**/*.c")
287
331
 
288
- .. py:function:: quote(s)
289
- .. py:function:: q(s)
332
+ .. py:function:: quote(*s)
333
+ .. py:function:: q(*s)
290
334
 
291
- Convert ``s`` to string and quote for use as a shell command argument. This function is a wrapper around `shlex.quote() <https://docs.python.org/3/library/shlex.html#shlex.quote>`_.
335
+ Quote strings in ``s``. Each ``s`` is flattend.
292
336
 
293
337
  :param s: The string to quote.
294
- :type s: str
338
+ :type s: str | list
295
339
 
296
- :return: The quoted string.
297
- :rtype: str
340
+ :return: The list of quoted strings.
341
+ :rtype: list[str]
298
342
 
299
- .. py:function:: squote(*s)
300
- .. py:function:: sq(*s)
343
+ .. py:function:: squote(s)
344
+ .. py:function:: sq(s)
301
345
 
302
- Quote strings in ``s``. Each ``s`` is flattend.
346
+ Convert ``s`` to string and quote for use as a shell command argument. This function is a wrapper around `shlex.quote() <https://docs.python.org/3/library/shlex.html#shlex.quote>`_.
303
347
 
304
- :param s: The string to quote.
348
+ :param s: The string to quote. If ``s`` is sequence, it is flattened and joined with space.
305
349
  :type s: str | list
306
350
 
307
- :return: The list of quoted strings.
308
- :rtype: list[str]
351
+ :return: The quoted string.
352
+ :rtype: str
353
+
354
+ .. py:function:: use_git(use)
355
+
356
+ Enable or disable git support. If enabled, PyProd retrieves the last modified time of the files from the git log.
357
+
358
+ :param use: Enable or disable git support.
359
+ :type bool: bool
309
360
 
310
361
  .. py:class:: Path
311
362
 
@@ -316,8 +367,7 @@ Example:
316
367
 
317
368
  .. py:data:: shutil
318
369
 
319
- Module to perform high-level file operations. See `shutil <https://docs.python.org/3/library/shutil.html>`_ for detail.
320
-
370
+ An alias for the Python Standard Library's `shutil <https://docs.python.org/3/library/shutil.html>`_ module. This module provides a higher-level interface for file operations than the built-in `os <https://docs.python.org/3/library/os.html>`_ module.
321
371
 
322
372
  .. py:data:: env
323
373
 
@@ -0,0 +1,22 @@
1
+ Release Notes
2
+ ================
3
+
4
+ 0.5.0 (2025-2-12)
5
+ -----------------------------
6
+
7
+ - Added ``default`` to the ``@task``.
8
+ - Removed ``depends`` from thr ``@task``.
9
+ - Added --use-git commandline option.
10
+
11
+ 0.4.0 (2025-1-17)
12
+ -------------------------
13
+ - Swapped the behavior of quote() and squote() to make their naming more intuitive.
14
+ - Add @task decorator.
15
+ - Change the parameter name target to targets.
16
+ - Added --rebuild option.
17
+
18
+ 0.3.0 (2025-01-03)
19
+ ------------------
20
+ - Arguments for build and check function are converted to string.
21
+ - Add built-in functions.
22
+ - Validate rule dependencies.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "PyProd"
3
- version = "0.3.0"
3
+ dynamic = ["version"]
4
4
  description = "PyProd: More Makeable than Make"
5
5
  readme = "README.rst"
6
6
  requires-python = ">=3.10"
@@ -12,7 +12,9 @@ classifiers = [
12
12
  "Environment :: Console",
13
13
  "Topic :: Software Development :: Build Tools",
14
14
  ]
15
- dependencies = []
15
+ dependencies = [
16
+ "python-dateutil",
17
+ ]
16
18
 
17
19
  [project.urls]
18
20
  Homepage = "https://github.com/atsuoishimoto/pyprod"
@@ -25,10 +27,14 @@ pyprod = "pyprod.main:main"
25
27
  requires = ["hatchling"]
26
28
  build-backend = "hatchling.build"
27
29
 
30
+ [tool.hatch.version]
31
+ path = "src/pyprod/__init__.py"
32
+
28
33
  [dependency-groups]
29
34
  dev = [
30
35
  "pytest>=8.3.4",
31
36
  "pytest-asyncio>=0.25.0",
37
+ "pytest-mock>=3.14.0",
32
38
  "ruff>=0.8.4",
33
39
  "sphinx>=8.1.3",
34
40
  "sphinx-autobuild>=2024.10.3",
@@ -7,7 +7,7 @@ OBJS = main.o hello.o
7
7
  %.o: %.c $(DEPS)
8
8
  $(CC) -c -o $@ $< $(CFLAGS)
9
9
 
10
- hello.exe a.x: $(OBJS)
10
+ hello.exe: $(OBJS)
11
11
  $(CC) -o $@ $^
12
12
 
13
13
  clean:
@@ -3,7 +3,7 @@
3
3
 
4
4
  APP = "hello.exe"
5
5
  CC = "gcc"
6
- CFLAGS = "-I."
6
+ CFLAGS = "-c -I."
7
7
  DEPS = "hello.h"
8
8
  OBJS = "hello.o main.o".split()
9
9
 
@@ -15,11 +15,14 @@ def link(target, *src):
15
15
 
16
16
  @rule("%.o", depends=("%.c", DEPS))
17
17
  def compile(target, src, *deps):
18
- run(CC, "-c -o", target, src, CFLAGS)
18
+ run(CC, "-o", target, src, CFLAGS)
19
19
 
20
20
 
21
+ @task
21
22
  def clean():
22
23
  run("rm", "-rf", OBJS, APP)
23
24
 
24
25
 
25
- all = APP
26
+ @task
27
+ def rebuild():
28
+ build(clean, APP)
@@ -15,7 +15,7 @@ def build_app(target, *src):
15
15
 
16
16
  @rule(BUILDDIR)
17
17
  def build_dir(target):
18
- run("mkdir", target)
18
+ run("mkdir -p", target)
19
19
 
20
20
 
21
21
  @rule(BUILDDIR / "%.o", depends=("%.txt", COMMON), uses=BUILDDIR)
@@ -23,8 +23,11 @@ def build_c(target, src, *commons):
23
23
  run("cat", *commons, src, ">", target)
24
24
 
25
25
 
26
+ @task
26
27
  def clean():
27
28
  run("rm", "-rf", BUILDDIR, BUILDFILES, DOC)
28
29
 
29
30
 
30
- all = DOC
31
+ @task
32
+ def rebuild():
33
+ build(clean, DOC)
@@ -39,9 +39,15 @@ def make_html(target, src, template, *_):
39
39
  # create outputs directory
40
40
  @rule(BUILD)
41
41
  def builds(target):
42
- os.makedirs(target)
42
+ os.makedirs(target, exist_ok=True)
43
43
 
44
44
 
45
+ @task
45
46
  def clean():
46
47
  shutil.rmtree(BUILD, ignore_errors=True)
47
48
  PDF.unlink(missing_ok=True)
49
+
50
+
51
+ @task
52
+ def rebuild():
53
+ build(clean, PDF)
@@ -1,7 +1,7 @@
1
1
  # ruff: NOQA
2
2
  # type: ignore
3
3
 
4
- pip("boto3") # install boto3
4
+ pip("boto3", "-q") # install boto3
5
5
 
6
6
  import boto3, botocore
7
7
  from urllib.parse import urlparse
@@ -17,7 +17,7 @@ def parse_s3url(s3url):
17
17
  return parsed.netloc, parsed.path.lstrip("/")
18
18
 
19
19
 
20
- @rule(target=TARGET, pattern="*/%.txt", depends="%.txt")
20
+ @rule(targets=TARGET, pattern="*/%.txt", depends="%.txt")
21
21
  def copyfile(target, src):
22
22
  """Copies a file to an S3 bucket."""
23
23
  bucket, key = parse_s3url(target)
@@ -36,16 +36,20 @@ def check_s3file(s3url):
36
36
  raise
37
37
 
38
38
 
39
+ @task
39
40
  def clean():
40
41
  """Deletes an S3 file."""
41
42
  bucket, key = parse_s3url(TARGET)
42
43
  s3.delete_object(Bucket=bucket, Key=key)
43
44
 
44
45
 
46
+ @task
45
47
  def ls():
46
48
  """Lists the contents of an S3 bucket."""
47
49
  bucket, key = parse_s3url(TARGET)
48
50
  run("aws s3 ls", bucket)
49
51
 
50
52
 
51
- rule("S3TEST.txt") # Define target for default goal
53
+ @task
54
+ def rebuild():
55
+ build(clean, TARGET)
@@ -0,0 +1 @@
1
+ __version__ = "0.5.0"