From ab82cbe3cf11741cbae3204e37693227dc32c9d4 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sat, 3 May 2025 14:14:59 +0200 Subject: [PATCH 01/38] Removed old Python versions --- .travis.yml | 8 +++----- lint.sh | 2 +- setup.cfg | 2 +- setup.py | 9 +++------ tox.ini | 2 +- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab6ba6bf..dfeece70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,11 @@ os: linux -dist: focal +dist: noble language: python jobs: include: - - python: "3.8" - env: TOXENV=py38 - - python: "3.9" - env: TOXENV=py39 + - python: "3.12" + env: TOXENV=py312 cache: - pip diff --git a/lint.sh b/lint.sh index 5c418249..a7eebda1 100755 --- a/lint.sh +++ b/lint.sh @@ -13,4 +13,4 @@ tox mypy --ignore-missing-imports "${source_dir}" || true pytest "${source_dir}" pytest --doctest-modules "${source_dir}" || true -shopt -s globstar && pyupgrade --py37-plus ${source_dir}/*.py +shopt -s globstar && pyupgrade --py312-plus ${source_dir}/*.py diff --git a/setup.cfg b/setup.cfg index eb556c0a..e109555b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,5 +9,5 @@ filterwarnings = ignore:.*test class 'TestRunner'.*:Warning [mypy] -python_version = 3.8 +python_version = 3.12 ignore_missing_imports = True diff --git a/setup.py b/setup.py index ec2528f4..72bc2b46 100644 --- a/setup.py +++ b/setup.py @@ -5,13 +5,10 @@ packages=find_packages(), description="A collection of design patterns and idioms in Python.", classifiers=[ - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ], ) diff --git a/tox.ini b/tox.ini index 3ce6e132..7c23885f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38,py39,py310,cov-report +envlist = py310,py312,cov-report skip_missing_interpreters = true From eae9c780b59815a3651c89a646be16c8069a4f9e Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sat, 3 May 2025 17:17:05 +0200 Subject: [PATCH 02/38] Removed 3.10 from tox and upgraded requirements-dev.txt becasue of higher versions in lint.sh --- requirements-dev.txt | 13 +++++++------ setup.cfg | 2 +- tox.ini | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 0de4748b..67dc3633 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,8 +1,9 @@ -e . -pytest~=6.2.0 -pytest-cov~=2.11.0 -pytest-randomly~=3.1.0 -black>=20.8b1 -isort~=5.7.0 -flake8~=3.8.0 \ No newline at end of file +pytest>=6.2.0 +pytest-cov>=2.11.0 +pytest-randomly>=3.1.0 +black>=25.1.0 +isort>=5.7.0 +flake8>=7.2.0 +tox>=4.25.0 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index e109555b..4f3d0e10 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,5 +9,5 @@ filterwarnings = ignore:.*test class 'TestRunner'.*:Warning [mypy] -python_version = 3.12 +python_version = 1.15.0 ignore_missing_imports = True diff --git a/tox.ini b/tox.ini index 7c23885f..cf1d48d1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py310,py312,cov-report +envlist = py313,cov-report skip_missing_interpreters = true From 41c9cb2519bfb62313e318b9640e0ec3530461c9 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sat, 3 May 2025 17:25:12 +0200 Subject: [PATCH 03/38] 3.13 changed to 3.12 --- .github/workflows/lint_python.yml | 4 ++-- setup.cfg | 2 +- tox.ini | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 4b654cff..87b39860 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -2,12 +2,12 @@ name: lint_python on: [pull_request, push] jobs: lint_python: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: 3.x + python-version: 3.12 - shell: bash name: Lint and test run: ./lint.sh diff --git a/setup.cfg b/setup.cfg index 4f3d0e10..e109555b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,5 +9,5 @@ filterwarnings = ignore:.*test class 'TestRunner'.*:Warning [mypy] -python_version = 1.15.0 +python_version = 3.12 ignore_missing_imports = True diff --git a/tox.ini b/tox.ini index cf1d48d1..67453421 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py313,cov-report +envlist = py312,cov-report skip_missing_interpreters = true From 3ffb3cb3301651bb3d1cf64b5fdab2a91ae39a88 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 22:25:24 +0200 Subject: [PATCH 04/38] Adjusted lint_python workflow Upgraded flake8 to 7.1 --- .github/workflows/lint_python.yml | 23 ++++++++++++++++++++--- requirements-dev.txt | 6 +++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index 87b39860..ab9847a7 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -8,6 +8,23 @@ jobs: - uses: actions/setup-python@v4 with: python-version: 3.12 - - shell: bash - name: Lint and test - run: ./lint.sh + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + - name: Lint with flake8 + run: flake8 ./patterns --count --show-source --statistics + - name: Format check with isort and black + run: | + isort --profile black --check ./patterns + black --check ./patterns + - name: Type check with mypy + run: mypy --ignore-missing-imports ./patterns || true + - name: Run tests with pytest + run: | + pytest ./patterns + pytest --doctest-modules ./patterns || true + - name: Check Python version compatibility + run: shopt -s globstar && pyupgrade --py312-plus ./patterns/**/*.py + - name: Run tox + run: tox diff --git a/requirements-dev.txt b/requirements-dev.txt index 67dc3633..4aaa81f2 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,9 +1,9 @@ --e . - +mypy +pyupgrade pytest>=6.2.0 pytest-cov>=2.11.0 pytest-randomly>=3.1.0 black>=25.1.0 isort>=5.7.0 -flake8>=7.2.0 +flake8>=7.1.0 tox>=4.25.0 \ No newline at end of file From 68fdae65a09ba0730c266bcd6b7e031823a922bb Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 22:31:03 +0200 Subject: [PATCH 05/38] Added continue-on-error: true. So that if the workflow stop comes in error, it will continue. --- .github/workflows/lint_python.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index ab9847a7..19d6c078 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -14,17 +14,23 @@ jobs: pip install -r requirements-dev.txt - name: Lint with flake8 run: flake8 ./patterns --count --show-source --statistics + continue-on-error: true - name: Format check with isort and black run: | isort --profile black --check ./patterns black --check ./patterns + continue-on-error: true - name: Type check with mypy run: mypy --ignore-missing-imports ./patterns || true + continue-on-error: true - name: Run tests with pytest run: | pytest ./patterns pytest --doctest-modules ./patterns || true + continue-on-error: true - name: Check Python version compatibility run: shopt -s globstar && pyupgrade --py312-plus ./patterns/**/*.py + continue-on-error: true - name: Run tox run: tox + continue-on-error: true From 31159350ae2e7642bd913d549131bf1a5e8b7feb Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 22:55:36 +0200 Subject: [PATCH 06/38] Added workflow to check per PR --- .github/lint_pr.yml | 69 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 .github/lint_pr.yml diff --git a/.github/lint_pr.yml b/.github/lint_pr.yml new file mode 100644 index 00000000..36c8a8c9 --- /dev/null +++ b/.github/lint_pr.yml @@ -0,0 +1,69 @@ +name: lint_python +on: [pull_request, push] +jobs: + lint_python: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # To get all history for git diff commands + + - uses: actions/setup-python@v4 + with: + python-version: 3.12 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Get changed Python files + id: changed-files + run: | + if [ "${{ github.event_name }}" == "pull_request" ]; then + # For PRs, compare against base branch + CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep '\.py$' || echo "") + else + # For pushes, use the before/after SHAs + CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep '\.py$' || echo "") + fi + echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT + echo "Changed Python files: $CHANGED_FILES" + + - name: Lint with flake8 + if: ${{ steps.changed-files.outputs.files != '' }} + run: | + echo "Linting files: ${{ steps.changed-files.outputs.files }}" + flake8 ${{ steps.changed-files.outputs.files }} --count --show-source --statistics + continue-on-error: true + + - name: Format check with isort and black + if: ${{ steps.changed-files.outputs.files != '' }} + run: | + echo "Checking format with isort for: ${{ steps.changed-files.outputs.files }}" + isort --profile black --check ${{ steps.changed-files.outputs.files }} + echo "Checking format with black for: ${{ steps.changed-files.outputs.files }}" + black --check ${{ steps.changed-files.outputs.files }} + continue-on-error: true + + - name: Type check with mypy + if: ${{ steps.changed-files.outputs.files != '' }} + run: | + echo "Type checking: ${{ steps.changed-files.outputs.files }}" + mypy --ignore-missing-imports ${{ steps.changed-files.outputs.files }} + continue-on-error: true + + - name: Run tests with pytest + run: | + pytest ./patterns + pytest --doctest-modules ./patterns || true + continue-on-error: true + + - name: Check Python version compatibility + if: ${{ steps.changed-files.outputs.files != '' }} + run: pyupgrade --py312-plus ${{ steps.changed-files.outputs.files }} + continue-on-error: true + + - name: Run tox + run: tox + continue-on-error: true From 8b9400632a3b357bad4e35293392cee78e00f79d Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 23:06:48 +0200 Subject: [PATCH 07/38] Moved workflow --- .github/{ => workflows}/lint_pr.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{ => workflows}/lint_pr.yml (100%) diff --git a/.github/lint_pr.yml b/.github/workflows/lint_pr.yml similarity index 100% rename from .github/lint_pr.yml rename to .github/workflows/lint_pr.yml From 928fdcfdd6b2b4dfc1842e69c2ec04f34a6ff962 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 23:08:26 +0200 Subject: [PATCH 08/38] Changed name workflow --- .github/workflows/lint_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 36c8a8c9..5e2cd6fe 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -1,4 +1,4 @@ -name: lint_python +name: lint_pull_request on: [pull_request, push] jobs: lint_python: From a48d192c5627886ec85eab1afca5791c6026a0e5 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 23:10:34 +0200 Subject: [PATCH 09/38] Changed job name --- .github/workflows/lint_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 5e2cd6fe..724a6089 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -1,7 +1,7 @@ name: lint_pull_request on: [pull_request, push] jobs: - lint_python: + lint_pull_request: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 From b14815c405b64db877f4f85017c3c551628e5fb6 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 23:21:27 +0200 Subject: [PATCH 10/38] Added approval for non-Python files and removed continue-on-error --- .github/workflows/lint_pr.yml | 48 ++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 724a6089..420234d3 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -8,15 +8,6 @@ jobs: with: fetch-depth: 0 # To get all history for git diff commands - - uses: actions/setup-python@v4 - with: - python-version: 3.12 - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements-dev.txt - - name: Get changed Python files id: changed-files run: | @@ -28,42 +19,59 @@ jobs: CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep '\.py$' || echo "") fi echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT - echo "Changed Python files: $CHANGED_FILES" + if [ -z "$CHANGED_FILES" ]; then + echo "No Python files changed, PR will still require approval" + echo "has_python_changes=false" >> $GITHUB_OUTPUT + else + echo "Changed Python files: $CHANGED_FILES" + echo "has_python_changes=true" >> $GITHUB_OUTPUT + fi + + - name: PR information + if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.has_python_changes == 'false' }} + run: echo "This PR contains no Python changes, but still requires manual approval." + + - uses: actions/setup-python@v4 + if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} + with: + python-version: 3.12 + + - name: Install dependencies + if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt - name: Lint with flake8 - if: ${{ steps.changed-files.outputs.files != '' }} + if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} run: | echo "Linting files: ${{ steps.changed-files.outputs.files }}" flake8 ${{ steps.changed-files.outputs.files }} --count --show-source --statistics - continue-on-error: true - name: Format check with isort and black - if: ${{ steps.changed-files.outputs.files != '' }} + if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} run: | echo "Checking format with isort for: ${{ steps.changed-files.outputs.files }}" isort --profile black --check ${{ steps.changed-files.outputs.files }} echo "Checking format with black for: ${{ steps.changed-files.outputs.files }}" black --check ${{ steps.changed-files.outputs.files }} - continue-on-error: true - name: Type check with mypy - if: ${{ steps.changed-files.outputs.files != '' }} + if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} run: | echo "Type checking: ${{ steps.changed-files.outputs.files }}" mypy --ignore-missing-imports ${{ steps.changed-files.outputs.files }} - continue-on-error: true - name: Run tests with pytest + if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} run: | pytest ./patterns pytest --doctest-modules ./patterns || true - continue-on-error: true - name: Check Python version compatibility - if: ${{ steps.changed-files.outputs.files != '' }} + if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} run: pyupgrade --py312-plus ${{ steps.changed-files.outputs.files }} - continue-on-error: true - name: Run tox + if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} run: tox - continue-on-error: true From ce40583f6cbc84ca9161c853f1906a2d4b069cca Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 23:31:17 +0200 Subject: [PATCH 11/38] Optimzed lint_pr.yml --- .github/workflows/lint_pr.yml | 94 +++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 25 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 420234d3..c9154dc6 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -1,8 +1,11 @@ name: lint_pull_request on: [pull_request, push] jobs: - lint_pull_request: + check_changes: runs-on: ubuntu-24.04 + outputs: + has_python_changes: ${{ steps.changed-files.outputs.has_python_changes }} + files: ${{ steps.changed-files.outputs.files }} steps: - uses: actions/checkout@v3 with: @@ -30,48 +33,89 @@ jobs: - name: PR information if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.has_python_changes == 'false' }} run: echo "This PR contains no Python changes, but still requires manual approval." + + lint: + needs: check_changes + if: ${{ needs.check_changes.outputs.has_python_changes == 'true' }} + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + tool: [flake8, format, mypy, pytest, pyupgrade, tox] + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 - uses: actions/setup-python@v4 - if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} with: python-version: 3.12 + - uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install dependencies - if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} run: | python -m pip install --upgrade pip pip install -r requirements-dev.txt - + + # Flake8 linting - name: Lint with flake8 - if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} + if: ${{ matrix.tool == 'flake8' }} + id: flake8 run: | - echo "Linting files: ${{ steps.changed-files.outputs.files }}" - flake8 ${{ steps.changed-files.outputs.files }} --count --show-source --statistics - - - name: Format check with isort and black - if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} + echo "Linting files: ${{ needs.check_changes.outputs.files }}" + flake8 ${{ needs.check_changes.outputs.files }} --count --show-source --statistics + + # Format checking with isort and black + - name: Format check + if: ${{ matrix.tool == 'format' }} + id: format run: | - echo "Checking format with isort for: ${{ steps.changed-files.outputs.files }}" - isort --profile black --check ${{ steps.changed-files.outputs.files }} - echo "Checking format with black for: ${{ steps.changed-files.outputs.files }}" - black --check ${{ steps.changed-files.outputs.files }} - + echo "Checking format with isort for: ${{ needs.check_changes.outputs.files }}" + isort --profile black --check ${{ needs.check_changes.outputs.files }} + echo "Checking format with black for: ${{ needs.check_changes.outputs.files }}" + black --check ${{ needs.check_changes.outputs.files }} + + # Type checking with mypy - name: Type check with mypy - if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} + if: ${{ matrix.tool == 'mypy' }} + id: mypy run: | - echo "Type checking: ${{ steps.changed-files.outputs.files }}" - mypy --ignore-missing-imports ${{ steps.changed-files.outputs.files }} - + echo "Type checking: ${{ needs.check_changes.outputs.files }}" + mypy --ignore-missing-imports ${{ needs.check_changes.outputs.files }} + + # Run tests with pytest - name: Run tests with pytest - if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} + if: ${{ matrix.tool == 'pytest' }} + id: pytest run: | pytest ./patterns pytest --doctest-modules ./patterns || true - + + # Check Python version compatibility - name: Check Python version compatibility - if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} - run: pyupgrade --py312-plus ${{ steps.changed-files.outputs.files }} - + if: ${{ matrix.tool == 'pyupgrade' }} + id: pyupgrade + run: pyupgrade --py312-plus ${{ needs.check_changes.outputs.files }} + + # Run tox - name: Run tox - if: ${{ steps.changed-files.outputs.has_python_changes == 'true' }} + if: ${{ matrix.tool == 'tox' }} + id: tox run: tox + + summary: + needs: [check_changes, lint] + if: ${{ always() && needs.check_changes.outputs.has_python_changes == 'true' }} + runs-on: ubuntu-24.04 + steps: + - name: Summarize results + run: | + echo "## Pull Request Lint Results" >> $GITHUB_STEP_SUMMARY + echo "Linting has completed for all Python files changed in this PR." >> $GITHUB_STEP_SUMMARY + echo "See individual job logs for detailed results." >> $GITHUB_STEP_SUMMARY From cbfd21b327bacce03d878839abe1e1360bc2cdcc Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 23:45:52 +0200 Subject: [PATCH 12/38] Added fix for PyTest --- .github/workflows/lint_pr.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index c9154dc6..58d3c134 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -94,8 +94,11 @@ jobs: if: ${{ matrix.tool == 'pytest' }} id: pytest run: | - pytest ./patterns - pytest --doctest-modules ./patterns || true + echo "Running pytest discovery..." + python -m pytest --collect-only -v + echo "Running tests..." + python -m pytest ./tests -v + python -m pytest --doctest-modules ./patterns -v || true # Check Python version compatibility - name: Check Python version compatibility From ed9d604926dbc9fdf40757662cfeebe98058118d Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 23:49:59 +0200 Subject: [PATCH 13/38] Let pytest only test on changed python design patterns --- .github/workflows/lint_pr.yml | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 58d3c134..42c253ea 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -96,9 +96,36 @@ jobs: run: | echo "Running pytest discovery..." python -m pytest --collect-only -v - echo "Running tests..." - python -m pytest ./tests -v - python -m pytest --doctest-modules ./patterns -v || true + + # First run any test files that correspond to changed files + echo "Running tests for changed files..." + changed_files="${{ needs.check_changes.outputs.files }}" + + # Extract module paths from changed files + modules=() + for file in $changed_files; do + # Convert file path to module path (remove .py and replace / with .) + if [[ $file == patterns/* ]]; then + module_path=${file%.py} + module_path=${module_path//\//.} + modules+=("$module_path") + fi + done + + # Run tests for each module + for module in "${modules[@]}"; do + echo "Testing module: $module" + python -m pytest -xvs tests/ -k "$module" || true + done + + # Then run doctests on the changed files + echo "Running doctests for changed files..." + for file in $changed_files; do + if [[ $file == *.py ]]; then + echo "Running doctest for $file" + python -m pytest --doctest-modules -v $file || true + fi + done # Check Python version compatibility - name: Check Python version compatibility From 2acd613743cbb8d26cf5b3deddcd2d688b271001 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 23:53:37 +0200 Subject: [PATCH 14/38] Optimized Tox --- .github/workflows/lint_pr.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 42c253ea..2db83614 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -137,7 +137,25 @@ jobs: - name: Run tox if: ${{ matrix.tool == 'tox' }} id: tox - run: tox + run: | + echo "Running tox for changed files..." + changed_files="${{ needs.check_changes.outputs.files }}" + + # Create a temporary tox configuration for the changed files + echo "[testenv]" > tox_pr.ini + echo "commands =" >> tox_pr.ini + + # Add specific testing commands for each changed file + for file in $changed_files; do + if [[ $file == *.py ]]; then + echo " pytest {posargs} -xvs $file" >> tox_pr.ini + echo " flake8 $file" >> tox_pr.ini + echo " mypy --ignore-missing-imports $file" >> tox_pr.ini + fi + done + + # Run tox with the temporary configuration + tox -c tox_pr.ini || true summary: needs: [check_changes, lint] From a7d2745cfd7d1264ac84dae03c5954d56ae9d0d4 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 00:01:18 +0200 Subject: [PATCH 15/38] Allow tox execute it's checks --- .github/workflows/lint_pr.yml | 42 +++++++++++++++++++++++++++-------- tox.ini | 4 ++++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 2db83614..8c42913d 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -138,24 +138,48 @@ jobs: if: ${{ matrix.tool == 'tox' }} id: tox run: | - echo "Running tox for changed files..." + echo "Running tox integration for changed files..." changed_files="${{ needs.check_changes.outputs.files }}" - # Create a temporary tox configuration for the changed files - echo "[testenv]" > tox_pr.ini + # Create a temporary tox configuration that extends the original one + echo "[tox]" > tox_pr.ini + echo "envlist = py312" >> tox_pr.ini + echo "skip_missing_interpreters = true" >> tox_pr.ini + + echo "[testenv]" >> tox_pr.ini + echo "setenv =" >> tox_pr.ini + echo " COVERAGE_FILE = .coverage.{envname}" >> tox_pr.ini + echo "deps =" >> tox_pr.ini + echo " -r requirements-dev.txt" >> tox_pr.ini + echo "allowlist_externals =" >> tox_pr.ini + echo " pytest" >> tox_pr.ini echo "commands =" >> tox_pr.ini - # Add specific testing commands for each changed file + # For tox, let's focus on integration tests and coverage only + # to avoid duplicating what individual matrix jobs are doing + + # Add coverage-focused test commands for file in $changed_files; do if [[ $file == *.py ]]; then - echo " pytest {posargs} -xvs $file" >> tox_pr.ini - echo " flake8 $file" >> tox_pr.ini - echo " mypy --ignore-missing-imports $file" >> tox_pr.ini + # Run coverage tests for implementation files + if [[ $file == patterns/* ]]; then + module_name=$(basename $file .py) + echo " pytest --cov=patterns/ --cov-append tests/ -k \"$module_name\"" >> tox_pr.ini + fi + + # Run test files directly if modified + if [[ $file == tests/* ]]; then + echo " pytest --cov=patterns/ --cov-append $file" >> tox_pr.ini + fi fi done - # Run tox with the temporary configuration - tox -c tox_pr.ini || true + # Add coverage report command + echo " coverage report" >> tox_pr.ini + + # Run tox with the custom configuration + echo "Running tox with custom PR configuration..." + tox -c tox_pr.ini summary: needs: [check_changes, lint] diff --git a/tox.ini b/tox.ini index 67453421..9c80b456 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,10 @@ setenv = COVERAGE_FILE = .coverage.{envname} deps = -r requirements-dev.txt +allowlist_externals = + pytest + flake8 + mypy commands = flake8 --exclude="venv/,.tox/" patterns/ ; `randomly-seed` option from `pytest-randomly` helps with deterministic outputs for examples like `other/blackboard.py` From c509128420e5fe840fc75617458adcd66e8565ec Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 00:09:04 +0200 Subject: [PATCH 16/38] Tox optimization 2 --- .github/workflows/lint_pr.yml | 58 ++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 8c42913d..2208a493 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -21,18 +21,26 @@ jobs: # For pushes, use the before/after SHAs CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep '\.py$' || echo "") fi - echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT + + # Check if any Python files were changed and set the output accordingly if [ -z "$CHANGED_FILES" ]; then - echo "No Python files changed, PR will still require approval" + echo "No Python files changed" echo "has_python_changes=false" >> $GITHUB_OUTPUT + echo "files=" >> $GITHUB_OUTPUT else echo "Changed Python files: $CHANGED_FILES" echo "has_python_changes=true" >> $GITHUB_OUTPUT + echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT fi - name: PR information - if: ${{ github.event_name == 'pull_request' && steps.changed-files.outputs.has_python_changes == 'false' }} - run: echo "This PR contains no Python changes, but still requires manual approval." + if: ${{ github.event_name == 'pull_request' }} + run: | + if [[ "${{ steps.changed-files.outputs.has_python_changes }}" == "false" ]]; then + echo "This PR contains no Python changes, but still requires manual approval." + else + echo "This PR contains Python changes that will be linted." + fi lint: needs: check_changes @@ -43,6 +51,14 @@ jobs: matrix: tool: [flake8, format, mypy, pytest, pyupgrade, tox] steps: + # Additional check to ensure we have Python files before proceeding + - name: Verify Python changes + run: | + if [[ "${{ needs.check_changes.outputs.has_python_changes }}" != "true" ]]; then + echo "No Python files were changed. Skipping linting." + exit 0 + fi + - uses: actions/checkout@v3 with: fetch-depth: 0 @@ -153,36 +169,56 @@ jobs: echo " -r requirements-dev.txt" >> tox_pr.ini echo "allowlist_externals =" >> tox_pr.ini echo " pytest" >> tox_pr.ini + echo " coverage" >> tox_pr.ini echo "commands =" >> tox_pr.ini - # For tox, let's focus on integration tests and coverage only - # to avoid duplicating what individual matrix jobs are doing + # Always run a baseline test with coverage to ensure we have some data + echo " pytest -xvs --cov=patterns tests/ --cov-report=term-missing || true" >> tox_pr.ini # Add coverage-focused test commands + echo " # Run specific tests for changed files" >> tox_pr.ini for file in $changed_files; do if [[ $file == *.py ]]; then # Run coverage tests for implementation files if [[ $file == patterns/* ]]; then module_name=$(basename $file .py) - echo " pytest --cov=patterns/ --cov-append tests/ -k \"$module_name\"" >> tox_pr.ini + pattern_dir=$(dirname $file | cut -d'/' -f2) + echo " # Testing $file" >> tox_pr.ini + + # First check if there's a specific test for this module + echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/test_${module_name}.py 2>/dev/null || true" >> tox_pr.ini + + # Also run more general tests for the directory + echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\" || true" >> tox_pr.ini fi # Run test files directly if modified if [[ $file == tests/* ]]; then - echo " pytest --cov=patterns/ --cov-append $file" >> tox_pr.ini + echo " pytest -xvs --cov=patterns --cov-append $file || true" >> tox_pr.ini fi fi done - # Add coverage report command - echo " coverage report" >> tox_pr.ini + # Run doctests on pattern files + echo " # Run doctests" >> tox_pr.ini + for file in $changed_files; do + if [[ $file == patterns/*.py ]]; then + echo " pytest --doctest-modules -v --cov=patterns --cov-append $file || true" >> tox_pr.ini + fi + done + + # Add coverage report command (only executed if there's coverage data) + echo " coverage combine || true" >> tox_pr.ini + echo " coverage report || echo 'No coverage data available'" >> tox_pr.ini # Run tox with the custom configuration echo "Running tox with custom PR configuration..." - tox -c tox_pr.ini + cat tox_pr.ini + tox -c tox_pr.ini || true # Don't fail the build if tox fails summary: needs: [check_changes, lint] + # Only run if there are Python changes and after the lint job completes (success or failure) if: ${{ always() && needs.check_changes.outputs.has_python_changes == 'true' }} runs-on: ubuntu-24.04 steps: From 9c755966043a4f947e69ff4cd6c5fd1fb1170c82 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 00:14:43 +0200 Subject: [PATCH 17/38] Optimized check --- .github/workflows/lint_pr.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 2208a493..a866cd02 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -218,12 +218,18 @@ jobs: summary: needs: [check_changes, lint] - # Only run if there are Python changes and after the lint job completes (success or failure) - if: ${{ always() && needs.check_changes.outputs.has_python_changes == 'true' }} + # Run summary in all cases, regardless of whether lint job ran + if: ${{ always() }} runs-on: ubuntu-24.04 steps: - name: Summarize results run: | echo "## Pull Request Lint Results" >> $GITHUB_STEP_SUMMARY - echo "Linting has completed for all Python files changed in this PR." >> $GITHUB_STEP_SUMMARY - echo "See individual job logs for detailed results." >> $GITHUB_STEP_SUMMARY + if [[ "${{ needs.check_changes.outputs.has_python_changes }}" == "true" ]]; then + echo "Linting has completed for all Python files changed in this PR." >> $GITHUB_STEP_SUMMARY + echo "See individual job logs for detailed results." >> $GITHUB_STEP_SUMMARY + else + echo "No Python files were changed in this PR. Linting was skipped." >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "⚠️ **Note:** This PR still requires manual approval regardless of linting results." >> $GITHUB_STEP_SUMMARY From e3fa2e0cf7a5136507dc13fa8b0211bc646d55df Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 00:20:12 +0200 Subject: [PATCH 18/38] Ignore setup.py from linting unless it is changes --- .github/workflows/lint_pr.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index a866cd02..4911c7a0 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -16,10 +16,20 @@ jobs: run: | if [ "${{ github.event_name }}" == "pull_request" ]; then # For PRs, compare against base branch - CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep '\.py$' || echo "") + CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep '\.py$' | grep -v "^setup\.py$" || echo "") + # Check if setup.py specifically changed + SETUP_PY_CHANGED=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep "^setup\.py$" || echo "") + if [ ! -z "$SETUP_PY_CHANGED" ]; then + CHANGED_FILES="$CHANGED_FILES $SETUP_PY_CHANGED" + fi else # For pushes, use the before/after SHAs - CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep '\.py$' || echo "") + CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep '\.py$' | grep -v "^setup\.py$" || echo "") + # Check if setup.py specifically changed + SETUP_PY_CHANGED=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep "^setup\.py$" || echo "") + if [ ! -z "$SETUP_PY_CHANGED" ]; then + CHANGED_FILES="$CHANGED_FILES $SETUP_PY_CHANGED" + fi fi # Check if any Python files were changed and set the output accordingly From 4f16b18f61ad3ba682e4adec1a31706216a2a217 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 00:27:33 +0200 Subject: [PATCH 19/38] Fixed bug --- .github/workflows/lint_pr.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 4911c7a0..05731a7a 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -183,7 +183,7 @@ jobs: echo "commands =" >> tox_pr.ini # Always run a baseline test with coverage to ensure we have some data - echo " pytest -xvs --cov=patterns tests/ --cov-report=term-missing || true" >> tox_pr.ini + echo " pytest -xvs --cov=patterns tests/ --cov-report=term-missing" >> tox_pr.ini # Add coverage-focused test commands echo " # Run specific tests for changed files" >> tox_pr.ini @@ -196,15 +196,15 @@ jobs: echo " # Testing $file" >> tox_pr.ini # First check if there's a specific test for this module - echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/test_${module_name}.py 2>/dev/null || true" >> tox_pr.ini + echo " - python -c \"import os.path; exit(0 if os.path.exists('tests/${pattern_dir}/test_${module_name}.py') else 1)\" && pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/test_${module_name}.py" >> tox_pr.ini # Also run more general tests for the directory - echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\" || true" >> tox_pr.ini + echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\"" >> tox_pr.ini fi # Run test files directly if modified if [[ $file == tests/* ]]; then - echo " pytest -xvs --cov=patterns --cov-append $file || true" >> tox_pr.ini + echo " pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini fi fi done @@ -213,18 +213,18 @@ jobs: echo " # Run doctests" >> tox_pr.ini for file in $changed_files; do if [[ $file == patterns/*.py ]]; then - echo " pytest --doctest-modules -v --cov=patterns --cov-append $file || true" >> tox_pr.ini + echo " pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini fi done - # Add coverage report command (only executed if there's coverage data) - echo " coverage combine || true" >> tox_pr.ini - echo " coverage report || echo 'No coverage data available'" >> tox_pr.ini + # Add coverage report command + echo " coverage combine" >> tox_pr.ini + echo " coverage report" >> tox_pr.ini # Run tox with the custom configuration echo "Running tox with custom PR configuration..." cat tox_pr.ini - tox -c tox_pr.ini || true # Don't fail the build if tox fails + tox -c tox_pr.ini summary: needs: [check_changes, lint] From c90567738dca6d461d6114a885e0cc2edac1fb81 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 00:45:12 +0200 Subject: [PATCH 20/38] Testing a idea --- .github/scripts/detect_changes.py | 67 +++++++++++ .github/scripts/generate_summary.py | 39 +++++++ .github/scripts/generate_tox_config.py | 80 +++++++++++++ .github/scripts/run_tests.py | 52 +++++++++ .github/workflows/lint_pr.yml | 149 +++---------------------- 5 files changed, 255 insertions(+), 132 deletions(-) create mode 100644 .github/scripts/detect_changes.py create mode 100644 .github/scripts/generate_summary.py create mode 100644 .github/scripts/generate_tox_config.py create mode 100644 .github/scripts/run_tests.py diff --git a/.github/scripts/detect_changes.py b/.github/scripts/detect_changes.py new file mode 100644 index 00000000..39b8bc3c --- /dev/null +++ b/.github/scripts/detect_changes.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +""" +Script to detect changed Python files in a git repository. +Used by GitHub Actions workflow to determine which files to lint/test. +""" +import os +import subprocess +import sys + + +def get_changed_files(event_name, base_ref=None, before_sha=None, after_sha=None): + """ + Get list of changed Python files based on git diff. + + Args: + event_name: GitHub event name ('pull_request' or 'push') + base_ref: Base branch for PR comparisons + before_sha: Before SHA for push comparisons + after_sha: After SHA for push comparisons + + Returns: + tuple: (has_python_changes, changed_files) + """ + # Determine the correct git diff command based on event type + if event_name == 'pull_request': + # For PRs, compare against base branch + cmd = ['git', 'diff', '--name-only', '--diff-filter=ACMRT', f'origin/{base_ref}', 'HEAD'] + else: + # For pushes, use the before/after SHAs + cmd = ['git', 'diff', '--name-only', '--diff-filter=ACMRT', before_sha, after_sha] + + # Execute git command and get output + result = subprocess.run(cmd, capture_output=True, text=True) + all_changed_files = [f for f in result.stdout.strip().split('\n') if f] + + # Filter for Python files, excluding setup.py initially + changed_files = [f for f in all_changed_files if f.endswith('.py') and f != 'setup.py'] + + # Add setup.py only if it was actually changed + if 'setup.py' in all_changed_files: + changed_files.append('setup.py') + + # Check if we have any Python changes + has_python_changes = len(changed_files) > 0 + + return has_python_changes, changed_files + + +if __name__ == "__main__": + # Get parameters from environment variables or command line + event_name = os.environ.get('GITHUB_EVENT_NAME', sys.argv[1] if len(sys.argv) > 1 else None) + base_ref = os.environ.get('GITHUB_BASE_REF', sys.argv[2] if len(sys.argv) > 2 else None) + before_sha = os.environ.get('GITHUB_BEFORE', sys.argv[3] if len(sys.argv) > 3 else None) + after_sha = os.environ.get('GITHUB_AFTER', sys.argv[4] if len(sys.argv) > 4 else None) + + # Get changed files + has_changes, files = get_changed_files(event_name, base_ref, before_sha, after_sha) + + # Output for GitHub Actions + if has_changes: + print(f"::set-output name=has_python_changes::true") + print(f"::set-output name=files::{' '.join(files)}") + print("Changed Python files:", ' '.join(files)) + else: + print("::set-output name=has_python_changes::false") + print("::set-output name=files::") + print("No Python files changed") \ No newline at end of file diff --git a/.github/scripts/generate_summary.py b/.github/scripts/generate_summary.py new file mode 100644 index 00000000..fce8492a --- /dev/null +++ b/.github/scripts/generate_summary.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +""" +Script to generate a summary for GitHub Actions workflow. +Used to create a consistent summary at the end of the workflow. +""" +import os +import sys + + +def generate_summary(has_python_changes): + """ + Generate a summary for GitHub Actions step summary. + + Args: + has_python_changes: Boolean indicating if any Python files were changed + """ + # Get the path to the GitHub step summary file + summary_file = os.environ.get('GITHUB_STEP_SUMMARY') + if not summary_file: + print("GITHUB_STEP_SUMMARY environment variable not found.") + return + + with open(summary_file, 'a') as f: + f.write('## Pull Request Lint Results\n') + if has_python_changes: + f.write('Linting has completed for all Python files changed in this PR.\n') + f.write('See individual job logs for detailed results.\n') + else: + f.write('No Python files were changed in this PR. Linting was skipped.\n') + f.write('\n') + f.write('⚠️ **Note:** This PR still requires manual approval regardless of linting results.\n') + + +if __name__ == "__main__": + # Get whether there were Python changes from arguments + has_python_changes = sys.argv[1].lower() == 'true' if len(sys.argv) > 1 else False + + # Generate the summary + generate_summary(has_python_changes) \ No newline at end of file diff --git a/.github/scripts/generate_tox_config.py b/.github/scripts/generate_tox_config.py new file mode 100644 index 00000000..3662a94d --- /dev/null +++ b/.github/scripts/generate_tox_config.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +""" +Script to generate a custom tox configuration for testing changed files. +Used by GitHub Actions workflow for PR testing. +""" +import os +import sys + + +def generate_tox_config(changed_files, output_file='tox_pr.ini'): + """ + Generate a customized tox configuration for testing changed files. + + Args: + changed_files: List of changed Python files + output_file: Path to write the tox configuration to + """ + with open(output_file, 'w') as tox_file: + # Write tox section + tox_file.write('[tox]\n') + tox_file.write('envlist = py312\n') + tox_file.write('skip_missing_interpreters = true\n\n') + + # Write testenv section + tox_file.write('[testenv]\n') + tox_file.write('setenv =\n') + tox_file.write(' COVERAGE_FILE = .coverage.{envname}\n') + tox_file.write('deps =\n') + tox_file.write(' -r requirements-dev.txt\n') + tox_file.write('allowlist_externals =\n') + tox_file.write(' pytest\n') + tox_file.write(' coverage\n') + tox_file.write('commands =\n') + + # Always run a baseline test with coverage + tox_file.write(' pytest -xvs --cov=patterns tests/ --cov-report=term-missing\n') + + # Add test commands for changed files + tox_file.write(' # Run specific tests for changed files\n') + + for file in changed_files: + if file.endswith('.py'): + # Handle implementation files + if file.startswith('patterns/'): + module_name = os.path.basename(file)[:-3] # Remove .py extension + pattern_dir = os.path.dirname(file).split('/', 1)[1] if '/' in os.path.dirname(file) else '' + + tox_file.write(f' # Testing {file}\n') + + # Check for specific test file and add it conditionally + test_file = f'tests/{pattern_dir}/test_{module_name}.py' + # Use conditional for test file + tox_file.write(f' python -c "import os.path; test_path=\'{test_file}\'; print(f\'Test file {{test_path}} exists: {{os.path.exists(test_path)}}\')" \n') + tox_file.write(f' pytest -xvs --cov=patterns --cov-append tests/{pattern_dir}/ -k "{module_name}"\n') + + # Run test files directly if modified + if file.startswith('tests/'): + tox_file.write(f' pytest -xvs --cov=patterns --cov-append {file}\n') + + # Run doctests on pattern files + tox_file.write(' # Run doctests\n') + for file in changed_files: + if file.startswith('patterns/') and file.endswith('.py'): + tox_file.write(f' pytest --doctest-modules -v --cov=patterns --cov-append {file}\n') + + # Add coverage report commands + tox_file.write(' coverage combine\n') + tox_file.write(' coverage report\n') + + +if __name__ == "__main__": + # Get list of changed files from arguments + changed_files = sys.argv[1].split() if len(sys.argv) > 1 else [] + + # Generate the tox configuration + generate_tox_config(changed_files) + + # Print the configuration to stdout + with open('tox_pr.ini', 'r') as f: + print(f.read()) \ No newline at end of file diff --git a/.github/scripts/run_tests.py b/.github/scripts/run_tests.py new file mode 100644 index 00000000..f89c2f71 --- /dev/null +++ b/.github/scripts/run_tests.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +""" +Script to run pytest on specific files based on changes. +Used by GitHub Actions workflow for PR testing. +""" +import os +import subprocess +import sys + + +def run_tests_for_changed_files(changed_files): + """ + Run appropriate tests for the changed files. + + Args: + changed_files: List of changed Python files + """ + # Run test discovery first + print("Running pytest discovery...") + subprocess.run(['python', '-m', 'pytest', '--collect-only', '-v']) + + # Extract module paths from changed files + print("Running tests for changed files...") + modules = [] + for file in changed_files: + if file.startswith('patterns/'): + # Convert file path to module path (remove .py and replace / with .) + module_path = file.replace('.py', '').replace('/', '.') + modules.append(module_path) + + # Run tests for each module + for module in modules: + module_name = module.split('.')[-1] + print(f"Testing module: {module}") + subprocess.run(['python', '-m', 'pytest', '-xvs', 'tests/', '-k', module_name], + check=False) + + # Then run doctests on the changed files + print("Running doctests for changed files...") + for file in changed_files: + if file.endswith('.py'): + print(f"Running doctest for {file}") + subprocess.run(['python', '-m', 'pytest', '--doctest-modules', '-v', file], + check=False) + + +if __name__ == "__main__": + # Get list of changed files from arguments + changed_files = sys.argv[1].split() if len(sys.argv) > 1 else [] + + # Run the tests + run_tests_for_changed_files(changed_files) \ No newline at end of file diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 05731a7a..09208fb7 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -14,42 +14,19 @@ jobs: - name: Get changed Python files id: changed-files run: | - if [ "${{ github.event_name }}" == "pull_request" ]; then - # For PRs, compare against base branch - CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep '\.py$' | grep -v "^setup\.py$" || echo "") - # Check if setup.py specifically changed - SETUP_PY_CHANGED=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep "^setup\.py$" || echo "") - if [ ! -z "$SETUP_PY_CHANGED" ]; then - CHANGED_FILES="$CHANGED_FILES $SETUP_PY_CHANGED" - fi - else - # For pushes, use the before/after SHAs - CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep '\.py$' | grep -v "^setup\.py$" || echo "") - # Check if setup.py specifically changed - SETUP_PY_CHANGED=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep "^setup\.py$" || echo "") - if [ ! -z "$SETUP_PY_CHANGED" ]; then - CHANGED_FILES="$CHANGED_FILES $SETUP_PY_CHANGED" - fi - fi + # Make sure the scripts are executable + chmod +x .github/scripts/detect_changes.py - # Check if any Python files were changed and set the output accordingly - if [ -z "$CHANGED_FILES" ]; then - echo "No Python files changed" - echo "has_python_changes=false" >> $GITHUB_OUTPUT - echo "files=" >> $GITHUB_OUTPUT - else - echo "Changed Python files: $CHANGED_FILES" - echo "has_python_changes=true" >> $GITHUB_OUTPUT - echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT - fi + # Run the Python script to detect changes + .github/scripts/detect_changes.py - name: PR information if: ${{ github.event_name == 'pull_request' }} run: | - if [[ "${{ steps.changed-files.outputs.has_python_changes }}" == "false" ]]; then - echo "This PR contains no Python changes, but still requires manual approval." - else + if [[ "${{ steps.changed-files.outputs.has_python_changes }}" == "true" ]]; then echo "This PR contains Python changes that will be linted." + else + echo "This PR contains no Python changes, but still requires manual approval." fi lint: @@ -88,6 +65,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements-dev.txt + # Make all scripts executable + chmod +x .github/scripts/*.py # Flake8 linting - name: Lint with flake8 @@ -115,43 +94,12 @@ jobs: echo "Type checking: ${{ needs.check_changes.outputs.files }}" mypy --ignore-missing-imports ${{ needs.check_changes.outputs.files }} - # Run tests with pytest + # Run tests with pytest using our Python script - name: Run tests with pytest if: ${{ matrix.tool == 'pytest' }} id: pytest run: | - echo "Running pytest discovery..." - python -m pytest --collect-only -v - - # First run any test files that correspond to changed files - echo "Running tests for changed files..." - changed_files="${{ needs.check_changes.outputs.files }}" - - # Extract module paths from changed files - modules=() - for file in $changed_files; do - # Convert file path to module path (remove .py and replace / with .) - if [[ $file == patterns/* ]]; then - module_path=${file%.py} - module_path=${module_path//\//.} - modules+=("$module_path") - fi - done - - # Run tests for each module - for module in "${modules[@]}"; do - echo "Testing module: $module" - python -m pytest -xvs tests/ -k "$module" || true - done - - # Then run doctests on the changed files - echo "Running doctests for changed files..." - for file in $changed_files; do - if [[ $file == *.py ]]; then - echo "Running doctest for $file" - python -m pytest --doctest-modules -v $file || true - fi - done + .github/scripts/run_tests.py "${{ needs.check_changes.outputs.files }}" # Check Python version compatibility - name: Check Python version compatibility @@ -159,71 +107,13 @@ jobs: id: pyupgrade run: pyupgrade --py312-plus ${{ needs.check_changes.outputs.files }} - # Run tox + # Run tox using our Python script - name: Run tox if: ${{ matrix.tool == 'tox' }} id: tox run: | echo "Running tox integration for changed files..." - changed_files="${{ needs.check_changes.outputs.files }}" - - # Create a temporary tox configuration that extends the original one - echo "[tox]" > tox_pr.ini - echo "envlist = py312" >> tox_pr.ini - echo "skip_missing_interpreters = true" >> tox_pr.ini - - echo "[testenv]" >> tox_pr.ini - echo "setenv =" >> tox_pr.ini - echo " COVERAGE_FILE = .coverage.{envname}" >> tox_pr.ini - echo "deps =" >> tox_pr.ini - echo " -r requirements-dev.txt" >> tox_pr.ini - echo "allowlist_externals =" >> tox_pr.ini - echo " pytest" >> tox_pr.ini - echo " coverage" >> tox_pr.ini - echo "commands =" >> tox_pr.ini - - # Always run a baseline test with coverage to ensure we have some data - echo " pytest -xvs --cov=patterns tests/ --cov-report=term-missing" >> tox_pr.ini - - # Add coverage-focused test commands - echo " # Run specific tests for changed files" >> tox_pr.ini - for file in $changed_files; do - if [[ $file == *.py ]]; then - # Run coverage tests for implementation files - if [[ $file == patterns/* ]]; then - module_name=$(basename $file .py) - pattern_dir=$(dirname $file | cut -d'/' -f2) - echo " # Testing $file" >> tox_pr.ini - - # First check if there's a specific test for this module - echo " - python -c \"import os.path; exit(0 if os.path.exists('tests/${pattern_dir}/test_${module_name}.py') else 1)\" && pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/test_${module_name}.py" >> tox_pr.ini - - # Also run more general tests for the directory - echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\"" >> tox_pr.ini - fi - - # Run test files directly if modified - if [[ $file == tests/* ]]; then - echo " pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini - fi - fi - done - - # Run doctests on pattern files - echo " # Run doctests" >> tox_pr.ini - for file in $changed_files; do - if [[ $file == patterns/*.py ]]; then - echo " pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini - fi - done - - # Add coverage report command - echo " coverage combine" >> tox_pr.ini - echo " coverage report" >> tox_pr.ini - - # Run tox with the custom configuration - echo "Running tox with custom PR configuration..." - cat tox_pr.ini + .github/scripts/generate_tox_config.py "${{ needs.check_changes.outputs.files }}" tox -c tox_pr.ini summary: @@ -232,14 +122,9 @@ jobs: if: ${{ always() }} runs-on: ubuntu-24.04 steps: + - uses: actions/checkout@v3 + - name: Summarize results run: | - echo "## Pull Request Lint Results" >> $GITHUB_STEP_SUMMARY - if [[ "${{ needs.check_changes.outputs.has_python_changes }}" == "true" ]]; then - echo "Linting has completed for all Python files changed in this PR." >> $GITHUB_STEP_SUMMARY - echo "See individual job logs for detailed results." >> $GITHUB_STEP_SUMMARY - else - echo "No Python files were changed in this PR. Linting was skipped." >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - echo "⚠️ **Note:** This PR still requires manual approval regardless of linting results." >> $GITHUB_STEP_SUMMARY + chmod +x .github/scripts/generate_summary.py + .github/scripts/generate_summary.py "${{ needs.check_changes.outputs.has_python_changes }}" From b3be9b2cfefea1f4708882432f85e6848eda7afc Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 00:51:19 +0200 Subject: [PATCH 21/38] Revert idea --- .github/scripts/detect_changes.py | 67 ------------ .github/scripts/generate_summary.py | 39 ------- .github/scripts/generate_tox_config.py | 80 -------------- .github/scripts/run_tests.py | 52 --------- .github/workflows/lint_pr.yml | 142 ++++++++++++++++++++++--- 5 files changed, 130 insertions(+), 250 deletions(-) delete mode 100644 .github/scripts/detect_changes.py delete mode 100644 .github/scripts/generate_summary.py delete mode 100644 .github/scripts/generate_tox_config.py delete mode 100644 .github/scripts/run_tests.py diff --git a/.github/scripts/detect_changes.py b/.github/scripts/detect_changes.py deleted file mode 100644 index 39b8bc3c..00000000 --- a/.github/scripts/detect_changes.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to detect changed Python files in a git repository. -Used by GitHub Actions workflow to determine which files to lint/test. -""" -import os -import subprocess -import sys - - -def get_changed_files(event_name, base_ref=None, before_sha=None, after_sha=None): - """ - Get list of changed Python files based on git diff. - - Args: - event_name: GitHub event name ('pull_request' or 'push') - base_ref: Base branch for PR comparisons - before_sha: Before SHA for push comparisons - after_sha: After SHA for push comparisons - - Returns: - tuple: (has_python_changes, changed_files) - """ - # Determine the correct git diff command based on event type - if event_name == 'pull_request': - # For PRs, compare against base branch - cmd = ['git', 'diff', '--name-only', '--diff-filter=ACMRT', f'origin/{base_ref}', 'HEAD'] - else: - # For pushes, use the before/after SHAs - cmd = ['git', 'diff', '--name-only', '--diff-filter=ACMRT', before_sha, after_sha] - - # Execute git command and get output - result = subprocess.run(cmd, capture_output=True, text=True) - all_changed_files = [f for f in result.stdout.strip().split('\n') if f] - - # Filter for Python files, excluding setup.py initially - changed_files = [f for f in all_changed_files if f.endswith('.py') and f != 'setup.py'] - - # Add setup.py only if it was actually changed - if 'setup.py' in all_changed_files: - changed_files.append('setup.py') - - # Check if we have any Python changes - has_python_changes = len(changed_files) > 0 - - return has_python_changes, changed_files - - -if __name__ == "__main__": - # Get parameters from environment variables or command line - event_name = os.environ.get('GITHUB_EVENT_NAME', sys.argv[1] if len(sys.argv) > 1 else None) - base_ref = os.environ.get('GITHUB_BASE_REF', sys.argv[2] if len(sys.argv) > 2 else None) - before_sha = os.environ.get('GITHUB_BEFORE', sys.argv[3] if len(sys.argv) > 3 else None) - after_sha = os.environ.get('GITHUB_AFTER', sys.argv[4] if len(sys.argv) > 4 else None) - - # Get changed files - has_changes, files = get_changed_files(event_name, base_ref, before_sha, after_sha) - - # Output for GitHub Actions - if has_changes: - print(f"::set-output name=has_python_changes::true") - print(f"::set-output name=files::{' '.join(files)}") - print("Changed Python files:", ' '.join(files)) - else: - print("::set-output name=has_python_changes::false") - print("::set-output name=files::") - print("No Python files changed") \ No newline at end of file diff --git a/.github/scripts/generate_summary.py b/.github/scripts/generate_summary.py deleted file mode 100644 index fce8492a..00000000 --- a/.github/scripts/generate_summary.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to generate a summary for GitHub Actions workflow. -Used to create a consistent summary at the end of the workflow. -""" -import os -import sys - - -def generate_summary(has_python_changes): - """ - Generate a summary for GitHub Actions step summary. - - Args: - has_python_changes: Boolean indicating if any Python files were changed - """ - # Get the path to the GitHub step summary file - summary_file = os.environ.get('GITHUB_STEP_SUMMARY') - if not summary_file: - print("GITHUB_STEP_SUMMARY environment variable not found.") - return - - with open(summary_file, 'a') as f: - f.write('## Pull Request Lint Results\n') - if has_python_changes: - f.write('Linting has completed for all Python files changed in this PR.\n') - f.write('See individual job logs for detailed results.\n') - else: - f.write('No Python files were changed in this PR. Linting was skipped.\n') - f.write('\n') - f.write('⚠️ **Note:** This PR still requires manual approval regardless of linting results.\n') - - -if __name__ == "__main__": - # Get whether there were Python changes from arguments - has_python_changes = sys.argv[1].lower() == 'true' if len(sys.argv) > 1 else False - - # Generate the summary - generate_summary(has_python_changes) \ No newline at end of file diff --git a/.github/scripts/generate_tox_config.py b/.github/scripts/generate_tox_config.py deleted file mode 100644 index 3662a94d..00000000 --- a/.github/scripts/generate_tox_config.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to generate a custom tox configuration for testing changed files. -Used by GitHub Actions workflow for PR testing. -""" -import os -import sys - - -def generate_tox_config(changed_files, output_file='tox_pr.ini'): - """ - Generate a customized tox configuration for testing changed files. - - Args: - changed_files: List of changed Python files - output_file: Path to write the tox configuration to - """ - with open(output_file, 'w') as tox_file: - # Write tox section - tox_file.write('[tox]\n') - tox_file.write('envlist = py312\n') - tox_file.write('skip_missing_interpreters = true\n\n') - - # Write testenv section - tox_file.write('[testenv]\n') - tox_file.write('setenv =\n') - tox_file.write(' COVERAGE_FILE = .coverage.{envname}\n') - tox_file.write('deps =\n') - tox_file.write(' -r requirements-dev.txt\n') - tox_file.write('allowlist_externals =\n') - tox_file.write(' pytest\n') - tox_file.write(' coverage\n') - tox_file.write('commands =\n') - - # Always run a baseline test with coverage - tox_file.write(' pytest -xvs --cov=patterns tests/ --cov-report=term-missing\n') - - # Add test commands for changed files - tox_file.write(' # Run specific tests for changed files\n') - - for file in changed_files: - if file.endswith('.py'): - # Handle implementation files - if file.startswith('patterns/'): - module_name = os.path.basename(file)[:-3] # Remove .py extension - pattern_dir = os.path.dirname(file).split('/', 1)[1] if '/' in os.path.dirname(file) else '' - - tox_file.write(f' # Testing {file}\n') - - # Check for specific test file and add it conditionally - test_file = f'tests/{pattern_dir}/test_{module_name}.py' - # Use conditional for test file - tox_file.write(f' python -c "import os.path; test_path=\'{test_file}\'; print(f\'Test file {{test_path}} exists: {{os.path.exists(test_path)}}\')" \n') - tox_file.write(f' pytest -xvs --cov=patterns --cov-append tests/{pattern_dir}/ -k "{module_name}"\n') - - # Run test files directly if modified - if file.startswith('tests/'): - tox_file.write(f' pytest -xvs --cov=patterns --cov-append {file}\n') - - # Run doctests on pattern files - tox_file.write(' # Run doctests\n') - for file in changed_files: - if file.startswith('patterns/') and file.endswith('.py'): - tox_file.write(f' pytest --doctest-modules -v --cov=patterns --cov-append {file}\n') - - # Add coverage report commands - tox_file.write(' coverage combine\n') - tox_file.write(' coverage report\n') - - -if __name__ == "__main__": - # Get list of changed files from arguments - changed_files = sys.argv[1].split() if len(sys.argv) > 1 else [] - - # Generate the tox configuration - generate_tox_config(changed_files) - - # Print the configuration to stdout - with open('tox_pr.ini', 'r') as f: - print(f.read()) \ No newline at end of file diff --git a/.github/scripts/run_tests.py b/.github/scripts/run_tests.py deleted file mode 100644 index f89c2f71..00000000 --- a/.github/scripts/run_tests.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to run pytest on specific files based on changes. -Used by GitHub Actions workflow for PR testing. -""" -import os -import subprocess -import sys - - -def run_tests_for_changed_files(changed_files): - """ - Run appropriate tests for the changed files. - - Args: - changed_files: List of changed Python files - """ - # Run test discovery first - print("Running pytest discovery...") - subprocess.run(['python', '-m', 'pytest', '--collect-only', '-v']) - - # Extract module paths from changed files - print("Running tests for changed files...") - modules = [] - for file in changed_files: - if file.startswith('patterns/'): - # Convert file path to module path (remove .py and replace / with .) - module_path = file.replace('.py', '').replace('/', '.') - modules.append(module_path) - - # Run tests for each module - for module in modules: - module_name = module.split('.')[-1] - print(f"Testing module: {module}") - subprocess.run(['python', '-m', 'pytest', '-xvs', 'tests/', '-k', module_name], - check=False) - - # Then run doctests on the changed files - print("Running doctests for changed files...") - for file in changed_files: - if file.endswith('.py'): - print(f"Running doctest for {file}") - subprocess.run(['python', '-m', 'pytest', '--doctest-modules', '-v', file], - check=False) - - -if __name__ == "__main__": - # Get list of changed files from arguments - changed_files = sys.argv[1].split() if len(sys.argv) > 1 else [] - - # Run the tests - run_tests_for_changed_files(changed_files) \ No newline at end of file diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 09208fb7..d33e98a4 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -14,11 +14,34 @@ jobs: - name: Get changed Python files id: changed-files run: | - # Make sure the scripts are executable - chmod +x .github/scripts/detect_changes.py + if [ "${{ github.event_name }}" == "pull_request" ]; then + # For PRs, compare against base branch + CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep '\.py$' | grep -v "^setup\.py$" || echo "") + # Check if setup.py specifically changed + SETUP_PY_CHANGED=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep "^setup\.py$" || echo "") + if [ ! -z "$SETUP_PY_CHANGED" ]; then + CHANGED_FILES="$CHANGED_FILES $SETUP_PY_CHANGED" + fi + else + # For pushes, use the before/after SHAs + CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep '\.py$' | grep -v "^setup\.py$" || echo "") + # Check if setup.py specifically changed + SETUP_PY_CHANGED=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep "^setup\.py$" || echo "") + if [ ! -z "$SETUP_PY_CHANGED" ]; then + CHANGED_FILES="$CHANGED_FILES $SETUP_PY_CHANGED" + fi + fi - # Run the Python script to detect changes - .github/scripts/detect_changes.py + # Check if any Python files were changed and set the output accordingly + if [ -z "$CHANGED_FILES" ]; then + echo "No Python files changed" + echo "has_python_changes=false" >> $GITHUB_OUTPUT + echo "files=" >> $GITHUB_OUTPUT + else + echo "Changed Python files: $CHANGED_FILES" + echo "has_python_changes=true" >> $GITHUB_OUTPUT + echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT + fi - name: PR information if: ${{ github.event_name == 'pull_request' }} @@ -65,8 +88,6 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements-dev.txt - # Make all scripts executable - chmod +x .github/scripts/*.py # Flake8 linting - name: Lint with flake8 @@ -94,12 +115,43 @@ jobs: echo "Type checking: ${{ needs.check_changes.outputs.files }}" mypy --ignore-missing-imports ${{ needs.check_changes.outputs.files }} - # Run tests with pytest using our Python script + # Run tests with pytest - name: Run tests with pytest if: ${{ matrix.tool == 'pytest' }} id: pytest run: | - .github/scripts/run_tests.py "${{ needs.check_changes.outputs.files }}" + echo "Running pytest discovery..." + python -m pytest --collect-only -v + + # First run any test files that correspond to changed files + echo "Running tests for changed files..." + changed_files="${{ needs.check_changes.outputs.files }}" + + # Extract module paths from changed files + modules=() + for file in $changed_files; do + # Convert file path to module path (remove .py and replace / with .) + if [[ $file == patterns/* ]]; then + module_path=${file%.py} + module_path=${module_path//\//.} + modules+=("$module_path") + fi + done + + # Run tests for each module + for module in "${modules[@]}"; do + echo "Testing module: $module" + python -m pytest -xvs tests/ -k "$module" || true + done + + # Then run doctests on the changed files + echo "Running doctests for changed files..." + for file in $changed_files; do + if [[ $file == *.py ]]; then + echo "Running doctest for $file" + python -m pytest --doctest-modules -v $file || true + fi + done # Check Python version compatibility - name: Check Python version compatibility @@ -107,13 +159,72 @@ jobs: id: pyupgrade run: pyupgrade --py312-plus ${{ needs.check_changes.outputs.files }} - # Run tox using our Python script + # Run tox - name: Run tox if: ${{ matrix.tool == 'tox' }} id: tox run: | echo "Running tox integration for changed files..." - .github/scripts/generate_tox_config.py "${{ needs.check_changes.outputs.files }}" + changed_files="${{ needs.check_changes.outputs.files }}" + + # Create a temporary tox configuration that extends the original one + echo "[tox]" > tox_pr.ini + echo "envlist = py312" >> tox_pr.ini + echo "skip_missing_interpreters = true" >> tox_pr.ini + + echo "[testenv]" >> tox_pr.ini + echo "setenv =" >> tox_pr.ini + echo " COVERAGE_FILE = .coverage.{envname}" >> tox_pr.ini + echo "deps =" >> tox_pr.ini + echo " -r requirements-dev.txt" >> tox_pr.ini + echo "allowlist_externals =" >> tox_pr.ini + echo " pytest" >> tox_pr.ini + echo " coverage" >> tox_pr.ini + echo "commands =" >> tox_pr.ini + + # For tox, let's focus on integration tests and coverage only + # to avoid duplicating what individual matrix jobs are doing + + # Always run a baseline test with coverage + echo " pytest -xvs --cov=patterns tests/ --cov-report=term-missing" >> tox_pr.ini + + # Add coverage-focused test commands + echo " # Run specific tests for changed files" >> tox_pr.ini + for file in $changed_files; do + if [[ $file == *.py ]]; then + # Run coverage tests for implementation files + if [[ $file == patterns/* ]]; then + module_name=$(basename $file .py) + pattern_dir=$(dirname $file | cut -d'/' -f2) + echo " # Testing $file" >> tox_pr.ini + + # Run appropriate tests for this module + echo " python -c \"import os.path; test_path='tests/${pattern_dir}/test_${module_name}.py'; print(f'Test file {test_path} exists: {os.path.exists(test_path)}')\"" >> tox_pr.ini + echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\"" >> tox_pr.ini + fi + + # Run test files directly if modified + if [[ $file == tests/* ]]; then + echo " pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini + fi + fi + done + + # Run doctests on pattern files + echo " # Run doctests" >> tox_pr.ini + for file in $changed_files; do + if [[ $file == patterns/*.py ]]; then + echo " pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini + fi + done + + # Add coverage report command + echo " coverage combine" >> tox_pr.ini + echo " coverage report" >> tox_pr.ini + + # Run tox with the custom configuration + echo "Running tox with custom PR configuration..." + cat tox_pr.ini tox -c tox_pr.ini summary: @@ -126,5 +237,12 @@ jobs: - name: Summarize results run: | - chmod +x .github/scripts/generate_summary.py - .github/scripts/generate_summary.py "${{ needs.check_changes.outputs.has_python_changes }}" + echo "## Pull Request Lint Results" >> $GITHUB_STEP_SUMMARY + if [[ "${{ needs.check_changes.outputs.has_python_changes }}" == "true" ]]; then + echo "Linting has completed for all Python files changed in this PR." >> $GITHUB_STEP_SUMMARY + echo "See individual job logs for detailed results." >> $GITHUB_STEP_SUMMARY + else + echo "No Python files were changed in this PR. Linting was skipped." >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "⚠️ **Note:** This PR still requires manual approval regardless of linting results." >> $GITHUB_STEP_SUMMARY From 4c78f086e1f937323f4c492288d392fa7a357497 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 00:55:02 +0200 Subject: [PATCH 22/38] added __init__.py to tests/ for tox --- tests/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b From 4b32f1b5907d540e78ebada3b7ea2d479eefe8b7 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:00:38 +0200 Subject: [PATCH 23/38] Let tox only test on Python files that are in the PR. --- .github/workflows/lint_pr.yml | 70 +++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index d33e98a4..d025bb8e 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -180,43 +180,79 @@ jobs: echo "allowlist_externals =" >> tox_pr.ini echo " pytest" >> tox_pr.ini echo " coverage" >> tox_pr.ini + echo " python" >> tox_pr.ini echo "commands =" >> tox_pr.ini - # For tox, let's focus on integration tests and coverage only - # to avoid duplicating what individual matrix jobs are doing + # Check if we have any implementation files that changed + pattern_files=0 + test_files=0 - # Always run a baseline test with coverage - echo " pytest -xvs --cov=patterns tests/ --cov-report=term-missing" >> tox_pr.ini + for file in $changed_files; do + if [[ $file == patterns/* ]]; then + pattern_files=1 + elif [[ $file == tests/* ]]; then + test_files=1 + fi + done - # Add coverage-focused test commands + # Only run targeted tests, no baseline echo " # Run specific tests for changed files" >> tox_pr.ini + + has_tests=false + + # Add coverage-focused test commands for file in $changed_files; do if [[ $file == *.py ]]; then # Run coverage tests for implementation files if [[ $file == patterns/* ]]; then module_name=$(basename $file .py) - pattern_dir=$(dirname $file | cut -d'/' -f2) + + # Get the pattern type (behavioral, structural, etc.) + if [[ $file == patterns/behavioral/* ]]; then + pattern_dir="behavioral" + elif [[ $file == patterns/creational/* ]]; then + pattern_dir="creational" + elif [[ $file == patterns/structural/* ]]; then + pattern_dir="structural" + elif [[ $file == patterns/fundamental/* ]]; then + pattern_dir="fundamental" + elif [[ $file == patterns/other/* ]]; then + pattern_dir="other" + else + pattern_dir="" + fi + echo " # Testing $file" >> tox_pr.ini - # Run appropriate tests for this module - echo " python -c \"import os.path; test_path='tests/${pattern_dir}/test_${module_name}.py'; print(f'Test file {test_path} exists: {os.path.exists(test_path)}')\"" >> tox_pr.ini - echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\"" >> tox_pr.ini + # Check if specific test exists + if [ -n "$pattern_dir" ]; then + test_path="tests/${pattern_dir}/test_${module_name}.py" + echo " python -c \"import os.path; test_path='${test_path}'; exists=os.path.exists(test_path); print(f'Test file {test_path} exists: {exists}'); exit(0 if exists else 1)\" && pytest -xvs --cov=patterns --cov-append ${test_path}" >> tox_pr.ini || true + + # Also try to find any test that might include this module + echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini + fi + + # Run doctests for the file + echo " pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini + + has_tests=true fi # Run test files directly if modified if [[ $file == tests/* ]]; then echo " pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini + has_tests=true fi fi done - # Run doctests on pattern files - echo " # Run doctests" >> tox_pr.ini - for file in $changed_files; do - if [[ $file == patterns/*.py ]]; then - echo " pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini - fi - done + # If we didn't find any specific tests to run, mention it + if [ "$has_tests" = false ]; then + echo " python -c \"print('No specific tests found for changed files. Consider adding tests.')\"" >> tox_pr.ini + # Add a minimal test to avoid failure + echo " pytest -xk \"not integration\" --no-header" >> tox_pr.ini + fi # Add coverage report command echo " coverage combine" >> tox_pr.ini @@ -224,7 +260,9 @@ jobs: # Run tox with the custom configuration echo "Running tox with custom PR configuration..." + echo "======================== TOX CONFIG ========================" cat tox_pr.ini + echo "===========================================================" tox -c tox_pr.ini summary: From d77760671e489d46165aa6d659662b3217bbce34 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:10:30 +0200 Subject: [PATCH 24/38] Adjusted .coveragerc --- .coveragerc | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/.coveragerc b/.coveragerc index 3778bf3d..98306ea9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,6 +1,25 @@ +[run] +branch = True + [report] -exclude_lines = - pragma: no cover - # Don't complain if tests don't hit defensive assertion code: - # See: https://stackoverflow.com/a/9212387/3407256 +; Regexes for lines to exclude from consideration +exclude_also = + ; Don't complain about missing debug-only code: + def __repr__ + if self\.debug + + ; Don't complain if tests don't hit defensive assertion code: + raise AssertionError raise NotImplementedError + + ; Don't complain if non-runnable code isn't run: + if 0: + if __name__ == .__main__.: + + ; Don't complain about abstract methods, they aren't run: + @(abc\.)?abstractmethod + +ignore_errors = True + +[html] +directory = coverage_html_report \ No newline at end of file From bdb6c0af13f62b73ad1994b6b4115cd8cc607675 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:16:02 +0200 Subject: [PATCH 25/38] added usedevelop = true to tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9c80b456..36e2577e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = py312,cov-report skip_missing_interpreters = true - +usedevelop = true [testenv] setenv = From b9a9c026325ca67d2f0223b0e9ffc925ed0078b1 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:26:24 +0200 Subject: [PATCH 26/38] Change cov from patterns to main --- .github/workflows/lint_pr.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index d025bb8e..e03a1a4f 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -230,18 +230,18 @@ jobs: echo " python -c \"import os.path; test_path='${test_path}'; exists=os.path.exists(test_path); print(f'Test file {test_path} exists: {exists}'); exit(0 if exists else 1)\" && pytest -xvs --cov=patterns --cov-append ${test_path}" >> tox_pr.ini || true # Also try to find any test that might include this module - echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini + echo " pytest -xvs --cov-config=.coveragerc --cov=main --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini fi # Run doctests for the file - echo " pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini + echo " pytest --cov-config=.coveragerc --doctest-modules -v --cov=main --cov-append $file" >> tox_pr.ini has_tests=true fi # Run test files directly if modified if [[ $file == tests/* ]]; then - echo " pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini + echo " pytest -xvs --cov-config=.coveragerc --cov=main --cov-append $file" >> tox_pr.ini has_tests=true fi fi From 09b2e42c74a1edb2dd4176dd520184924c761fe0 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:30:10 +0200 Subject: [PATCH 27/38] Rewrote check. --- .github/workflows/lint_pr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index e03a1a4f..6e93c91d 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -227,10 +227,10 @@ jobs: # Check if specific test exists if [ -n "$pattern_dir" ]; then test_path="tests/${pattern_dir}/test_${module_name}.py" - echo " python -c \"import os.path; test_path='${test_path}'; exists=os.path.exists(test_path); print(f'Test file {test_path} exists: {exists}'); exit(0 if exists else 1)\" && pytest -xvs --cov=patterns --cov-append ${test_path}" >> tox_pr.ini || true + echo " if [ -f \"${test_path}\" ]; then echo \"Test file ${test_path} exists: true\" && pytest -xvs --cov=patterns --cov-append ${test_path}; else echo \"Test file ${test_path} exists: false\"; fi" >> tox_pr.ini # Also try to find any test that might include this module - echo " pytest -xvs --cov-config=.coveragerc --cov=main --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini + echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini fi # Run doctests for the file From 29a56b44228fb871495dfe8495568cc820c2899d Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:33:36 +0200 Subject: [PATCH 28/38] retry fixing coverage --- .github/workflows/lint_pr.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 6e93c91d..07c84322 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -234,14 +234,14 @@ jobs: fi # Run doctests for the file - echo " pytest --cov-config=.coveragerc --doctest-modules -v --cov=main --cov-append $file" >> tox_pr.ini + echo " pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini has_tests=true fi # Run test files directly if modified if [[ $file == tests/* ]]; then - echo " pytest -xvs --cov-config=.coveragerc --cov=main --cov-append $file" >> tox_pr.ini + echo " pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini has_tests=true fi fi @@ -250,8 +250,8 @@ jobs: # If we didn't find any specific tests to run, mention it if [ "$has_tests" = false ]; then echo " python -c \"print('No specific tests found for changed files. Consider adding tests.')\"" >> tox_pr.ini - # Add a minimal test to avoid failure - echo " pytest -xk \"not integration\" --no-header" >> tox_pr.ini + # Add a minimal test to avoid failure, but ensure it generates coverage data + echo " pytest -xvs --cov=patterns --cov-append -k \"not integration\" --no-header" >> tox_pr.ini fi # Add coverage report command From 5a30b1cbdf13aad97bee570d18f9e21841cb14cc Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:35:56 +0200 Subject: [PATCH 29/38] Change cov to main --- .github/workflows/lint_pr.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 07c84322..2c328fa1 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -227,21 +227,21 @@ jobs: # Check if specific test exists if [ -n "$pattern_dir" ]; then test_path="tests/${pattern_dir}/test_${module_name}.py" - echo " if [ -f \"${test_path}\" ]; then echo \"Test file ${test_path} exists: true\" && pytest -xvs --cov=patterns --cov-append ${test_path}; else echo \"Test file ${test_path} exists: false\"; fi" >> tox_pr.ini + echo " if [ -f \"${test_path}\" ]; then echo \"Test file ${test_path} exists: true\" && pytest -xvs --cov=main --cov-append ${test_path}; else echo \"Test file ${test_path} exists: false\"; fi" >> tox_pr.ini # Also try to find any test that might include this module - echo " pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini + echo " pytest -xvs --cov=main --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini fi # Run doctests for the file - echo " pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini + echo " pytest --doctest-modules -v --cov=main --cov-append $file" >> tox_pr.ini has_tests=true fi # Run test files directly if modified if [[ $file == tests/* ]]; then - echo " pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini + echo " pytest -xvs --cov=main --cov-append $file" >> tox_pr.ini has_tests=true fi fi @@ -251,7 +251,7 @@ jobs: if [ "$has_tests" = false ]; then echo " python -c \"print('No specific tests found for changed files. Consider adding tests.')\"" >> tox_pr.ini # Add a minimal test to avoid failure, but ensure it generates coverage data - echo " pytest -xvs --cov=patterns --cov-append -k \"not integration\" --no-header" >> tox_pr.ini + echo " pytest -xvs --cov=main --cov-append -k \"not integration\" --no-header" >> tox_pr.ini fi # Add coverage report command From 75267d83adad6fd1e3d28b5f5b939bf1fbd90b2a Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:42:02 +0200 Subject: [PATCH 30/38] Added coverage run to execute pytest --- .github/workflows/lint_pr.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 2c328fa1..5141a756 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -227,21 +227,21 @@ jobs: # Check if specific test exists if [ -n "$pattern_dir" ]; then test_path="tests/${pattern_dir}/test_${module_name}.py" - echo " if [ -f \"${test_path}\" ]; then echo \"Test file ${test_path} exists: true\" && pytest -xvs --cov=main --cov-append ${test_path}; else echo \"Test file ${test_path} exists: false\"; fi" >> tox_pr.ini + echo " if [ -f \"${test_path}\" ]; then echo \"Test file ${test_path} exists: true\" && coverage run -m pytest -xvs --cov=main --cov-append ${test_path}; else echo \"Test file ${test_path} exists: false\"; fi" >> tox_pr.ini # Also try to find any test that might include this module - echo " pytest -xvs --cov=main --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini + echo " coverage run -m pytest -xvs --cov=main --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini fi # Run doctests for the file - echo " pytest --doctest-modules -v --cov=main --cov-append $file" >> tox_pr.ini + echo " coverage run -m pytest --doctest-modules -v --cov=main --cov-append $file" >> tox_pr.ini has_tests=true fi # Run test files directly if modified if [[ $file == tests/* ]]; then - echo " pytest -xvs --cov=main --cov-append $file" >> tox_pr.ini + echo " coverage run -m pytest -xvs --cov=main --cov-append $file" >> tox_pr.ini has_tests=true fi fi @@ -251,12 +251,12 @@ jobs: if [ "$has_tests" = false ]; then echo " python -c \"print('No specific tests found for changed files. Consider adding tests.')\"" >> tox_pr.ini # Add a minimal test to avoid failure, but ensure it generates coverage data - echo " pytest -xvs --cov=main --cov-append -k \"not integration\" --no-header" >> tox_pr.ini + echo " coverage run -m pytest -xvs --cov=main --cov-append -k \"not integration\" --no-header" >> tox_pr.ini fi # Add coverage report command echo " coverage combine" >> tox_pr.ini - echo " coverage report" >> tox_pr.ini + echo " coverage report -m" >> tox_pr.ini # Run tox with the custom configuration echo "Running tox with custom PR configuration..." From 9153332b1f5f4e2fdc5be7123d546fa3e9280b74 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 01:49:31 +0200 Subject: [PATCH 31/38] changed cov to patterns --- .github/workflows/lint_pr.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint_pr.yml b/.github/workflows/lint_pr.yml index 5141a756..f18e5c2e 100644 --- a/.github/workflows/lint_pr.yml +++ b/.github/workflows/lint_pr.yml @@ -227,21 +227,21 @@ jobs: # Check if specific test exists if [ -n "$pattern_dir" ]; then test_path="tests/${pattern_dir}/test_${module_name}.py" - echo " if [ -f \"${test_path}\" ]; then echo \"Test file ${test_path} exists: true\" && coverage run -m pytest -xvs --cov=main --cov-append ${test_path}; else echo \"Test file ${test_path} exists: false\"; fi" >> tox_pr.ini + echo " if [ -f \"${test_path}\" ]; then echo \"Test file ${test_path} exists: true\" && coverage run -m pytest -xvs --cov=patterns --cov-append ${test_path}; else echo \"Test file ${test_path} exists: false\"; fi" >> tox_pr.ini # Also try to find any test that might include this module - echo " coverage run -m pytest -xvs --cov=main --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini + echo " coverage run -m pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini fi # Run doctests for the file - echo " coverage run -m pytest --doctest-modules -v --cov=main --cov-append $file" >> tox_pr.ini + echo " coverage run -m pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini has_tests=true fi # Run test files directly if modified if [[ $file == tests/* ]]; then - echo " coverage run -m pytest -xvs --cov=main --cov-append $file" >> tox_pr.ini + echo " coverage run -m pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini has_tests=true fi fi @@ -251,7 +251,7 @@ jobs: if [ "$has_tests" = false ]; then echo " python -c \"print('No specific tests found for changed files. Consider adding tests.')\"" >> tox_pr.ini # Add a minimal test to avoid failure, but ensure it generates coverage data - echo " coverage run -m pytest -xvs --cov=main --cov-append -k \"not integration\" --no-header" >> tox_pr.ini + echo " coverage run -m pytest -xvs --cov=patterns --cov-append -k \"not integration\" --no-header" >> tox_pr.ini fi # Add coverage report command From 91661247616982577e46178177a1192c96c08210 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 02:01:21 +0200 Subject: [PATCH 32/38] created pyproject.toml and moved old config to backup folder --- .coveragerc => config_backup/.coveragerc | 0 setup.cfg => config_backup/setup.cfg | 0 tox.ini => config_backup/tox.ini | 0 pyproject.toml | 90 ++++++++++++++++++++++++ 4 files changed, 90 insertions(+) rename .coveragerc => config_backup/.coveragerc (100%) rename setup.cfg => config_backup/setup.cfg (100%) rename tox.ini => config_backup/tox.ini (100%) create mode 100644 pyproject.toml diff --git a/.coveragerc b/config_backup/.coveragerc similarity index 100% rename from .coveragerc rename to config_backup/.coveragerc diff --git a/setup.cfg b/config_backup/setup.cfg similarity index 100% rename from setup.cfg rename to config_backup/setup.cfg diff --git a/tox.ini b/config_backup/tox.ini similarity index 100% rename from tox.ini rename to config_backup/tox.ini diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..f642557e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,90 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "patterns" +description = "A collection of design patterns and idioms in Python." +version = "0.1.0" +readme = "README.md" +requires-python = ">=3.9" +license = {text = "MIT"} +classifiers = [ + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] + +[project.optional-dependencies] +dev = ["pytest", "pytest-cov", "pytest-randomly", "flake8", "mypy", "coverage"] + +[tool.setuptools] +packages = ["patterns"] + +[tool.pytest.ini_options] +filterwarnings = [ + "ignore::Warning:.*test class 'TestRunner'.*" +] +# Adding settings from tox.ini for pytest +testpaths = ["tests", "patterns"] +python_files = ["test_*.py", "*_test.py"] +doctest_modules = ["patterns"] +randomly_seed = 1234 +log_level = "INFO" + +[tool.coverage.run] +branch = true +source = ["patterns"] + +[tool.coverage.report] +# Regexes for lines to exclude from consideration +exclude_lines = [ + "def __repr__", + "if self\\.debug", + "raise AssertionError", + "raise NotImplementedError", + "if 0:", + "if __name__ == .__main__.:", + "@(abc\\.)?abstractmethod" +] +ignore_errors = true + +[tool.coverage.html] +directory = "coverage_html_report" + +[tool.mypy] +python_version = "3.12" +ignore_missing_imports = true + +[tool.flake8] +max-line-length = 120 +ignore = ["E266", "E731", "W503"] +exclude = ["venv*"] + +[tool.tox] +legacy_tox_ini = """ +[tox] +envlist = py312,cov-report +skip_missing_interpreters = true +usedevelop = true + +[testenv] +setenv = + COVERAGE_FILE = .coverage.{envname} +deps = + -r requirements-dev.txt +commands = + flake8 --exclude="venv/,.tox/" patterns/ + pytest --randomly-seed=1234 --doctest-modules patterns/ + pytest -s -vv --cov=patterns/ --log-level=INFO tests/ + +[testenv:cov-report] +setenv = + COVERAGE_FILE = .coverage +deps = coverage +commands = + coverage combine + coverage report +""" \ No newline at end of file From 5e78e5b43539ad205be12582afb81204b900de41 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 02:08:15 +0200 Subject: [PATCH 33/38] Testing --- pyproject.toml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f642557e..f9a0f453 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,21 +70,21 @@ envlist = py312,cov-report skip_missing_interpreters = true usedevelop = true -[testenv] -setenv = - COVERAGE_FILE = .coverage.{envname} -deps = - -r requirements-dev.txt -commands = - flake8 --exclude="venv/,.tox/" patterns/ - pytest --randomly-seed=1234 --doctest-modules patterns/ - pytest -s -vv --cov=patterns/ --log-level=INFO tests/ +#[testenv] +#setenv = +# COVERAGE_FILE = .coverage.{envname} +#deps = +# -r requirements-dev.txt +#commands = +# flake8 --exclude="venv/,.tox/" patterns/ +# coverage run -m pytest --randomly-seed=1234 --doctest-modules patterns/ +# coverage run -m pytest -s -vv --cov=patterns/ --log-level=INFO tests/ -[testenv:cov-report] -setenv = - COVERAGE_FILE = .coverage -deps = coverage -commands = - coverage combine - coverage report -""" \ No newline at end of file +#[testenv:cov-report] +#setenv = +# COVERAGE_FILE = .coverage +#deps = coverage +#commands = +# coverage combine +# coverage report +#""" \ No newline at end of file From 88b374484e8e7f752f26d2319a29d4fe93f91590 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 02:12:19 +0200 Subject: [PATCH 34/38] Changed opts to doctest --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f9a0f453..d79c69ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,9 @@ filterwarnings = [ # Adding settings from tox.ini for pytest testpaths = ["tests", "patterns"] python_files = ["test_*.py", "*_test.py"] -doctest_modules = ["patterns"] +# Enable doctest discovery in patterns directory +addopts = "--doctest-modules" +doctest_optionflags = ["ELLIPSIS", "NORMALIZE_WHITESPACE"] randomly_seed = 1234 log_level = "INFO" From e6a3df8b12a73ab370fabdd5c8b65d0a0849d883 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 02:16:32 +0200 Subject: [PATCH 35/38] Fix for error Unknown config option: randomly_seed --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d79c69ca..7810b2a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,9 +31,8 @@ filterwarnings = [ testpaths = ["tests", "patterns"] python_files = ["test_*.py", "*_test.py"] # Enable doctest discovery in patterns directory -addopts = "--doctest-modules" +addopts = "--doctest-modules --randomly-seed=1234" doctest_optionflags = ["ELLIPSIS", "NORMALIZE_WHITESPACE"] -randomly_seed = 1234 log_level = "INFO" [tool.coverage.run] From 0cdee773a6ea0c0f05a1e60ccb9796a7b11fe0d0 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 02:21:04 +0200 Subject: [PATCH 36/38] Trying fix for No data was collected. (no-data-collected) --- pyproject.toml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7810b2a2..7c109b41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,13 +31,18 @@ filterwarnings = [ testpaths = ["tests", "patterns"] python_files = ["test_*.py", "*_test.py"] # Enable doctest discovery in patterns directory -addopts = "--doctest-modules --randomly-seed=1234" +addopts = "--doctest-modules --randomly-seed=1234 --cov=patterns --cov-report=term-missing" doctest_optionflags = ["ELLIPSIS", "NORMALIZE_WHITESPACE"] log_level = "INFO" [tool.coverage.run] branch = true source = ["patterns"] +# Ensure coverage data is collected properly +relative_files = true +parallel = true +dynamic_context = "test_function" +data_file = ".coverage" [tool.coverage.report] # Regexes for lines to exclude from consideration From a84c6887674268ce03ba3dfbb857b06c0438c79e Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Mon, 5 May 2025 02:27:44 +0200 Subject: [PATCH 37/38] Changed source from patterns to ./ --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7c109b41..57f6fbe7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,8 @@ filterwarnings = [ "ignore::Warning:.*test class 'TestRunner'.*" ] # Adding settings from tox.ini for pytest -testpaths = ["tests", "patterns"] +testpaths = ["tests"] +#testpaths = ["tests", "patterns"] python_files = ["test_*.py", "*_test.py"] # Enable doctest discovery in patterns directory addopts = "--doctest-modules --randomly-seed=1234 --cov=patterns --cov-report=term-missing" @@ -37,7 +38,8 @@ log_level = "INFO" [tool.coverage.run] branch = true -source = ["patterns"] +source = ["./"] +#source = ["patterns"] # Ensure coverage data is collected properly relative_files = true parallel = true From 2644109f9022f0a76e48cd4c2faab5f5627c0b49 Mon Sep 17 00:00:00 2001 From: Chris Dorsman <39407105+cdorsman@users.noreply.github.com> Date: Sun, 4 May 2025 22:25:24 +0200 Subject: [PATCH 38/38] Changed source from patterns to ./