Lint Python tools in CI with a checker-specific baseline ratchet (#323)
Add pinned ruff and pyright checks, the existing-findings baseline, and a workflow that rejects new findings and requires fixed findings to be removed. Compare checker pins numerically and permit baseline growth only for the checker whose release version increased. Comments, unrelated dependency edits and downgrades retain the guard. Add 10 regression tests using Git trees and document the policy. Validation: 14 guard/documentation tests pass; pinned lint reports 414 existing findings, zero new findings and zero stale baseline entries. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
This commit is contained in:
1 parent
ed3007f1ef
commit
7f5ef4155e
7 files changed
+600
No files matched your search
@@ -0,0 +1,7 @@
|
||||
# The Python lint job's tools (.github/workflows/lint-python.yml, dm/tools/lint_python.py), pinned: their findings change with their versions, so raising one
|
||||
# goes with `python3 dm/tools/lint_python.py --rebaseline` in the same commit. The last three are the packages the tools import (as in tests.yml), so pyright resolves them.
|
||||
ruff==0.17.2
|
||||
pyright==1.1.414
|
||||
lz4==4.4.5
|
||||
capstone==5.0.9
|
||||
fonttools==4.67.0
|
||||
@@ -0,0 +1,48 @@
|
||||
# Python lint and types over scripts/ and the tools under dm/: ruff (lint rules for bugs, never formatting) and pyright in basic mode, configured in pyproject.toml.
|
||||
# A ratchet: the findings the code had when this came in are in dm/tools/lint_python_baseline.tsv, so the job fails only on a new finding, and on a fixed one still
|
||||
# listed there (`python3 dm/tools/lint_python.py --update` shrinks it). On a pull request the baseline may not grow over the base branch's either.
|
||||
# ty (Astral's type checker, beta) runs beside it as advisory: its findings go to the job summary and never fail the build.
|
||||
# The tool versions are pinned in .github/requirements/lint.txt; docs/development.md has the commands.
|
||||
name: lint-python
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths: ['**.py', pyproject.toml, .github/requirements/lint.txt, .github/workflows/lint-python.yml, dm/tools/lint_python_baseline.tsv]
|
||||
push:
|
||||
branches: [main]
|
||||
paths: ['**.py', pyproject.toml, .github/requirements/lint.txt, .github/workflows/lint-python.yml, dm/tools/lint_python_baseline.tsv]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: lint-python-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# Actions are pinned to commit SHAs (the tag in the comment), as in tests.yml.
|
||||
jobs:
|
||||
lint:
|
||||
name: ruff and pyright (ratchet)
|
||||
runs-on: ubuntu-24.04 # pyproject.toml fixes the platform pyright assumes (Darwin), so the findings match a Mac's
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
||||
with:
|
||||
python-version: '3.14'
|
||||
cache: pip
|
||||
cache-dependency-path: .github/requirements/lint.txt
|
||||
- name: Install the pinned tools
|
||||
run: python -m pip install -r .github/requirements/lint.txt
|
||||
- name: Base branch's baseline (pull requests)
|
||||
if: github.event_name == 'pull_request'
|
||||
run: git fetch --no-tags --depth=1 origin "$GITHUB_BASE_REF"
|
||||
- name: ruff and pyright against the baseline
|
||||
run: python dm/tools/lint_python.py ${{ github.event_name == 'pull_request' && '--against FETCH_HEAD' || '' }}
|
||||
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env python3
|
||||
# Python lint and type check with a ratchet (.github/workflows/lint-python.yml): ruff (pyproject.toml's [tool.ruff]: lint rules for bugs, no formatting) and pyright in basic
|
||||
# mode ([tool.pyright]) over scripts/ and the tools under dm/. The findings the code had when the check came in are listed in dm/tools/lint_python_baseline.tsv, keyed by tool,
|
||||
# file, rule and message with a count (no line numbers: they survive edits elsewhere in the file). The check fails on a finding beyond its key's count (a new one) and on a
|
||||
# count above what the code has now (a fixed finding still listed: run --update). So the baseline only shrinks:
|
||||
# --update lowers counts to what the code has now and drops fixed entries; it never adds one (a new finding is fixed, or silenced on its line with a noqa or
|
||||
# `# pyright: ignore[<rule>]` and a reason)
|
||||
# --rebaseline writes every current finding: only with a raised tool version in .github/requirements/lint.txt, whose findings change with it
|
||||
# --against REV fails when the baseline has an entry or a count that REV's has not, unless that checker's pinned version increased (CI uses the PR's base)
|
||||
# Run it with the pinned tools, so the findings match CI's (other versions or other packages in the environment change them):
|
||||
# python3 -m venv <dir> && <dir>/bin/pip install -r .github/requirements/lint.txt && <dir>/bin/python3 dm/tools/lint_python.py [--update]
|
||||
# Under GitHub Actions, new findings are annotated on their lines and a summary goes to $GITHUB_STEP_SUMMARY.
|
||||
import argparse, collections, json, os, re, subprocess, sys, pathlib
|
||||
|
||||
REPO = pathlib.Path(__file__).resolve().parents[2]
|
||||
BASELINE = REPO / 'dm/tools/lint_python_baseline.tsv'
|
||||
REQS = '.github/requirements/lint.txt'
|
||||
HEADER = '# tool\tfile\trule\tcount\tmessage (dm/tools/lint_python.py; shrink with --update, never edit by hand to add)\n'
|
||||
|
||||
def rel(p): return pathlib.Path(p).resolve().relative_to(REPO).as_posix()
|
||||
def norm(msg): return re.sub(r'\s+', ' ', msg).strip() # pyright's messages span lines and use no-break spaces
|
||||
|
||||
def run(cmd):
|
||||
r = subprocess.run(cmd, cwd=REPO, capture_output=True, text=True)
|
||||
if not r.stdout.strip(): sys.exit(f'[RED] lint_python: {" ".join(cmd[:3])} printed nothing (exit {r.returncode}):\n{r.stderr}')
|
||||
return r.stdout
|
||||
|
||||
def ruff():
|
||||
out = json.loads(run([sys.executable, '-m', 'ruff', 'check', '--no-cache', '--exit-zero', '--output-format', 'json', '.']))
|
||||
return [('ruff', rel(f['filename']), f['code'] or 'syntax', norm(f['message']), f['location']['row']) for f in out]
|
||||
|
||||
def pyright():
|
||||
out = json.loads(run([sys.executable, '-m', 'pyright', '--outputjson', '--pythonpath', sys.executable]))
|
||||
return [('pyright', rel(d['file']), d.get('rule') or d['severity'], norm(d['message']), d['range']['start']['line'] + 1)
|
||||
for d in out['generalDiagnostics'] if d['severity'] in ('error', 'warning')]
|
||||
|
||||
def load(text):
|
||||
base = collections.Counter()
|
||||
for line in text.splitlines():
|
||||
if not line or line.startswith('#'): continue
|
||||
tool, path, rule, n, msg = line.split('\t', 4)
|
||||
base[(tool, path, rule, msg)] = int(n)
|
||||
return base
|
||||
|
||||
def write(base):
|
||||
rows = sorted(f'{k[0]}\t{k[1]}\t{k[2]}\t{n}\t{k[3]}\n' for k, n in base.items() if n > 0)
|
||||
BASELINE.write_text(HEADER + ''.join(rows))
|
||||
|
||||
def git(*a): return subprocess.run(['git', *a], cwd=REPO, capture_output=True, text=True)
|
||||
|
||||
def versions(text):
|
||||
# The checkers use three-part release pins. Reject missing, duplicate or unsupported pins instead of authorizing a baseline rewrite.
|
||||
pins = {}
|
||||
for line in text.splitlines():
|
||||
name, _, version = line.split('#', 1)[0].strip().partition('==')
|
||||
name, version = name.strip().lower(), version.strip()
|
||||
if name not in ('ruff', 'pyright'): continue
|
||||
if name in pins or not re.fullmatch(r'\d+\.\d+\.\d+', version):
|
||||
raise ValueError(f'{REQS}: {name} must have one numeric release pin (name==X.Y.Z)')
|
||||
pins[name] = tuple(map(int, version.split('.')))
|
||||
if set(pins) != {'ruff', 'pyright'}: raise ValueError(f'{REQS}: both ruff and pyright need numeric release pins (name==X.Y.Z)')
|
||||
return pins
|
||||
|
||||
def against(rev, base):
|
||||
# Only an upgraded checker may gain entries or counts; dependency edits and downgrades do not change the ratchet.
|
||||
old = git('show', f'{rev}:{rel(BASELINE)}')
|
||||
if old.returncode: print(f'lint_python: no baseline at {rev}: nothing to compare'); return 0
|
||||
old_reqs = git('show', f'{rev}:{REQS}')
|
||||
if old_reqs.returncode: print(f'[RED] lint_python: cannot read {REQS} at {rev}: {old_reqs.stderr.strip()}'); return 1
|
||||
try:
|
||||
before, after = versions(old_reqs.stdout), versions((REPO / REQS).read_text())
|
||||
except (OSError, ValueError) as e:
|
||||
print(f'[RED] lint_python: {e}'); return 1
|
||||
upgraded = {t for t in before if after[t] > before[t]}
|
||||
for t in sorted(upgraded): print(f'lint_python: {t} upgraded since {rev}: its baseline may be rewritten')
|
||||
was = load(old.stdout)
|
||||
grown = [(k, n, was[k]) for k, n in base.items() if n > was[k] and k[0] not in upgraded]
|
||||
for (tool, path, rule, msg), n, w in grown: print(f'::error file={rel(BASELINE)}::baseline grew: {tool} {path} {rule} {w} -> {n}: {msg}')
|
||||
if grown: print(f'lint_python: the baseline gained {len(grown)} entries over {rev}: fix the new findings instead (it only shrinks)')
|
||||
return 1 if grown else 0
|
||||
|
||||
def summary(md):
|
||||
if os.environ.get('GITHUB_STEP_SUMMARY'):
|
||||
with open(os.environ['GITHUB_STEP_SUMMARY'], 'a') as f: f.write(md + '\n')
|
||||
|
||||
def check(args):
|
||||
found = ruff() + pyright()
|
||||
cur = collections.Counter(f[:4] for f in found)
|
||||
base = load(BASELINE.read_text()) if BASELINE.exists() else collections.Counter()
|
||||
if args.rebaseline:
|
||||
write(cur); print(f'lint_python: wrote {sum(cur.values())} findings to {rel(BASELINE)}'); return 0
|
||||
new = {k: n - base[k] for k, n in cur.items() if n > base[k]}
|
||||
fixed = {k: base[k] - cur[k] for k in base if base[k] > cur[k]}
|
||||
if args.update:
|
||||
shrunk = collections.Counter({k: min(n, cur[k]) for k, n in base.items()})
|
||||
write(shrunk); print(f'lint_python: baseline {sum(base.values())} -> {sum(shrunk.values())} findings')
|
||||
base, fixed = shrunk, {}
|
||||
gha = os.environ.get('GITHUB_ACTIONS') == 'true'
|
||||
for tool, path, rule, msg, line in found:
|
||||
k = (tool, path, rule, msg)
|
||||
if new.get(k): # with several of one key, every line is shown: which one is new is not known
|
||||
print(f'::error file={path},line={line},title={tool} {rule}::{msg}' if gha else f'{path}:{line}: {tool} {rule}: {msg}')
|
||||
for (tool, path, rule, msg), n in sorted(fixed.items()):
|
||||
print(f'fixed, still in the baseline: {tool} {path} {rule} x{n}: {msg}')
|
||||
n_new, n_fixed = sum(new.values()), sum(fixed.values())
|
||||
rows = ['| tool | findings | in the baseline | new | fixed, still listed |', '|---|---:|---:|---:|---:|']
|
||||
for t in ('ruff', 'pyright'):
|
||||
rows.append(f'| {t} | {sum(n for k, n in cur.items() if k[0] == t)} | {sum(n for k, n in base.items() if k[0] == t)} '
|
||||
f'| {sum(n for k, n in new.items() if k[0] == t)} | {sum(n for k, n in fixed.items() if k[0] == t)} |')
|
||||
verdict = ('New findings: fix them (or silence one on its line with `# noqa: <rule>` / `# pyright: ignore[<rule>]` and a reason).' if n_new else
|
||||
'Fixed findings are still in the baseline: run `python3 dm/tools/lint_python.py --update` and commit it.' if n_fixed else
|
||||
'No new findings.')
|
||||
summary('### Python lint and types (ruff, pyright basic)\n\n' + '\n'.join(rows) + f'\n\n{verdict}\n')
|
||||
print(f'lint_python: {sum(cur.values())} findings, {sum(base.values())} in the baseline, {n_new} new, {n_fixed} fixed but still listed')
|
||||
if n_fixed: print('lint_python: run python3 dm/tools/lint_python.py --update to shrink the baseline')
|
||||
rc = 1 if n_new or n_fixed else 0
|
||||
if args.against: rc |= against(args.against, load(BASELINE.read_text()) if BASELINE.exists() else collections.Counter())
|
||||
return rc
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description='ruff and pyright with a ratchet baseline')
|
||||
g = ap.add_mutually_exclusive_group()
|
||||
g.add_argument('--update', action='store_true', help='shrink the baseline to the findings the code still has')
|
||||
g.add_argument('--rebaseline', action='store_true', help='write every current finding (only after raising a pinned tool version)')
|
||||
ap.add_argument('--against', metavar='REV', help='also fail when the baseline grew over the one at REV')
|
||||
args = ap.parse_args()
|
||||
return check(args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,257 @@
|
||||
# tool file rule count message (dm/tools/lint_python.py; shrink with --update, never edit by hand to add)
|
||||
pyright dm/games/profile_guess.py reportArgumentType 1 Argument of type "set[Unknown]" cannot be assigned to parameter "nro_imports" of type "frozenset[Unknown]" in function "shader_sources" "set[Unknown]" is not assignable to "frozenset[Unknown]"
|
||||
pyright dm/gfx/tools/c1_guard.py reportOptionalMemberAccess 1 "startswith" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/c1_guard.py reportOptionalOperand 1 Operator "+" not supported for "None"
|
||||
pyright dm/gfx/tools/c1_guard.py reportOptionalOperand 1 Operator "-" not supported for "None"
|
||||
pyright dm/gfx/tools/c1_guard.py reportOptionalOperand 2 Operator ">=" not supported for "None"
|
||||
pyright dm/gfx/tools/cb_extent.py reportArgumentType 1 Argument of type "Unknown | None" cannot be assigned to parameter "arg2" of type "SupportsRichComparisonT@max" in function "max" Type "Unknown | None" is not assignable to type "SupportsRichComparison" Type "Unknown | None" is not assignable to type "SupportsRichComparison" Type "None" is not assignable to type "SupportsRichComparison" "None" is incompatible with protocol "SupportsDunderLT[Any]" "__lt__" is not present "None" is incompatible with protocol "SupportsDunderGT[Any]" "__gt__" is not present
|
||||
pyright dm/gfx/tools/cb_extent.py reportArgumentType 1 Argument of type "Unknown | None" cannot be assigned to parameter "arg2" of type "SupportsRichComparisonT@max" in function "max" Type "Unknown | None" is not assignable to type "int" "None" is not assignable to "int"
|
||||
pyright dm/gfx/tools/cb_extent.py reportOptionalOperand 1 Operator "<" not supported for "None"
|
||||
pyright dm/gfx/tools/dmsh_build.py reportArgumentType 1 Argument of type "str | None" cannot be assigned to parameter "file" of type "FileDescriptorOrPath" in function "open" Type "str | None" is not assignable to type "FileDescriptorOrPath" Type "None" is not assignable to type "FileDescriptorOrPath" "None" is not assignable to "int" "None" is not assignable to "str" "None" is not assignable to "bytes" "None" is incompatible with protocol "PathLike[str]" "__fspath__" is not present "None" is incompatible with protocol "PathLike[bytes]" ...
|
||||
pyright dm/gfx/tools/dmsh_build.py reportArgumentType 3 Argument of type "str | None" cannot be assigned to parameter "a" of type "BytesPath" in function "join" Type "str | None" is not assignable to type "BytesPath" Type "str" is not assignable to type "BytesPath" "str" is not assignable to "bytes" "str" is incompatible with protocol "PathLike[bytes]" "__fspath__" is not present
|
||||
pyright dm/gfx/tools/dmsh_build.py reportAttributeAccessIssue 1 Cannot access attribute "items" for class "str" Attribute "items" is unknown
|
||||
pyright dm/gfx/tools/dmsh_build.py reportAttributeAccessIssue 1 Cannot access attribute "lineno" for class "AST" Attribute "lineno" is unknown
|
||||
pyright dm/gfx/tools/dmsh_build.py reportCallIssue 1 No overloads for "open" match the provided arguments
|
||||
pyright dm/gfx/tools/dmsh_build.py reportCallIssue 3 No overloads for "join" match the provided arguments
|
||||
pyright dm/gfx/tools/dmsh_build.py reportGeneralTypeIssues 2 "None" is not iterable "__iter__" method not defined
|
||||
pyright dm/gfx/tools/dmsh_build.py reportOperatorIssue 1 Operator "+" not supported for types "Literal[128]" and "int | None" Operator "+" not supported for types "Literal[128]" and "None" when expected type is "int | Unknown"
|
||||
pyright dm/gfx/tools/dmsh_build.py reportOptionalMemberAccess 4 "group" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/dmsh_build.py reportOptionalSubscript 13 Object of type "None" is not subscriptable
|
||||
pyright dm/gfx/tools/gl_shaders.py reportArgumentType 1 Argument of type "list[str]" cannot be assigned to parameter "iterable" of type "Iterable[LiteralString]" in function "join" "list[str]" is not assignable to "Iterable[LiteralString]" Type parameter "_T_co@Iterable" is covariant, but "str" is not a subtype of "LiteralString" "str" is not assignable to "LiteralString"
|
||||
pyright dm/gfx/tools/gl_shaders.py reportCallIssue 1 No overloads for "join" match the provided arguments
|
||||
pyright dm/gfx/tools/own_compilers.py reportOptionalSubscript 3 Object of type "None" is not subscriptable
|
||||
pyright dm/gfx/tools/shader_split.py reportArgumentType 1 Argument of type "Literal['m_Name']" cannot be assigned to parameter "s" of type "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" in function "__getitem__" "Literal['m_Name']" is not assignable to "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]"
|
||||
pyright dm/gfx/tools/shader_split.py reportArgumentType 1 Argument of type "Literal['m_ParsedForm']" cannot be assigned to parameter "s" of type "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" in function "__getitem__" "Literal['m_ParsedForm']" is not assignable to "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]"
|
||||
pyright dm/gfx/tools/shader_split.py reportArgumentType 1 Argument of type "Literal['variants']" cannot be assigned to parameter "s" of type "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" in function "__getitem__" "Literal['variants']" is not assignable to "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]"
|
||||
pyright dm/gfx/tools/shader_split.py reportArgumentType 1 Argument of type "bytes | None" cannot be assigned to parameter "buffer" of type "ReadableBuffer" in function "unpack_from" Type "bytes | None" is not assignable to type "ReadableBuffer" "None" is incompatible with protocol "Buffer" "__buffer__" is not present
|
||||
pyright dm/gfx/tools/shader_split.py reportArgumentType 1 Argument of type "list[str | None]" cannot be assigned to parameter "args" of type "_CMD" in function "__init__" Type "str | None" is not assignable to type "StrOrBytesPath" Type "None" is not assignable to type "StrOrBytesPath" "None" is not assignable to "str" "None" is not assignable to "bytes" "None" is incompatible with protocol "PathLike[str]" "__fspath__" is not present "None" is incompatible with protocol "PathLike[bytes]" "__fspath__" is not present
|
||||
pyright dm/gfx/tools/shader_split.py reportArgumentType 2 Argument of type "Unknown | int | None" cannot be assigned to parameter "offset" of type "int" in function "unpack_from" Type "Unknown | int | None" is not assignable to type "int" "None" is not assignable to "int"
|
||||
pyright dm/gfx/tools/shader_split.py reportAssignmentType 1 Expression with type "tuple[Any, Any] | Any" cannot be assigned to target tuple Type "tuple[Any, Any]" is incompatible with target tuple Tuple size mismatch; expected 4 but received 2
|
||||
pyright dm/gfx/tools/shader_split.py reportAttributeAccessIssue 1 Cannot access attribute "get" for class "list[Any]" Attribute "get" is unknown
|
||||
pyright dm/gfx/tools/shader_split.py reportCallIssue 1 No overloads for "__init__" match the provided arguments
|
||||
pyright dm/gfx/tools/shader_split.py reportCallIssue 3 No overloads for "__getitem__" match the provided arguments
|
||||
pyright dm/gfx/tools/shader_split.py reportGeneralTypeIssues 2 "None" is not iterable "__iter__" method not defined
|
||||
pyright dm/gfx/tools/shader_split.py reportMissingImports 1 Import "backports" could not be resolved
|
||||
pyright dm/gfx/tools/shader_split.py reportOperatorIssue 1 Operator "<=" not supported for types "int" and "Any | tuple[Any, ...]" Operator "<=" not supported for types "int" and "tuple[Any, ...]"
|
||||
pyright dm/gfx/tools/shader_split.py reportOptionalIterable 5 Object of type "None" cannot be used as iterable value
|
||||
pyright dm/gfx/tools/shader_split.py reportOptionalMemberAccess 1 "flush" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/shader_split.py reportOptionalMemberAccess 2 "read" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/shader_split.py reportOptionalMemberAccess 2 "write" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/shader_split.py reportOptionalSubscript 1 Object of type "None" is not subscriptable
|
||||
pyright dm/gfx/tools/shader_split.py reportSelfClsParameterName 5 Instance methods should take a "self" parameter
|
||||
pyright dm/gfx/tools/smash_arc.py reportMissingImports 1 Import "backports" could not be resolved
|
||||
pyright dm/gfx/tools/uepak.py reportArgumentType 9 Argument of type "tuple[Any, Any, *tuple[Any, ...]] | Any" cannot be assigned to parameter "stop" of type "SupportsIndex" in function "__new__" Type "tuple[Any, Any, *tuple[Any, ...]] | Any" is not assignable to type "SupportsIndex" "tuple[Any, Any, *tuple[Any, ...]]" is incompatible with protocol "SupportsIndex" "__index__" is not present
|
||||
pyright dm/gfx/tools/uepak.py reportAssignmentType 4 Expression with type "tuple[Any, Any] | Any" cannot be assigned to target tuple Type "tuple[Any, Any]" is incompatible with target tuple Tuple size mismatch; expected 4 but received 2
|
||||
pyright dm/gfx/tools/uepak.py reportGeneralTypeIssues 1 Index 0 is out of range for type tuple[()]
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator "*" not supported for types "list[None]" and "tuple[Any, Any, *tuple[Any, ...]] | Any" Operator "*" not supported for types "list[None]" and "tuple[Any, Any, *tuple[Any, ...]]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator "+" not supported for types "Unknown | tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[53]" Operator "+" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[53]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator "+" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[15]" Operator "+" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[15]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator "+=" not supported for types "Unknown | Any | int" and "Unknown | Any | tuple[Any, Any, *tuple[Any, ...]]" Operator "+" not supported for types "int" and "tuple[Any, Any, *tuple[Any, ...]]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator "-=" not supported for types "Unknown | tuple[Any, Any, *tuple[Any, ...]] | Any" and "Unknown | tuple[Any, Any, *tuple[Any, ...]] | Any" Operator "-" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "tuple[Any, Any, *tuple[Any, ...]]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator "<" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[0]" Operator "<" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[0]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[22]" Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[22]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[23]" Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[23]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[29]" Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[29]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[30]" Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[30]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[31]" Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[31]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 1 Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[6]" Operator ">>" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[6]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 2 Operator "&" not supported for types "tuple[Any, Any, *tuple[Any, ...]] | Any" and "Literal[63]" Operator "&" not supported for types "tuple[Any, Any, *tuple[Any, ...]]" and "Literal[63]"
|
||||
pyright dm/gfx/tools/uepak.py reportOperatorIssue 2 Operator "+=" not supported for types "int | Unknown" and "tuple[Any, ...] | Any" Operator "+" not supported for types "int" and "tuple[Any, ...]"
|
||||
pyright dm/gfx/tools/uepak.py reportOptionalMemberAccess 1 "close" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/uepak.py reportOptionalMemberAccess 1 "flush" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/uepak.py reportOptionalMemberAccess 2 "read" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/uepak.py reportOptionalMemberAccess 2 "write" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/unityfs.py reportArgumentType 4 Argument of type "Any | tuple[Any, ...]" cannot be assigned to parameter "stop" of type "SupportsIndex" in function "__new__" Type "Any | tuple[Any, ...]" is not assignable to type "SupportsIndex" "tuple[Any, ...]" is incompatible with protocol "SupportsIndex" "__index__" is not present
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 1 Operator "+" not supported for types "int | Any" and "Any | tuple[Any, ...]" Operator "+" not supported for types "int" and "tuple[Any, ...]"
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 1 Operator "+=" not supported for types "int | Any" and "Any | tuple[Any, ...]" Operator "+" not supported for types "int" and "tuple[Any, ...]"
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 1 Operator "<" not supported for types "Any | tuple[Any, ...]" and "Literal[202012090]" Operator "<" not supported for types "tuple[Any, ...]" and "Literal[202012090]"
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 1 Operator "<=" not supported for types "Any | tuple[Any, ...]" and "int" Operator "<=" not supported for types "tuple[Any, ...]" and "int"
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 1 Operator "<=" not supported for types "Literal[201806140]" and "Any | tuple[Any, ...]" Operator "<=" not supported for types "Literal[201806140]" and "tuple[Any, ...]"
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 1 Operator ">=" not supported for types "Any | tuple[Any, ...]" and "Literal[201608170]" Operator ">=" not supported for types "tuple[Any, ...]" and "Literal[201608170]"
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 2 Operator "+" not supported for types "int" and "Any | tuple[Any, ...]" Operator "+" not supported for types "int" and "tuple[Any, ...]"
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 2 Operator "+=" not supported for types "int" and "Any | tuple[Any, ...]" Operator "+" not supported for types "int" and "tuple[Any, ...]"
|
||||
pyright dm/gfx/tools/unityfs.py reportOperatorIssue 2 Operator "<=" not supported for types "Literal[0]" and "Any | tuple[Any, ...]" Operator "<=" not supported for types "Literal[0]" and "tuple[Any, ...]"
|
||||
pyright dm/gfx/tools/unityfs.py reportSelfClsParameterName 4 Instance methods should take a "self" parameter
|
||||
pyright dm/gfx/tools/vk_shaders.py reportArgumentType 1 Argument of type "list[str]" cannot be assigned to parameter "iterable" of type "Iterable[LiteralString]" in function "join" "list[str]" is not assignable to "Iterable[LiteralString]" Type parameter "_T_co@Iterable" is covariant, but "str" is not a subtype of "LiteralString" "str" is not assignable to "LiteralString"
|
||||
pyright dm/gfx/tools/vk_shaders.py reportCallIssue 1 No overloads for "join" match the provided arguments
|
||||
pyright dm/gfx/tools/vk_shaders.py reportOptionalMemberAccess 2 "group" is not a known attribute of "None"
|
||||
pyright dm/gfx/tools/vk_shaders.py reportOptionalMemberAccess 2 "start" is not a known attribute of "None"
|
||||
pyright dm/ios/tools/pack_ipa.py reportCallIssue 1 Expected 4 positional arguments
|
||||
pyright dm/ios/tools/xcode_projects.py reportArgumentType 1 Argument of type "Element[str] | None" cannot be assigned to parameter "parent" of type "Element[Any]" in function "SubElement" Type "Element[str] | None" is not assignable to type "Element[Any]" "None" is not assignable to "Element[Any]"
|
||||
pyright dm/ios/tools/xcode_projects.py reportOptionalMemberAccess 1 "findall" is not a known attribute of "None"
|
||||
pyright dm/tools/check_thread_cuts.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/check_thread_cuts.py reportMissingImports 1 Import "unicorn" could not be resolved
|
||||
pyright dm/tools/check_thread_cuts.py reportMissingImports 1 Import "unicorn.arm64_const" could not be resolved
|
||||
pyright dm/tools/check_thread_cuts.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/check_thread_cuts.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/docs_symptoms.py reportOptionalMemberAccess 1 "group" is not a known attribute of "None"
|
||||
pyright dm/tools/gpuprof.py reportArgumentType 1 Argument of type "Unknown | None" cannot be assigned to parameter "value" of type "int" in function "__setitem__" Type "Unknown | None" is not assignable to type "int" "None" is not assignable to "int"
|
||||
pyright dm/tools/gpuprof.py reportOptionalMemberAccess 1 "split" is not a known attribute of "None"
|
||||
pyright dm/tools/make_ext_font.py reportOptionalSubscript 1 Object of type "None" is not subscriptable
|
||||
pyright dm/tools/nro_collect.py reportMissingImports 1 Import "backports" could not be resolved
|
||||
pyright dm/tools/nro_collect.py reportOptionalIterable 1 Object of type "None" cannot be used as iterable value
|
||||
pyright dm/tools/nso_fnmap.py reportMissingImports 1 Import "numpy" could not be resolved
|
||||
pyright dm/tools/nvn_slots_got.py reportOperatorIssue 1 Operator "+=" not supported for types "int | None" and "int" Operator "+" not supported for types "None" and "int"
|
||||
pyright dm/tools/nvn_slots_got.py reportOptionalOperand 2 Operator "+" not supported for "None"
|
||||
pyright dm/tools/patch_nso.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/patch_nso.py reportArgumentType 1 Argument of type "set[Unknown] | list[Unknown]" cannot be assigned to parameter "a" of type "SupportsLenAndGetItem[SupportsRichComparisonT@bisect_right]" in function "bisect_right" Type "set[Unknown] | list[Unknown]" is not assignable to type "SupportsLenAndGetItem[Unknown]" "set[Unknown]" is incompatible with protocol "SupportsLenAndGetItem[Unknown]" "__getitem__" is not present
|
||||
pyright dm/tools/patch_nso.py reportArgumentType 1 Argument of type "tuple[Any, ...] | None" cannot be assigned to parameter "iterable" of type "Iterable[SupportsRichComparisonT@max]" in function "max" Type "tuple[Any, ...] | None" is not assignable to type "Iterable[Any]" "None" is incompatible with protocol "Iterable[Any]" "__iter__" is not present
|
||||
pyright dm/tools/patch_nso.py reportArgumentType 4 Argument of type "str | None" cannot be assigned to parameter "string" of type "str" in function "fullmatch" Type "str | None" is not assignable to type "str" "None" is not assignable to "str"
|
||||
pyright dm/tools/patch_nso.py reportCallIssue 4 No overloads for "fullmatch" match the provided arguments
|
||||
pyright dm/tools/patch_nso.py reportIndexIssue 3 "__getitem__" method not defined on type "set[Unknown]"
|
||||
pyright dm/tools/patch_nso.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/patch_nso.py reportOptionalMemberAccess 1 "group" is not a known attribute of "None"
|
||||
pyright dm/tools/patch_nso.py reportOptionalMemberAccess 1 "groups" is not a known attribute of "None"
|
||||
pyright dm/tools/patch_nso.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/patch_nso.py reportOptionalMemberAccess 1 "op_str" is not a known attribute of "None"
|
||||
pyright dm/tools/patch_nso.py reportOptionalMemberAccess 1 "replace" is not a known attribute of "None"
|
||||
pyright dm/tools/patch_nso.py reportOptionalOperand 2 Operator "+" not supported for "None"
|
||||
pyright dm/tools/patch_nso.py reportOptionalOperand 2 Operator "<=" not supported for "None"
|
||||
pyright dm/tools/patch_nso.py reportOptionalSubscript 3 Object of type "None" is not subscriptable
|
||||
pyright dm/tools/patch_nso.py reportWildcardImportFromLibrary 1 Wildcard import from a library not allowed
|
||||
pyright dm/tools/sdis.py reportWildcardImportFromLibrary 1 Wildcard import from a library not allowed
|
||||
pyright dm/tools/tests/test_astral_fps.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportMissingImports 2 Import "unicorn" could not be resolved
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_ARCH_ARM64" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_ARM64_REG_LR" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_ARM64_REG_S1" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_ARM64_REG_S10" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_ARM64_REG_S8" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_ARM64_REG_SP" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_ARM64_REG_X19" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_ARM64_REG_X24" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "UC_MODE_ARM" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "Uc" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 2 "UC_ARM64_REG_NZCV" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 2 "UC_ARM64_REG_W21" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 2 "UC_ARM64_REG_X0" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 2 "UC_ARM64_REG_X1" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 2 "UC_ARM64_REG_X16" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 2 "UC_ARM64_REG_X17" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 2 "UC_ARM64_REG_X2" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 2 "UC_HOOK_CODE" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 3 "UC_ARM64_REG_S0" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 4 "UC_ARM64_REG_X8" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 6 "UC_ARM64_REG_PC" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_astral_fps.py reportOptionalMemberAccess 6 "UC_ARM64_REG_W8" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_bench.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_bench.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_bench.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_gpuprof.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_gpuprof.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_gpuprof.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_image_atomic_bounds.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_image_atomic_bounds.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_image_atomic_bounds.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_image_atomic_bounds.py reportOptionalSubscript 1 Object of type "None" is not subscriptable
|
||||
pyright dm/tools/tests/test_launcher_settings.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_launcher_settings.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_launcher_settings.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nro_graphics.py reportArgumentType 2 Argument of type "set[str]" cannot be assigned to parameter "nro_imports" of type "frozenset[Unknown]" in function "shader_sources" "set[str]" is not assignable to "frozenset[Unknown]"
|
||||
pyright dm/tools/tests/test_nro_pack.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nro_pack.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nro_pack.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nso_match.py reportIndexIssue 3 "__setitem__" method not defined on type "str"
|
||||
pyright dm/tools/tests/test_nsp_alias.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nsp_alias.py reportAttributeAccessIssue 1 Cannot assign to attribute "nacp" for class "ModuleType" Attribute "nacp" is unknown
|
||||
pyright dm/tools/tests/test_nsp_alias.py reportAttributeAccessIssue 1 Cannot assign to attribute "pg" for class "ModuleType" Attribute "pg" is unknown
|
||||
pyright dm/tools/tests/test_nsp_alias.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_alias.py reportOptionalMemberAccess 1 "id" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_alias.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_chain.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nsp_chain.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_chain.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_dotnet.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nsp_dotnet.py reportArgumentType 1 Argument of type "OSError | TimeoutExpired | CalledProcessError | CompletedProcess[str]" cannot be assigned to parameter "create" of type "bool" in function "object" Type "OSError | TimeoutExpired | CalledProcessError | CompletedProcess[str]" is not assignable to type "bool" "CalledProcessError" is not assignable to "bool"
|
||||
pyright dm/tools/tests/test_nsp_dotnet.py reportArgumentType 1 Argument of type "OSError | TimeoutExpired | CalledProcessError | CompletedProcess[str]" cannot be assigned to parameter "new_callable" of type "None" in function "object" Type "OSError | TimeoutExpired | CalledProcessError | CompletedProcess[str]" is not assignable to type "None" "CalledProcessError" is not assignable to "None"
|
||||
pyright dm/tools/tests/test_nsp_dotnet.py reportArgumentType 1 Argument of type "OSError | TimeoutExpired | CalledProcessError | CompletedProcess[str]" cannot be assigned to parameter "unsafe" of type "bool" in function "object" Type "OSError | TimeoutExpired | CalledProcessError | CompletedProcess[str]" is not assignable to type "bool" "CalledProcessError" is not assignable to "bool"
|
||||
pyright dm/tools/tests/test_nsp_dotnet.py reportCallIssue 1 No overloads for "object" match the provided arguments
|
||||
pyright dm/tools/tests/test_nsp_dotnet.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_dotnet.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_incremental.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nsp_incremental.py reportArgumentType 1 Argument of type "int | str | tuple[str, str]" cannot be assigned to parameter "ver" of type "str" in function "derive" Type "int | str | tuple[str, str]" is not assignable to type "str" "int" is not assignable to "str"
|
||||
pyright dm/tools/tests/test_nsp_incremental.py reportAttributeAccessIssue 1 Cannot assign to attribute "nacp" for class "ModuleType" Attribute "nacp" is unknown
|
||||
pyright dm/tools/tests/test_nsp_incremental.py reportAttributeAccessIssue 1 Cannot assign to attribute "pg" for class "ModuleType" Attribute "pg" is unknown
|
||||
pyright dm/tools/tests/test_nsp_incremental.py reportOptionalCall 2 Object of type "None" cannot be called
|
||||
pyright dm/tools/tests/test_nsp_incremental.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_incremental.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_mac.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nsp_mac.py reportOperatorIssue 1 Operator "in" not supported for types "Literal['IOSOUT']" and "Unknown | None" Operator "in" not supported for types "Literal['IOSOUT']" and "None"
|
||||
pyright dm/tools/tests/test_nsp_mac.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_mac.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_mac.py reportOptionalSubscript 1 Object of type "None" is not subscriptable
|
||||
pyright dm/tools/tests/test_nsp_mac_app.py reportArgumentType 1 Argument of type "Unknown | None" cannot be assigned to parameter "obj" of type "Sized" in function "len" Type "Unknown | None" is not assignable to type "Sized" "None" is incompatible with protocol "Sized" "__len__" is not present
|
||||
pyright dm/tools/tests/test_nsp_mac_app.py reportArgumentType 1 Argument of type "str | None" cannot be assigned to parameter "src" of type "StrPath" in function "copy2" Type "str | None" is not assignable to type "StrPath" Type "None" is not assignable to type "StrPath" "None" is not assignable to "str" "None" is incompatible with protocol "PathLike[str]" "__fspath__" is not present
|
||||
pyright dm/tools/tests/test_nsp_mac_app.py reportArgumentType 2 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nsp_mac_app.py reportCallIssue 1 No overloads for "copy2" match the provided arguments
|
||||
pyright dm/tools/tests/test_nsp_mac_app.py reportOptionalMemberAccess 2 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_mac_app.py reportOptionalMemberAccess 2 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_mac_app.py reportOptionalSubscript 4 Object of type "None" is not subscriptable
|
||||
pyright dm/tools/tests/test_nsp_nsz.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nsp_nsz.py reportArgumentType 2 Argument of type "Unknown | None" cannot be assigned to parameter "args" of type "StrPath" in function "__init__" Type "Unknown | None" is not assignable to type "StrPath" Type "None" is not assignable to type "StrPath" "None" is not assignable to "str" "None" is incompatible with protocol "PathLike[str]" "__fspath__" is not present
|
||||
pyright dm/tools/tests/test_nsp_nsz.py reportArgumentType 2 Argument of type "Unknown | None" cannot be assigned to parameter "args" of type "StrPath" in function "__new__" Type "Unknown | None" is not assignable to type "StrPath" Type "None" is not assignable to type "StrPath" "None" is not assignable to "str" "None" is incompatible with protocol "PathLike[str]" "__fspath__" is not present
|
||||
pyright dm/tools/tests/test_nsp_nsz.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_nsz.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_progress.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_nsp_progress.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_nsp_progress.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_patches.py reportArgumentType 1 Argument of type "Literal['CUTS', 'OBS', 'FRAME_STEP']" cannot be assigned to parameter "key" of type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" in function "__getitem__" Type "Literal['CUTS', 'OBS', 'FRAME_STEP']" is not assignable to type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" Type "Literal['CUTS']" is not assignable to type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" "Literal['CUTS']" is incompatible with protocol "SupportsIndex" "__index__" is not present "Literal['CUTS']" is not assignable to "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]"
|
||||
pyright dm/tools/tests/test_patches.py reportArgumentType 1 Argument of type "Literal['CUTS']" cannot be assigned to parameter "key" of type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" in function "__getitem__" Type "Literal['CUTS']" is not assignable to type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" "Literal['CUTS']" is incompatible with protocol "SupportsIndex" "__index__" is not present "Literal['CUTS']" is not assignable to "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]"
|
||||
pyright dm/tools/tests/test_patches.py reportArgumentType 1 Argument of type "tuple[Literal['CUTS', 'OBS', 'FRAME_STEP'], LiteralString]" cannot be assigned to parameter "key" of type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" in function "__getitem__" Type "tuple[Literal['CUTS', 'OBS', 'FRAME_STEP'], LiteralString]" is not assignable to type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" "tuple[Literal['CUTS', 'OBS', 'FRAME_STEP'], LiteralString]" is incompatible with protocol "SupportsIndex" "__index__" is not present "tuple[Literal['CUTS', 'OBS', 'FRAME_STEP'], LiteralString]" is not assignable to "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]"
|
||||
pyright dm/tools/tests/test_patches.py reportArgumentType 3 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_patches.py reportArgumentType 3 Argument of type "str" cannot be assigned to parameter "key" of type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" in function "__getitem__" Type "str" is not assignable to type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" "str" is incompatible with protocol "SupportsIndex" "__index__" is not present "str" is not assignable to "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]"
|
||||
pyright dm/tools/tests/test_patches.py reportArgumentType 5 Argument of type "Literal['MATCH_CUTS']" cannot be assigned to parameter "key" of type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" in function "__getitem__" Type "Literal['MATCH_CUTS']" is not assignable to type "SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]" "Literal['MATCH_CUTS']" is incompatible with protocol "SupportsIndex" "__index__" is not present "Literal['MATCH_CUTS']" is not assignable to "slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None]"
|
||||
pyright dm/tools/tests/test_patches.py reportIndexIssue 8 Object of type "Module("glob")" is not subscriptable
|
||||
pyright dm/tools/tests/test_patches.py reportIndexIssue 8 Object of type "Module("importlib")" is not subscriptable
|
||||
pyright dm/tools/tests/test_patches.py reportIndexIssue 8 Object of type "Module("os")" is not subscriptable
|
||||
pyright dm/tools/tests/test_patches.py reportOptionalMemberAccess 3 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_patches.py reportOptionalMemberAccess 3 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_pso_offline.py reportArgumentType 1 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_pso_offline.py reportOptionalMemberAccess 1 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_pso_offline.py reportOptionalMemberAccess 1 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_shader_regressions.py reportArgumentType 2 Argument of type "ModuleSpec | None" cannot be assigned to parameter "spec" of type "ModuleSpec" in function "module_from_spec" Type "ModuleSpec | None" is not assignable to type "ModuleSpec" "None" is not assignable to "ModuleSpec"
|
||||
pyright dm/tools/tests/test_shader_regressions.py reportOptionalMemberAccess 2 "exec_module" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_shader_regressions.py reportOptionalMemberAccess 2 "loader" is not a known attribute of "None"
|
||||
pyright dm/tools/tests/test_spin_waits.py reportArgumentType 1 Argument of type "list[FunctionDef | ClassDef | Assign]" cannot be assigned to parameter "body" of type "list[stmt]" in function "__init__" "list[FunctionDef | ClassDef | Assign]" is not assignable to "list[stmt]" Type parameter "_T@list" is invariant, but "FunctionDef | ClassDef | Assign" is not the same as "stmt" Consider switching from "list" to "Sequence" which is covariant
|
||||
pyright dm/tools/tests/test_tail_call.py reportCallIssue 3 Object of type "ModuleType" is not callable Attribute "__call__" is unknown
|
||||
pyright scripts/bench.py reportArgumentType 1 Argument of type "Unknown | None" cannot be assigned to parameter "number" of type "_SupportsRound2[_T@round]" in function "round" Type "Unknown | None" is not assignable to type "_SupportsRound2[_T@round]" "None" is incompatible with protocol "_SupportsRound2[_T@round]" "__round__" is not present
|
||||
pyright scripts/bench.py reportArgumentType 1 Argument of type "float" cannot be assigned to parameter "value" of type "int" in function "__setitem__" "float" is not assignable to "int"
|
||||
pyright scripts/bench.py reportCallIssue 1 No overloads for "round" match the provided arguments
|
||||
pyright scripts/bench.py reportOptionalMemberAccess 1 "group" is not a known attribute of "None"
|
||||
pyright scripts/bench.py reportOptionalOperand 1 Operator "/" not supported for "None"
|
||||
pyright scripts/build_ipa_from_nsp.py reportArgumentType 1 Argument of type "str | ((n: Unknown) -> (Unknown | None))" cannot be assigned to parameter "func" of type "(_T1@__new__) -> _S@map" in function "__new__" Type "str | ((n: Unknown) -> (Unknown | None))" is not assignable to type "(Unknown) -> _S@map" Type "str" is not assignable to type "(Unknown) -> _S@map"
|
||||
pyright scripts/build_ipa_from_nsp.py reportArgumentType 1 Argument of type "str | ((n: Unknown) -> (Unknown | None))" cannot be assigned to parameter "func" of type "(_T1@__new__) -> _S@map" in function "__new__" Type "str | ((n: Unknown) -> (Unknown | None))" is not assignable to type "(_T1@__new__) -> _S@map" Type "str" is not assignable to type "(_T1@__new__) -> _S@map"
|
||||
pyright scripts/build_ipa_from_nsp.py reportCallIssue 1 Argument expression after ** must be a mapping with a "str" key type
|
||||
pyright scripts/build_ipa_from_nsp.py reportCallIssue 1 No overloads for "__init__" match the provided arguments Argument types: (Unknown, str, str, str, str, **dict[str | ((n: Unknown) -> (Unknown | None)), str])
|
||||
pyright scripts/build_ipa_from_nsp.py reportOptionalIterable 1 Object of type "None" cannot be used as iterable value
|
||||
pyright scripts/build_ipa_from_nsp.py reportOptionalMemberAccess 1 "close" is not a known attribute of "None"
|
||||
pyright scripts/build_ipa_from_nsp.py reportOptionalOperand 1 Operator "-" not supported for "None"
|
||||
ruff dm/gfx/tools/dmsh_build.py F841 1 Local variable `sb_cb` is assigned to but never used
|
||||
ruff dm/gfx/tools/pso_offline.py F401 1 `shutil` imported but unused
|
||||
ruff dm/gfx/tools/shader_split.py B006 1 Do not use mutable data structures for argument defaults
|
||||
ruff dm/gfx/tools/shader_split.py B023 1 Function definition does not bind loop variable `c`
|
||||
ruff dm/gfx/tools/shader_split.py B023 1 Function definition does not bind loop variable `order`
|
||||
ruff dm/gfx/tools/shader_split.py B023 1 Function definition does not bind loop variable `tab`
|
||||
ruff dm/gfx/tools/shader_split.py B023 3 Function definition does not bind loop variable `r`
|
||||
ruff dm/gfx/tools/shader_split.py B023 3 Function definition does not bind loop variable `sec`
|
||||
ruff dm/gfx/tools/shader_split.py B023 3 Function definition does not bind loop variable `secs`
|
||||
ruff dm/gfx/tools/shader_split.py F841 1 Local variable `pre` is assigned to but never used
|
||||
ruff dm/gfx/tools/unityfs.py B023 2 Function definition does not bind loop variable `buf`
|
||||
ruff dm/tools/patch_nso.py B023 1 Function definition does not bind loop variable `at`
|
||||
ruff dm/tools/patch_nso.py B023 2 Function definition does not bind loop variable `n`
|
||||
ruff dm/tools/patch_nso.py PIE808 1 Unnecessary `start` argument in `range`
|
||||
ruff dm/tools/sdis.py F841 1 Local variable `lo` is assigned to but never used
|
||||
ruff dm/tools/tests/test_gpuprof.py F401 1 `os` imported but unused
|
||||
ruff dm/tools/tests/test_gpuprof.py F401 1 `sys` imported but unused
|
||||
ruff dm/tools/tests/test_image_atomic_bounds.py B023 1 Function definition does not bind loop variable `dependencies`
|
||||
ruff dm/tools/tests/test_nsp_incremental.py B023 1 Function definition does not bind loop variable `build`
|
||||
ruff dm/tools/tests/test_nsp_incremental.py B023 1 Function definition does not bind loop variable `own`
|
||||
ruff dm/tools/tests/test_nsp_incremental.py B023 1 Function definition does not bind loop variable `roots`
|
||||
ruff dm/tools/tests/test_nsp_incremental.py B023 1 Function definition does not bind loop variable `sh`
|
||||
ruff dm/tools/tests/test_nsp_nsz.py F401 1 `sys` imported but unused
|
||||
ruff dm/tools/tests/test_spin_waits.py F401 1 `sys` imported but unused
|
||||
ruff scripts/bench.py B023 1 Function definition does not bind loop variable `ok`
|
||||
ruff scripts/build_ipa_from_nsp.py B020 1 Loop control variable `note` overrides iterable it iterates
|
||||
ruff scripts/build_ipa_from_nsp.py F401 1 `zlib` imported but unused
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -0,0 +1,119 @@
|
||||
"""The lint baseline may grow only for a checker whose pinned version increased.
|
||||
Uses temporary Git trees; no linters, game files or keys needed.
|
||||
"""
|
||||
import collections
|
||||
import contextlib
|
||||
import io
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
import lint_python as lint
|
||||
|
||||
REQS = 'ruff==0.17.2\npyright==1.1.414\nlz4==4.4.5\n'
|
||||
RUFF = ('ruff', 'scripts/example.py', 'F821', 'Undefined name `missing`')
|
||||
PYRIGHT = ('pyright', 'scripts/example.py', 'reportUndefinedVariable', '"missing" is not defined')
|
||||
|
||||
|
||||
class BaselineGuard(unittest.TestCase):
|
||||
def setUp(self):
|
||||
tmp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(tmp.cleanup)
|
||||
self.root = Path(tmp.name).resolve()
|
||||
self.baseline = self.root / 'dm/tools/lint_python_baseline.tsv'
|
||||
self.baseline.parent.mkdir(parents=True)
|
||||
self.reqs = self.root / lint.REQS
|
||||
self.reqs.parent.mkdir(parents=True)
|
||||
self.reqs.write_text(REQS)
|
||||
patch = mock.patch.multiple(lint, REPO=self.root, BASELINE=self.baseline)
|
||||
patch.start(); self.addCleanup(patch.stop)
|
||||
self.base: collections.Counter[tuple[str, str, str, str]] = collections.Counter({RUFF: 1, PYRIGHT: 1})
|
||||
lint.write(self.base)
|
||||
self.git('init', '-q')
|
||||
self.git('add', '.')
|
||||
self.rev = self.git('write-tree')
|
||||
|
||||
def git(self, *args):
|
||||
return subprocess.run(['git', *args], cwd=self.root, capture_output=True, text=True, check=True).stdout.strip()
|
||||
|
||||
def compare(self, base):
|
||||
with contextlib.redirect_stdout(io.StringIO()) as out:
|
||||
rc = lint.against(self.rev, base)
|
||||
return rc, out.getvalue()
|
||||
|
||||
def grown(self, tool):
|
||||
base = self.base.copy()
|
||||
base[RUFF if tool == 'ruff' else PYRIGHT] += 1
|
||||
return base
|
||||
|
||||
def test_unchanged_and_shrunk_baselines_pass(self):
|
||||
for base in (self.base, collections.Counter({RUFF: 1}), collections.Counter()):
|
||||
with self.subTest(base=base): self.assertEqual(self.compare(base)[0], 0)
|
||||
|
||||
def test_new_entry_and_increased_count_fail_without_upgrade(self):
|
||||
added = self.base.copy()
|
||||
added[('ruff', 'scripts/another.py', 'F821', 'Undefined name `missing`')] = 1
|
||||
for base in (added, self.grown('ruff'), self.grown('pyright')):
|
||||
with self.subTest(base=base): self.assertEqual(self.compare(base)[0], 1)
|
||||
|
||||
def test_comments_whitespace_and_dependencies_do_not_allow_growth(self):
|
||||
edits = (REQS + '# comment only\n', REQS.replace('ruff==', 'ruff == ') + '\n',
|
||||
REQS.replace('4.4.5', '4.4.6'), REQS + 'capstone==5.0.9\n')
|
||||
for reqs in edits:
|
||||
self.reqs.write_text(reqs)
|
||||
with self.subTest(reqs=reqs): self.assertEqual(self.compare(self.base)[0], 0)
|
||||
for tool in ('ruff', 'pyright'):
|
||||
with self.subTest(reqs=reqs, tool=tool): self.assertEqual(self.compare(self.grown(tool))[0], 1)
|
||||
|
||||
def test_downgrades_do_not_allow_growth(self):
|
||||
for old, new in (('0.17.2', '0.17.1'), ('1.1.414', '1.1.413')):
|
||||
self.reqs.write_text(REQS.replace(old, new))
|
||||
with self.subTest(version=new): self.assertEqual(self.compare(self.base)[0], 0)
|
||||
for tool in ('ruff', 'pyright'):
|
||||
with self.subTest(version=new, tool=tool): self.assertEqual(self.compare(self.grown(tool))[0], 1)
|
||||
|
||||
def test_upgrade_allows_only_that_checkers_growth(self):
|
||||
for upgraded, old, new, other in (('ruff', '0.17.2', '0.18.0', 'pyright'), ('pyright', '1.1.414', '1.1.415', 'ruff')):
|
||||
self.reqs.write_text(REQS.replace(old, new))
|
||||
with self.subTest(tool=upgraded):
|
||||
self.assertEqual(self.compare(self.grown(upgraded))[0], 0)
|
||||
self.assertEqual(self.compare(self.grown(other))[0], 1)
|
||||
both = self.grown(upgraded); both.update({RUFF if other == 'ruff' else PYRIGHT: 1})
|
||||
self.assertEqual(self.compare(both)[0], 1)
|
||||
|
||||
def test_version_comparison_is_numeric(self):
|
||||
self.reqs.write_text(REQS.replace('0.17.2', '0.9.0'))
|
||||
self.assertEqual(self.compare(self.grown('ruff'))[0], 1)
|
||||
self.reqs.write_text(REQS.replace('0.17.2', '0.100.0'))
|
||||
self.assertEqual(self.compare(self.grown('ruff'))[0], 0)
|
||||
|
||||
def test_both_upgrades_allow_both_checkers_growth(self):
|
||||
self.reqs.write_text(REQS.replace('0.17.2', '0.18.0').replace('1.1.414', '1.1.415'))
|
||||
self.assertEqual(self.compare(collections.Counter({RUFF: 2, PYRIGHT: 2}))[0], 0)
|
||||
|
||||
def test_missing_or_invalid_pins_fail_closed(self):
|
||||
edits = (REQS.replace('ruff==0.17.2\n', ''), REQS.replace('ruff==0.17.2', 'ruff>=0.18.0'),
|
||||
REQS.replace('0.17.2', 'invalid'), REQS + 'ruff==0.18.0\n')
|
||||
for reqs in edits:
|
||||
self.reqs.write_text(reqs)
|
||||
with self.subTest(reqs=reqs): self.assertEqual(self.compare(self.grown('ruff'))[0], 1)
|
||||
|
||||
def test_missing_base_requirements_fail_closed(self):
|
||||
self.git('rm', '--cached', '-q', lint.REQS)
|
||||
self.rev = self.git('write-tree')
|
||||
self.reqs.write_text(REQS)
|
||||
self.assertEqual(self.compare(self.grown('ruff'))[0], 1)
|
||||
|
||||
def test_first_baseline_needs_no_previous_requirements(self):
|
||||
self.git('rm', '--cached', '-q', lint.rel(self.baseline), lint.REQS)
|
||||
self.rev = self.git('write-tree')
|
||||
self.reqs.write_text(REQS)
|
||||
self.assertEqual(self.compare(self.base)[0], 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -71,6 +71,26 @@ Generated projects and Xcode build products stay in that folder; the host profil
|
||||
header is generated under `dm/host/gen/` as usual. CI uploads failure logs.
|
||||
GPU regression tests still run locally with `make -C dm/gfx/tests GAME=<id> run`.
|
||||
|
||||
`.github/workflows/lint-python.yml` lints `scripts/` and the Python tools under
|
||||
`dm/` with ruff (rules for bugs, never reformatting) and type-checks them with
|
||||
pyright in basic mode (`pyproject.toml`). It is a ratchet: today's findings are
|
||||
in `dm/tools/lint_python_baseline.tsv`, so it fails only on a new finding, or on
|
||||
a fixed one still listed there. Astral's ty, a faster type checker, can replace
|
||||
pyright once it is stable. With the pinned tools in a new venv:
|
||||
|
||||
```sh
|
||||
python3 -m venv /path/to/lint-venv && /path/to/lint-venv/bin/pip install -r .github/requirements/lint.txt
|
||||
/path/to/lint-venv/bin/python3 dm/tools/lint_python.py # the check CI runs
|
||||
/path/to/lint-venv/bin/python3 dm/tools/lint_python.py --update # after fixing findings: shrink the baseline
|
||||
```
|
||||
|
||||
The baseline never gains entries: fix a new finding, or silence it on its line
|
||||
(`# noqa: <rule>`, `# pyright: ignore[<rule>]`) with a reason. Only a raised tool
|
||||
version in `.github/requirements/lint.txt` rewrites it (`--rebaseline`). On pull
|
||||
requests, only the checker whose pinned release version increased may gain
|
||||
baseline entries or counts. Comments, dependency updates and checker downgrades
|
||||
do not allow growth.
|
||||
|
||||
## The packing script in detail
|
||||
|
||||
`scripts/build_ipa_from_nsp.py` (`-h` lists every option):
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Configuration of the Python lint and type checks only (.github/workflows/lint-python.yml, dm/tools/lint_python.py); the repository is not a Python package.
|
||||
# Scope: scripts/ and the tools under dm/. extraPaths / extra-paths are the folders the tools put on sys.path to import each other.
|
||||
|
||||
[tool.pyright]
|
||||
include = ["scripts", "dm/tools", "dm/gfx/tools", "dm/games/game.py", "dm/games/profile_guess.py", "dm/games/settings.py", "dm/ios/tools", "dm/mac"]
|
||||
extraPaths = ["dm/tools", "dm/gfx/tools", "dm/games", "dm/ios/tools", "dm/mac"]
|
||||
typeCheckingMode = "basic"
|
||||
pythonVersion = "3.14"
|
||||
pythonPlatform = "Darwin"
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py310"
|
||||
include = ["scripts/**/*.py", "dm/tools/**/*.py", "dm/gfx/tools/**/*.py", "dm/games/*.py", "dm/ios/tools/**/*.py", "dm/mac/**/*.py"]
|
||||
|
||||
# Rules that find bugs (pyflakes, syntax, bugbear, pylint's errors and warnings, a few of ruff's own), not style: the code's dense layout (several statements on a
|
||||
# line, star imports of the rewriter's tables, short names) is the house style, so those rules are off, and `ruff format` is not used.
|
||||
[tool.ruff.lint]
|
||||
select = ["F", "E7", "E9", "B", "PLE", "PLW", "PIE", "ISC001", "T10", "RUF006", "RUF008", "RUF009", "RUF013", "RUF016", "RUF017", "RUF018", "RUF024", "RUF026"]
|
||||
ignore = ["F403", "F405", "E701", "E702", "E731", "E741", "B007", "B905", "PLW0603", "PLW1510", "PLW2901"]
|
||||
Reference in new issue
Block a user