Skip to content

Conversation

@loonghao
Copy link

  • Add comprehensive fix for bpy.app.translations missing attributes
  • Implement sys.modules patch to intercept module registration
  • Use complete wrapper with all required Shiboken attributes
  • Fix AttributeError when Shiboken tries to introspect bpy.app.translations
  • Apply dual-layer protection: sys.modules patch + existing object fix
  • Tested with Blender 3.1+, 3.6, 4.1 + PySide6 6.5.3

Fixes compatibility issues where PySide6/Shiboken fails during initialization due to missing name, module, qualname, and ne attributes on the bpy.app.translations object. Issue affects all Blender 3.1+ versions when bqt plugin is enabled.

This enhanced approach provides early intervention at module registration level to prevent AttributeError from occurring in other modules that import from bpy.app.translations.

Fix #127

@loonghao
Copy link
Author

@hannesdelbeke Please have a look.

@hannesdelbeke
Copy link
Collaborator

afraid i'm not able to reproduce the error you have.
from your description it reads as if it should error for every bqt user once enabled

Copy link
Contributor

@Jerakin Jerakin left a comment

Choose a reason for hiding this comment

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

Hi @loonghao

I haven't tried with Blender 3.6 but I did get these error in Blender 2.83. However I also got it with .handlers, would love to see this changed to also patch that.

bqt/__init__.py Outdated
except (AttributeError, TypeError):
# If direct setting fails, use wrapper
try:
bpy.app.translations = _create_translations_wrapper(translations)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that in all cases that setattr would fail so would direct assignment. I think this whole except block can be removed.

bqt/__init__.py Outdated
Comment on lines 63 to 67
except Exception:
pass
return False
except Exception:
return False
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not a fan catching blanket exceptions like this.

Did you add these because you want to be sure that your change is 100% safe if something goes wrong? Or do you use this to actually catch any errors ?

I think all exception handling should be removed from _patch_bpy_translations_in_sys_modules

@Jerakin
Copy link
Contributor

Jerakin commented Dec 12, 2025

In additions to translations, in 2.83 I also had to patch handlers. I changed this patch to accommodate for that.

# CRITICAL: Fix bpy.app.* modules BEFORE importing any Qt/PySide modules
# This prevents Shiboken from failing when it tries to introspect bpy.app.* modules
import sys


def _create_wrapper(original, cls_name):
    """Create a compatibility wrapper for bpy.app.*"""
    class Wrapper:
        def __init__(self, orig):
            self._orig = orig

        def __getattr__(self, name):
            # Provide missing attributes that Shiboken expects
            if name == '__name__':
                return f'bpy.app.{cls_name}'
            elif name == '__module__':
                return 'bpy.app'
            elif name == '__qualname__':
                return cls_name
            elif name == '_ne_':
                return lambda x, y: x != y
            elif name == '__doc__':
                return f'Blender {cls_name} compatibility wrapper'
            else:
                return getattr(self._orig, name)

        def __setattr__(self, name, value):
            if name == '_orig':
                super().__setattr__(name, value)
            else:
                setattr(self._orig, name, value)

        def __dir__(self):
            orig_attrs = (dir(self._orig)
                          if hasattr(self._orig, '__dir__') else [])
            extra_attrs = ['__name__', '__module__', '__qualname__',
                           '_ne_', '__doc__']
            return list(set(orig_attrs + extra_attrs))

    return Wrapper(original)


def _patch_bpy_module_in_sys_modules(name):
    """Directly patch bpy.app.* modules in sys.modules if it exists"""
    # Check if bpy.app.* module is already in sys.modules
    if f"bpy.app.{name}" in sys.modules:
        module = sys.modules[f"bpy.app.{name}"]
        required_attrs = ['__name__', '__module__', "__qualname__", "_ne_"]

        # Check if any required attributes are missing
        if any(not hasattr(module, attr) for attr in required_attrs):
            wrapped = _create_wrapper(module, name)
            sys.modules[f"bpy.app.{name}"] = wrapped
            return True
    return False


def _fix_existing_module(name):
    """Fix bpy.app.* modules if it already exists"""
    import bpy
    if not hasattr(bpy.app, name):
        return

    module = getattr(bpy.app, name)
    required_attrs = ['__name__', '__module__', '__qualname__']

    # Check if any required attributes are missing
    if any(not hasattr(module, attr) for attr in required_attrs):
        try:
            # Try direct attribute setting first
            attrs_to_add = {
                '__name__': f'bpy.app.{name}',
                '__module__': 'bpy.app',
                '__qualname__': name,
            }

            for attr_name, attr_value in attrs_to_add.items():
                if not hasattr(module, attr_name):
                    setattr(module, attr_name, attr_value)
        except (AttributeError, TypeError):
            pass



