Disclosure
This issue was diagnosed and drafted with the help of an AI coding assistant (Claude) — it
reproduced the crash live in a running Blender session via MCP, traced it to the SpoutGL
version mismatch below, and drafted this write-up and patch. I reviewed and validated the
fix before posting.
For full transparency (yes, this is getting recursive): I then asked the AI to add this
disclosure paragraph after it had already written the issue, and then asked it to make the
disclosure paragraph funnier after that. So if this reads like a Wikipedia "citation needed"
chain, that's why. The bug and the fix are real either way — feel free to hold the patch to
the same standard you'd hold any other PR.
This part is the real me writing: I asked Claude to be a bit funny about it. It's not,
at all... but hey, maybe the world isn't so f***ed up right now.
Bug
After updating the addon (or on a machine that already had an older SpoutGL installed
from a previous version of this addon), register() throws:
Error: 'SpoutGL._spoutgl.SpoutReceiver' object has no attribute 'getSenderList'
Root cause
pip_importer.check_module() only checks whether the module is importable — it never
compares the installed version against the version pin declared via
add_package(Package(name, version="==0.1.1", ...)):
def check_module(package):
...
try:
module = sys.modules[package.module]
if hasattr(module, '__path__'):
package._location = module.__path__[0]
package._registered = True # <-- marks "installed" regardless of version
except KeyError:
...
So if a stale SpoutGL==0.0.6 (which predates getSenderList(), added in 0.1.x) is already
on sys.path, auto_install_packages() never upgrades it, and register() crashes as soon
as it tries to enumerate senders.
Secondary issue (makes this harder to debug)
__init__.py::register() only wraps the operators/ui/keys import+register in
try/except ModuleNotFoundError. Any other exception (like the one above) propagates up
uncaught, but pip_importer.register() has already run and registered its own operator/
preferences classes. Since Blender's addon_enable then reports the addon as not enabled,
any subsequent retry immediately fails on:
Error: register_class(...): already registered as a subclass 'Pip_Update_package'
...which completely hides the real error (the SpoutGL version mismatch) behind a confusing,
unrelated one. A user hitting this has no way to see the actual crash without manually
unregistering the orphaned classes first.
Suggested fix
- In
check_module, compare the installed version to package.version (e.g. via
importlib.metadata.version(package.module)) and only set _registered = True if it
satisfies the pin — otherwise let auto_install_packages() reinstall/upgrade it.
- In
__init__.py::register(), catch broader exceptions around the whole registration
block, call unregister() to roll back any partially-registered classes, and re-raise
(or report) the original exception so the real cause is visible on the next attempt.
Happy to open a PR with both fixes if useful.
Suggested patch (pip_importer.py)
+from importlib import metadata as importlib_metadata
+
def check_module(package):
import sys, site
p = site.USER_SITE
if p not in sys.path:
sys.path.append(p)
try:
module = sys.modules[package.module]
if hasattr(module, '__path__'):
package._location = module.__path__[0]
- package._registered = True
+ package._registered = _version_satisfies(package)
except KeyError:
package._registered = False
try:
__import__(package.module)
get_package_show(package)
+ package._registered = _version_satisfies(package)
except ModuleNotFoundError:
pass
return package._registered
+def _version_satisfies(package):
+ if not package.version:
+ return True
+ try:
+ installed = importlib_metadata.version(package.name)
+ except importlib_metadata.PackageNotFoundError:
+ return True # can't verify, don't block on it
+ required = package.version.lstrip("=<>~! ")
+ return installed == required
Disclosure
This issue was diagnosed and drafted with the help of an AI coding assistant (Claude) — it
reproduced the crash live in a running Blender session via MCP, traced it to the SpoutGL
version mismatch below, and drafted this write-up and patch. I reviewed and validated the
fix before posting.
For full transparency (yes, this is getting recursive): I then asked the AI to add this
disclosure paragraph after it had already written the issue, and then asked it to make the
disclosure paragraph funnier after that. So if this reads like a Wikipedia "citation needed"
chain, that's why. The bug and the fix are real either way — feel free to hold the patch to
the same standard you'd hold any other PR.
This part is the real me writing: I asked Claude to be a bit funny about it. It's not,
at all... but hey, maybe the world isn't so f***ed up right now.
Bug
After updating the addon (or on a machine that already had an older
SpoutGLinstalledfrom a previous version of this addon),
register()throws:Root cause
pip_importer.check_module()only checks whether the module is importable — it nevercompares the installed version against the version pin declared via
add_package(Package(name, version="==0.1.1", ...)):So if a stale
SpoutGL==0.0.6(which predatesgetSenderList(), added in 0.1.x) is alreadyon
sys.path,auto_install_packages()never upgrades it, andregister()crashes as soonas it tries to enumerate senders.
Secondary issue (makes this harder to debug)
__init__.py::register()only wraps theoperators/ui/keysimport+register intry/except ModuleNotFoundError. Any other exception (like the one above) propagates upuncaught, but
pip_importer.register()has already run and registered its own operator/preferences classes. Since Blender's
addon_enablethen reports the addon as not enabled,any subsequent retry immediately fails on:
...which completely hides the real error (the SpoutGL version mismatch) behind a confusing,
unrelated one. A user hitting this has no way to see the actual crash without manually
unregistering the orphaned classes first.
Suggested fix
check_module, compare the installed version topackage.version(e.g. viaimportlib.metadata.version(package.module)) and only set_registered = Trueif itsatisfies the pin — otherwise let
auto_install_packages()reinstall/upgrade it.__init__.py::register(), catch broader exceptions around the whole registrationblock, call
unregister()to roll back any partially-registered classes, and re-raise(or report) the original exception so the real cause is visible on the next attempt.
Happy to open a PR with both fixes if useful.
Suggested patch (pip_importer.py)