Skip to content

Conversation

@sansrem
Copy link

@sansrem sansrem commented Dec 8, 2025

This pull request refactors how signal handlers are connected in loader_action_manager.py by replacing lambda functions with functools.partial for binding parameters to the _execute_hook method. This change improves code readability and maintainability.

Refactoring of signal handler connections:

  • Replaced lambda functions with functools.partial when connecting the triggered signal to _execute_hook in both get_actions_for_publishes and get_actions_for_folder, making the handler binding more explicit and easier to read. [1] [2]
  • Added the import of partial from functools to support the new handler binding method.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug in the LoaderActionManager where the _execute_hook method was incorrectly receiving a boolean as its first parameter instead of the expected Qt action object. The fix replaces lambda functions with functools.partial to properly bind parameters.

  • Replaced lambda-based signal connections with functools.partial to ensure correct parameter binding
  • Added import for functools.partial

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

qt_action, actions
)
)
handler = partial(self._execute_hook, a, actions)
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The action object a is captured by reference in the partial call within a loop. This creates a closure issue where all handlers will reference the last value of a from the loop. Consider using partial with a default argument pattern: partial(self._execute_hook, qt_action=a, actions=actions) or ensure each iteration captures its own action reference.

Suggested change
handler = partial(self._execute_hook, a, actions)
handler = partial(self._execute_hook, qt_action=a, actions=actions)

Copilot uses AI. Check for mistakes.
qt_action, actions
)
)
handler = partial(self._execute_hook, a, actions)
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The action object a is captured by reference in the partial call within a loop. This creates a closure issue where all handlers will reference the last value of a from the loop. Consider using partial with a default argument pattern: partial(self._execute_hook, qt_action=a, actions=actions) or ensure each iteration captures its own action reference.

Suggested change
handler = partial(self._execute_hook, a, actions)
handler = partial(self._execute_hook, qt_action=a, actions=actions)

Copilot uses AI. Check for mistakes.
@sansrem sansrem requested a review from Copilot December 8, 2025 22:45
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Member

@julien-lang julien-lang left a comment

Choose a reason for hiding this comment

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

Can you provide more information about the problem and why the current code does not work specifically on Python 3.13?

Also, given the change, are we expecting to replicate this change in all other TK components calling a hook?

@sansrem
Copy link
Author

sansrem commented Dec 9, 2025

We were getting this error in the shell when pressing on a button in the loader:

Traceback (most recent call last):
  File ".../shotgun/bundle_cache/app_store/tk-multi-loader2/v1.25.4/python/tk_multi_loader/dialog.py", line 1229, in _pre_execute_action
    data = action.data()
           ^^^^^^^^^^^
AttributeError: 'bool' object has no attribute 'data'

So I added debug print and confirmed that the type of action was bool and I also printed the stack

  File ".../shotgun/bundle_cache/app_store/tk-multi-loader2/v1.25.4/python/tk_multi_loader/loader_action_manager.py", line 103, in <lambda>
    lambda qt_action=a, actions=actions: self._execute_hook(
  File ".../shotgun/bundle_cache/app_store/tk-multi-loader2/v1.25.4/python/tk_multi_loader/loader_action_manager.py", line 222, in _execute_hook
    self.pre_execute_action.emit(qt_action)
  File ".../shotgun/bundle_cache/app_store/tk-multi-loader2/v1.25.4/python/tk_multi_loader/dialog.py", line 1232, in _pre_execute_action
    traceback.print_stack()

So the first argument, the qt_action, was no longer a QAction but a bool, asking Gemini I received the answer:

When a Qt signal fires, it attempts to pass its own arguments to the connected Python callable first.
The a.triggered signal fires and passes one argument: a boolean (True or False, representing the checked state).
Your lambda function signature is lambda qt_action=a, actions=actions: ....
In Python, when a function or lambda is called, positional arguments supplied by the caller are assigned before default arguments are used.
The boolean value emitted by the signal is interpreted as a positional argument that maps to the first argument of the lambda, which you named qt_action.
Therefore:
qt_action becomes the boolean (True or False).
actions becomes the value you defined as the default (actions).

And I used a proposed solution that worked. When asked about what changed between Python 3.13.3 and 3.11.5 or PySide 6.8.3 and 6.5.2 that could explain the change of behaviour Gemini answered:
The update to PySide 6.8.3 (and potentially changes in Python 3.13's C API interactions) likely enforced the correct, stricter behavior as defined by standard Python function calls and the underlying C++ Qt framework: positional arguments supplied by the signal must match up with the function signature.

So yes, this modification should probably be done in other places ... I just tested our specific case

@eduardoChaucaGallegos eduardoChaucaGallegos changed the title Fix LoaderActionManager._execute_hook which was receiving a bool as f… SG-41525 Fix LoaderActionManager._execute_hook Dec 16, 2025
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.

4 participants