Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[pydoclint] Fix false positive for exceptions raised via classmethods and chained calls (DOC501, DOC502)#23637

Open
bxff wants to merge 2 commits intoastral-sh:mainfrom
bxff:investigate/doc501-classmethod-exception
Open

[pydoclint] Fix false positive for exceptions raised via classmethods and chained calls (DOC501, DOC502)#23637
bxff wants to merge 2 commits intoastral-sh:mainfrom
bxff:investigate/doc501-classmethod-exception

Conversation

@bxff
Copy link
Contributor

@bxff bxff commented Feb 28, 2026

Summary

Fixes #23570.

raise ValueError.from_exception_data(...) causes DOC501 to report from_exception_data as the missing exception instead of ValueError, and DOC502 to flag ValidationError as not raised. The same happens with chained calls like raise Error.create(...).with_traceback(tb).

The issue is that map_callable unwraps the call, leaving an Expr::Attribute (ValueError.from_exception_data), and resolve_qualified_name then resolves the method name rather than the class.

This replaces the map_callable + resolve_qualified_name one-shot with a loop that peels off Call+Attribute layers until it hits a resolvable name. Bare attribute raises like raise module.SomeError are unaffected since they skip the loop entirely.

Test Plan

Added test cases to DOC501_google.py for classmethod raises (documented + undocumented), imported exceptions via classmethod, and chained .with_traceback() calls. All 18 pydoclint tests pass, no regressions on existing raise something.SomeError tests.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 28, 2026

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+34 -33 violations, +0 -0 fixes in 6 projects; 50 projects unchanged)

