Repository navigation
ref(typing)!: enforce strict mypy across Sentry's Python codebase (types only) - #129614
sentry-junior[bot] wants to merge 1 commit into
Conversation
82096e2 to
9fda5d0
Compare
decision-model-linterapi
audit
decision-model-linter: 3423 calls on 1214 files, 7,322,057 input tokens, $0.31, model typesafe/jev-1.13-20260917 |
|
|
||
| try: | ||
| # grab the filter out of the brackets of the string that looks | ||
| # like so: members[value eq "123124"] | ||
| regex_search = re.search(r"\[(.*?)\]", operation["path"]) | ||
| regex_search = re.search(r"\[(.*?)\]", cast(str, operation["path"])) |
Turn on `strict = true` for the whole codebase and empty the mypy weaklist. This change is types only and keeps master's runtime behavior. Behavior fixes land as separate PRs on top. - `strict = true` with `warn_return_any = false`. There are no `return cast(...)` calls or runtime guards that exist only to satisfy `no-any-return`. - Where strict typing and master behavior conflict, master wins: use a cast, `Any`, or a scoped `# type: ignore[...]`, for example the paginator `order_b` typo that #127799 fixes. - The `get_mapping`/`post_mapping`/`get_sequence` client helpers are pure casts and never raise for an unexpected shape. - `Bounded*Field` stay bare subclasses (`# type: ignore[type-arg]`), so call sites don't need `[int | None, int | None]` subscripts. Co-Authored-By: Joshua Li <14209781+joshuarli@users.noreply.github.com>
9fda5d0 to
73fa505
Compare
|
This PR is too large for Bugbot to review. It changes 24,218 lines and 3,674,192 characters. Split the change into smaller pull requests to get a review. |
| csv_content = cast(str, self._generate_csv(projects)) | ||
| response = HttpResponse(content_type="text/csv", status=200) | ||
| response["Content-Disposition"] = 'attachment; filename="stats_summary.csv"' | ||
| response.write(csv_content) | ||
| return response |
There was a problem hiding this comment.
Empty stats download writes None into HttpResponse
_generate_csv returns None for empty projects; cast(str, ...) is a no-op at runtime, so response.write(None) raises AttributeError. Return an empty string instead of None when there are no projects.
Evidence
massage_sessions_result_summaryreturnsprojects={}when Snuba totals are empty (e.g. future/empty range; covered bytest_future_request).- On
download, line 174 doescast(str, self._generate_csv(projects));castdoes not convert None. _generate_csvreturns None whennot len(projects)(lines 212-213).response.write(csv_content)then calls.encodeon None and raises AttributeError.
Identified by Warden · sentry-backend-bugs · BKS-KKR
This is the types-only version of #129447. It turns on
strict = truefor the whole codebase and empties the mypy weaklist. It keeps today's master runtime behavior. The behavior fixes that were folded into #129447 come back as separate PRs stacked on this branch.Changes from #129447
strict = truewithwarn_return_any = false. Theno-any-returnerrors were most of the work, and fixing them addedreturn cast(...)calls,isinstance/raise TypeErrorguards, and# justification:comments. Those are gone.cast, anAny, or a scoped# type: ignore[...]. Examples:order_btypo is still there behind# type: ignore[attr-defined]. fix(api): Reverse previous-page ordering for descending paginators #129615 fixes it.or 0, coercions withstr()/int()/bool(), defensive copies that changed in-place mutation, and serializer output are back to master.get_mapping,post_mappingandget_sequenceinshared_integrations/client/base.pyare pure casts. They no longer raiseApiErrorwhen a response has an unexpected shape.Bounded*Fieldare bare subclasses again, with# type: ignore[type-arg]on 7 class lines. The[int | None, int | None]subscripts are gone from call sites. These fields type-check asAny, as they do on master.check_typing_campaign.pywith its hook and tests, the weaklist sort tooling, the.github/workflows/pre-commit.ymlrewrite, and theinviteStatusnullability change instatic/app/types/organization.tsx.allow_redefinition = true. Under mypy 2.1 it adds about 150 errors in existing code, so it's off and the variable renames stay.Rebased on master (
e39c07b6). Conflicts were resolved in master's favor, with types added on top. Master code added since the old base needed a few more stub entries infixtures/stubs-for-mypy(PGAccessExclusive/PGLock, two selenium exceptions,WebDriverWait.untilacceptingLiteral[False]) and annotations on a handful of new tests.Deliberately left in
assert x is not Nonelines for type narrowing. I haven't checked each one against master behavior.UNBOUNDED_DATETIME = cast("datetime", None)intests/snuba/search/test_backend.py. Wideningsnuba_searchtodatetime | Nonespreads intorun_eap_group_searchand_prepare_params_for_categories.Stack (all based on this branch, land after it):
order_bytypo (was fix(api): Reverse previous-page ordering for descending paginators #127799)#129433 isn't restacked. Master's
owned_by_acting_user()already returnsQ(pk__in=[])for anonymous users, so those queries are skipped there.No getsentry change needed. getsentry's
backend typingflagged 7 errors against an earlier push of this branch. Each one was a Sentry signature this PR had made narrower than master's contract, so they're fixed here, not in getsentry:BaseApiClient.request/get/get_cached/post/put/patch/delete/head_cachedreturnAnyagain, as on master. Theget_mapping/get_sequencehelpers keep their typed returns.OAuth2Provider.get_oauth_client_id()returnsAny. getsentry overrides it with an option typedstr | int.AbstractFile.getfile()returnsAny. getsentry's uploader treats it as aBufferedIOBase.BidirectionalMappingis generic in its values (BidirectionalMapping[KT, VT]), so lookups inferstrinstead ofobject.BitFieldsubclassesBigIntegerField[Any, Any], sosubscription.flags.<name>resolves the way it does on master.The
BitFieldfix also restores two master behaviors the earlier push had changed: plain string flags are added tolabelsagain, and_arg_flagsholds the normalized flag list again, which is whatdeconstruct()writes into migrations.getsentry/getsentry#22868 is no longer needed for this PR.
Verification
mypy(full repo, strict):Success: no issues found in 8527 source files, on this branch and on this branch with all 10 stacked PRs applied.ruff check/ruff format --checkon the changed Python files, plusruff --select F821,F401acrosssrcandtests.scripts.*anddevlocalmodules missing in my sandbox) and 3 are already ingetsentry/jobs/migrate_legacy_seer.py. None come from this PR.Supersedes #129447 (fork branch, so I couldn't push to it).
via @joshuarli.
--
View Session [Sentry]