Skip to content

Commit

Permalink
Merge branch 'ynput:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
krishnaavril authored Mar 6, 2024
2 parents 50103ee + a27ba1b commit 4db4768
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 38 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Build Pype docker image
# Build AYON docker image
FROM ubuntu:focal AS builder
ARG PYTHON_VERSION=3.9.12
ARG BUILD_DATE
Expand Down
46 changes: 38 additions & 8 deletions common/ayon_common/connection/ui/login_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,41 @@
)


class ShowPasswordButton(QtWidgets.QPushButton):
state_changed = QtCore.Signal(bool)

def __init__(self, parent):
super().__init__(parent)

show_password_icon = QtGui.QIcon(get_resource_path("eye.png"))
hide_password_icon = QtGui.QIcon(get_resource_path("eye_closed.png"))

self.setObjectName("PasswordBtn")
self.setIcon(show_password_icon)
self.setToolTip("Show")

self.clicked.connect(self._on_click)

self._password_visible = False
self._show_password_icon = show_password_icon
self._hide_password_icon = hide_password_icon

def _on_click(self):
self._password_visible = not self._password_visible
if self._password_visible:
new_icon = self._hide_password_icon
new_hint = "Show"
else:
new_icon = self._show_password_icon
new_hint = "Hide"
self.setIcon(new_icon)
self.setToolTip(new_hint)
self.state_changed.emit(self._password_visible)

def is_password_visible(self):
return self._password_visible


