Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,82 @@ jobs:
run: |
pytest --verbose --timeout=30

mutation-tests:
name: Targeted mutation tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
with:
fetch-depth: 0

- name: Check targeted mutation inputs changed
id: changes
shell: bash
run: |
set -euo pipefail

if [[ "${{ github.event_name }}" == "pull_request" ]]; then
base="${{ github.event.pull_request.base.sha }}"
head="${{ github.event.pull_request.head.sha }}"
else
base="${{ github.event.before }}"
head="${{ github.sha }}"
fi

changed_files="$(git diff --name-only "$base" "$head" -- \
posthog/utils.py \
posthog/test/test_utils.py \
posthog/test/test_size_limited_dict.py)"

if [[ -n "$changed_files" ]]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Targeted mutation inputs changed:"
echo "$changed_files"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "Skipping targeted mutation tests: inputs unchanged."
fi

- name: Set up Python 3.11
if: steps.changes.outputs.changed == 'true'
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55
with:
python-version: 3.11.11

- name: Install uv
if: steps.changes.outputs.changed == 'true'
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true

- name: Restore mutmut cache
id: mutmut-cache
if: steps.changes.outputs.changed == 'true'
uses: actions/cache@v4
with:
path: mutants
key: mutmut-${{ runner.os }}-py311-${{ hashFiles('posthog/utils.py', 'posthog/test/test_utils.py', 'posthog/test/test_size_limited_dict.py') }}
restore-keys: |
mutmut-${{ runner.os }}-py311-

- name: Skip mutation tests on exact cache hit
if: steps.changes.outputs.changed == 'true' && steps.mutmut-cache.outputs.cache-hit == 'true'
run: |
echo "Skipping targeted mutation tests: exact mutmut cache hit."

- name: Run targeted mutation tests
if: steps.changes.outputs.changed == 'true' && steps.mutmut-cache.outputs.cache-hit != 'true'
shell: bash
run: |
set -euo pipefail
UV_PROJECT_ENVIRONMENT=$pythonLocation uv run --extra test --with mutmut mutmut run --max-children 1
results="$(UV_PROJECT_ENVIRONMENT=$pythonLocation uv run --extra test --with mutmut mutmut results)"
if [[ -n "$results" ]]; then
echo "$results"
exit 1
fi

import-check:
name: Python ${{ matrix.python-version }} import check
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ pyrightconfig.json
.DS_Store
posthog-python-references.json
.claude/settings.local.json
mutants/
10 changes: 10 additions & 0 deletions posthog/test/test_size_limited_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,13 @@ def test_size_limited_dict(self, size: int, iterations: int) -> None:
self.assertIsNone(values.get(i - 3))
self.assertIsNone(values.get(i - 5))
self.assertIsNone(values.get(i - 9))

def test_size_limited_dict_forwards_defaultdict_args_and_kwargs(self) -> None:
values = utils.SizeLimitedDict(
3, lambda: "missing", {"existing": "value"}, other="item"
)

assert values["missing"] == "missing"
assert values["existing"] == "value"
assert values["other"] == "item"
assert values.max_size == 3
Loading
Loading