ppqs 2.7.0__tar.gz → 3.0.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 (29) hide show
  1. ppqs-3.0.0/.github/dependabot.yml +34 -0
  2. {ppqs-2.7.0 → ppqs-3.0.0}/.github/workflows/publish.yml +11 -12
  3. {ppqs-2.7.0 → ppqs-3.0.0}/.github/workflows/test.yml +5 -3
  4. {ppqs-2.7.0 → ppqs-3.0.0}/.pre-commit-config.yaml +3 -3
  5. {ppqs-2.7.0 → ppqs-3.0.0}/PKG-INFO +9 -4
  6. {ppqs-2.7.0 → ppqs-3.0.0}/README.md +6 -3
  7. {ppqs-2.7.0 → ppqs-3.0.0}/pyproject.toml +8 -3
  8. ppqs-3.0.0/requirements-dev.txt +8 -0
  9. {ppqs-2.7.0 → ppqs-3.0.0}/src/ppqs.egg-info/PKG-INFO +9 -4
  10. {ppqs-2.7.0 → ppqs-3.0.0}/src/ppqs.egg-info/SOURCES.txt +1 -0
  11. {ppqs-2.7.0 → ppqs-3.0.0}/src/ppqs.egg-info/scm_file_list.json +1 -0
  12. ppqs-3.0.0/src/ppqs.egg-info/scm_version.json +8 -0
  13. {ppqs-2.7.0 → ppqs-3.0.0}/src/py_proj_quick_scripts/__init__.py +30 -18
  14. {ppqs-2.7.0 → ppqs-3.0.0}/test/test_cli.py +18 -0
  15. ppqs-2.7.0/requirements-dev.txt +0 -8
  16. ppqs-2.7.0/src/ppqs.egg-info/scm_version.json +0 -8
  17. {ppqs-2.7.0 → ppqs-3.0.0}/.gitignore +0 -0
  18. {ppqs-2.7.0 → ppqs-3.0.0}/LICENSE +0 -0
  19. {ppqs-2.7.0 → ppqs-3.0.0}/LICENSES/CC0-1.0.txt +0 -0
  20. {ppqs-2.7.0 → ppqs-3.0.0}/LICENSES/MIT.txt +0 -0
  21. {ppqs-2.7.0 → ppqs-3.0.0}/REUSE.toml +0 -0
  22. {ppqs-2.7.0 → ppqs-3.0.0}/setup.cfg +0 -0
  23. {ppqs-2.7.0 → ppqs-3.0.0}/src/ppqs.egg-info/dependency_links.txt +0 -0
  24. {ppqs-2.7.0 → ppqs-3.0.0}/src/ppqs.egg-info/entry_points.txt +0 -0
  25. {ppqs-2.7.0 → ppqs-3.0.0}/src/ppqs.egg-info/requires.txt +0 -0
  26. {ppqs-2.7.0 → ppqs-3.0.0}/src/ppqs.egg-info/top_level.txt +0 -0
  27. {ppqs-2.7.0 → ppqs-3.0.0}/test/__init__.py +0 -0
  28. {ppqs-2.7.0 → ppqs-3.0.0}/test/test_find_pyproject.py +0 -0
  29. {ppqs-2.7.0 → ppqs-3.0.0}/test/test_parse_scripts.py +0 -0
@@ -0,0 +1,34 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
+
6
+ version: 2
7
+ updates:
8
+
9
+ - package-ecosystem: "pip"
10
+ directory: "/"
11
+ schedule:
12
+ interval: "monthly"
13
+ groups:
14
+ pip-updates:
15
+ patterns:
16
+ - "*"
17
+
18
+ - package-ecosystem: "github-actions"
19
+ directory: "/"
20
+ schedule:
21
+ interval: "monthly"
22
+ groups:
23
+ action-updates:
24
+ patterns:
25
+ - "*"
26
+
27
+ - package-ecosystem: "pre-commit"
28
+ directory: "/"
29
+ schedule:
30
+ interval: "monthly"
31
+ groups:
32
+ pre-commit-updates:
33
+ patterns:
34
+ - "*"
@@ -7,7 +7,11 @@ on:
7
7
  workflow_dispatch: null
