From 53bb407664e3cccf169e9ae628201f5bbe77cb78 Mon Sep 17 00:00:00 2001 From: Peter Schuster Date: Tue, 17 Mar 2026 15:36:21 +0100 Subject: [PATCH] chore: extract glob for pyupgrade to separate script for cross-platform compatibility 'sh' in tox.ini does not work on Windows in PowerShell. Signed-off-by: Peter Schuster --- tools/run_pyupgrade.py | 35 +++++++++++++++++++++++++++++++++++ tox.ini | 6 ++---- 2 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 tools/run_pyupgrade.py diff --git a/tools/run_pyupgrade.py b/tools/run_pyupgrade.py new file mode 100644 index 000000000..f67ae15d2 --- /dev/null +++ b/tools/run_pyupgrade.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +# Wrapper around pyupgrade to perform a lookup of all *.py/*.pyi files in passed directories +# and pass them to pyupgrade in a single invocation. +# +# Usage: run_pyupgrade.py -- + +import subprocess # nosec - subprocess is used to run pyupgrade and not part of published library +import sys +from pathlib import Path + +if '--' not in sys.argv: + print('Usage: run_pyupgrade.py -- ', file=sys.stderr) + sys.exit(1) + +sep = sys.argv.index('--') +pyupgrade_args = sys.argv[1:sep] +directories = sys.argv[sep + 1:] + +if not directories: + print('Error: at least one directory must be specified after --', file=sys.stderr) + sys.exit(1) + +files = sorted({ + str(file) + for directory in directories + for pattern in ['*.py', '*.pyi'] + for file in Path(directory).rglob(pattern) +}) + +result = subprocess.run( # nosec - shell=False is used to prevent injection, all arg passed as a list + [sys.executable, '-m', 'pyupgrade', *pyupgrade_args, *files], + shell=False # w/o shell all args are passed directly to the process without the need for quotes or escaping +) +sys.exit(result.returncode) diff --git a/tox.ini b/tox.ini index af228b75a..8afcf3aa0 100644 --- a/tox.ini +++ b/tox.ini @@ -52,10 +52,8 @@ commands = poetry run deptry -v . [testenv:pyupgrade] -allowlist_externals = poetry, sh -commands = sh -c "\ - find cyclonedx typings tests tools examples -type f \( -name '*.py' -or -name '*.pyi' \) -print0 \ - | xargs -0 poetry run pyupgrade --py39-plus {posargs} " +# first -- stops command parsing by poetry run, the second -- splits pyupgrade args from args for glob patterns +commands = poetry run -- python tools/run_pyupgrade.py --py39-plus {posargs} -- cyclonedx typings tests tools examples [testenv:isort] commands = poetry run isort .