Skip to content

Improve error handling for Windows and MSS context#519

Merged
BoboTiG merged 5 commits intoBoboTiG:mainfrom
halldorfannar:task/improve-error-handling
Apr 29, 2026
Merged

Improve error handling for Windows and MSS context#519
BoboTiG merged 5 commits intoBoboTiG:mainfrom
halldorfannar:task/improve-error-handling

Conversation

@halldorfannar
Copy link
Copy Markdown
Contributor

@halldorfannar halldorfannar commented Apr 28, 2026

Changes proposed in this PR

We essentially had three problems:

  1. The error handling in Windows was slightly confusing where a Windows error object was created when it should not have been. This object was not being returned but it made log reading confusing. We now have two separate error handling functions and only create the Windows error object when we truly have a last error from Windows.
  2. The MSS context object was masking inner exceptions (from with scope) with outer exceptions (generated during __exit__) - this led to the wrong exception being surfaced by our tests. The MSS Context object has been enhanced to not mask the inner exception with an outer exception. Once Python 3.11 becomes baseline we can use ExceptionGroups to surface both exceptions and still get the right outcome, but until then the common pattern I applied here will suffice.
  3. The thread tests were not designed to propagate exceptions back to the main thread, which is required so that the test can report the correct failure. This has been fixed and made available in a separate file so this mistake does not get repeated.

This relates to pull request #516. If you combine this with that you will see massive improvements in the error handling.

  • Tests added/updated
  • Documentation updated
  • Changelog entry added
  • ./check.sh passed

Comment thread src/mss/base.py
try:
self.close()
except Exception:
# This extra work is needed so that exceptions generated during __exit__
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Wouldn't these normally be chained? Is there a reason not to use chained exceptions here? I'm a little hesitant to just swallow exceptions entirely.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No. When a with body is already failing, and __exit__ also fails during cleanup, chaining creates the wrong relationship and headline. Python/pytest reports the exception raised from __exit__ as the active failure, so the real body failure becomes secondary context. That was the ReleaseDC masking the actual BitBlt/thread failure in the PR that triggered this work.

Python 3.11 has a new feature that is designed for this case, https://docs.python.org/3/library/exceptions.html#lib-exception-groups - but we cannot use that since we support 3.10.

Make the thread helper available separately so it can be reused in the future. That will hopefully prevent this accident going forward.
@halldorfannar halldorfannar marked this pull request as ready for review April 29, 2026 12:32
@BoboTiG BoboTiG merged commit 4c05ba9 into BoboTiG:main Apr 29, 2026
18 checks passed
@BoboTiG
Copy link
Copy Markdown
Owner

BoboTiG commented Apr 29, 2026

Thanks @halldorfannar !

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants