Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions docs/platform.rst
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,7 @@ portable between the two systems and it should be no problem writing code that w

In order to use QT, import it from Sgtk::

from sgtk.platform.qt import QtCore, QtGui
from sgtk.platform.qt6 import QtCore, QtGui

Toolkit will make sure Qt is sourced in the correct way. Keep in mind that many applications (for example Nuke)
may not have a functional Qt that can be imported when they run in batch mode.
Expand Down Expand Up @@ -892,14 +892,14 @@ you from managing this by yourself, but for maximum compatibility and portabilty
et Toolkit handle it. When using Sgtk to set up your UI, just let your UI class derive from QtGui.QWidget and pass
it to one of the UI factory methods that the engine has. For example::

from sgtk.platform.qt import QtCore, QtGui
from sgtk.platform.qt6 import QtWidgets

# derive from QtGui.QWidget for your UI components.
# derive from QtWidgets.QWidget for your UI components.

class AppDialog(QtGui.QWidget):
class AppDialog(QtWidgets.QWidget):

def __init__(self, param1, param2):
QtGui.QWidget.__init__(self)
QtWidgets.QWidget.__init__(self)

# the engine is then used to correctly launch this dialog. In your app code
# you can now do create a window using the engine's factory methods.
Expand All @@ -924,12 +924,12 @@ property called ``exit_code``. Typically, your code for a modal dialog would loo

def on_ok_button_clicked(self):
# user clicked ok
self.exit_code = QtGui.QDialog.Accepted
self.exit_code = QtWidgets.QDialog.Accepted
self.close()

def on_cancel_button_clicked(self):
# user clicked cancel
self.exit_code = QtGui.QDialog.Rejected
self.exit_code = QtWidgets.QDialog.Rejected
self.close()

The call to self.engine.show_modal() will return the appropriate status code depending on which button was clicked.
Expand Down
6 changes: 3 additions & 3 deletions python/tank/authentication/interactive_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
# in the context of a DCC, but occur too early for the Toolkit logging to be
# fully in place to record it.
try:
from .ui.qt_abstraction import QtGui
from .ui.qt_abstraction import QtWidgets
except Exception:
QtGui = None
QtWidgets = None

logger = LogManager.get_logger(__name__)

Expand Down Expand Up @@ -77,7 +77,7 @@ def _get_ui_state():
Returns the state of UI: do we have a ui or not.
:returns: True or False)
"""
if QtGui and QtGui.QApplication.instance() is not None:
if QtWidgets and QtWidgets.QApplication.instance() is not None:
return True
else:
return False
Expand Down
10 changes: 5 additions & 5 deletions python/tank/authentication/invoker.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
# in the context of a DCC, but occur too early for the Toolkit logging to be
# fully in place to record it.
try:
from .ui.qt_abstraction import QtCore, QtGui
from .ui.qt_abstraction import QtCore, QtWidgets
except Exception:
QtCore, QtGui = None, None
QtCore, QtWidgets = None, None


def create():
Expand All @@ -44,7 +44,7 @@ def create():
def show_ui():
# show QT dialog
dlg = MyQtDialog()
result = dlg.exec_()
result = dlg.exec()
return result

# create invoker object
Expand All @@ -59,7 +59,7 @@ def show_ui():
thread will be produced.
"""
# If we are already in the main thread, no need for an invoker, invoke directly in this thread.
if QtCore.QThread.currentThread() == QtGui.QApplication.instance().thread():
if QtCore.QThread.currentThread() == QtWidgets.QApplication.instance().thread():
return lambda fn, *args, **kwargs: fn(*args, **kwargs)

class MainThreadInvoker(QtCore.QObject):
Expand All @@ -80,7 +80,7 @@ def __init__(self):
self._res = None
self._exception = None
# Make sure that the invoker is bound to the main thread
self.moveToThread(QtGui.QApplication.instance().thread())
self.moveToThread(QtWidgets.QApplication.instance().thread())

def __call__(self, fn, *args, **kwargs):
"""
Expand Down
68 changes: 40 additions & 28 deletions python/tank/authentication/login_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
QtCore,
QtNetwork,
QtWebEngineWidgets,
QtWidgets,
QtWebEngineCore,
Comment on lines 39 to +41
Copy link
Contributor

Choose a reason for hiding this comment

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

Please re-alpha order

qt_version_tuple,
)
from . import app_session_launcher
Expand Down Expand Up @@ -114,7 +116,8 @@ def run(self):
"""
self._site_info.reload(self._url_to_test, self._http_proxy)

class LoginDialog(QtGui.QDialog):

class LoginDialog(QtWidgets.QDialog):
"""
Dialog for getting user credentials.
"""
Expand Down Expand Up @@ -144,13 +147,15 @@ def __init__(
:param parent: The Qt parent for the dialog (defaults to None)
:param session_metadata: Metadata used in the context of SSO. This is an obscure blob of data.
"""
QtGui.QDialog.__init__(self, parent)
super().__init__(parent)

qt_modules = {
"QtCore": QtCore,
"QtGui": QtGui,
"QtNetwork": QtNetwork,
"QtWidgets": QtWidgets,
"QtWebEngineWidgets": QtWebEngineWidgets,
"QtWebEngineCore": QtWebEngineCore,
}
try:
self._sso_saml2 = SsoSaml2Toolkit(
Expand Down Expand Up @@ -245,7 +250,7 @@ def __init__(
self.ui.stackedWidget.setCurrentWidget(self.ui.login_page)

# Initialize Options menu
menu = QtGui.QMenu(self.ui.button_options)
menu = QtWidgets.QMenu(self.ui.button_options)
self.ui.button_options.setMenu(menu)
self.ui.button_options.setVisible(False)

Expand Down Expand Up @@ -321,11 +326,11 @@ def __init__(
)

# Initialize exit confirm message box
self.confirm_box = QtGui.QMessageBox(
QtGui.QMessageBox.Question,
self.confirm_box = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Question,
"Flow Production Tracking Login", # title
"Would you like to cancel your request?", # text
buttons=QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
# parent=self,
# Passing the parent parameter here, in the constructor, makes
# Nuke versions<=13 crash.
Expand Down Expand Up @@ -353,7 +358,7 @@ def __del__(self):
self._query_task.wait()

def _confirm_exit(self):
return self.confirm_box.exec_() == QtGui.QMessageBox.StandardButton.Yes
return self.confirm_box.exec_() == QtWidgets.QMessageBox.StandardButton.Yes
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return self.confirm_box.exec_() == QtWidgets.QMessageBox.StandardButton.Yes
return self.confirm_box.exec() == QtWidgets.QMessageBox.StandardButton.Yes

# PySide uses "exec_" instead of "exec" because "exec" is a reserved
# keyword in Python 2.

Expand Down Expand Up @@ -491,15 +496,21 @@ def _toggle_web(self, method_selected=None):
# - they need to use the legacy login / passphrase to use a PAT with
# Autodesk Identity authentication
if os.environ.get("SGTK_FORCE_STANDARD_LOGIN_DIALOG"):
logger.info("Using the standard login dialog with the Flow Production Tracking")
logger.info(
"Using the standard login dialog with the Flow Production Tracking"
)
else:
if _is_running_in_desktop():
can_use_web = can_use_web or self.site_info.autodesk_identity_enabled
can_use_web = (
can_use_web or self.site_info.autodesk_identity_enabled
)

# If we have full support for Web-based login, or if we enable it in our
# environment, use the Unified Login Flow for all authentication modes.
if get_shotgun_authenticator_support_web_login():
can_use_web = can_use_web or self.site_info.unified_login_flow_enabled
can_use_web = (
can_use_web or self.site_info.unified_login_flow_enabled
)

if method_selected:
# Selecting requested mode (credentials, qt_web_login or app_session_launcher)
Expand All @@ -511,9 +522,7 @@ def _toggle_web(self, method_selected=None):
method_selected = session_cache.get_preferred_method(site)

# Make sure that the method_selected is currently supported
if (
method_selected == auth_constants.METHOD_WEB_LOGIN and not can_use_web
) or (
if (method_selected == auth_constants.METHOD_WEB_LOGIN and not can_use_web) or (
method_selected == auth_constants.METHOD_ASL and not can_use_asl
):
method_selected = None
Expand All @@ -525,9 +534,7 @@ def _toggle_web(self, method_selected=None):
)

# Make sure that the method_selected is currently supported
if (
method_selected == auth_constants.METHOD_WEB_LOGIN and not can_use_web
) or (
if (method_selected == auth_constants.METHOD_WEB_LOGIN and not can_use_web) or (
method_selected == auth_constants.METHOD_ASL and not can_use_asl
):
method_selected = None
Expand Down Expand Up @@ -667,7 +674,7 @@ def exec_(self):
# to freeze, so only set the WindowStaysOnTopHint flag as this appears to not disable the
# other flags.
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
return QtGui.QDialog.exec_(self)
return QtWidgets.QDialog.exec_(self)
Copy link
Contributor

Choose a reason for hiding this comment

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

What about the exec_ method? I though we were not supposed to use it anymore with recent syntax?

Copy link
Contributor

Choose a reason for hiding this comment

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

According to Copilot, on this same line, asking if the exec_ method is deprecated:

No, the exec_ method is not deprecated in PySide6, but the preferred method name is now exec. In PySide6 (and PyQt6), exec_() is still available for backward compatibility, but the trailing underscore was originally used because exec is a reserved keyword in Python 2. Since Python 3, exec is no longer a reserved word, so you can use exec() directly.

So, for PySide6, you should use:

return QtWidgets.QDialog.exec(self)

The exec_() method will still work in PySide6 for now, but using exec() is the modern and recommended approach. If you want your code to be future-proof and style-compliant with the latest PySide6 standards, switch to exec().

Summary:

  • exec_() is not deprecated yet, but is considered legacy.
  • exec() is preferred in PySide6 and PyQt6.

However, reading the documentation and not relying only on AI (I should've done this in the first place to avoid double lookup), I realized that we're encouraged to use open instead (Reference).

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the detailed explanation @carlos-villavicencio-adsk!

However, switching from exec_ to open is not straightforward because I am aware that, in some places (TK auth), we rely on exec_ blocking call. So we would have to re-think the workflow to use open.


def result(self):
"""
Expand All @@ -688,21 +695,23 @@ def result(self):
profile_location=profile_location,
)
# If the offscreen session renewal failed, show the GUI as a failsafe
if res != QtGui.QDialog.Accepted:
if res != QtWidgets.QDialog.Accepted:
return

