8000 TYP: use mypy_primer to surface type checking regressions by hauntsaninja · Pull Request #28073 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

TYP: use mypy_primer to surface type checking regressions #28073

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 30, 2024
Merged
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
99 changes: 99 additions & 0 deletions .github/workflows/mypy_primer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Run mypy_primer

on:
# Only run on PR, since we diff against main
pull_request:
paths:
- "**/*.pyi"
- ".github/workflows/mypy_primer.yml"
- ".github/workflows/mypy_primer_comment.yml"

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read

jobs:
mypy_primer:
name: Run
runs-on: ubuntu-latest
strategy:
matrix:
shard-index: [0] # e.g. change this to [0, 1, 2] and --num-shards below to 3
fail-fast: false
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
path: numpy_to_test
fetch-depth: 0
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: "3.12"
- name: Install dependencies
run: pip install git+https://github.com/hauntsaninja/mypy_primer.git
- name: Run mypy_primer
shell: bash
run: |
cd numpy_to_test
MYPY_VERSION=$(grep mypy== requirements/test_requirements.txt | sed -n 's/mypy==\([^;]*\).*/\1/p')

echo "new commit"
git checkout $GITHUB_SHA
git rev-list --format=%s --max-count=1 HEAD

MERGE_BASE=$(git merge-base $GITHUB_SHA origin/$GITHUB_BASE_REF)
git worktree add ../numpy_base $MERGE_BASE
cd ../numpy_base

echo "base commit"
git rev-list --format=%s --max-count=1 HEAD

echo ''
cd ..
# fail action if exit code isn't zero or one
# TODO: note that we don't build numpy, so if a project attempts to use the
# numpy mypy plugin, we may see some issues involving version skew.
(
mypy_primer \
--new v${MYPY_VERSION} --old v${MYPY_VERSION} \
--known-dependency-selector numpy \
--old-prepend-path numpy_base --new-prepend-path numpy_to_test \
--num-shards 1 --shard-index ${{ matrix.shard-index }} \
--debug \
--output concise \
| tee diff_${{ matrix.shard-index }}.txt
) || [ $? -eq 1 ]
- if: ${{ matrix.shard-index == 0 }}
name: Save PR number
run: |
echo ${{ github.event.pull_request.number }} | tee pr_number.txt
- name: Upload mypy_primer diff + PR number
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
if: ${{ matrix.shard-index == 0 }}
with:
name: mypy_primer_diffs-${{ matrix.shard-index }}
path: |
diff_${{ matrix.shard-index }}.txt
pr_number.txt
- name: Upload mypy_primer diff
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
if: ${{ matrix.shard-index != 0 }}
with:
name: mypy_primer_diffs-${{ matrix.shard-index }}
path: diff_${{ matrix.shard-index }}.txt

join_artifacts:
name: Join artifacts
runs-on: ubuntu-latest
needs: [mypy_primer]
permissions:
contents: read
steps:
- name: Merge artifacts
uses: actions/upload-artifact/merge@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: mypy_primer_diffs
pattern: mypy_primer_diffs-*
delete-merged: true
96 changes: 96 additions & 0 deletions .github/workflows/mypy_primer_comment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Comment with mypy_primer diff

on:
workflow_run:
workflows:
- Run mypy_primer
types:
- completed

permissions:
contents: read
pull-requests: write

jobs:
comment:
name: Comment PR from mypy_primer
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Hide old comments
uses: kanga333/comment-hider@c12bb20b48aeb8fc098e35967de8d4f8018fffdf # v0.4.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
issue_number: ${{ steps.post-comment.outputs.result }}

- name: Download diffs
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const fs = require('fs');
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
const [matchArtifact] = artifacts.data.artifacts.filter((artifact) =>
artifact.name == "mypy_primer_diffs");

const download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: "zip",
});
fs.writeFileSync("diff.zip", Buffer.from(download.data));

- run: unzip diff.zip
- run: |
cat diff_*.txt | tee fulldiff.txt

- name: Post comment
id: post-comment
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const MAX_CHARACTERS = 50000
const MAX_CHARACTERS_PER_PROJECT = MAX_CHARACTERS / 3

const fs = require('fs')
let data = fs.readFileSync('fulldiff.txt', { encoding: 'utf8' })

function truncateIfNeeded(original, maxLength) {
if (original.length <= maxLength) {
return original
}
let truncated = original.substring(0, maxLength)
// further, remove last line that might be truncated
truncated = truncated.substring(0, truncated.lastIndexOf('\n'))
let lines_truncated = original.split('\n').length - truncated.split('\n').length
return `${truncated}\n\n... (truncated ${lines_truncated} lines) ...`
}

const projects = data.split('\n\n')
// don't let one project dominate
data = projects.map(project => truncateIfNeeded(project, MAX_CHARACTERS_PER_PROJECT)).join('\n\n')
// posting comment fails if too long, so truncate
data = truncateIfNeeded(data, MAX_CHARACTERS)

console.log("Diff from mypy_primer:")
console.log(data)

let body
if (data.trim()) {
body = 'Diff from [mypy_primer](https://github.com/hauntsaninja/mypy_primer), '
body += 'showing the effect of this PR on type check results on a corpus of open source code:\n```diff\n'
body += data + '```'
const prNumber = parseInt(fs.readFileSync("pr_number.txt", { encoding: "utf8" }))
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body
})
}
return prNumber
Loading
0