[Automated] Merged develop into main

This commit is contained in:
pypebot 2021-10-06 05:34:01 +02:00 committed by GitHub
commit 6bcf645c9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 319 additions and 249 deletions

View file

@ -1,18 +1,12 @@
# -*- coding: utf-8 -*-
"""Tools used in **Igniter** GUI.
Functions ``compose_url()`` and ``decompose_url()`` are the same as in
``openpype.lib`` and they are here to avoid importing OpenPype module before its
version is decided.
"""
import sys
"""Tools used in **Igniter** GUI."""
import os
from typing import Dict, Union
from typing import Union
from urllib.parse import urlparse, parse_qs
from pathlib import Path
import platform
import certifi
from pymongo import MongoClient
from pymongo.errors import (
ServerSelectionTimeoutError,
@ -22,89 +16,32 @@ from pymongo.errors import (
)
def decompose_url(url: str) -> Dict:
"""Decompose mongodb url to its separate components.
Args:
url (str): Mongodb url.
Returns:
dict: Dictionary of components.
def should_add_certificate_path_to_mongo_url(mongo_url):
"""Check if should add ca certificate to mongo url.
Since 30.9.2021 cloud mongo requires newer certificates that are not
available on most of workstation. This adds path to certifi certificate
which is valid for it. To add the certificate path url must have scheme
'mongodb+srv' or has 'ssl=true' or 'tls=true' in url query.
"""
components = {
"scheme": None,
"host": None,
"port": None,
"username": None,
"password": None,
"auth_db": None
}
parsed = urlparse(mongo_url)
query = parse_qs(parsed.query)
lowered_query_keys = set(key.lower() for key in query.keys())
add_certificate = False
# Check if url 'ssl' or 'tls' are set to 'true'
for key in ("ssl", "tls"):
if key in query and "true" in query["ssl"]:
add_certificate = True
break
result = urlparse(url)
if result.scheme is None:
_url = "mongodb://{}".format(url)
result = urlparse(_url)
# Check if url contains 'mongodb+srv'
if not add_certificate and parsed.scheme == "mongodb+srv":
add_certificate = True
components["scheme"] = result.scheme
components["host"] = result.hostname
try:
components["port"] = result.port
except ValueError:
raise RuntimeError("invalid port specified")
components["username"] = result.username
components["password"] = result.password
try:
components["auth_db"] = parse_qs(result.query)['authSource'][0]
except KeyError:
# no auth db provided, mongo will use the one we are connecting to
pass
return components
def compose_url(scheme: str = None,
host: str = None,
username: str = None,
password: str = None,
port: int = None,
auth_db: str = None) -> str:
"""Compose mongodb url from its individual components.
Args:
scheme (str, optional):
host (str, optional):
username (str, optional):
password (str, optional):
port (str, optional):
auth_db (str, optional):
Returns:
str: mongodb url
"""
url = "{scheme}://"
if username and password:
url += "{username}:{password}@"
url += "{host}"
if port:
url += ":{port}"
if auth_db:
url += "?authSource={auth_db}"
return url.format(**{
"scheme": scheme,
"host": host,
"username": username,
"password": password,
"port": port,
"auth_db": auth_db
})
# Check if url does already contain certificate path
if add_certificate and "tlscafile" in lowered_query_keys:
add_certificate = False
return add_certificate
def validate_mongo_connection(cnx: str) -> (bool, str):
@ -121,12 +58,18 @@ def validate_mongo_connection(cnx: str) -> (bool, str):
if parsed.scheme not in ["mongodb", "mongodb+srv"]:
return False, "Not mongodb schema"
kwargs = {
"serverSelectionTimeoutMS": 2000
}
# Add certificate path if should be required
if should_add_certificate_path_to_mongo_url(cnx):
kwargs["ssl_ca_certs"] = certifi.where()
try:
client = MongoClient(
cnx,
serverSelectionTimeoutMS=2000
)
client = MongoClient(cnx, **kwargs)
client.server_info()
with client.start_session():
pass
client.close()
except ServerSelectionTimeoutError as e:
return False, f"Cannot connect to server {cnx} - {e}"
@ -152,10 +95,7 @@ def validate_mongo_string(mongo: str) -> (bool, str):
"""
if not mongo:
return True, "empty string"
parsed = urlparse(mongo)
if parsed.scheme in ["mongodb", "mongodb+srv"]:
return validate_mongo_connection(mongo)
return False, "not valid mongodb schema"
return validate_mongo_connection(mongo)
def validate_path_string(path: str) -> (bool, str):
@ -195,21 +135,13 @@ def get_openpype_global_settings(url: str) -> dict:
Returns:
dict: With settings data. Empty dictionary is returned if not found.
"""
try:
components = decompose_url(url)
except RuntimeError:
return {}
mongo_kwargs = {
"host": compose_url(**components),
"serverSelectionTimeoutMS": 2000
}
port = components.get("port")
if port is not None:
mongo_kwargs["port"] = int(port)
kwargs = {}
if should_add_certificate_path_to_mongo_url(url):
kwargs["ssl_ca_certs"] = certifi.where()
try:
# Create mongo connection
client = MongoClient(**mongo_kwargs)
client = MongoClient(url, **kwargs)
# Access settings collection
col = client["openpype"]["settings"]
# Query global settings

View file

@ -3,4 +3,17 @@ from avalon.tvpaint import pipeline
class Creator(PypeCreatorMixin, pipeline.Creator):
pass
@classmethod
def get_dynamic_data(cls, *args, **kwargs):
dynamic_data = super(Creator, cls).get_dynamic_data(*args, **kwargs)
# Change asset and name by current workfile context
workfile_context = pipeline.get_current_workfile_context()
asset_name = workfile_context.get("asset")
task_name = workfile_context.get("task")
if "asset" not in dynamic_data and asset_name:
dynamic_data["asset"] = asset_name
if "task" not in dynamic_data and task_name:
dynamic_data["task"] = task_name
return dynamic_data

View file

@ -606,7 +606,7 @@ class ExtractSequence(pyblish.api.Extractor):
self._copy_image(eq_frame_filepath, new_filepath)
layer_files_by_frame[frame_idx] = new_filepath
elif pre_behavior == "loop":
elif pre_behavior in ("loop", "repeat"):
# Loop backwards from last frame of layer
for frame_idx in reversed(range(mark_in_index, frame_start_index)):
eq_frame_idx_offset = (
@ -678,7 +678,7 @@ class ExtractSequence(pyblish.api.Extractor):
self._copy_image(eq_frame_filepath, new_filepath)
layer_files_by_frame[frame_idx] = new_filepath
elif post_behavior == "loop":
elif post_behavior in ("loop", "repeat"):
# Loop backwards from last frame of layer
for frame_idx in range(frame_end_index + 1, mark_out_index + 1):
eq_frame_idx = frame_idx % frame_count

View file

@ -1,9 +1,11 @@
"""Functions useful for delivery action or loader"""
import os
import shutil
import glob
import clique
import collections
def collect_frames(files):
"""
Returns dict of source path and its frame, if from sequence
@ -228,7 +230,16 @@ def process_sequence(
Returns:
(collections.defaultdict , int)
"""
if not os.path.exists(src_path):
def hash_path_exist(myPath):
res = myPath.replace('#', '*')
glob_search_results = glob.glob(res)
if len(glob_search_results) > 0:
return True
else:
return False
if not hash_path_exist(src_path):
msg = "{} doesn't exist for {}".format(src_path,
repre["_id"])
report_items["Source file was not found"].append(msg)

View file

@ -3,6 +3,7 @@ import sys
import time
import logging
import pymongo
import certifi
if sys.version_info[0] == 2:
from urlparse import urlparse, parse_qs
@ -85,12 +86,33 @@ def get_default_components():
return decompose_url(mongo_url)
def extract_port_from_url(url):
parsed_url = urlparse(url)
if parsed_url.scheme is None:
_url = "mongodb://{}".format(url)
parsed_url = urlparse(_url)
return parsed_url.port
def should_add_certificate_path_to_mongo_url(mongo_url):
"""Check if should add ca certificate to mongo url.
Since 30.9.2021 cloud mongo requires newer certificates that are not
available on most of workstation. This adds path to certifi certificate
which is valid for it. To add the certificate path url must have scheme
'mongodb+srv' or has 'ssl=true' or 'tls=true' in url query.
"""
parsed = urlparse(mongo_url)
query = parse_qs(parsed.query)
lowered_query_keys = set(key.lower() for key in query.keys())
add_certificate = False
# Check if url 'ssl' or 'tls' are set to 'true'
for key in ("ssl", "tls"):
if key in query and "true" in query["ssl"]:
add_certificate = True
break
# Check if url contains 'mongodb+srv'
if not add_certificate and parsed.scheme == "mongodb+srv":
add_certificate = True
# Check if url does already contain certificate path
if add_certificate and "tlscafile" in lowered_query_keys:
add_certificate = False
return add_certificate
def validate_mongo_connection(mongo_uri):
@ -106,26 +128,9 @@ def validate_mongo_connection(mongo_uri):
passed so probably couldn't connect to mongo server.
"""
parsed = urlparse(mongo_uri)
# Force validation of scheme
if parsed.scheme not in ["mongodb", "mongodb+srv"]:
raise pymongo.errors.InvalidURI((
"Invalid URI scheme:"
" URI must begin with 'mongodb://' or 'mongodb+srv://'"
))
# we have mongo connection string. Let's try if we can connect.
components = decompose_url(mongo_uri)
mongo_args = {
"host": compose_url(**components),
"serverSelectionTimeoutMS": 1000
}
port = components.get("port")
if port is not None:
mongo_args["port"] = int(port)
# Create connection
client = pymongo.MongoClient(**mongo_args)
client.server_info()
client = OpenPypeMongoConnection.create_connection(
mongo_uri, retry_attempts=1
)
client.close()
@ -151,6 +156,8 @@ class OpenPypeMongoConnection:
# Naive validation of existing connection
try:
connection.server_info()
with connection.start_session():
pass
except Exception:
connection = None
@ -162,38 +169,53 @@ class OpenPypeMongoConnection:
return connection
@classmethod
def create_connection(cls, mongo_url, timeout=None):
def create_connection(cls, mongo_url, timeout=None, retry_attempts=None):
parsed = urlparse(mongo_url)
# Force validation of scheme
if parsed.scheme not in ["mongodb", "mongodb+srv"]:
raise pymongo.errors.InvalidURI((
"Invalid URI scheme:"
" URI must begin with 'mongodb://' or 'mongodb+srv://'"
))
if timeout is None:
timeout = int(os.environ.get("AVALON_TIMEOUT") or 1000)
kwargs = {
"host": mongo_url,
"serverSelectionTimeoutMS": timeout
}
if should_add_certificate_path_to_mongo_url(mongo_url):
kwargs["ssl_ca_certs"] = certifi.where()
port = extract_port_from_url(mongo_url)
if port is not None:
kwargs["port"] = int(port)
mongo_client = pymongo.MongoClient(mongo_url, **kwargs)
mongo_client = pymongo.MongoClient(**kwargs)
if retry_attempts is None:
retry_attempts = 3
for _retry in range(3):
elif not retry_attempts:
retry_attempts = 1
last_exc = None
valid = False
t1 = time.time()
for attempt in range(1, retry_attempts + 1):
try:
t1 = time.time()
mongo_client.server_info()
except Exception:
cls.log.warning("Retrying...")
time.sleep(1)
timeout *= 1.5
else:
with mongo_client.start_session():
pass
valid = True
break
else:
raise IOError((
"ERROR: Couldn't connect to {} in less than {:.3f}ms"
).format(mongo_url, timeout))
except Exception as exc:
last_exc = exc
if attempt < retry_attempts:
cls.log.warning(
"Attempt {} failed. Retrying... ".format(attempt)
)
time.sleep(1)
if not valid:
raise last_exc
cls.log.info("Connected to {}, delay {:.3f}s".format(
mongo_url, time.time() - t1

View file

@ -10,6 +10,7 @@ from openpype_modules.ftrack.lib import (
CUST_ATTR_GROUP,
CUST_ATTR_TOOLS,
CUST_ATTR_APPLICATIONS,
CUST_ATTR_INTENT,
default_custom_attributes_definition,
app_definitions_from_app_manager,
@ -431,7 +432,7 @@ class CustomAttributes(BaseAction):
intent_custom_attr_data = {
"label": "Intent",
"key": "intent",
"key": CUST_ATTR_INTENT,
"type": "enumerator",
"entity_type": "assetversion",
"group": CUST_ATTR_GROUP,

View file

@ -230,7 +230,13 @@ class FtrackModule(
return
import ftrack_api
from openpype_modules.ftrack.lib import get_openpype_attr
from openpype_modules.ftrack.lib import (
get_openpype_attr,
default_custom_attributes_definition,
CUST_ATTR_TOOLS,
CUST_ATTR_APPLICATIONS,
CUST_ATTR_INTENT
)
try:
session = self.create_ftrack_session()
@ -255,6 +261,15 @@ class FtrackModule(
project_id = project_entity["id"]
ca_defs = default_custom_attributes_definition()
hierarchical_attrs = ca_defs.get("is_hierarchical") or {}
project_attrs = ca_defs.get("show") or {}
ca_keys = (
set(hierarchical_attrs.keys())
| set(project_attrs.keys())
| {CUST_ATTR_TOOLS, CUST_ATTR_APPLICATIONS, CUST_ATTR_INTENT}
)
cust_attr, hier_attr = get_openpype_attr(session)
cust_attr_by_key = {attr["key"]: attr for attr in cust_attr}
hier_attrs_by_key = {attr["key"]: attr for attr in hier_attr}
@ -262,6 +277,9 @@ class FtrackModule(
failed = {}
missing = {}
for key, value in attributes_changes.items():
if key not in ca_keys:
continue
configuration = hier_attrs_by_key.get(key)
if not configuration:
configuration = cust_attr_by_key.get(key)

View file

@ -17,7 +17,8 @@ from openpype.lib import (
get_pype_execute_args,
OpenPypeMongoConnection,
get_openpype_version,
get_build_version
get_build_version,
validate_mongo_connection
)
from openpype_modules.ftrack import FTRACK_MODULE_DIR
from openpype_modules.ftrack.lib import credentials
@ -36,11 +37,15 @@ class MongoPermissionsError(Exception):
def check_mongo_url(mongo_uri, log_error=False):
"""Checks if mongo server is responding"""
try:
client = pymongo.MongoClient(mongo_uri)
# Force connection on a request as the connect=True parameter of
# MongoClient seems to be useless here
client.server_info()
client.close()
validate_mongo_connection(mongo_uri)
except pymongo.errors.InvalidURI as err:
if log_error:
print("Can't connect to MongoDB at {} because: {}".format(
mongo_uri, err
))
return False
except pymongo.errors.ServerSelectionTimeoutError as err:
if log_error:
print("Can't connect to MongoDB at {} because: {}".format(

View file

@ -3,7 +3,8 @@ from .constants import (
CUST_ATTR_AUTO_SYNC,
CUST_ATTR_GROUP,
CUST_ATTR_TOOLS,
CUST_ATTR_APPLICATIONS
CUST_ATTR_APPLICATIONS,
CUST_ATTR_INTENT
)
from .settings import (
get_ftrack_event_mongo_info

View file

@ -10,3 +10,5 @@ CUST_ATTR_AUTO_SYNC = "avalon_auto_sync"
CUST_ATTR_APPLICATIONS = "applications"
# Environment tools custom attribute
CUST_ATTR_TOOLS = "tools_env"
# Intent custom attribute name
CUST_ATTR_INTENT = "intent"

View file

@ -8,16 +8,14 @@ import platform
from openpype.api import Logger
from openpype.api import get_system_settings
from openpype.modules.default_modules.sync_server.providers.abstract_provider \
import AbstractProvider
from .abstract_provider import AbstractProvider
log = Logger().get_logger("SyncServer")
pysftp = None
try:
import pysftp
except (ImportError, SyntaxError):
if six.PY3:
six.reraise(*sys.exc_info())
pass
# handle imports from Python 2 hosts - in those only basic methods are used
log.warning("Import failed, imported from Python 2, operations will fail.")
@ -43,7 +41,7 @@ class SFTPHandler(AbstractProvider):
self.project_name = project_name
self.site_name = site_name
self.root = None
self.conn = None
self._conn = None
self.presets = presets
if not self.presets:
@ -65,11 +63,17 @@ class SFTPHandler(AbstractProvider):
self.sftp_key = provider_presets["sftp_key"]
self.sftp_key_pass = provider_presets["sftp_key_pass"]
self.conn = self._get_conn()
self._tree = None
self.active = True
@property
def conn(self):
"""SFTP connection, cannot be used in all places though."""
if not self._conn:
self._conn = self._get_conn()
return self._conn
def is_active(self):
"""
Returns True if provider is activated, eg. has working credentials.
@ -323,6 +327,7 @@ class SFTPHandler(AbstractProvider):
if not self.file_path_exists(path):
raise FileNotFoundError("File {} to be deleted doesn't exist."
.format(path))
self.conn.remove(path)
def list_folder(self, folder_path):
@ -396,6 +401,9 @@ class SFTPHandler(AbstractProvider):
Returns:
pysftp.Connection
"""
if not pysftp:
raise ImportError
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None

View file

@ -1,26 +1,28 @@
import os
import subprocess
from avalon import api
from openpype.api import ApplicationManager
def existing_djv_path():
djv_paths = os.environ.get("DJV_PATH") or ""
for path in djv_paths.split(os.pathsep):
if os.path.exists(path):
return path
return None
app_manager = ApplicationManager()
djv_list = []
for app_name, app in app_manager.applications.items():
if 'djv' in app_name and app.find_executable():
djv_list.append(app_name)
return djv_list
class OpenInDJV(api.Loader):
"""Open Image Sequence with system default"""
djv_path = existing_djv_path()
families = ["*"] if djv_path else []
djv_list = existing_djv_path()
families = ["*"] if djv_list else []
representations = [
"cin", "dpx", "avi", "dv", "gif", "flv", "mkv", "mov", "mpg", "mpeg",
"mp4", "m4v", "mxf", "iff", "z", "ifl", "jpeg", "jpg", "jfif", "lut",
"1dl", "exr", "pic", "png", "ppm", "pnm", "pgm", "pbm", "rla", "rpf",
"sgi", "rgba", "rgb", "bw", "tga", "tiff", "tif", "img"
"sgi", "rgba", "rgb", "bw", "tga", "tiff", "tif", "img", "h264",
]
label = "Open in DJV"
@ -41,20 +43,18 @@ class OpenInDJV(api.Loader):
)
if not remainder:
seqeunce = collections[0]
first_image = list(seqeunce)[0]
sequence = collections[0]
first_image = list(sequence)[0]
else:
first_image = self.fname
filepath = os.path.normpath(os.path.join(directory, first_image))
self.log.info("Opening : {}".format(filepath))
cmd = [
# DJV path
os.path.normpath(self.djv_path),
# PATH TO COMPONENT
os.path.normpath(filepath)
]
last_djv_version = sorted(self.djv_list)[-1]
# Run DJV with these commands
subprocess.Popen(cmd)
app_manager = ApplicationManager()
djv = app_manager.applications.get(last_djv_version)
djv.arguments.append(filepath)
app_manager.launch(last_djv_version)

View file

@ -0,0 +1,16 @@
from Qt import QtCore
DEFAULT_PROJECT_LABEL = "< Default >"
PROJECT_NAME_ROLE = QtCore.Qt.UserRole + 1
PROJECT_IS_ACTIVE_ROLE = QtCore.Qt.UserRole + 2
PROJECT_IS_SELECTED_ROLE = QtCore.Qt.UserRole + 3
__all__ = (
"DEFAULT_PROJECT_LABEL",
"PROJECT_NAME_ROLE",
"PROJECT_IS_ACTIVE_ROLE",
"PROJECT_IS_SELECTED_ROLE"
)

View file

@ -7,6 +7,12 @@ from avalon.mongodb import (
)
from openpype.settings.lib import get_system_settings
from .constants import (
DEFAULT_PROJECT_LABEL,
PROJECT_NAME_ROLE,
PROJECT_IS_ACTIVE_ROLE,
PROJECT_IS_SELECTED_ROLE
)
class SettingsLineEdit(QtWidgets.QLineEdit):
@ -602,10 +608,63 @@ class NiceCheckbox(QtWidgets.QFrame):
return super(NiceCheckbox, self).mouseReleaseEvent(event)
class ProjectListModel(QtGui.QStandardItemModel):
sort_role = QtCore.Qt.UserRole + 10
filter_role = QtCore.Qt.UserRole + 11
selected_role = QtCore.Qt.UserRole + 12
class ProjectModel(QtGui.QStandardItemModel):
def __init__(self, only_active, *args, **kwargs):
super(ProjectModel, self).__init__(*args, **kwargs)
self.dbcon = None
self._only_active = only_active
self._default_item = None
self._items_by_name = {}
def set_dbcon(self, dbcon):
self.dbcon = dbcon
def refresh(self):
new_items = []
if self._default_item is None:
item = QtGui.QStandardItem(DEFAULT_PROJECT_LABEL)
item.setData(None, PROJECT_NAME_ROLE)
item.setData(True, PROJECT_IS_ACTIVE_ROLE)
item.setData(False, PROJECT_IS_SELECTED_ROLE)
new_items.append(item)
self._default_item = item
project_names = set()
if self.dbcon is not None:
for project_doc in self.dbcon.projects(
projection={"name": 1, "data.active": 1},
only_active=self._only_active
):
project_name = project_doc["name"]
project_names.add(project_name)
if project_name in self._items_by_name:
item = self._items_by_name[project_name]
else:
item = QtGui.QStandardItem(project_name)
self._items_by_name[project_name] = item
new_items.append(item)
is_active = project_doc.get("data", {}).get("active", True)
item.setData(project_name, PROJECT_NAME_ROLE)
item.setData(is_active, PROJECT_IS_ACTIVE_ROLE)
item.setData(False, PROJECT_IS_SELECTED_ROLE)
if not is_active:
font = item.font()
font.setItalic(True)
item.setFont(font)
root_item = self.invisibleRootItem()
for project_name in tuple(self._items_by_name.keys()):
if project_name not in project_names:
item = self._items_by_name.pop(project_name)
root_item.removeRow(item.row())
if new_items:
root_item.appendRows(new_items)
class ProjectListView(QtWidgets.QListView):
@ -618,19 +677,36 @@ class ProjectListView(QtWidgets.QListView):
super(ProjectListView, self).mouseReleaseEvent(event)
class ProjectListSortFilterProxy(QtCore.QSortFilterProxyModel):
class ProjectSortFilterProxy(QtCore.QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(ProjectListSortFilterProxy, self).__init__(*args, **kwargs)
super(ProjectSortFilterProxy, self).__init__(*args, **kwargs)
self._enable_filter = True
def lessThan(self, left_index, right_index):
if left_index.data(PROJECT_NAME_ROLE) is None:
return True
if right_index.data(PROJECT_NAME_ROLE) is None:
return False
left_is_active = left_index.data(PROJECT_IS_ACTIVE_ROLE)
right_is_active = right_index.data(PROJECT_IS_ACTIVE_ROLE)
if right_is_active == left_is_active:
return super(ProjectSortFilterProxy, self).lessThan(
left_index, right_index
)
if left_is_active:
return True
return False
def filterAcceptsRow(self, source_row, source_parent):
if not self._enable_filter:
return True
index = self.sourceModel().index(source_row, 0, source_parent)
is_active = bool(index.data(self.filterRole()))
is_selected = bool(index.data(ProjectListModel.selected_role))
is_selected = bool(index.data(PROJECT_IS_SELECTED_ROLE))
return is_active or is_selected
@ -643,7 +719,6 @@ class ProjectListSortFilterProxy(QtCore.QSortFilterProxyModel):
class ProjectListWidget(QtWidgets.QWidget):
default = "< Default >"
project_changed = QtCore.Signal()
def __init__(self, parent, only_active=False):
@ -657,13 +732,10 @@ class ProjectListWidget(QtWidgets.QWidget):
label_widget = QtWidgets.QLabel("Projects")
project_list = ProjectListView(self)
project_model = ProjectListModel()
project_proxy = ProjectListSortFilterProxy()
project_proxy.setFilterRole(ProjectListModel.filter_role)
project_proxy.setSortRole(ProjectListModel.sort_role)
project_proxy.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
project_model = ProjectModel(only_active)
project_proxy = ProjectSortFilterProxy()
project_proxy.setFilterRole(PROJECT_IS_ACTIVE_ROLE)
project_proxy.setSourceModel(project_model)
project_list.setModel(project_proxy)
@ -693,13 +765,14 @@ class ProjectListWidget(QtWidgets.QWidget):
project_list.left_mouse_released_at.connect(self.on_item_clicked)
self._default_project_item = None
self.project_list = project_list
self.project_proxy = project_proxy
self.project_model = project_model
self.inactive_chk = inactive_chk
self.dbcon = None
self._only_active = only_active
def on_item_clicked(self, new_index):
new_project_name = new_index.data(QtCore.Qt.DisplayRole)
@ -746,12 +819,12 @@ class ProjectListWidget(QtWidgets.QWidget):
return not self._parent.entity.has_unsaved_changes
def project_name(self):
if self.current_project == self.default:
if self.current_project == DEFAULT_PROJECT_LABEL:
return None
return self.current_project
def select_default_project(self):
self.select_project(self.default)
self.select_project(DEFAULT_PROJECT_LABEL)
def select_project(self, project_name):
model = self.project_model
@ -759,10 +832,10 @@ class ProjectListWidget(QtWidgets.QWidget):
found_items = model.findItems(project_name)
if not found_items:
found_items = model.findItems(self.default)
found_items = model.findItems(DEFAULT_PROJECT_LABEL)
index = model.indexFromItem(found_items[0])
model.setData(index, True, ProjectListModel.selected_role)
model.setData(index, True, PROJECT_IS_SELECTED_ROLE)
index = proxy.mapFromSource(index)
@ -777,9 +850,6 @@ class ProjectListWidget(QtWidgets.QWidget):
selected_project = index.data(QtCore.Qt.DisplayRole)
break
model = self.project_model
model.clear()
mongo_url = os.environ["OPENPYPE_MONGO"]
# Force uninstall of whole avalon connection if url does not match
@ -797,35 +867,8 @@ class ProjectListWidget(QtWidgets.QWidget):
self.dbcon = None
self.current_project = None
items = [(self.default, True)]
if self.dbcon:
for doc in self.dbcon.projects(
projection={"name": 1, "data.active": 1},
only_active=self._only_active
):
items.append(
(doc["name"], doc.get("data", {}).get("active", True))
)
for project_name, is_active in items:
row = QtGui.QStandardItem(project_name)
row.setData(is_active, ProjectListModel.filter_role)
row.setData(False, ProjectListModel.selected_role)
if is_active:
row.setData(project_name, ProjectListModel.sort_role)
else:
row.setData("~" + project_name, ProjectListModel.sort_role)
font = row.font()
font.setItalic(True)
row.setFont(font)
model.appendRow(row)
self.project_model.set_dbcon(self.dbcon)
self.project_model.refresh()
self.project_proxy.sort(0)

@ -1 +1 @@
Subproject commit 8aee68fa10ab4d79be1a91e7728a609748e7c3c6
Subproject commit 4b80f81e66aca593784be8b299110a0b6541276f

View file

@ -102,9 +102,6 @@ import subprocess
import site
from pathlib import Path
from igniter.tools import get_openpype_global_settings
# OPENPYPE_ROOT is variable pointing to build (or code) directory
# WARNING `OPENPYPE_ROOT` must be defined before igniter import
# - igniter changes cwd which cause that filepath of this script won't lead
@ -192,6 +189,7 @@ else:
import igniter # noqa: E402
from igniter import BootstrapRepos # noqa: E402
from igniter.tools import (
get_openpype_global_settings,
get_openpype_path_from_db,
validate_mongo_connection
) # noqa