Skip to content

Fix ClassInitError crashing instead of reporting a missing class - #47

Open
jacquelinegarrahan wants to merge 1 commit into
lume-science:mainfrom
jacquelinegarrahan:bugfix/classiniterror-message
Open

Fix ClassInitError crashing instead of reporting a missing class#47
jacquelinegarrahan wants to merge 1 commit into
lume-science:mainfrom
jacquelinegarrahan:bugfix/classiniterror-message

Conversation

@jacquelinegarrahan

Copy link
Copy Markdown
Contributor

Fix ClassInitError crashing instead of reporting a missing class

Branch: bugfix/classiniterror-messagemain

Bug

Two coupled defects in HDF5Serializer.deserialize's error handling
(lume/serializers/hdf5.py, lume/serializers/base.py).

(a) The intended error is dead code. Line 80 was:

object_type = getattr(object_import_module, object_name)   # no default
if not object_type:
    raise ClassInitError(object_name, object_import_module, package_version)

getattr without a default raises AttributeError immediately when the class
is missing, so the if not object_type / ClassInitError branch could never
run. Deserializing an archive that names a class not present in the installed
package produced a bare AttributeError instead of the helpful, version-aware
ClassInitError.

(b) The error class crashes when constructed. ClassInitError.__init__
(and ModuleImportError.__init__) did module_name.split(".")[0], but the
caller passed the imported module object, not a string:

raise ClassInitError(object_name, object_import_module, package_version)
#                                  ^^^^^^^^^^^^^^^^^^^^ a module, not a str

So even if the branch were reached, building the exception raised
AttributeError: module '...' has no attribute 'split', masking the original
failure entirely.

Reproduction (before):

raise ClassInitError("Foo", some_module, "1.0")
# AttributeError: module '...' has no attribute 'split'

Fix

  • In deserialize, use getattr(..., None) and check is None, so the
    ClassInitError path actually fires for a missing class; pass the module
    name string (package_str).
  • Extract the base package name via a small _module_base helper that accepts
    either a dotted string or a module object, so the error path is robust
    regardless of caller.

Verification

pytest -q                                 # 121 passed
ClassInitError("Foo", "lume.x", "1.0")    # message OK (string arg)
ClassInitError("Foo", lume, "1.0")        # message OK (module arg, was crash)
deserialize(<archive naming a missing class>)  # -> ClassInitError (was AttributeError)

🤖 Generated with Claude Code

Two coupled defects in HDF5Serializer.deserialize's error path:

- getattr(module, object_name) had no default, so a missing class raised a
  raw AttributeError and the intended ClassInitError branch was dead code.
  Use a default of None and check for it.
- ClassInitError/ModuleImportError called module_name.split('.') but the
  caller passed the imported module object, so constructing the exception
  itself raised AttributeError, masking the real error. Extract the base
  package name via a helper that accepts a module object or a string, and
  pass the module name string from the caller.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant