Skip to content

Fix UnboundLocalError when all struct packings fail in calc_packing#942

Merged
junkmd merged 1 commit into
enthought:mainfrom
ryanda9910:fix-937-calc-packing-unbound-details
Jun 16, 2026
Merged

Fix UnboundLocalError when all struct packings fail in calc_packing#942
junkmd merged 1 commit into
enthought:mainfrom
ryanda9910:fix-937-calc-packing-unbound-details

Conversation

@ryanda9910

Copy link
Copy Markdown
Contributor

Problem

comtypes.client.CreateObject(...) (via GetModule -> code generation) can crash with:

File ".../comtypes/tools/codegenerator/packing.py", line 58, in calc_packing
    raise PackingError(f"PACKING FAILED: {details}")
UnboundLocalError: local variable 'details' referenced before assignment

instead of reporting the actual struct-layout problem. This was reported in #937 when generating wrappers for a vendor type library whose structure layout could not be matched.

Root cause

calc_packing() tries several packings and, on the failure path, re-raises with the captured error:

for pack in [None, 16 * 8, 8 * 8, 4 * 8, 2 * 8, 1 * 8]:
    try:
        _calc_packing(struct, fields, pack, isStruct)
    except PackingError as details:
        continue
    ...
raise PackingError(f"PACKING FAILED: {details}")

In Python 3 the except ... as details target is deleted when the except block ends (see the language reference). So when every packing attempt fails and execution reaches the final raise, details is unbound. The resulting UnboundLocalError masks the real PackingError and its diagnostic message.

Fix

Store the last PackingError in a separate variable that survives the loop, and use it in the final raise. The real layout error is now reported:

PackingError: PACKING FAILED: field x offset (0/8)

The change is minimal and does not alter behaviour for structs that pack successfully.

Test evidence

Added comtypes/test/test_packing.py with regression coverage for calc_packing:

  • successful default packing returns None
  • incomplete struct (size is None) returns None
  • an inconsistent layout raises PackingError whose message preserves the underlying reason ("PACKING FAILED: ... field x offset ...")

Before the fix the regression test fails with UnboundLocalError; after the fix all tests pass.

test_incomplete_struct_returns_none ... ok
test_raises_packing_error_with_details_when_layout_is_inconsistent ... ok
test_returns_none_for_default_packing ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK

ruff check and ruff format --check pass on both changed files.

Note: comtypes only imports on Windows, so the new tests were exercised by loading comtypes.tools.codegenerator.packing / comtypes.tools.typedesc_base directly. On the Windows CI they run via the standard unittest discover.

Fixes #937

When every packing attempt in calc_packing() raises PackingError, the
final 'raise PackingError(f"PACKING FAILED: {details}")' referenced the
'except ... as details' target after it had gone out of scope.

Per Python 3 semantics the exception target is deleted at the end of the
except block, so 'details' was unbound at the raise, producing an
UnboundLocalError that masked the real PackingError and its message.

Keep the last PackingError in a separate variable so the final raise
reports the actual layout failure. Add regression tests for calc_packing.

Fixes enthought#937
@ryanda9910 ryanda9910 marked this pull request as ready for review June 16, 2026 02:48
@codecov-commenter

codecov-commenter commented Jun 16, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.98%. Comparing base (f62fbc0) to head (bf97f2f).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #942      +/-   ##
==========================================
+ Coverage   88.94%   88.98%   +0.03%     
==========================================
  Files         139      140       +1     
  Lines       13651    13676      +25     
==========================================
+ Hits        12142    12169      +27     
+ Misses       1509     1507       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@junkmd

junkmd commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Thank you.

@junkmd junkmd added bug Something isn't working tests enhance or fix tests labels Jun 16, 2026
@junkmd junkmd added this to the 1.4.17 milestone Jun 16, 2026
@junkmd junkmd merged commit 339ea27 into enthought:main Jun 16, 2026
50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working tests enhance or fix tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error raising error in calc_packaging

3 participants