8
8
 
9
9
  jobs:
10
+ test:
11
+ uses: ./.github/workflows/test.yml
12
+
10
13
  publish:
14
+ needs: test
11
15
  runs-on: ubuntu-latest
12
16
 
13
17
  environment: ${{ github.event_name == 'workflow_dispatch' && 'testpypi' || 'pypi' }}
@@ -17,19 +21,22 @@ jobs:
17
21
  attestations: write
18
22
  contents: read
19
23
 
24
+ env:
25
+ SETUPTOOLS_SCM_OVERRIDES_FOR_PPQS: '{local_scheme="no-local-version"}'
26
+
20
27
  steps:
21
28
  - name: Checkout source code
22
- uses: actions/checkout@v4
29
+ uses: actions/checkout@v7
23
30
  with:
24
31
  fetch-depth: 0
25
32
 
26
33
  - name: Set up Python
27
- uses: actions/setup-python@v5
34
+ uses: actions/setup-python@v7
28
35
  with:
29
36
  python-version: '3.11'
30
37
 
31
38
  - name: Initialise project
32
- uses: nick-fields/retry@v2
39
+ uses: nick-fields/retry@v4
33
40
  with:
34
41
  timeout_minutes: 5
35
42
  max_attempts: 3
@@ -40,24 +47,16 @@ jobs:
40
47
  ppqs init
41
48
  ppqs version
42
49
 
43
- - name: Perform linting checks
44
- run: |
45
- ppqs lint
46
-
47
50
  - name: Build project
48
51
  run: |
49
52
  ppqs build
50
53
 
51
- - name: Run tests
52
- run: |
53
- ppqs test --no-cov
54
-
55
54
  - name: Validate metadata
56
55
  run: |
57
56
  twine check dist/*
58
57
 
59
58
  - name: Attest build
60
- uses: actions/attest-build-provenance@v2
59
+ uses: actions/attest-build-provenance@v4
61
60
  with:
62
61
  subject-path: "dist/*"
63
62
 
@@ -7,6 +7,8 @@ on:
7
7
  pull_request:
8
8
  branches:
9
9
  - "*"
10
+ workflow_call: null
11
+ workflow_dispatch: null
10
12
 
11
13
  jobs:
12
14
  test:
@@ -24,17 +26,17 @@ jobs:
24
26
 
25
27
  steps:
26
28
  - name: Checkout
27
- uses: actions/checkout@v4
29
+ uses: actions/checkout@v7
28
30
  with:
29
31
  fetch-depth: 0
30
32
 
31
33
  - name: Set up Python ${{ matrix.python-version }}
32
- uses: actions/setup-python@v5
34
+ uses: actions/setup-python@v7
33
35
  with:
34
36
  python-version: ${{ matrix.python-version }}
35
37
 
36
38
  - name: Initialise project
37
- uses: nick-fields/retry@v2
39
+ uses: nick-fields/retry@v4
38
40
  with:
39
41
  timeout_minutes: 5
40
42
  max_attempts: 3
@@ -17,17 +17,17 @@ repos:
17
17
  files: ^\.gitattributes$|^\.gitignore$|^requirements-dev\.txt$
18
18
 
19
19
  - repo: https://github.com/astral-sh/ruff-pre-commit
20
- rev: v0.15.8
20
+ rev: v0.17.4
21
21
  hooks:
22
22
  - id: ruff-check
23
23
 
24
24
  - repo: https://github.com/assorted-pre-commit-hooks/copyright
25
- rev: v0.11
25
+ rev: v0.12
26
26
  hooks:
27
27
  - id: copyright
28
28
 
29
29
  - repo: https://github.com/psf/black
30
- rev: 26.3.1
30
+ rev: 26.10.1
31
31
  hooks:
32
32
  - id: black
33
33
  args: [--target-version=py311]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ppqs
3
- Version: 2.7.0
3
+ Version: 3.0.0
4
4
  Summary: Python project quick scripts
5
5
  Author-email: Karl Wette <karl.wette@anu.edu.au>
6
6
  License-Expression: MIT
@@ -8,6 +8,8 @@ Project-URL: Homepage, https://github.com/kwwette/ppqs
8
8
  Project-URL: Issues, https://github.com/kwwette/ppqs/issues
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: Operating System :: OS Independent
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Software Development
11
13
  Requires-Python: >=3.11
12
14
  Description-Content-Type: text/markdown
13
15
  License-File: LICENSES/MIT.txt
@@ -57,8 +59,11 @@ command errors, the remainder of the script is aborted.
57
59
 
58
60
  Scripts are defined in `pyproject.toml` under the `[tool.ppqs.scripts]`
59
61
  section. Script names may contain only lowercase letters (`[a-z]`) and dashes
60
- (`-`). Scripts may be single or multi-line strings: commands are separated by
61
- newlines, and command arguments are separated by spaces.
62
+ (`-`).
63
+
64
+ Scripts may be single or multi-line strings. Command arguments are separated by
65
+ spaces, but quotes may be used for arguments containing whitespace, similar to
66
+ the Unix shell. In multi-line strings, commands are separated by newlines.
62
67
 
63
68
  ```toml
64
69
  [tool.ppqs.scripts]
@@ -68,7 +73,7 @@ command
68
73
  """
69
74
  build = """
70
75
  command1 -v
71
- command2 -q
76
+ command2 -q 'a string with whitespace'
72
77
  """
73
78
  ```
74
79
 
@@ -40,8 +40,11 @@ command errors, the remainder of the script is aborted.
40
40
 
41
41
  Scripts are defined in `pyproject.toml` under the `[tool.ppqs.scripts]`
42
42
  section. Script names may contain only lowercase letters (`[a-z]`) and dashes
43
- (`-`). Scripts may be single or multi-line strings: commands are separated by
44
- newlines, and command arguments are separated by spaces.
43
+ (`-`).
44
+
45
+ Scripts may be single or multi-line strings. Command arguments are separated by
46
+ spaces, but quotes may be used for arguments containing whitespace, similar to
47
+ the Unix shell. In multi-line strings, commands are separated by newlines.
45
48
 
46
49
  ```toml
47
50
  [tool.ppqs.scripts]
@@ -51,7 +54,7 @@ command
51
54
  """
52
55
  build = """
53
56
  command1 -v
54
- command2 -q
57
+ command2 -q 'a string with whitespace'
55
58
  """
56
59
  ```
57
60
 
@@ -14,10 +14,15 @@ dependencies = [
14
14
  ]
15
15
  readme = "README.md"
16
16
  license = "MIT"
17
- license-files = ["LICENSES/MIT.txt", "LICENSES/CC0-1.0.txt"]
17
+ license-files = [
18
+ 'LICENSES/MIT.txt',
19
+ 'LICENSES/CC0-1.0.txt',
20
+ ]
18
21
  classifiers = [
19
22
  "Programming Language :: Python :: 3",
20
23
  "Operating System :: OS Independent",
24
+ "Intended Audience :: Developers",
25
+ "Topic :: Software Development",
21
26
  ]
22
27
  dynamic = ["version"]
23
28
 
@@ -99,8 +104,8 @@ script = [
99
104
  ["ppqs", "lint"],
100
105
  ["ppqs", "build"],
101
106
  ["ppqs", "test"],
102
- ["git", "commit", "--allow-empty", "-m", "Version {1}"],
103
- ["git", "tag", "-a", "-m", "Version {1}", "v{1}"],
107
+ ["git", "commit", "--allow-empty", "-m", "Version {1}.{2}.{3}"],
108
+ ["git", "tag", "-a", "-m", "Version {1}.{2}.{3}", "v{1}.{2}.{3}"],
104
109
  ]
105
110
 
106
111
  [tool.ppqs.scripts.upload]
@@ -0,0 +1,8 @@
1
+ build>=1.6.1
2
+ coverage>=7.17.1
3
+ pre-commit>=4.7.0
4
+ pytest-cov>=7.1.0
5
+ pytest>=9.2.0
6
+ setuptools-scm>=8
7
+ setuptools>=80
8
+ twine>=7.0.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ppqs
3
- Version: 2.7.0
3
+ Version: 3.0.0
4
4
  Summary: Python project quick scripts
5
5
  Author-email: Karl Wette <karl.wette@anu.edu.au>
6
6
  License-Expression: MIT
@@ -8,6 +8,8 @@ Project-URL: Homepage, https://github.com/kwwette/ppqs
8
8
  Project-URL: Issues, https://github.com/kwwette/ppqs/issues
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: Operating System :: OS Independent
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Software Development
11
13
  Requires-Python: >=3.11
12
14
  Description-Content-Type: text/markdown
13
15
  License-File: LICENSES/MIT.txt
@@ -57,8 +59,11 @@ command errors, the remainder of the script is aborted.
57
59
 
58
60
  Scripts are defined in `pyproject.toml` under the `[tool.ppqs.scripts]`
59
61
  section. Script names may contain only lowercase letters (`[a-z]`) and dashes
60
- (`-`). Scripts may be single or multi-line strings: commands are separated by
61
- newlines, and command arguments are separated by spaces.
62
+ (`-`).
63
+
64
+ Scripts may be single or multi-line strings. Command arguments are separated by
65
+ spaces, but quotes may be used for arguments containing whitespace, similar to
66
+ the Unix shell. In multi-line strings, commands are separated by newlines.
62
67
 
63
68
  ```toml
64
69
  [tool.ppqs.scripts]
@@ -68,7 +73,7 @@ command
68
73
  """
69
74
  build = """
70
75
  command1 -v
71
- command2 -q
76
+ command2 -q 'a string with whitespace'
72
77
  """
73
78
  ```
74
79
 
@@ -5,6 +5,7 @@ README.md
5
5
  REUSE.toml
6
6
  pyproject.toml
7
7
  requirements-dev.txt
8
+ .github/dependabot.yml
8
9
  .github/workflows/publish.yml
9
10
  .github/workflows/test.yml
10
11
  LICENSES/CC0-1.0.txt
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "files": [
3
+ ".github/dependabot.yml",
3
4
  ".github/workflows/publish.yml",
4
5
  ".github/workflows/test.yml",
5
6
  ".gitignore",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "3.0.0",
3
+ "distance": 0,
4
+ "node": "g7aafe7aeb426efa3523c442b51493c6b15747723",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-11-08"
8
+ }
@@ -7,6 +7,7 @@
7
7
  import glob
8
8
  import os
9
9
  import re
10
+ import shlex
10
11
  import shutil
11
12
  import subprocess
12
13
  import sys
@@ -154,7 +155,7 @@ def parse_scripts(pyproject_path):
154
155
 
155
156
  # Parse a script as a string
156
157
  script_commands = [
157
- line.split()
158
+ shlex.split(line)
158
159
  for line in script_commands_toml.splitlines()
159
160
  if len(line.strip()) > 0
160
161
  ]
@@ -250,22 +251,12 @@ def run_script(pyproject_path, scripts, script_name, argv, cwd, has_been_run):
250
251
  cmd = []
251
252
  for arg in command:
252
253
 
253
- # Handle path arguments
254
- if isinstance(arg, Path):
255
-
256
- # Expand wildcards in last path element
257
- if "*" in arg.parts[-1]:
258
- cmd.extend(
259
- sorted(glob.glob(str(arg), root_dir=cwd, recursive=False))
260
- )
261
-
262
- else:
263
- cmd.append(str(arg))
264
-
265
- continue
254
+ # Convert to string
255
+ arg_type = type(arg)
256
+ arg_str = str(arg)
266
257
 
267
258
  # Replace positional arguments from command
268
- for arg_match in re.finditer(r"{(\d+)}", arg):
259
+ for arg_match in re.finditer(r"{(\d+)}", arg_str):
269
260
  arg_i = int(arg_match.group(1))
270
261
  if arg_i < 1:
271
262
  msg = (
@@ -279,10 +270,10 @@ def run_script(pyproject_path, scripts, script_name, argv, cwd, has_been_run):
279
270
  + "but only {} argument(s) were given"
280
271
  ).format(script_name, arg_i, len(argv))
281
272
  raise InvalidScriptCallError(pyproject_path, msg)
282
- arg = arg.replace(arg_match.group(0), argv[arg_i - 1])
273
+ arg_str = arg_str.replace(arg_match.group(0), argv[arg_i - 1])
283
274
  argv_remaining[arg_i - 1] = None
284
275
 
285
- cmd.append(arg)
276
+ cmd.append(arg_type(arg_str))
286
277
 
287
278
  cmds.append(cmd)
288
279
 
@@ -313,7 +304,28 @@ def run_script(pyproject_path, scripts, script_name, argv, cwd, has_been_run):
313
304
  raise InvalidScriptCallError(pyproject_path, msg)
314
305
 
315
306
  # Execute commands
316
- for cmd in cmds:
307
+ for command in cmds:
308
+
309
+ # Final pass of commands
310
+ cmd = []
311
+ for arg in command:
312
+
313
+ # Only process path arguments
314
+ if isinstance(arg, Path):
315
+
316
+ # Expand wildcards in last path element
317
+ if "*" in arg.parts[-1]:
318
+ cmd.extend(
319
+ sorted(glob.glob(str(arg), root_dir=cwd, recursive=False))
320
+ )
321
+
322
+ else:
323
+ cmd.append(str(arg))
324
+
325
+ continue
326
+
327
+ cmd.append(arg)
328
+
317
329
  if cmd[0] == "ppqs":
318
330
 
319
331
  # Recursively run script
@@ -48,6 +48,11 @@ def pyproject_path(tmp_path):
48
48
  ppqs greeting comrade
49
49
  echo Goodbye
50
50
  '''
51
+ [tool.ppqs.scripts.makefile]
52
+ script = [
53
+ ["python", "-c", "from pathlib import Path; Path('{1}/{2}').write_text('{3}')"],
54
+ ["cat", ["{1}", "*"]],
55
+ ]
51
56
  """
52
57
 
53
58
  write_file(pyproject_path, pyproject_toml)
@@ -146,3 +151,16 @@ def test_recursion(pyproject_path, capfd):
146
151
 
147
152
  with pytest.raises(InvalidScriptError):
148
153
  cli("no-script")
154
+
155
+
156
+ def test_makefile(pyproject_path, capfd, tmp_path):
157
+ """Test making a file and then finding it with wildcards."""
158
+
159
+ with in_dir(pyproject_path.parent):
160
+ makefile_path = tmp_path / "makefile"
161
+ makefile_path.mkdir(parents=True, exist_ok=True)
162
+
163
+ cli("makefile", str(makefile_path), "test.txt", "Good morning!")
164
+ captured = capfd.readouterr()
165
+ assert captured.out == "Good morning!"
166
+ assert captured.err == ""
@@ -1,8 +0,0 @@
1
- build>=1.2
2
- coverage>=7.6
3
- pre-commit>=3.7
4
- pytest-cov>=2.0
5
- pytest>=6.0
6
- setuptools-scm>=8
7
- setuptools>=80
8
- twine>=6.1
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "2.7.0",
3
- "distance": 0,
4
- "node": "g9e1dee20e5b9a7b19b6900fe61d4fb0d46718f6d",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-11-07"
8
- }
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