Skip to content

Commit 4187ff9

Browse files
authored
Merge pull request #3 from faif/master
update master
2 parents d4b7f97 + 879ac01 commit 4187ff9

30 files changed

+642
-166
lines changed

.codespellignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
__pycache__
2+
*.pyc
3+
.idea
4+
*.egg-info/
5+
.tox/
6+
env/
7+
venv/
8+
.env
9+
.venv
10+
.vscode/
11+
.python-version
12+
.coverage
13+
build/
14+
dist/

.coveragerc

Lines changed: 0 additions & 6 deletions
This file was deleted.

.github/workflows/lint_pr.yml

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
name: lint_pull_request
2+
on: [pull_request, push]
3+
jobs:
4+
check_changes:
5+
runs-on: ubuntu-24.04
6+
outputs:
7+
has_python_changes: ${{ steps.changed-files.outputs.has_python_changes }}
8+
files: ${{ steps.changed-files.outputs.files }}
9+
steps:
10+
- uses: actions/checkout@v3
11+
with:
12+
fetch-depth: 0 # To get all history for git diff commands
13+
14+
- name: Get changed Python files
15+
id: changed-files
16+
run: |
17+
if [ "${{ github.event_name }}" == "pull_request" ]; then
18+
# For PRs, compare against base branch
19+
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep '\.py$' | grep -v "^setup\.py$" || echo "")
20+
# Check if setup.py specifically changed
21+
SETUP_PY_CHANGED=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }} HEAD | grep "^setup\.py$" || echo "")
22+
if [ ! -z "$SETUP_PY_CHANGED" ]; then
23+
CHANGED_FILES="$CHANGED_FILES $SETUP_PY_CHANGED"
24+
fi
25+
else
26+
# For pushes, use the before/after SHAs
27+
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep '\.py$' | grep -v "^setup\.py$" || echo "")
28+
# Check if setup.py specifically changed
29+
SETUP_PY_CHANGED=$(git diff --name-only --diff-filter=ACMRT ${{ github.event.before }} ${{ github.event.after }} | grep "^setup\.py$" || echo "")
30+
if [ ! -z "$SETUP_PY_CHANGED" ]; then
31+
CHANGED_FILES="$CHANGED_FILES $SETUP_PY_CHANGED"
32+
fi
33+
fi
34+
35+
# Check if any Python files were changed and set the output accordingly
36+
if [ -z "$CHANGED_FILES" ]; then
37+
echo "No Python files changed"
38+
echo "has_python_changes=false" >> $GITHUB_OUTPUT
39+
echo "files=" >> $GITHUB_OUTPUT
40+
else
41+
echo "Changed Python files: $CHANGED_FILES"
42+
echo "has_python_changes=true" >> $GITHUB_OUTPUT
43+
echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT
44+
fi
45+
46+
- name: PR information
47+
if: ${{ github.event_name == 'pull_request' }}
48+
run: |
49+
if [[ "${{ steps.changed-files.outputs.has_python_changes }}" == "true" ]]; then
50+
echo "This PR contains Python changes that will be linted."
51+
else
52+
echo "This PR contains no Python changes, but still requires manual approval."
53+
fi
54+
55+
lint:
56+
needs: check_changes
57+
if: ${{ needs.check_changes.outputs.has_python_changes == 'true' }}
58+
runs-on: ubuntu-24.04
59+
strategy:
60+
fail-fast: false
61+
matrix:
62+
tool: [flake8, format, mypy, pytest, pyupgrade, tox]
63+
steps:
64+
# Additional check to ensure we have Python files before proceeding
65+
- name: Verify Python changes
66+
run: |
67+
if [[ "${{ needs.check_changes.outputs.has_python_changes }}" != "true" ]]; then
68+
echo "No Python files were changed. Skipping linting."
69+
exit 0
70+
fi
71+
72+
- uses: actions/checkout@v3
73+
with:
74+
fetch-depth: 0
75+
76+
- uses: actions/setup-python@v4
77+
with:
78+
python-version: 3.12
79+
80+
- uses: actions/cache@v3
81+
with:
82+
path: ~/.cache/pip
83+
key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }}
84+
restore-keys: |
85+
${{ runner.os }}-pip-
86+
87+
- name: Install dependencies
88+
run: |
89+
python -m pip install --upgrade pip
90+
pip install -r requirements-dev.txt
91+
92+
# Flake8 linting
93+
- name: Lint with flake8
94+
if: ${{ matrix.tool == 'flake8' }}
95+
id: flake8
96+
run: |
97+
echo "Linting files: ${{ needs.check_changes.outputs.files }}"
98+
flake8 ${{ needs.check_changes.outputs.files }} --count --show-source --statistics
99+
100+
# Format checking with isort and black
101+
- name: Format check
102+
if: ${{ matrix.tool == 'format' }}
103+
id: format
104+
run: |
105+
echo "Checking format with isort for: ${{ needs.check_changes.outputs.files }}"
106+
isort --profile black --check ${{ needs.check_changes.outputs.files }}
107+
echo "Checking format with black for: ${{ needs.check_changes.outputs.files }}"
108+
black --check ${{ needs.check_changes.outputs.files }}
109+
110+
# Type checking with mypy
111+
- name: Type check with mypy
112+
if: ${{ matrix.tool == 'mypy' }}
113+
id: mypy
114+
run: |
115+
echo "Type checking: ${{ needs.check_changes.outputs.files }}"
116+
mypy --ignore-missing-imports ${{ needs.check_changes.outputs.files }}
117+
118+
# Run tests with pytest
119+
- name: Run tests with pytest
120+
if: ${{ matrix.tool == 'pytest' }}
121+
id: pytest
122+
run: |
123+
echo "Running pytest discovery..."
124+
python -m pytest --collect-only -v
125+
126+
# First run any test files that correspond to changed files
127+
echo "Running tests for changed files..."
128+
changed_files="${{ needs.check_changes.outputs.files }}"
129+
130+
# Extract module paths from changed files
131+
modules=()
132+
for file in $changed_files; do
133+
# Convert file path to module path (remove .py and replace / with .)
134+
if [[ $file == patterns/* ]]; then
135+
module_path=${file%.py}
136+
module_path=${module_path//\//.}
137+
modules+=("$module_path")
138+
fi
139+
done
140+
141+
# Run tests for each module
142+
for module in "${modules[@]}"; do
143+
echo "Testing module: $module"
144+
python -m pytest -xvs tests/ -k "$module" || true
145+
done
146+
147+
# Then run doctests on the changed files
148+
echo "Running doctests for changed files..."
149+
for file in $changed_files; do
150+
if [[ $file == *.py ]]; then
151+
echo "Running doctest for $file"
152+
python -m pytest --doctest-modules -v $file || true
153+
fi
154+
done
155+
156+
# Check Python version compatibility
157+
- name: Check Python version compatibility
158+
if: ${{ matrix.tool == 'pyupgrade' }}
159+
id: pyupgrade
160+
run: pyupgrade --py312-plus ${{ needs.check_changes.outputs.files }}
161+
162+
# Run tox
163+
- name: Run tox
164+
if: ${{ matrix.tool == 'tox' }}
165+
id: tox
166+
run: |
167+
echo "Running tox integration for changed files..."
168+
changed_files="${{ needs.check_changes.outputs.files }}"
169+
170+
# Create a temporary tox configuration that extends the original one
171+
echo "[tox]" > tox_pr.ini
172+
echo "envlist = py312" >> tox_pr.ini
173+
echo "skip_missing_interpreters = true" >> tox_pr.ini
174+
175+
echo "[testenv]" >> tox_pr.ini
176+
echo "setenv =" >> tox_pr.ini
177+
echo " COVERAGE_FILE = .coverage.{envname}" >> tox_pr.ini
178+
echo "deps =" >> tox_pr.ini
179+
echo " -r requirements-dev.txt" >> tox_pr.ini
180+
echo "allowlist_externals =" >> tox_pr.ini
181+
echo " pytest" >> tox_pr.ini
182+
echo " coverage" >> tox_pr.ini
183+
echo " python" >> tox_pr.ini
184+
echo "commands =" >> tox_pr.ini
185+
186+
# Check if we have any implementation files that changed
187+
pattern_files=0
188+
test_files=0
189+
190+
for file in $changed_files; do
191+
if [[ $file == patterns/* ]]; then
192+
pattern_files=1
193+
elif [[ $file == tests/* ]]; then
194+
test_files=1
195+
fi
196+
done
197+
198+
# Only run targeted tests, no baseline
199+
echo " # Run specific tests for changed files" >> tox_pr.ini
200+
201+
has_tests=false
202+
203+
# Add coverage-focused test commands
204+
for file in $changed_files; do
205+
if [[ $file == *.py ]]; then
206+
# Run coverage tests for implementation files
207+
if [[ $file == patterns/* ]]; then
208+
module_name=$(basename $file .py)
209+
210+
# Get the pattern type (behavioral, structural, etc.)
211+
if [[ $file == patterns/behavioral/* ]]; then
212+
pattern_dir="behavioral"
213+
elif [[ $file == patterns/creational/* ]]; then
214+
pattern_dir="creational"
215+
elif [[ $file == patterns/structural/* ]]; then
216+
pattern_dir="structural"
217+
elif [[ $file == patterns/fundamental/* ]]; then
218+
pattern_dir="fundamental"
219+
elif [[ $file == patterns/other/* ]]; then
220+
pattern_dir="other"
221+
else
222+
pattern_dir=""
223+
fi
224+
225+
echo " # Testing $file" >> tox_pr.ini
226+
227+
# Check if specific test exists
228+
if [ -n "$pattern_dir" ]; then
229+
test_path="tests/${pattern_dir}/test_${module_name}.py"
230+
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
231+
232+
# Also try to find any test that might include this module
233+
echo " coverage run -m pytest -xvs --cov=patterns --cov-append tests/${pattern_dir}/ -k \"${module_name}\" --no-header" >> tox_pr.ini
234+
fi
235+
236+
# Run doctests for the file
237+
echo " coverage run -m pytest --doctest-modules -v --cov=patterns --cov-append $file" >> tox_pr.ini
238+
239+
has_tests=true
240+
fi
241+
242+
# Run test files directly if modified
243+
if [[ $file == tests/* ]]; then
244+
echo " coverage run -m pytest -xvs --cov=patterns --cov-append $file" >> tox_pr.ini
245+
has_tests=true
246+
fi
247+
fi
248+
done
249+
250+
# If we didn't find any specific tests to run, mention it
251+
if [ "$has_tests" = false ]; then
252+
echo " python -c \"print('No specific tests found for changed files. Consider adding tests.')\"" >> tox_pr.ini
253+
# Add a minimal test to avoid failure, but ensure it generates coverage data
254+
echo " coverage run -m pytest -xvs --cov=patterns --cov-append -k \"not integration\" --no-header" >> tox_pr.ini
255+
fi
256+
257+
# Add coverage report command
258+
echo " coverage combine" >> tox_pr.ini
259+
echo " coverage report -m" >> tox_pr.ini
260+
261+
# Run tox with the custom configuration
262+
echo "Running tox with custom PR configuration..."
263+
echo "======================== TOX CONFIG ========================"
264+
cat tox_pr.ini
265+
echo "==========================================================="
266+
tox -c tox_pr.ini
267+
268+
summary:
269+
needs: [check_changes, lint]
270+
# Run summary in all cases, regardless of whether lint job ran
271+
if: ${{ always() }}
272+
runs-on: ubuntu-24.04
273+
steps:
274+
- uses: actions/checkout@v3
275+
276+
- name: Summarize results
277+
run: |
278+
echo "## Pull Request Lint Results" >> $GITHUB_STEP_SUMMARY
279+
if [[ "${{ needs.check_changes.outputs.has_python_changes }}" == "true" ]]; then
280+
echo "Linting has completed for all Python files changed in this PR." >> $GITHUB_STEP_SUMMARY
281+
echo "See individual job logs for detailed results." >> $GITHUB_STEP_SUMMARY
282+
else
283+
echo "No Python files were changed in this PR. Linting was skipped." >> $GITHUB_STEP_SUMMARY
284+
fi
285+
echo "" >> $GITHUB_STEP_SUMMARY
286+
echo "⚠️ **Note:** This PR still requires manual approval regardless of linting results." >> $GITHUB_STEP_SUMMARY

.github/workflows/lint_python.yml

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,35 @@ name: lint_python
22
on: [pull_request, push]
33
jobs:
44
lint_python:
5-
runs-on: ubuntu-latest
5+
runs-on: ubuntu-24.04
66
steps:
77
- uses: actions/checkout@v3
88
- uses: actions/setup-python@v4
99
with:
10-
python-version: 3.x
11-
- run: pip install --upgrade pip
12-
- run: pip install black codespell flake8 isort mypy pytest pyupgrade tox
13-
- run: black --check .
14-
- run: codespell --quiet-level=2 # --ignore-words-list="" --skip=""
15-
- run: flake8 . --count --show-source --statistics
16-
- run: isort --profile black .
17-
- run: tox
18-
- run: pip install -e .
19-
- run: mypy --ignore-missing-imports . || true
20-
- run: pytest .
21-
- run: pytest --doctest-modules . || true
22-
- run: shopt -s globstar && pyupgrade --py37-plus **/*.py
10+
python-version: 3.12
11+
- name: Install dependencies
12+
run: |
13+
python -m pip install --upgrade pip
14+
pip install -r requirements-dev.txt
15+
- name: Lint with flake8
16+
run: flake8 ./patterns --count --show-source --statistics
17+
continue-on-error: true
18+
- name: Format check with isort and black
19+
run: |
20+
isort --profile black --check ./patterns
21+
black --check ./patterns
22+
continue-on-error: true
23+
- name: Type check with mypy
24+
run: mypy --ignore-missing-imports ./patterns || true
25+
continue-on-error: true
26+
- name: Run tests with pytest
27+
run: |
28+
pytest ./patterns
29+
pytest --doctest-modules ./patterns || true
30+
continue-on-error: true
31+
- name: Check Python version compatibility
32+
run: shopt -s globstar && pyupgrade --py312-plus ./patterns/**/*.py
33+
continue-on-error: true
34+
- name: Run tox
35+
run: tox
36+
continue-on-error: true

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ venv/
1010
.vscode/
1111
.python-version
1212
.coverage
13+
build/
14+
dist/

.travis.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
os: linux
2-
dist: focal
2+
dist: noble
33
language: python
44

55
jobs:
66
include:
7-
- python: "3.8"
8-
env: TOXENV=py38
9-
- python: "3.9"
10-
env: TOXENV=py39
7+
- python: "3.12"
8+
env: TOXENV=py312
119

1210
cache:
1311
- pip

0 commit comments

Comments
 (0)