# Apply patches immediately - order matters!
# Check sys.modules first
_patch_bpy_module_in_sys_modules("translations")
_patch_bpy_module_in_sys_modules("handlers")

# Fix existing translations if available
_fix_existing_module("translations")
_fix_existing_module("handlers")

- Add generic bpy.app module wrapper for Shiboken compatibility
- Patch both bpy.app.translations and bpy.app.handlers (fixes techartorg#127)
- Fix logging.basicConfig encoding parameter for Python < 3.9 (Blender 2.83)
- Use __slots__ for memory optimization in wrapper class

Thanks to @Jerakin for the suggestions in PR techartorg#128 and techartorg#133

Fixes: techartorg#127
Related: techartorg#133
@loonghao loonghao reopened this Dec 13, 2025
@loonghao
Copy link
Author

I've updated the fix based on @Jerakin's excellent suggestions from PR #128 and #133. The new implementation includes:

Changes:

Generic wrapper for bpy.app submodules - Refactored _create_translations_wrapper to a generic _create_bpy_app_wrapper that supports any bpy.app submodule
Extended patching scope - Now patches both bpy.app.translations AND bpy.app.handlers (fixes the Blender 2.83 issue)
Python 3.7+ compatibility - Fixed logging.basicConfig(encoding='utf-8') which requires Python 3.9+, now uses version check for Blender 2.83 compatibility
Code improvements - Used slots for memory optimization, fixed ne attribute name (was ne )
This should now work with:

✅ Blender 2.83 (Python 3.7)
✅ Blender 3.6+ (Python 3.10+)
✅ Blender 4.x
✅ PySide2 / PySide6
Thanks @Jerakin for the valuable feedback and suggestions! 🙏

Related: #127, #133

@hannesdelbeke
Copy link
Collaborator

hannesdelbeke commented Dec 14, 2025

thanks for the work in fixing this issue
i have some observations regarding this PR

What's the issue we're solving?
The original bug report #127 reads like it's written by AI, and I can't reproduce it.
Yet I don't want to dismiss it since it's posted by Loonghao, the developer of photoshop-python-api (an amazing python module).

increasing complexity
I'm concerned we're adding a lot of code, to work around some pyside limitations.
Instead of providing a fix (this PR), is there perhaps a way to find out what is causing this. Maybe we are using PySide in the wrong way? Or is one of the new bqt features like wrapper, causing issues.
Often simplifying code is better to maintain long term.

move code out of init
If we do go ahead with this PR, let's move it to a separate file, and import/run it in the init, document the code more in layman terms.

@hannesdelbeke
Copy link
Collaborator

i just noticed you tested with Blender 2.83 (Python 3.7), do we want to support such an old version of blender in bqt?
since industry is moving to pyside6, so below Python 3.9 won't work.

@Jerakin
Copy link
Contributor

Jerakin commented Dec 15, 2025

I only noticed this error on versions less than 4.0

But Loonghao mentioned that "4.1, 4.2 (confirmed affected on Windows)" in the issue report. So I don't think it's "safe" to dismiss the issue out right. Just cause we can't reproduce it doesn't mean that it doesn't happen.
I will try to figure out more in depth what is happening, as I can repro it on a very old version maybe that can give me a hint.

I do however think that if this patch is needed it should be moved into it's own file and imported into this location, instead of having it all in __init__.py.

(p.s. they might be using AI if they are not comfortable with English.)

@hannesdelbeke
Copy link
Collaborator

(p.s. they might be using AI if they are not comfortable with English.)

hm that made me think, is that why we can't repro, because our english blender never triggers bpy.app.translations?

i also noticed in the screenshots in the original issue, that all the errors happen in the fbx import/export addon. i assumed it errored when enabling the bqt addon.

@hannesdelbeke
Copy link
Collaborator

i moved it to a separate file, however still would like to understand and repro it

Copy link
Contributor

Choose a reason for hiding this comment

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

This file is empty?

@Jerakin
Copy link
Contributor

Jerakin commented Dec 15, 2025

Found some more information.

  • It's frequently reported; See here, here and here
  • It seems to be a PySide Bug affecting PySide between 6.4 and 6.5 with a fix in 6.6

For me using a newer version of PySide Works. It only happens on earlier versions of pyside for me cause 6.6 drops py37 support which older blender versions are using.

Blender 2.83 Blender 4.0 Blender 4.2 Blender 5.0
PySide 6.5.3
PySide 6.6.0 Not supported

@loonghao Could you try and see if installing PySide 6.6 or higher resolves this issue?
If that works we can do pyside>=6.6.0 in our pyproject.toml file.

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.

BQT causes AttributeError in bpy.app.translations on Blender 3.6+ with PySide2/PySide6

3 participants