DisnakeDev/disnake (+13 -10 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- disnake/ext/commands/bot_base.py:561:9: DOC501 Raised exception `CheckFailure` missing from docstring
+ disnake/ext/commands/bot_base.py:561:9: DOC501 Raised exception `errors` missing from docstring
+ disnake/ext/commands/common_bot_base.py:161:9: DOC501 Raised exception `disnake` missing from docstring
- disnake/ext/commands/common_bot_base.py:161:9: DOC502 Raised exception is not explicitly raised: `CommandError`
+ disnake/ext/commands/common_bot_base.py:161:9: DOC502 Raised exceptions are not explicitly raised: `CommandError`, `ClientException`
+ disnake/ext/commands/common_bot_base.py:340:9: DOC501 Raised exception `errors` missing from docstring
+ disnake/ext/commands/common_bot_base.py:340:9: DOC502 Raised exceptions are not explicitly raised: `ExtensionNotFound`, `ExtensionAlreadyLoaded`, `NoEntryPointError`, `ExtensionFailed`
- disnake/ext/commands/common_bot_base.py:340:9: DOC502 Raised exceptions are not explicitly raised: `NoEntryPointError`, `ExtensionFailed`
+ disnake/ext/commands/common_bot_base.py:386:9: DOC501 Raised exception `errors` missing from docstring
- disnake/ext/commands/common_bot_base.py:386:9: DOC502 Raised exception is not explicitly raised: `ExtensionNotFound`
+ disnake/ext/commands/common_bot_base.py:386:9: DOC502 Raised exceptions are not explicitly raised: `ExtensionNotFound`, `ExtensionNotLoaded`
+ disnake/ext/commands/common_bot_base.py:426:9: DOC501 Raised exception `errors` missing from docstring
- disnake/ext/commands/common_bot_base.py:426:9: DOC502 Raised exceptions are not explicitly raised: `ExtensionNotFound`, `NoEntryPointError`, `ExtensionFailed`
+ disnake/ext/commands/common_bot_base.py:426:9: DOC502 Raised exceptions are not explicitly raised: `ExtensionNotLoaded`, `ExtensionNotFound`, `NoEntryPointError`, `ExtensionFailed`
- disnake/ext/commands/interaction_bot_base.py:1392:9: DOC501 Raised exception `CheckFailure` missing from docstring
+ disnake/ext/commands/interaction_bot_base.py:1392:9: DOC501 Raised exception `errors` missing from docstring
- disnake/ext/commands/params.py:633:9: DOC501 Raised exception `MemberNotFound` missing from docstring
... 7 additional changes omitted for rule DOC501
... 6 additional changes omitted for project

apache/airflow (+9 -11 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL

- airflow-core/src/airflow/utils/process_utils.py:193:5: DOC501 Raised exception `CalledProcessError` missing from docstring
+ airflow-core/src/airflow/utils/process_utils.py:193:5: DOC501 Raised exception `subprocess` missing from docstring
- dev/breeze/src/airflow_breeze/utils/click_validators.py:26:5: DOC501 Raised exception `BadParameter` missing from docstring
+ dev/breeze/src/airflow_breeze/utils/click_validators.py:26:5: DOC501 Raised exception `click` missing from docstring
- dev/stats/get_important_pr_candidates.py:72:5: DOC501 Raised exception `ClickException` missing from docstring
+ dev/stats/get_important_pr_candidates.py:72:5: DOC501 Raised exception `rich_click` missing from docstring
- providers/google/src/airflow/providers/google/cloud/hooks/kubernetes_engine.py:138:9: DOC501 Raised exception `GoogleCloudError` missing from docstring
+ providers/google/src/airflow/providers/google/cloud/hooks/kubernetes_engine.py:138:9: DOC501 Raised exception `exceptions` missing from docstring
- providers/google/src/airflow/providers/google/common/utils/id_token_credentials.py:194:5: DOC501 Raised exception `DefaultCredentialsError` missing from docstring
+ providers/google/src/airflow/providers/google/common/utils/id_token_credentials.py:194:5: DOC501 Raised exception `exceptions` missing from docstring
- providers/google/src/airflow/providers/google/common/utils/id_token_credentials.py:83:5: DOC501 Raised exception `DefaultCredentialsError` missing from docstring
+ providers/google/src/airflow/providers/google/common/utils/id_token_credentials.py:83:5: DOC501 Raised exception `exceptions` missing from docstring
- providers/google/src/airflow/providers/google/go_module_utils.py:29:5: DOC501 Raised exception `CalledProcessError` missing from docstring
+ providers/google/src/airflow/providers/google/go_module_utils.py:29:5: DOC501 Raised exception `subprocess` missing from docstring
... 6 additional changes omitted for project

apache/superset (+2 -3 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL

- superset/cli/export_example.py:103:5: DOC501 Raised exception `ClickException` missing from docstring
- superset/cli/export_example.py:103:5: DOC501 Raised exception `UsageError` missing from docstring
+ superset/cli/export_example.py:103:5: DOC501 Raised exception `click` missing from docstring
- superset/cli/mcp.py:33:5: DOC501 Raised exception `ClickException` missing from docstring
+ superset/cli/mcp.py:33:5: DOC501 Raised exception `click` missing from docstring

langchain-ai/langchain (+2 -2 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- libs/partners/mistralai/langchain_mistralai/chat_models.py:179:5: DOC501 Raised exception `HTTPStatusError` missing from docstring
+ libs/partners/mistralai/langchain_mistralai/chat_models.py:179:5: DOC501 Raised exception `httpx` missing from docstring
- libs/partners/mistralai/langchain_mistralai/chat_models.py:194:5: DOC501 Raised exception `HTTPStatusError` missing from docstring
+ libs/partners/mistralai/langchain_mistralai/chat_models.py:194:5: DOC501 Raised exception `httpx` missing from docstring

zulip/zulip (+4 -3 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL

- zerver/lib/scim.py:137:9: DOC501 Raised exception `BadRequestError` missing from docstring
+ zerver/lib/scim.py:137:9: DOC501 Raised exception `exceptions` missing from docstring
+ zerver/lib/scim.py:225:9: DOC501 Raised exception `exceptions` missing from docstring
- zerver/lib/scim.py:262:9: DOC501 Raised exception `BadRequestError` missing from docstring
+ zerver/lib/scim.py:262:9: DOC501 Raised exception `exceptions` missing from docstring
- zerver/lib/scim.py:351:9: DOC501 Raised exception `BadRequestError` missing from docstring
+ zerver/lib/scim.py:351:9: DOC501 Raised exception `exceptions` missing from docstring

wntrblm/nox (+4 -4 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- nox/_options.py:210:5: DOC501 Raised exception `ArgumentError` missing from docstring
+ nox/_options.py:210:5: DOC501 Raised exception `_option_set` missing from docstring
- nox/_options.py:263:5: DOC501 Raised exception `ArgumentError` missing from docstring
+ nox/_options.py:263:5: DOC501 Raised exception `_option_set` missing from docstring
- nox/sessions.py:339:9: DOC501 Raised exception `CommandFailed` missing from docstring
+ nox/sessions.py:339:9: DOC501 Raised exception `command` missing from docstring
- tests/test_command.py:276:5: DOC501 Raised exception `WinError` missing from docstring
+ tests/test_command.py:276:5: DOC501 Raised exception `ctypes` missing from docstring

Changes by rule (2 rules affected)

code total + violation - violation + fix - fix
DOC501 59 30 29 0 0
DOC502 8 4 4 0 0

@bxff bxff force-pushed the investigate/doc501-classmethod-exception branch from 398651f to cd49412 Compare February 28, 2026 20:08
@bxff bxff changed the title [pydoclint] Fix false positive for exception raised via classmethod (DOC501, DOC502) [pydoclint] Fix false positive for exceptions raised via classmethods and chained calls (DOC501, DOC502) Feb 28, 2026
…ds and chained calls (`DOC501`, `DOC502`)

When an exception is raised via a classmethod, factory method, or chained method call (e.g., `raise ValueError.from_exception_data(...)` or `raise Error.create(...).with_traceback(tb)`), the rule incorrectly extracted the method name as the exception type instead of the class name.

The fix replaces the simple `map_callable` + `resolve_qualified_name` approach with a loop that recursively unwraps method chain calls (Call+Attribute layers) until it reaches a resolvable name. This correctly handles:
- `raise Error(...)` → resolves `Error`
- `raise Error.from_data(...)` → resolves `Error`
- `raise Error.create(...).with_traceback(tb)` → resolves `Error`
- `raise module.Error` → resolves `module.Error` (bare attribute, not unwrapped)
@bxff bxff force-pushed the investigate/doc501-classmethod-exception branch from cd49412 to d8b50f5 Compare February 28, 2026 20:13
@ntBre ntBre added bug Something isn't working docstring Related to docstring linting or formatting labels Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working docstring Related to docstring linting or formatting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[pydoclint] DOC501: False positive for exception created via classmethod

3 participants