class LogoutConfirmDialog(QtWidgets.QDialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -178,12 +213,7 @@ def __init__(self, *args, **kwargs):
api_preview.setReadOnly(True)
api_preview.setObjectName("LikeDisabledInput")

show_password_icon_path = get_resource_path("eye.png")
show_password_icon = QtGui.QIcon(show_password_icon_path)
show_password_btn = PressHoverButton(user_cred_widget)
show_password_btn.setObjectName("PasswordBtn")
show_password_btn.setIcon(show_password_icon)
show_password_btn.setFocusPolicy(QtCore.Qt.ClickFocus)
show_password_btn = ShowPasswordButton(user_cred_widget)

cred_msg_sep = QtWidgets.QFrame(self)
cred_msg_sep.setObjectName("Separator")
Expand Down Expand Up @@ -258,7 +288,7 @@ def __init__(self, *args, **kwargs):
username_input.textChanged.connect(self._on_user_change)
username_input.returnPressed.connect(self._on_username_enter_press)
password_input.returnPressed.connect(self._on_password_enter_press)
show_password_btn.change_state.connect(self._on_show_password)
show_password_btn.state_changed.connect(self._on_password_state_change)
url_edit_btn.clicked.connect(self._on_url_edit_click)
username_edit_btn.clicked.connect(self._on_username_edit_click)
logout_btn.clicked.connect(self._on_logout_click)
Expand Down Expand Up @@ -452,7 +482,7 @@ def _on_username_enter_press(self):
def _on_password_enter_press(self):
self._login()

def _on_show_password(self, show_password):
def _on_password_state_change(self, show_password):
if show_password:
placeholder_text = "< MySecret124 >"
echo_mode = QtWidgets.QLineEdit.Normal
Expand Down
Binary file modified common/ayon_common/resources/eye.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added common/ayon_common/resources/eye_closed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 9 additions & 2 deletions common/ayon_common/startup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from ayon_common.utils import get_ayon_launch_args


def show_startup_error(title, message):
def show_startup_error(title, message, detail=None):
"""Show startup error message.
This will trigger a subprocess with UI message dialog.
Expand All @@ -26,7 +26,14 @@ def show_startup_error(title, message):
filepath = tmp.name

with open(filepath, "w") as stream:
json.dump({"title": title, "message": message}, stream)
json.dump(
{
"title": title,
"message": message,
"detail": detail,
},
stream
)

args = get_ayon_launch_args(
script_path, "--skip-bootstrap", filepath
Expand Down
31 changes: 28 additions & 3 deletions common/ayon_common/startup/ui/startup_error.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys
import json

from qtpy import QtWidgets, QtGui
from qtpy import QtWidgets, QtGui, QtCore

from ayon_common.resources import (
get_icon_path,
Expand All @@ -14,7 +14,7 @@ class MessageWindow(QtWidgets.QDialog):
default_width = 410
default_height = 170

def __init__(self, title, message, parent=None):
def __init__(self, title, message, detail, parent=None):
super().__init__(parent)

icon_path = get_icon_path()
Expand All @@ -37,9 +37,28 @@ def __init__(self, title, message, parent=None):
info_label = QtWidgets.QLabel(message, info_widget)
info_label.setWordWrap(True)

details_wrapper = QtWidgets.QWidget(info_widget)

details_separator = QtWidgets.QFrame(details_wrapper)
details_separator.setObjectName("Separator")
details_separator.setMinimumHeight(2)
details_separator.setMaximumHeight(2)

details_widget = QtWidgets.QLabel(details_wrapper)
details_widget.setWordWrap(True)
details_widget.setTextInteractionFlags(
QtCore.Qt.TextBrowserInteraction
)

details_wrapper_layout = QtWidgets.QVBoxLayout(details_wrapper)
details_wrapper_layout.setContentsMargins(0, 0, 0, 0)
details_wrapper_layout.addWidget(details_separator, 0)
details_wrapper_layout.addWidget(details_widget, 0)

info_layout = QtWidgets.QVBoxLayout(info_widget)
info_layout.setContentsMargins(0, 0, 0, 0)
info_layout.addWidget(info_label, 0)
info_layout.addWidget(details_wrapper, 0)
info_layout.addStretch(1)

body_layout = QtWidgets.QHBoxLayout(body_widget)
Expand All @@ -61,8 +80,14 @@ def __init__(self, title, message, parent=None):

confirm_btn.clicked.connect(self._on_confirm_click)

if detail:
details_widget.setText(detail)
else:
details_wrapper.setVisible(False)

self._icon_label = icon_label
self._confirm_btn = confirm_btn
self._details_widget = details_widget

def showEvent(self, event):
super().showEvent(event)
Expand Down Expand Up @@ -111,7 +136,7 @@ def main():
data = json.load(stream)

app = get_qt_app()
window = MessageWindow(data["title"], data["message"])
window = MessageWindow(data["title"], data["message"], data["detail"])
window.show()
app.exec_()

Expand Down
12 changes: 5 additions & 7 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "AYON"
version = "1.0.2-dev.1"
version = "1.0.2"
description = "Open VFX and Animation pipeline with support."
authors = ["Ynput s.r.o. <[email protected]>"]
license = "MIT License"
Expand Down
51 changes: 42 additions & 9 deletions start.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@

ORIGINAL_ARGS = list(sys.argv)

PREVIOUS_AYON_VERSION = os.getenv("AYON_VERSION")

os.environ["AYON_VERSION"] = __version__

# Define which bundle is used
Expand Down Expand Up @@ -176,6 +178,36 @@
sys.argv.remove("--ayon-login")
SHOW_LOGIN_UI = True


def _is_in_login_mode():
# Handle cases when source AYON launcher has version before '1.0.1'
# - When user launcher an executable of AYON launcher it will run correct
# version of AYON launcher by bundle, but older launcher versions
# will not set 'AYON_IN_LOGIN_MODE' environment variable. Therefore
# we need to check 'PREVIOUS_AYON_VERSION' and set 'AYON_IN_LOGIN_MODE'
# to 'True' when version is before '1.0.1'.
# - this would be `return "AYON_API_KEY" not in os.environ` otherwise
if "AYON_API_KEY" not in os.environ:
return True

# Handle cases when source AYON launcher has version before '1.0.1'
version_parts = PREVIOUS_AYON_VERSION.split(".")
if len(version_parts) < 3:
return False

try:
# Keep only first 3 version parts which should be integers
new_version_parts = [
int(value)
for idx, value in enumerate(version_parts)
if idx < 3
]
except ValueError:
return False
milestone = (1, 0, 1)
return tuple(new_version_parts) < milestone


# Login mode is helper to detect if user is using AYON server credentials
# from login UI (and keyring), or from environment variables.
# - Variable is set in first AYON launcher process for possible subprocesses
Expand All @@ -184,9 +216,7 @@
os.environ["AYON_IN_LOGIN_MODE"] = "1"

elif "AYON_IN_LOGIN_MODE" not in os.environ:
os.environ["AYON_IN_LOGIN_MODE"] = (
"0" if "AYON_API_KEY" in os.environ else "1"
)
os.environ["AYON_IN_LOGIN_MODE"] = str(int(_is_in_login_mode()))

if "--headless" in sys.argv:
os.environ["AYON_HEADLESS_MODE"] = "1"
Expand Down Expand Up @@ -709,7 +739,7 @@ def _on_main_addon_missing():
sys.exit(1)


def _on_main_addon_import_error():
def _on_main_addon_import_error(exception):
if HEADLESS_MODE_ENABLED:
raise RuntimeError(
"Failed to import AYON core addon. Probably because"
Expand All @@ -722,7 +752,8 @@ def _on_main_addon_import_error():
" addons."
"<br/><br/>Please contact your administrator"
" to resolve the issue."
)
),
str(exception)
)
sys.exit(1)

Expand All @@ -735,8 +766,9 @@ def _main_cli_openpype():

try:
from openpype import cli
except ImportError:
_on_main_addon_import_error()
except ImportError as exc:
traceback.print_exception(*sys.exc_info())
_on_main_addon_import_error(exc)

python_path = os.getenv("PYTHONPATH", "")
split_paths = python_path.split(os.pathsep)
Expand Down Expand Up @@ -805,8 +837,9 @@ def main_cli():

try:
from ayon_core import cli
except ImportError:
_on_main_addon_import_error()
except ImportError as exc:
traceback.print_exception(*sys.exc_info())
_on_main_addon_import_error(exc)

# print info when not running scripts defined in 'silent commands'
if not SKIP_HEADERS:
Expand Down
49 changes: 47 additions & 2 deletions tools/build_post_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,20 +364,60 @@ def get_runtime_modules(root):
def get_packages_info(build_root):
"""Read lock file to get packages.
Retruns:
Combine requirements freeze from venv and from poetry export. Requirements
freezed with pip 24 do not contain git urls, instead are pointing to
source folder on a disk. In that case is used poetry export which contains
the git url.
Notes:
This is not ideal solution. The most ideal would be to get all the
information from poetry. But poetry export is limited only to
requirements.txt and using custom export logic would require
to implement it on our own.
The custom logic would also require to run venv located inside poetry
because poetry does not have mechanism to run internal python
via poetry executable. Parsing poetry lock on our own is also not
ideal because it can change based on poetry version.
We might hit an issue that newer poetry export won't be able to export
the urls either.
Returns:
list[tuple[str, Union[str, None]]]: List of tuples containing package
name and version.
"""

requirements_path = build_root / "requirements.txt"
poetry_requirements_path = build_root / "poetry_requirements.txt"
if not requirements_path.exists():
raise RuntimeError(
"Failed to get packages info -> couldn't find 'requirements.txt'."
)

if not poetry_requirements_path.exists():
raise RuntimeError(
"Failed to get packages info"
" -> couldn't find 'poetry_requirements.txt'."
)

with open(str(requirements_path), "r", encoding="utf-8") as stream:
content = stream.read()

with open(str(poetry_requirements_path), "r", encoding="utf-8") as stream:
poetry_content = stream.read()

poetry_packages = {}
for line in poetry_content.split("\n"):
line = line.strip()
if not line:
continue

match = re.match(r"^(.+?)(?:==|>=|<=|~=|!=|@)(.+)$", line)
if not match:
raise ValueError(f"Cannot parse package info '{line}'.")
package_name, version = match.groups()
version = version.split(";")[0].strip()
poetry_packages[package_name.rstrip()] = version

packages = {}
for line in content.split("\n"):
line = line.strip()
Expand All @@ -388,7 +428,12 @@ def get_packages_info(build_root):
if not match:
raise ValueError(f"Cannot parse package info '{line}'.")
package_name, version = match.groups()
packages[package_name.rstrip()] = version.lstrip()
package_name = package_name.rstrip()
version = version.lstrip()

if version.startswith("file:"):
version = poetry_packages[package_name]
packages[package_name] = version.lstrip()

return packages

Expand Down
Loading

0 comments on commit 4db4768

Please sign in to comment.