return self._sso_saml2.get_session_data()

res = self.exec_()
if res != QtGui.QDialog.Accepted:
if res != QtWidgets.QDialog.Accepted:
return

metrics_cache.log(
EventMetric.GROUP_TOOLKIT,
"Logged In",
properties={
"authentication_method": self.site_info.user_authentication_method,
"authentication_experience": auth_constants.method_resolve.get(self.method_selected),
"authentication_experience": auth_constants.method_resolve.get(
self.method_selected
),
"authentication_interface": "qt_dialog",
"authentication_renewal": self._is_session_renewal,
},
Expand Down Expand Up @@ -747,15 +756,15 @@ def _ok_pressed(self):
Validate the values, accepting if login is successful and display an error message if not.
"""
# Wait for any ongoing Site Configuration check thread.
QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
try:
if not self._query_task.wait(THREAD_WAIT_TIMEOUT_MS):
logger.warning(
"Timed out awaiting configuration information on the site: %s"
% self._get_current_site()
)
finally:
QtGui.QApplication.restoreOverrideCursor()
QtWidgets.QApplication.restoreOverrideCursor()

# pull values from the gui
site = self._get_current_site()
Expand All @@ -771,7 +780,10 @@ def _ok_pressed(self):

# Cleanup the URL and update the GUI.
if self.method_selected != auth_constants.METHOD_BASIC:
if site.startswith("http://") and "SGTK_AUTH_ALLOW_NO_HTTPS" not in os.environ:
if (
site.startswith("http://")
and "SGTK_AUTH_ALLOW_NO_HTTPS" not in os.environ
):
site = "https" + site[4:]
self.ui.site.setEditText(site)

Expand Down Expand Up @@ -827,7 +839,7 @@ def _authenticate(self, error_label, site, login, password, auth_code=None):
product=PRODUCT_IDENTIFIER,
profile_location=profile_location,
)
if res == QtGui.QDialog.Accepted:
if res == QtWidgets.QDialog.Accepted:
self._new_session_token = self._sso_saml2.session_id
self._session_metadata = self._sso_saml2.cookies
else:
Expand All @@ -837,8 +849,8 @@ def _authenticate(self, error_label, site, login, password, auth_code=None):
return
else:
# set the wait cursor
QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
QtGui.QApplication.processEvents()
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
QtWidgets.QApplication.processEvents()

# try and authenticate
self._new_session_token = session_cache.generate_session_token(
Expand All @@ -851,9 +863,9 @@ def _authenticate(self, error_label, site, login, password, auth_code=None):
success = True
finally:
# restore the cursor
QtGui.QApplication.restoreOverrideCursor()
QtWidgets.QApplication.restoreOverrideCursor()
# dialog is done
QtGui.QApplication.processEvents()
QtWidgets.QApplication.processEvents()

# Do not accept while the cursor is overriden, if freezes the dialog.
if success:
Expand Down
1 change: 1 addition & 0 deletions python/tank/authentication/sso_saml2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
SsoSaml2MissingQtGui,
SsoSaml2MissingQtModuleError,
SsoSaml2MissingQtNetwork,
SsoSaml2MissingQtWebEngineWidgets,
SsoSaml2MultiSessionNotSupportedError,
)

Expand Down
Loading
Loading