Skip to content

Improve error message for module-level __getattr__ issues#14170

Open
veeceey wants to merge 3 commits intopytest-dev:mainfrom
veeceey:fix/issue-8265-getattr-error-message
Open

Improve error message for module-level __getattr__ issues#14170
veeceey wants to merge 3 commits intopytest-dev:mainfrom
veeceey:fix/issue-8265-getattr-error-message

Conversation

@veeceey
Copy link

@veeceey veeceey commented Feb 8, 2026

Summary

Fixes #8265

This PR improves the error message when a module-level __getattr__ returns None instead of raising AttributeError.

Problem

When a module defines a custom __getattr__ that returns None instead of raising AttributeError, pytest gives a cryptic error message:

TypeError: got None instead of Mark

This is confusing for users who don't understand what a "Mark" is or why pytest is looking for one.

Solution

Added a special check in get_unpacked_marks() to detect when the pytestmark attribute resolves to None and emit a PytestCollectionWarning that explains:

  1. What the likely cause is (module-level __getattr__)
  2. What the fix is (raise AttributeError)

Changes

  • Modified get_unpacked_marks() in /src/_pytest/mark/structures.py to detect None and emit a warning
  • Added test case to verify the new warning message
  • Added changelog entry

Test plan

When a module defines a custom __getattr__ that returns None instead
of raising AttributeError, pytest now provides a helpful error message
explaining the likely cause and suggesting the fix.

The previous error was: "got None instead of Mark"
The new error includes: "this is likely caused by a module-level
__getattr__ that does not raise AttributeError for missing attributes"

Fixes pytest-dev#8265
@psf-chronographer psf-chronographer bot added the bot:chronographer:provided (automation) changelog entry is part of PR label Feb 8, 2026
Copy link
Member

@RonnyPfannschmidt RonnyPfannschmidt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the wrong place for the check there should be a warning triggered in the helper to get that list

…marks

Per reviewer feedback, move the check for module-level __getattr__
returning None to get_unpacked_marks() (the helper that fetches the
mark list) instead of normalize_mark_list(). Also change from raising
a TypeError to emitting a PytestCollectionWarning, so the module can
still be collected normally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@veeceey
Copy link
Author

veeceey commented Feb 9, 2026

Thanks for the review @RonnyPfannschmidt! You're right — the check was in the wrong place.

I've moved it from normalize_mark_list() to get_unpacked_marks(), which is the helper that actually fetches the pytestmark attribute list. Now when a module-level __getattr__ returns None instead of raising AttributeError, a PytestCollectionWarning is emitted (instead of raising a TypeError), and the module continues to be collected normally.

Changes in the latest push:

  • Moved the None check to get_unpacked_marks() where getattr(obj, "pytestmark", []) is called
  • Changed from raising TypeError to emitting a PytestCollectionWarning
  • Updated the test and changelog accordingly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided (automation) changelog entry is part of PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cryptic Error Message when module-level __getattr__ fails to raise AttributeError

2 participants