diff --git a/openpype/client/__init__.py b/openpype/client/__init__.py
new file mode 100644
index 0000000000..16b1dcf321
--- /dev/null
+++ b/openpype/client/__init__.py
@@ -0,0 +1,71 @@
+from .entities import (
+ get_projects,
+ get_project,
+
+ get_asset_by_id,
+ get_asset_by_name,
+ get_assets,
+ get_asset_ids_with_subsets,
+
+ get_subset_by_id,
+ get_subset_by_name,
+ get_subsets,
+ get_subset_families,
+
+ get_version_by_id,
+ get_version_by_name,
+ get_versions,
+ get_hero_version_by_id,
+ get_hero_version_by_subset_id,
+ get_hero_versions,
+ get_last_versions,
+ get_last_version_by_subset_id,
+ get_last_version_by_subset_name,
+ get_output_link_versions,
+
+ get_representation_by_id,
+ get_representation_by_name,
+ get_representations,
+ get_representation_parents,
+ get_representations_parents,
+
+ get_thumbnail,
+ get_thumbnails,
+ get_thumbnail_id_from_source,
+)
+
+__all__ = (
+ "get_projects",
+ "get_project",
+
+ "get_asset_by_id",
+ "get_asset_by_name",
+ "get_assets",
+ "get_asset_ids_with_subsets",
+
+ "get_subset_by_id",
+ "get_subset_by_name",
+ "get_subsets",
+ "get_subset_families",
+
+ "get_version_by_id",
+ "get_version_by_name",
+ "get_versions",
+ "get_hero_version_by_id",
+ "get_hero_version_by_subset_id",
+ "get_hero_versions",
+ "get_last_versions",
+ "get_last_version_by_subset_id",
+ "get_last_version_by_subset_name",
+ "get_output_link_versions",
+
+ "get_representation_by_id",
+ "get_representation_by_name",
+ "get_representations",
+ "get_representation_parents",
+ "get_representations_parents",
+
+ "get_thumbnail",
+ "get_thumbnails",
+ "get_thumbnail_id_from_source",
+)
diff --git a/openpype/client/entities.py b/openpype/client/entities.py
new file mode 100644
index 0000000000..a56288c1e8
--- /dev/null
+++ b/openpype/client/entities.py
@@ -0,0 +1,1663 @@
+"""Unclear if these will have public functions like these.
+
+Goal is that most of functions here are called on (or with) an object
+that has project name as a context (e.g. on 'ProjectEntity'?).
+
++ We will need more specific functions doing wery specific queires really fast.
+"""
+
+import os
+import collections
+
+import six
+from bson.objectid import ObjectId
+
+from openpype.lib.mongo import OpenPypeMongoConnection
+
+
+def _get_project_connection(project_name=None):
+ db_name = os.environ.get("AVALON_DB") or "avalon"
+ mongodb = OpenPypeMongoConnection.get_mongo_client()[db_name]
+ if project_name:
+ return mongodb[project_name]
+ return mongodb
+
+
+def _prepare_fields(fields):
+ if not fields:
+ return None
+
+ output = {
+ field: True
+ for field in fields
+ }
+ if "_id" not in output:
+ output["_id"] = True
+ return output
+
+
+def _convert_id(in_id):
+ if isinstance(in_id, six.string_types):
+ return ObjectId(in_id)
+ return in_id
+
+
+def _convert_ids(in_ids):
+ _output = set()
+ for in_id in in_ids:
+ if in_id is not None:
+ _output.add(_convert_id(in_id))
+ return list(_output)
+
+
+def get_projects(active=True, inactive=False, fields=None):
+ mongodb = _get_project_connection()
+ for project_name in mongodb.collection_names():
+ if project_name in ("system.indexes",):
+ continue
+ project_doc = get_project(
+ project_name, active=active, inactive=inactive, fields=fields
+ )
+ if project_doc is not None:
+ yield project_doc
+
+
+def get_project(project_name, active=True, inactive=False, fields=None):
+ # Skip if both are disabled
+ if not active and not inactive:
+ return None
+
+ query_filter = {"type": "project"}
+ # Keep query untouched if both should be available
+ if active and inactive:
+ pass
+
+ # Add filter to keep only active
+ elif active:
+ query_filter["$or"] = [
+ {"data.active": {"$exists": False}},
+ {"data.active": True},
+ ]
+
+ # Add filter to keep only inactive
+ elif inactive:
+ query_filter["$or"] = [
+ {"data.active": {"$exists": False}},
+ {"data.active": False},
+ ]
+
+ conn = _get_project_connection(project_name)
+ return conn.find_one(query_filter, _prepare_fields(fields))
+
+
+def get_asset_by_id(project_name, asset_id, fields=None):
+ """Receive asset data by it's id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ asset_id (str|ObjectId): Asset's id.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ dict: Asset entity data.
+ None: Asset was not found by id.
+ """
+
+ asset_id = _convert_id(asset_id)
+ if not asset_id:
+ return None
+
+ query_filter = {"type": "asset", "_id": asset_id}
+ conn = _get_project_connection(project_name)
+ return conn.find_one(query_filter, _prepare_fields(fields))
+
+
+def get_asset_by_name(project_name, asset_name, fields=None):
+ """Receive asset data by it's name.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ asset_name (str): Asset's name.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ dict: Asset entity data.
+ None: Asset was not found by name.
+ """
+
+ if not asset_name:
+ return None
+
+ query_filter = {"type": "asset", "name": asset_name}
+ conn = _get_project_connection(project_name)
+ return conn.find_one(query_filter, _prepare_fields(fields))
+
+
+def get_assets(
+ project_name, asset_ids=None, asset_names=None, archived=False, fields=None
+):
+ """Assets for specified project by passed filters.
+
+ Passed filters (ids and names) are always combined so all conditions must
+ match.
+
+ To receive all assets from project just keep filters empty.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ asset_ids (list[str|ObjectId]): Asset ids that should be found.
+ asset_names (list[str]): Name assets that should be found.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ Cursor: Query cursor as iterable which returns asset documents matching
+ passed filters.
+ """
+
+ asset_types = ["asset"]
+ if archived:
+ asset_types.append("archived_asset")
+
+ if len(asset_types) == 1:
+ query_filter = {"type": asset_types[0]}
+ else:
+ query_filter = {"type": {"$in": asset_types}}
+
+ if asset_ids is not None:
+ asset_ids = _convert_ids(asset_ids)
+ if not asset_ids:
+ return []
+ query_filter["_id"] = {"$in": asset_ids}
+
+ if asset_names is not None:
+ if not asset_names:
+ return []
+ query_filter["name"] = {"$in": list(asset_names)}
+
+ conn = _get_project_connection(project_name)
+
+ return conn.find(query_filter, _prepare_fields(fields))
+
+
+def get_asset_ids_with_subsets(project_name, asset_ids=None):
+ """Find out which assets have existing subsets.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ asset_ids (list[str|ObjectId]): Look only for entered asset ids.
+
+ Returns:
+ List[ObjectId]: Asset ids that have existing subsets.
+ """
+
+ subset_query = {
+ "type": "subset"
+ }
+ if asset_ids is not None:
+ asset_ids = _convert_ids(asset_ids)
+ if not asset_ids:
+ return []
+ subset_query["parent"] = {"$in": asset_ids}
+
+ conn = _get_project_connection(project_name)
+ result = conn.aggregate([
+ {
+ "$match": subset_query
+ },
+ {
+ "$group": {
+ "_id": "$parent",
+ "count": {"$sum": 1}
+ }
+ }
+ ])
+ asset_ids_with_subsets = []
+ for item in result:
+ asset_id = item["_id"]
+ count = item["count"]
+ if count > 0:
+ asset_ids_with_subsets.append(asset_id)
+ return asset_ids_with_subsets
+
+
+def get_subset_by_id(project_name, subset_id, fields=None):
+ """Single subset entity data by it's id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ subset_id (str|ObjectId): Id of subset which should be found.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If subset with specified filters was not found.
+ Dict: Subset document which can be reduced to specified 'fields'.
+ """
+
+ subset_id = _convert_id(subset_id)
+ if not subset_id:
+ return None
+
+ query_filters = {"type": "subset", "_id": subset_id}
+ conn = _get_project_connection(project_name)
+ return conn.find_one(query_filters, _prepare_fields(fields))
+
+
+def get_subset_by_name(project_name, subset_name, asset_id, fields=None):
+ """Single subset entity data by it's name and it's version id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ subset_name (str): Name of subset.
+ asset_id (str|ObjectId): Id of parent asset.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If subset with specified filters was not found.
+ Dict: Subset document which can be reduced to specified 'fields'.
+ """
+
+ if not subset_name:
+ return None
+
+ asset_id = _convert_id(asset_id)
+ if not asset_id:
+ return None
+
+ query_filters = {
+ "type": "subset",
+ "name": subset_name,
+ "parent": asset_id
+ }
+ conn = _get_project_connection(project_name)
+ return conn.find_one(query_filters, _prepare_fields(fields))
+
+
+def get_subsets(
+ project_name,
+ subset_ids=None,
+ subset_names=None,
+ asset_ids=None,
+ archived=False,
+ fields=None
+):
+ """Subset entities data from one project filtered by entered filters.
+
+ Filters are additive (all conditions must pass to return subset).
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ subset_ids (list[str|ObjectId]): Subset ids that should be queried.
+ Filter ignored if 'None' is passed.
+ subset_names (list[str]): Subset names that should be queried.
+ Filter ignored if 'None' is passed.
+ asset_ids (list[str|ObjectId]): Asset ids under which should look for
+ the subsets. Filter ignored if 'None' is passed.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ Cursor: Iterable cursor yielding all matching subsets.
+ """
+
+ subset_types = ["subset"]
+ if archived:
+ subset_types.append("archived_subset")
+
+ if len(subset_types) == 1:
+ query_filter = {"type": subset_types[0]}
+ else:
+ query_filter = {"type": {"$in": subset_types}}
+
+ if asset_ids is not None:
+ asset_ids = _convert_ids(asset_ids)
+ if not asset_ids:
+ return []
+ query_filter["parent"] = {"$in": asset_ids}
+
+ if subset_ids is not None:
+ subset_ids = _convert_ids(subset_ids)
+ if not subset_ids:
+ return []
+ query_filter["_id"] = {"$in": subset_ids}
+
+ if subset_names is not None:
+ if not subset_names:
+ return []
+ query_filter["name"] = {"$in": list(subset_names)}
+
+ conn = _get_project_connection(project_name)
+ return conn.find(query_filter, _prepare_fields(fields))
+
+
+def get_subset_families(project_name, subset_ids=None):
+ """Set of main families of subsets.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ subset_ids (list[str|ObjectId]): Subset ids that should be queried.
+ All subsets from project are used if 'None' is passed.
+
+ Returns:
+ set[str]: Main families of matching subsets.
+ """
+
+ subset_filter = {
+ "type": "subset"
+ }
+ if subset_ids is not None:
+ if not subset_ids:
+ return set()
+ subset_filter["_id"] = {"$in": list(subset_ids)}
+
+ conn = _get_project_connection(project_name)
+ result = list(conn.aggregate([
+ {"$match": subset_filter},
+ {"$project": {
+ "family": {"$arrayElemAt": ["$data.families", 0]}
+ }},
+ {"$group": {
+ "_id": "family_group",
+ "families": {"$addToSet": "$family"}
+ }}
+ ]))
+ if result:
+ return set(result[0]["families"])
+ return set()
+
+
+def get_version_by_id(project_name, version_id, fields=None):
+ """Single version entity data by it's id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ version_id (str|ObjectId): Id of version which should be found.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If version with specified filters was not found.
+ Dict: Version document which can be reduced to specified 'fields'.
+ """
+
+ version_id = _convert_id(version_id)
+ if not version_id:
+ return None
+
+ query_filter = {
+ "type": {"$in": ["version", "hero_version"]},
+ "_id": version_id
+ }
+ conn = _get_project_connection(project_name)
+ return conn.find_one(query_filter, _prepare_fields(fields))
+
+
+def get_version_by_name(project_name, version, subset_id, fields=None):
+ """Single version entity data by it's name and subset id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ version (int): name of version entity (it's version).
+ subset_id (str|ObjectId): Id of version which should be found.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If version with specified filters was not found.
+ Dict: Version document which can be reduced to specified 'fields'.
+ """
+
+ subset_id = _convert_id(subset_id)
+ if not subset_id:
+ return None
+
+ conn = _get_project_connection(project_name)
+ query_filter = {
+ "type": "version",
+ "parent": subset_id,
+ "name": version
+ }
+ return conn.find_one(query_filter, _prepare_fields(fields))
+
+
+def _get_versions(
+ project_name,
+ subset_ids=None,
+ version_ids=None,
+ standard=True,
+ hero=False,
+ fields=None
+):
+ version_types = []
+ if standard:
+ version_types.append("version")
+
+ if hero:
+ version_types.append("hero_version")
+
+ if not version_types:
+ return []
+ elif len(version_types) == 1:
+ query_filter = {"type": version_types[0]}
+ else:
+ query_filter = {"type": {"$in": version_types}}
+
+ if subset_ids is not None:
+ subset_ids = _convert_ids(subset_ids)
+ if not subset_ids:
+ return []
+ query_filter["parent"] = {"$in": subset_ids}
+
+ if version_ids is not None:
+ version_ids = _convert_ids(version_ids)
+ if not version_ids:
+ return []
+ query_filter["_id"] = {"$in": version_ids}
+
+ conn = _get_project_connection(project_name)
+
+ return conn.find(query_filter, _prepare_fields(fields))
+
+
+def get_versions(
+ project_name,
+ version_ids=None,
+ subset_ids=None,
+ hero=False,
+ fields=None
+):
+ """Version entities data from one project filtered by entered filters.
+
+ Filters are additive (all conditions must pass to return subset).
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ version_ids (list[str|ObjectId]): Version ids that will be queried.
+ Filter ignored if 'None' is passed.
+ subset_ids (list[str]): Subset ids that will be queried.
+ Filter ignored if 'None' is passed.
+ hero (bool): Look also for hero versions.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ Cursor: Iterable cursor yielding all matching versions.
+ """
+
+ return _get_versions(
+ project_name,
+ subset_ids,
+ version_ids,
+ standard=True,
+ hero=hero,
+ fields=fields
+ )
+
+
+def get_hero_version_by_subset_id(project_name, subset_id, fields=None):
+ """Hero version by subset id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ subset_id (str|ObjectId): Subset id under which is hero version.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If hero version for passed subset id does not exists.
+ Dict: Hero version entity data.
+ """
+
+ subset_id = _convert_id(subset_id)
+ if not subset_id:
+ return None
+
+ versions = list(_get_versions(
+ project_name,
+ subset_ids=[subset_id],
+ standard=False,
+ hero=True,
+ fields=fields
+ ))
+ if versions:
+ return versions[0]
+ return None
+
+
+def get_hero_version_by_id(project_name, version_id, fields=None):
+ """Hero version by it's id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ version_id (str|ObjectId): Hero version id.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If hero version with passed id was not found.
+ Dict: Hero version entity data.
+ """
+
+ version_id = _convert_id(version_id)
+ if not version_id:
+ return None
+
+ versions = list(_get_versions(
+ project_name,
+ version_ids=[version_id],
+ standard=False,
+ hero=True,
+ fields=fields
+ ))
+ if versions:
+ return versions[0]
+ return None
+
+
+def get_hero_versions(
+ project_name,
+ subset_ids=None,
+ version_ids=None,
+ fields=None
+):
+ """Hero version entities data from one project filtered by entered filters.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ subset_ids (list[str|ObjectId]): Subset ids for which should look for
+ hero versions. Filter ignored if 'None' is passed.
+ version_ids (list[str|ObjectId]): Hero version ids. Filter ignored if
+ 'None' is passed.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ Cursor|list: Iterable yielding hero versions matching passed filters.
+ """
+
+ return _get_versions(
+ project_name,
+ subset_ids,
+ version_ids,
+ standard=False,
+ hero=True,
+ fields=fields
+ )
+
+
+def get_output_link_versions(project_name, version_id, fields=None):
+ """Versions where passed version was used as input.
+
+ Question:
+ Not 100% sure about the usage of the function so the name and docstring
+ maybe does not match what it does?
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ version_id (str|ObjectId): Version id which can be used as input link
+ for other versions.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ Cursor|list: Iterable cursor yielding versions that are used as input
+ links for passed version.
+ """
+
+ version_id = _convert_id(version_id)
+ if not version_id:
+ return []
+
+ conn = _get_project_connection(project_name)
+ # Does make sense to look for hero versions?
+ query_filter = {
+ "type": "version",
+ "data.inputLinks.input": version_id
+ }
+ return conn.find(query_filter, _prepare_fields(fields))
+
+
+def get_last_versions(project_name, subset_ids, fields=None):
+ """Latest versions for entered subset_ids.
+
+ Args:
+ subset_ids (list): List of subset ids.
+
+ Returns:
+ dict[ObjectId, int]: Key is subset id and value is last version name.
+ """
+
+ subset_ids = _convert_ids(subset_ids)
+ if not subset_ids:
+ return {}
+
+ _pipeline = [
+ # Find all versions of those subsets
+ {"$match": {
+ "type": "version",
+ "parent": {"$in": subset_ids}
+ }},
+ # Sorting versions all together
+ {"$sort": {"name": 1}},
+ # Group them by "parent", but only take the last
+ {"$group": {
+ "_id": "$parent",
+ "_version_id": {"$last": "$_id"}
+ }}
+ ]
+
+ conn = _get_project_connection(project_name)
+ version_ids = [
+ doc["_version_id"]
+ for doc in conn.aggregate(_pipeline)
+ ]
+ fields = _prepare_fields(fields)
+ if fields and "parent" not in fields:
+ fields.append("parent")
+
+ version_docs = get_versions(
+ project_name, version_ids=version_ids, fields=fields
+ )
+
+ return {
+ version_doc["parent"]: version_doc
+ for version_doc in version_docs
+ }
+
+
+def get_last_version_by_subset_id(project_name, subset_id, fields=None):
+ """Last version for passed subset id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ subset_id (str|ObjectId): Id of version which should be found.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If version with specified filters was not found.
+ Dict: Version document which can be reduced to specified 'fields'.
+ """
+
+ subset_id = _convert_id(subset_id)
+ if not subset_id:
+ return None
+
+ last_versions = get_last_versions(
+ project_name, subset_ids=[subset_id], fields=fields
+ )
+ return last_versions.get(subset_id)
+
+
+def get_last_version_by_subset_name(
+ project_name, subset_name, asset_id, fields=None
+):
+ """Last version for passed subset name under asset id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ subset_name (str): Name of subset.
+ asset_id (str|ObjectId): Asset id which is parnt of passed subset name.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If version with specified filters was not found.
+ Dict: Version document which can be reduced to specified 'fields'.
+ """
+
+ subset_doc = get_subset_by_name(
+ project_name, subset_name, asset_id, fields=["_id"]
+ )
+ if not subset_doc:
+ return None
+ return get_last_version_by_subset_id(
+ project_name, subset_doc["_id"], fields=fields
+ )
+
+
+def get_representation_by_id(project_name, representation_id, fields=None):
+ """Representation entity data by it's id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ representation_id (str|ObjectId): Representation id.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If representation with specified filters was not found.
+ Dict: Representation entity data which can be reduced
+ to specified 'fields'.
+ """
+
+ if not representation_id:
+ return None
+
+ repre_types = ["representation", "archived_representations"]
+ query_filter = {
+ "type": {"$in": repre_types}
+ }
+ if representation_id is not None:
+ query_filter["_id"] = _convert_id(representation_id)
+
+ conn = _get_project_connection(project_name)
+
+ return conn.find_one(query_filter, _prepare_fields(fields))
+
+
+def get_representation_by_name(
+ project_name, representation_name, version_id, fields=None
+):
+ """Representation entity data by it's name and it's version id.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ representation_name (str): Representation name.
+ version_id (str|ObjectId): Id of parent version entity.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If representation with specified filters was not found.
+ Dict: Representation entity data which can be reduced
+ to specified 'fields'.
+ """
+
+ version_id = _convert_id(version_id)
+ if not version_id or not representation_name:
+ return None
+ repre_types = ["representation", "archived_representations"]
+ query_filter = {
+ "type": {"$in": repre_types},
+ "name": representation_name,
+ "parent": version_id
+ }
+
+ conn = _get_project_connection(project_name)
+ return conn.find_one(query_filter, _prepare_fields(fields))
+
+
+def get_representations(
+ project_name,
+ representation_ids=None,
+ representation_names=None,
+ version_ids=None,
+ extensions=None,
+ names_by_version_ids=None,
+ archived=False,
+ fields=None
+):
+ """Representaion entities data from one project filtered by filters.
+
+ Filters are additive (all conditions must pass to return subset).
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ representation_ids (list[str|ObjectId]): Representation ids used as
+ filter. Filter ignored if 'None' is passed.
+ representation_names (list[str]): Representations names used as filter.
+ Filter ignored if 'None' is passed.
+ version_ids (list[str]): Subset ids used as parent filter. Filter
+ ignored if 'None' is passed.
+ extensions (list[str]): Filter by extension of main representation
+ file (without dot).
+ names_by_version_ids (dict[ObjectId, list[str]]): Complex filtering
+ using version ids and list of names under the version.
+ archived (bool): Output will also contain archived representations.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ Cursor: Iterable cursor yielding all matching representations.
+ """
+
+ repre_types = ["representation"]
+ if archived:
+ repre_types.append("archived_representations")
+ if len(repre_types) == 1:
+ query_filter = {"type": repre_types[0]}
+ else:
+ query_filter = {"type": {"$in": repre_types}}
+
+ if representation_ids is not None:
+ representation_ids = _convert_ids(representation_ids)
+ if not representation_ids:
+ return []
+ query_filter["_id"] = {"$in": representation_ids}
+
+ if representation_names is not None:
+ if not representation_names:
+ return []
+ query_filter["name"] = {"$in": list(representation_names)}
+
+ if version_ids is not None:
+ version_ids = _convert_ids(version_ids)
+ if not version_ids:
+ return []
+ query_filter["parent"] = {"$in": version_ids}
+
+ if extensions is not None:
+ if not extensions:
+ return []
+ query_filter["context.ext"] = {"$in": list(extensions)}
+
+ if names_by_version_ids is not None:
+ or_query = []
+ for version_id, names in names_by_version_ids.items():
+ if version_id and names:
+ or_query.append({
+ "parent": _convert_id(version_id),
+ "name": {"$in": list(names)}
+ })
+ if not or_query:
+ return []
+ query_filter["$or"] = or_query
+
+ conn = _get_project_connection(project_name)
+
+ return conn.find(query_filter, _prepare_fields(fields))
+
+
+def get_representations_parents(project_name, representations):
+ """Prepare parents of representation entities.
+
+ Each item of returned dictionary contains version, subset, asset
+ and project in that order.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ representations (list[dict]): Representation entities with at least
+ '_id' and 'parent' keys.
+
+ Returns:
+ dict[ObjectId, tuple]: Parents by representation id.
+ """
+
+ repres_by_version_id = collections.defaultdict(list)
+ versions_by_version_id = {}
+ versions_by_subset_id = collections.defaultdict(list)
+ subsets_by_subset_id = {}
+ subsets_by_asset_id = collections.defaultdict(list)
+ for representation in representations:
+ repre_id = representation["_id"]
+ version_id = representation["parent"]
+ repres_by_version_id[version_id].append(representation)
+
+ versions = get_versions(
+ project_name, version_ids=repres_by_version_id.keys()
+ )
+ for version in versions:
+ version_id = version["_id"]
+ subset_id = version["parent"]
+ versions_by_version_id[version_id] = version
+ versions_by_subset_id[subset_id].append(version)
+
+ subsets = get_subsets(
+ project_name, subset_ids=versions_by_subset_id.keys()
+ )
+ for subset in subsets:
+ subset_id = subset["_id"]
+ asset_id = subset["parent"]
+ subsets_by_subset_id[subset_id] = subset
+ subsets_by_asset_id[asset_id].append(subset)
+
+ assets = get_assets(project_name, asset_ids=subsets_by_asset_id.keys())
+ assets_by_id = {
+ asset["_id"]: asset
+ for asset in assets
+ }
+
+ project = get_project(project_name)
+
+ output = {}
+ for version_id, representations in repres_by_version_id.items():
+ asset = None
+ subset = None
+ version = versions_by_version_id.get(version_id)
+ if version:
+ subset_id = version["parent"]
+ subset = subsets_by_subset_id.get(subset_id)
+ if subset:
+ asset_id = subset["parent"]
+ asset = assets_by_id.get(asset_id)
+
+ for representation in representations:
+ repre_id = representation["_id"]
+ output[repre_id] = (version, subset, asset, project)
+ return output
+
+
+def get_representation_parents(project_name, representation):
+ """Prepare parents of representation entity.
+
+ Each item of returned dictionary contains version, subset, asset
+ and project in that order.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ representation (dict): Representation entities with at least
+ '_id' and 'parent' keys.
+
+ Returns:
+ dict[ObjectId, tuple]: Parents by representation id.
+ """
+
+ if not representation:
+ return None
+
+ repre_id = representation["_id"]
+ parents_by_repre_id = get_representations_parents(
+ project_name, [representation]
+ )
+ return parents_by_repre_id.get(repre_id)
+
+
+def get_thumbnail_id_from_source(project_name, src_type, src_id):
+ """Receive thumbnail id from source entity.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ src_type (str): Type of source entity ('asset', 'version').
+ src_id (str|objectId): Id of source entity.
+
+ Returns:
+ ObjectId: Thumbnail id assigned to entity.
+ None: If Source entity does not have any thumbnail id assigned.
+ """
+
+ if not src_type or not src_id:
+ return None
+
+ query_filter = {"_id": _convert_id(src_id)}
+
+ conn = _get_project_connection(project_name)
+ src_doc = conn.find_one(query_filter, {"data.thumbnail_id"})
+ if src_doc:
+ return src_doc.get("data", {}).get("thumbnail_id")
+ return None
+
+
+def get_thumbnails(project_name, thumbnail_ids, fields=None):
+ """Receive thumbnails entity data.
+
+ Thumbnail entity can be used to receive binary content of thumbnail based
+ on it's content and ThumbnailResolvers.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ thumbnail_ids (list[str|ObjectId]): Ids of thumbnail entities.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ cursor: Cursor of queried documents.
+ """
+
+ if thumbnail_ids:
+ thumbnail_ids = _convert_ids(thumbnail_ids)
+
+ if not thumbnail_ids:
+ return []
+ query_filter = {
+ "type": "thumbnail",
+ "_id": {"$in": thumbnail_ids}
+ }
+ conn = _get_project_connection(project_name)
+ return conn.find(query_filter, _prepare_fields(fields))
+
+
+def get_thumbnail(project_name, thumbnail_id, fields=None):
+ """Receive thumbnail entity data.
+
+ Args:
+ project_name (str): Name of project where to look for queried entities.
+ thumbnail_id (str|ObjectId): Id of thumbnail entity.
+ fields (list[str]): Fields that should be returned. All fields are
+ returned if 'None' is passed.
+
+ Returns:
+ None: If thumbnail with specified id was not found.
+ Dict: Thumbnail entity data which can be reduced to specified 'fields'.
+ """
+
+ if not thumbnail_id:
+ return None
+ query_filter = {"type": "thumbnail", "_id": _convert_id(thumbnail_id)}
+ conn = _get_project_connection(project_name)
+ return conn.find_one(query_filter, _prepare_fields(fields))
+
+
+"""
+## Custom data storage:
+- Settings - OP settings overrides and local settings
+- Logging - logs from PypeLogger
+- Webpublisher - jobs
+- Ftrack - events
+- Maya - Shaders
+ - openpype/hosts/maya/api/shader_definition_editor.py
+ - openpype/hosts/maya/plugins/publish/validate_model_name.py
+
+## Global launch hooks
+- openpype/hooks/pre_global_host_data.py
+ Query:
+ - project
+ - asset
+
+## Global load plugins
+- openpype/plugins/load/delete_old_versions.py
+ Query:
+ - versions
+ - representations
+- openpype/plugins/load/delivery.py
+ Query:
+ - representations
+
+## Global publish plugins
+- openpype/plugins/publish/collect_avalon_entities.py
+ Query:
+ - asset
+ - project
+- openpype/plugins/publish/collect_anatomy_instance_data.py
+ Query:
+ - assets
+ - subsets
+ - last version
+- openpype/plugins/publish/collect_scene_loaded_versions.py
+ Query:
+ - representations
+- openpype/plugins/publish/extract_hierarchy_avalon.py
+ Query:
+ - asset
+ - assets
+ - project
+ Create:
+ - asset
+ Update:
+ - asset
+- openpype/plugins/publish/integrate_hero_version.py
+ Query:
+ - version
+ - hero version
+ - representations
+- openpype/plugins/publish/integrate_new.py
+ Query:
+ - asset
+ - subset
+ - version
+ - representations
+- openpype/plugins/publish/integrate_thumbnail.py
+ Query:
+ - version
+- openpype/plugins/publish/validate_editorial_asset_name.py
+ Query:
+ - assets
+
+## Lib
+- openpype/lib/applications.py
+ Query:
+ - project
+ - asset
+- openpype/lib/avalon_context.py
+ Query:
+ - project
+ - asset
+ - linked assets (new function get_linked_assets?)
+ - subset
+ - subsets
+ - version
+ - versions
+ - last version
+ - representations
+ - linked representations (new function get_linked_ids_for_representations)
+ Update:
+ - workfile data
+- openpype/lib/plugin_tools.py
+ Query:
+ - asset
+- openpype/lib/project_backpack.py
+ Query:
+ - project
+ - everything from mongo
+ Update:
+ - project
+- openpype/lib/usdlib.py
+ Query:
+ - project
+ - asset
+
+## Pipeline
+- openpype/pipeline/load/utils.py
+ Query:
+ - project
+ - assets
+ - subsets
+ - version
+ - versions
+ - representation
+ - representations
+- openpype/pipeline/mongodb.py
+ Query:
+ - project
+- openpype/pipeline/thumbnail.py
+ Query:
+ - project
+
+## Hosts
+### Aftereffects
+- openpype/hosts/aftereffects/plugins/create/workfile_creator.py
+ Query:
+ - asset
+
+### Blender
+- openpype/hosts/blender/api/pipeline.py
+ Query:
+ - asset
+- openpype/hosts/blender/plugins/publish/extract_layout.py
+ Query:
+ - representation
+
+### Celaction
+- openpype/hosts/celaction/plugins/publish/collect_audio.py
+ Query:
+ - subsets
+ - last versions
+ - representations
+
+### Fusion
+- openpype/hosts/fusion/api/lib.py
+ Query:
+ - asset
+ - subset
+ - version
+ - representation
+- openpype/hosts/fusion/plugins/load/load_sequence.py
+ Query:
+ - version
+- openpype/hosts/fusion/scripts/fusion_switch_shot.py
+ Query:
+ - project
+ - asset
+ - versions
+- openpype/hosts/fusion/utility_scripts/switch_ui.py
+ Query:
+ - assets
+
+### Harmony
+- openpype/hosts/harmony/api/pipeline.py
+ Query:
+ - representation
+
+### Hiero
+- openpype/hosts/hiero/api/lib.py
+ Query:
+ - project
+ - version
+ - versions
+ - representation
+- openpype/hosts/hiero/api/tags.py
+ Query:
+ - task types
+ - assets
+- openpype/hosts/hiero/plugins/load/load_clip.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/hiero/plugins/publish_old_workflow/collect_assetbuilds.py
+ Query:
+ - assets
+
+### Houdini
+- openpype/hosts/houdini/api/lib.py
+ Query:
+ - asset
+- openpype/hosts/houdini/api/usd.py
+ Query:
+ - asset
+- openpype/hosts/houdini/plugins/create/create_hda.py
+ Query:
+ - asset
+ - subsets
+- openpype/hosts/houdini/plugins/publish/collect_usd_bootstrap.py
+ Query:
+ - asset
+ - subset
+- openpype/hosts/houdini/plugins/publish/extract_usd_layered.py
+ Query:
+ - asset
+ - subset
+ - version
+ - representation
+- openpype/hosts/houdini/plugins/publish/validate_usd_shade_model_exists.py
+ Query:
+ - asset
+ - subset
+- openpype/hosts/houdini/vendor/husdoutputprocessors/avalon_uri_processor.py
+ Query:
+ - project
+ - asset
+
+### Maya
+- openpype/hosts/maya/api/action.py
+ Query:
+ - asset
+- openpype/hosts/maya/api/commands.py
+ Query:
+ - asset
+ - project
+- openpype/hosts/maya/api/lib.py
+ Query:
+ - project
+ - asset
+ - subset
+ - subsets
+ - version
+ - representation
+- openpype/hosts/maya/api/setdress.py
+ Query:
+ - version
+ - representation
+- openpype/hosts/maya/plugins/inventory/import_modelrender.py
+ Query:
+ - representation
+- openpype/hosts/maya/plugins/load/load_audio.py
+ Query:
+ - asset
+ - subset
+ - version
+- openpype/hosts/maya/plugins/load/load_image_plane.py
+ Query:
+ - asset
+ - subset
+ - version
+- openpype/hosts/maya/plugins/load/load_look.py
+ Query:
+ - representation
+- openpype/hosts/maya/plugins/load/load_vrayproxy.py
+ Query:
+ - representation
+- openpype/hosts/maya/plugins/load/load_yeti_cache.py
+ Query:
+ - representation
+- openpype/hosts/maya/plugins/publish/collect_review.py
+ Query:
+ - subsets
+- openpype/hosts/maya/plugins/publish/validate_node_ids_in_database.py
+ Query:
+ - assets
+- openpype/hosts/maya/plugins/publish/validate_node_ids_related.py
+ Query:
+ - asset
+- openpype/hosts/maya/plugins/publish/validate_renderlayer_aovs.py
+ Query:
+ - asset
+ - subset
+
+### Nuke
+- openpype/hosts/nuke/api/command.py
+ Query:
+ - project
+ - asset
+- openpype/hosts/nuke/api/lib.py
+ Query:
+ - project
+ - asset
+ - version
+ - versions
+ - representation
+- openpype/hosts/nuke/plugins/load/load_backdrop.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_camera_abc.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_clip.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_effects_ip.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_effects.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_gizmo_ip.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_gizmo.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_image.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_model.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/load/load_script_precomp.py
+ Query:
+ - version
+ - versions
+- openpype/hosts/nuke/plugins/publish/collect_reads.py
+ Query:
+ - asset
+- openpype/hosts/nuke/plugins/publish/precollect_instances.py
+ Query:
+ - asset
+- openpype/hosts/nuke/plugins/publish/precollect_writes.py
+ Query:
+ - representation
+- openpype/hosts/nuke/plugins/publish/validate_script.py
+ Query:
+ - asset
+ - project
+
+### Photoshop
+- openpype/hosts/photoshop/plugins/create/workfile_creator.py
+ Query:
+ - asset
+
+### Resolve
+- openpype/hosts/resolve/plugins/load/load_clip.py
+ Query:
+ - version
+ - versions
+
+### Standalone publisher
+- openpype/hosts/standalonepublisher/plugins/publish/collect_bulk_mov_instances.py
+ Query:
+ - asset
+- openpype/hosts/standalonepublisher/plugins/publish/collect_matching_asset.py
+ Query:
+ - assets
+- openpype/hosts/standalonepublisher/plugins/publish/collect_hierarchy.py
+ Query:
+ - project
+ - asset
+- openpype/hosts/standalonepublisher/plugins/publish/validate_task_existence.py
+ Query:
+ - assets
+
+### TVPaint
+- openpype/hosts/tvpaint/api/pipeline.py
+ Query:
+ - project
+ - asset
+- openpype/hosts/tvpaint/plugins/load/load_workfile.py
+ Query:
+ - project
+ - asset
+- openpype/hosts/tvpaint/plugins/publish/collect_instances.py
+ Query:
+ - asset
+- openpype/hosts/tvpaint/plugins/publish/collect_scene_render.py
+ Query:
+ - asset
+- openpype/hosts/tvpaint/plugins/publish/collect_workfile.py
+ Query:
+ - asset
+
+### Unreal
+- openpype/hosts/unreal/plugins/load/load_camera.py
+ Query:
+ - asset
+ - assets
+- openpype/hosts/unreal/plugins/load/load_layout.py
+ Query:
+ - asset
+ - assets
+- openpype/hosts/unreal/plugins/publish/extract_layout.py
+ Query:
+ - representation
+
+### Webpublisher
+- openpype/hosts/webpublisher/webserver_service/webpublish_routes.py
+ Query:
+ - assets
+- openpype/hosts/webpublisher/plugins/publish/collect_published_files.py
+ Query:
+ - last versions
+
+## Tools
+openpype/tools/assetlinks/widgets.py
+- SimpleLinkView
+ Query:
+ - get_versions
+ - get_subsets
+ - get_assets
+ - get_output_link_versions
+
+openpype/tools/creator/window.py
+- CreatorWindow
+ Query:
+ - get_asset_by_name
+ - get_subsets
+
+openpype/tools/launcher/models.py
+- LauncherModel
+ Query:
+ - get_project
+ - get_assets
+
+openpype/tools/libraryloader/app.py
+- LibraryLoaderWindow
+ Query:
+ - get_project
+
+openpype/tools/loader/app.py
+- LoaderWindow
+ Query:
+ - get_project
+- show
+ Query:
+ - get_projects
+
+openpype/tools/loader/model.py
+- SubsetsModel
+ Query:
+ - get_assets
+ - get_subsets
+ - get_last_versions
+ - get_versions
+ - get_hero_versions
+ - get_version_by_name
+- RepresentationModel
+ Query:
+ - get_representations
+ - sync server specific queries (separated into multiple functions?)
+ - NOT REPLACED
+
+openpype/tools/loader/widgets.py
+- FamilyModel
+ Query:
+ - get_subset_families
+- VersionTextEdit
+ Query:
+ - get_subset_by_id
+ - get_version_by_id
+- SubsetWidget
+ Query:
+ - get_subsets
+ - get_representations
+ Update:
+ - Subset groups (combination of asset id and subset names)
+- RepresentationWidget
+ Query:
+ - get_subsets
+ - get_versions
+ - get_representations
+- ThumbnailWidget
+ Query:
+ - get_thumbnail_id_from_source
+ - get_thumbnail
+
+openpype/tools/mayalookassigner/app.py
+- MayaLookAssignerWindow
+ Query:
+ - get_last_version_by_subset_id
+
+openpype/tools/mayalookassigner/commands.py
+- create_items_from_nodes
+ Query:
+ - get_asset_by_id
+
+openpype/tools/mayalookassigner/vray_proxies.py
+- get_look_relationships
+ Query:
+ - get_representation_by_name
+- load_look
+ Query:
+ - get_representation_by_name
+- vrayproxy_assign_look
+ Query:
+ - get_last_version_by_subset_name
+
+openpype/tools/project_manager/project_manager/model.py
+- HierarchyModel
+ Query:
+ - get_asset_ids_with_subsets
+ - get_project
+ - get_assets
+
+openpype/tools/project_manager/project_manager/view.py
+- ProjectDocCache
+ Query:
+ - get_project
+
+openpype/tools/project_manager/project_manager/widgets.py
+- CreateProjectDialog
+ Query:
+ - get_projects
+
+openpype/tools/publisher/widgets/create_dialog.py
+- CreateDialog
+ Query:
+ - get_asset_by_name
+ - get_subsets
+
+openpype/tools/publisher/control.py
+- AssetDocsCache
+ Query:
+ - get_assets
+
+openpype/tools/sceneinventory/model.py
+- InventoryModel
+ Query:
+ - get_asset_by_id
+ - get_subset_by_id
+ - get_version_by_id
+ - get_last_version_by_subset_id
+ - get_representation
+
+openpype/tools/sceneinventory/switch_dialog.py
+- SwitchAssetDialog
+ Query:
+ - get_asset_by_name
+ - get_assets
+ - get_subset_by_name
+ - get_subsets
+ - get_versions
+ - get_hero_versions
+ - get_last_versions
+ - get_representations
+
+openpype/tools/sceneinventory/view.py
+- SceneInventoryView
+ Query:
+ - get_version_by_id
+ - get_versions
+ - get_hero_versions
+ - get_representation_by_id
+ - get_representations
+
+openpype/tools/standalonepublish/widgets/model_asset.py
+- AssetModel
+ Query:
+ - get_assets
+
+openpype/tools/standalonepublish/widgets/widget_asset.py
+- AssetWidget
+ Query:
+ - get_project
+ - get_asset_by_id
+
+openpype/tools/standalonepublish/widgets/widget_family.py
+- FamilyWidget
+ Query:
+ - get_asset_by_name
+ - get_subset_by_name
+ - get_subsets
+ - get_last_version_by_subset_id
+
+openpype/tools/standalonepublish/app.py
+- Window
+ Query:
+ - get_asset_by_id
+
+openpype/tools/texture_copy/app.py
+- TextureCopy
+ Query:
+ - get_project
+ - get_asset_by_name
+
+openpype/tools/workfiles/files_widget.py
+- FilesWidget
+ Query:
+ - get_asset_by_id
+
+openpype/tools/workfiles/model.py
+- PublishFilesModel
+ Query:
+ - get_subsets
+ - get_versions
+ - get_representations
+
+openpype/tools/workfiles/save_as_dialog.py
+- build_workfile_data
+ Query:
+ - get_project
+ - get_asset_by_name
+
+openpype/tools/workfiles/window.py
+- Window
+ Query:
+ - get_asset_by_id
+ - get_asset_by_name
+
+openpype/tools/utils/assets_widget.py
+- AssetModel
+ Query:
+ - get_project
+ - get_assets
+
+openpype/tools/utils/delegates.py
+- VersionDelegate
+ Query:
+ - get_versions
+ - get_hero_versions
+
+openpype/tools/utils/lib.py
+- GroupsConfig
+ Query:
+ - get_project
+- FamilyConfigCache
+ Query:
+ - get_asset_by_name
+
+openpype/tools/utils/tasks_widget.py
+- TasksModel
+ Query:
+ - get_project
+ - get_asset_by_id
+"""
diff --git a/openpype/hosts/blender/api/pipeline.py b/openpype/hosts/blender/api/pipeline.py
index 5b81764644..93d81145bc 100644
--- a/openpype/hosts/blender/api/pipeline.py
+++ b/openpype/hosts/blender/api/pipeline.py
@@ -10,6 +10,7 @@ from . import ops
import pyblish.api
+from openpype.client import get_asset_by_name
from openpype.pipeline import (
schema,
legacy_io,
@@ -83,11 +84,9 @@ def uninstall():
def set_start_end_frames():
+ project_name = legacy_io.active_project()
asset_name = legacy_io.Session["AVALON_ASSET"]
- asset_doc = legacy_io.find_one({
- "type": "asset",
- "name": asset_name
- })
+ asset_doc = get_asset_by_name(project_name, asset_name)
scene = bpy.context.scene
diff --git a/openpype/hosts/blender/plugins/publish/extract_layout.py b/openpype/hosts/blender/plugins/publish/extract_layout.py
index 8ecc78a2c6..75d9cf440d 100644
--- a/openpype/hosts/blender/plugins/publish/extract_layout.py
+++ b/openpype/hosts/blender/plugins/publish/extract_layout.py
@@ -1,13 +1,11 @@
import os
import json
-from bson.objectid import ObjectId
-
import bpy
import bpy_extras
import bpy_extras.anim_utils
-from openpype.pipeline import legacy_io
+from openpype.client import get_representation_by_name
from openpype.hosts.blender.api import plugin
from openpype.hosts.blender.api.pipeline import AVALON_PROPERTY
import openpype.api
@@ -131,43 +129,32 @@ class ExtractLayout(openpype.api.Extractor):
fbx_count = 0
+ project_name = instance.context.data["projectEntity"]["name"]
for asset in asset_group.children:
metadata = asset.get(AVALON_PROPERTY)
- parent = metadata["parent"]
+ version_id = metadata["parent"]
family = metadata["family"]
- self.log.debug("Parent: {}".format(parent))
+ self.log.debug("Parent: {}".format(version_id))
# Get blend reference
- blend = legacy_io.find_one(
- {
- "type": "representation",
- "parent": ObjectId(parent),
- "name": "blend"
- },
- projection={"_id": True})
+ blend = get_representation_by_name(
+ project_name, "blend", version_id, fields=["_id"]
+ )
blend_id = None
if blend:
blend_id = blend["_id"]
# Get fbx reference
- fbx = legacy_io.find_one(
- {
- "type": "representation",
- "parent": ObjectId(parent),
- "name": "fbx"
- },
- projection={"_id": True})
+ fbx = get_representation_by_name(
+ project_name, "fbx", version_id, fields=["_id"]
+ )
fbx_id = None
if fbx:
fbx_id = fbx["_id"]
# Get abc reference
- abc = legacy_io.find_one(
- {
- "type": "representation",
- "parent": ObjectId(parent),
- "name": "abc"
- },
- projection={"_id": True})
+ abc = get_representation_by_name(
+ project_name, "abc", version_id, fields=["_id"]
+ )
abc_id = None
if abc:
abc_id = abc["_id"]
diff --git a/openpype/hosts/hiero/api/otio/hiero_export.py b/openpype/hosts/hiero/api/otio/hiero_export.py
index 1e4088d9c0..81cb43fa12 100644
--- a/openpype/hosts/hiero/api/otio/hiero_export.py
+++ b/openpype/hosts/hiero/api/otio/hiero_export.py
@@ -132,7 +132,7 @@ def create_time_effects(otio_clip, track_item):
otio_effect = otio.schema.TimeEffect()
otio_effect.name = name
otio_effect.effect_name = effect_name
- otio_effect.metadata = metadata
+ otio_effect.metadata.update(metadata)
# add otio effect to clip effects
otio_clip.effects.append(otio_effect)
diff --git a/openpype/hosts/maya/plugins/publish/collect_look.py b/openpype/hosts/maya/plugins/publish/collect_look.py
index dc17ddc605..e8ada57f8f 100644
--- a/openpype/hosts/maya/plugins/publish/collect_look.py
+++ b/openpype/hosts/maya/plugins/publish/collect_look.py
@@ -603,6 +603,18 @@ class CollectLook(pyblish.api.InstancePlugin):
source,
computed_source))
+ # renderman allows nodes to have filename attribute empty while
+ # you can have another incoming connection from different node.
+ pxr_nodes = set()
+ if cmds.pluginInfo("RenderMan_for_Maya", query=True, loaded=True):
+ pxr_nodes = set(
+ cmds.pluginInfo("RenderMan_for_Maya",
+ query=True,
+ dependNode=True)
+ )
+ if not source and cmds.nodeType(node) in pxr_nodes:
+ self.log.info("Renderman: source is empty, skipping...")
+ continue
# We replace backslashes with forward slashes because V-Ray
# can't handle the UDIM files with the backslashes in the
# paths as the computed patterns
diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py
index 2c5989309b..505eb19419 100644
--- a/openpype/hosts/nuke/api/lib.py
+++ b/openpype/hosts/nuke/api/lib.py
@@ -539,7 +539,9 @@ def get_created_node_imageio_setting_legacy(nodeclass, creator, subset):
imageio_nodes = get_nuke_imageio_settings()["nodes"]
required_nodes = imageio_nodes["requiredNodes"]
- override_nodes = imageio_nodes["overrideNodes"]
+
+ # HACK: for backward compatibility this needs to be optional
+ override_nodes = imageio_nodes.get("overrideNodes", [])
imageio_node = None
for node in required_nodes:
diff --git a/openpype/hosts/nuke/plugins/create/create_write_still.py b/openpype/hosts/nuke/plugins/create/create_write_still.py
index 4007ccf51e..bb08e8c2c6 100644
--- a/openpype/hosts/nuke/plugins/create/create_write_still.py
+++ b/openpype/hosts/nuke/plugins/create/create_write_still.py
@@ -2,7 +2,20 @@ import nuke
from openpype.hosts.nuke.api import plugin
from openpype.hosts.nuke.api.lib import (
- create_write_node, create_write_node_legacy)
+ create_write_node,
+ create_write_node_legacy,
+ get_created_node_imageio_setting_legacy
+)
+
+# HACK: just to disable still image on projects which
+# are not having anatomy imageio preset for CreateWriteStill
+# TODO: remove this code as soon as it will be obsolete
+imageio_writes = get_created_node_imageio_setting_legacy(
+ "Write",
+ "CreateWriteStill",
+ "stillMain"
+)
+print(imageio_writes["knobs"])
class CreateWriteStill(plugin.AbstractWriteRender):
diff --git a/openpype/modules/ftrack/event_handlers_server/action_create_review_session.py b/openpype/modules/ftrack/event_handlers_server/action_create_review_session.py
new file mode 100644
index 0000000000..8a8e86e7b9
--- /dev/null
+++ b/openpype/modules/ftrack/event_handlers_server/action_create_review_session.py
@@ -0,0 +1,288 @@
+import threading
+import datetime
+import copy
+import collections
+
+import ftrack_api
+
+from openpype.lib import get_datetime_data
+from openpype.api import get_project_settings
+from openpype_modules.ftrack.lib import ServerAction
+
+
+class CreateDailyReviewSessionServerAction(ServerAction):
+ """Create daily review session object per project.
+
+ Action creates review sessions based on settings. Settings define if is
+ action enabled and what is a template for review session name. Logic works
+ in a way that if review session with the name already exists then skip
+ process. If review session for current day does not exist but yesterdays
+ review exists and is empty then yesterdays is renamed otherwise creates
+ new review session.
+
+ Also contains cycle creation of dailies which is triggered each morning.
+ This option must be enabled in project settings. Cycle creation is also
+ checked on registration of action.
+ """
+
+ identifier = "create.daily.review.session"
+ #: Action label.
+ label = "OpenPype Admin"
+ variant = "- Create Daily Review Session (Server)"
+ #: Action description.
+ description = "Manually create daily review session"
+ role_list = {"Pypeclub", "Administrator", "Project Manager"}
+
+ settings_key = "create_daily_review_session"
+ default_template = "{yy}{mm}{dd}"
+
+ def __init__(self, *args, **kwargs):
+ super(CreateDailyReviewSessionServerAction, self).__init__(
+ *args, **kwargs
+ )
+
+ self._cycle_timer = None
+ self._last_cyle_time = None
+ self._day_delta = datetime.timedelta(days=1)
+
+ def discover(self, session, entities, event):
+ """Show action only on AssetVersions."""
+
+ valid_selection = False
+ for ent in event["data"]["selection"]:
+ # Ignore entities that are not tasks or projects
+ if ent["entityType"].lower() in (
+ "show", "task", "reviewsession", "assetversion"
+ ):
+ valid_selection = True
+ break
+
+ if not valid_selection:
+ return False
+ return self.valid_roles(session, entities, event)
+
+ def launch(self, session, entities, event):
+ project_entity = self.get_project_from_entity(entities[0], session)
+ project_name = project_entity["full_name"]
+ project_settings = self.get_project_settings_from_event(
+ event, project_name
+ )
+ action_settings = self._extract_action_settings(project_settings)
+ project_name_by_id = {
+ project_entity["id"]: project_name
+ }
+ settings_by_project_id = {
+ project_entity["id"]: action_settings
+ }
+ self._process_review_session(
+ session, settings_by_project_id, project_name_by_id
+ )
+ return True
+
+ def register(self, *args, **kwargs):
+ """Override register to be able trigger """
+ # Register server action as would be normally
+ super(CreateDailyReviewSessionServerAction, self).register(
+ *args, **kwargs
+ )
+
+ # Create threading timer which will trigger creation of report
+ # at the 00:00:01 of next day
+ # - callback will trigger another timer which will have 1 day offset
+ now = datetime.datetime.now()
+ # Create object of today morning
+ today_morning = datetime.datetime(
+ now.year, now.month, now.day, 0, 0, 1
+ )
+ # Add a day delta (to calculate next day date)
+ next_day_morning = today_morning + self._day_delta
+ # Calculate first delta in seconds for first threading timer
+ first_delta = (next_day_morning - now).total_seconds()
+ # Store cycle time which will be used to create next timer
+ self._last_cyle_time = next_day_morning
+ # Create timer thread
+ self._cycle_timer = threading.Timer(first_delta, self._timer_callback)
+ self._cycle_timer.start()
+
+ self._check_review_session()
+
+ def _timer_callback(self):
+ if (
+ self._cycle_timer is not None
+ and self._last_cyle_time is not None
+ ):
+ now = datetime.datetime.now()
+ while self._last_cyle_time < now:
+ self._last_cyle_time = self._last_cyle_time + self._day_delta
+
+ delay = (self._last_cyle_time - now).total_seconds()
+
+ self._cycle_timer = threading.Timer(delay, self._timer_callback)
+ self._cycle_timer.start()
+ self._check_review_session()
+
+ def _check_review_session(self):
+ session = ftrack_api.Session(
+ server_url=self.session.server_url,
+ api_key=self.session.api_key,
+ api_user=self.session.api_user,
+ auto_connect_event_hub=False
+ )
+ project_entities = session.query(
+ "select id, full_name from Project"
+ ).all()
+ project_names_by_id = {
+ project_entity["id"]: project_entity["full_name"]
+ for project_entity in project_entities
+ }
+
+ action_settings_by_project_id = self._get_action_settings(
+ project_names_by_id
+ )
+ enabled_action_settings_by_project_id = {}
+ for item in action_settings_by_project_id.items():
+ project_id, action_settings = item
+ if action_settings.get("cycle_enabled"):
+ enabled_action_settings_by_project_id[project_id] = (
+ action_settings
+ )
+
+ if not enabled_action_settings_by_project_id:
+ self.log.info((
+ "There are no projects that have enabled"
+ " cycle review sesison creation"
+ ))
+
+ else:
+ self._process_review_session(
+ session,
+ enabled_action_settings_by_project_id,
+ project_names_by_id
+ )
+
+ session.close()
+
+ def _process_review_session(
+ self, session, settings_by_project_id, project_names_by_id
+ ):
+ review_sessions = session.query((
+ "select id, name, project_id"
+ " from ReviewSession where project_id in ({})"
+ ).format(self.join_query_keys(settings_by_project_id))).all()
+
+ review_sessions_by_project_id = collections.defaultdict(list)
+ for review_session in review_sessions:
+ project_id = review_session["project_id"]
+ review_sessions_by_project_id[project_id].append(review_session)
+
+ # Prepare fill data for today's review sesison and yesterdays
+ now = datetime.datetime.now()
+ today_obj = datetime.datetime(
+ now.year, now.month, now.day, 0, 0, 0
+ )
+ yesterday_obj = today_obj - self._day_delta
+
+ today_fill_data = get_datetime_data(today_obj)
+ yesterday_fill_data = get_datetime_data(yesterday_obj)
+
+ # Loop through projects and try to create daily reviews
+ for project_id, action_settings in settings_by_project_id.items():
+ review_session_template = (
+ action_settings["review_session_template"]
+ ).strip() or self.default_template
+
+ today_project_fill_data = copy.deepcopy(today_fill_data)
+ yesterday_project_fill_data = copy.deepcopy(yesterday_fill_data)
+ project_name = project_names_by_id[project_id]
+ today_project_fill_data["project_name"] = project_name
+ yesterday_project_fill_data["project_name"] = project_name
+
+ today_session_name = self._fill_review_template(
+ review_session_template, today_project_fill_data
+ )
+ yesterday_session_name = self._fill_review_template(
+ review_session_template, yesterday_project_fill_data
+ )
+ # Skip if today's session name could not be filled
+ if not today_session_name:
+ continue
+
+ # Find matchin review session
+ project_review_sessions = review_sessions_by_project_id[project_id]
+ todays_session = None
+ yesterdays_session = None
+ for review_session in project_review_sessions:
+ session_name = review_session["name"]
+ if session_name == today_session_name:
+ todays_session = review_session
+ break
+ elif session_name == yesterday_session_name:
+ yesterdays_session = review_session
+
+ # Skip if today's session already exist
+ if todays_session is not None:
+ self.log.debug((
+ "Todays ReviewSession \"{}\""
+ " in project \"{}\" already exists"
+ ).format(today_session_name, project_name))
+ continue
+
+ # Check if there is yesterday's session and is empty
+ # - in that case just rename it
+ if (
+ yesterdays_session is not None
+ and len(yesterdays_session["review_session_objects"]) == 0
+ ):
+ self.log.debug((
+ "Renaming yesterdays empty review session \"{}\" to \"{}\""
+ " in project \"{}\""
+ ).format(
+ yesterday_session_name, today_session_name, project_name
+ ))
+ yesterdays_session["name"] = today_session_name
+ session.commit()
+ continue
+
+ # Create new review session with new name
+ self.log.debug((
+ "Creating new review session \"{}\" in project \"{}\""
+ ).format(today_session_name, project_name))
+ session.create("ReviewSession", {
+ "project_id": project_id,
+ "name": today_session_name
+ })
+ session.commit()
+
+ def _get_action_settings(self, project_names_by_id):
+ settings_by_project_id = {}
+ for project_id, project_name in project_names_by_id.items():
+ project_settings = get_project_settings(project_name)
+ action_settings = self._extract_action_settings(project_settings)
+ settings_by_project_id[project_id] = action_settings
+ return settings_by_project_id
+
+ def _extract_action_settings(self, project_settings):
+ return (
+ project_settings
+ .get("ftrack", {})
+ .get(self.settings_frack_subkey, {})
+ .get(self.settings_key)
+ ) or {}
+
+ def _fill_review_template(self, template, data):
+ output = None
+ try:
+ output = template.format(**data)
+ except Exception:
+ self.log.warning(
+ (
+ "Failed to fill review session template {} with data {}"
+ ).format(template, data),
+ exc_info=True
+ )
+ return output
+
+
+def register(session):
+ '''Register plugin. Called when used as an plugin.'''
+ CreateDailyReviewSessionServerAction(session).register()
diff --git a/openpype/pipeline/legacy_io.py b/openpype/pipeline/legacy_io.py
index c8e7e79600..9359e3057b 100644
--- a/openpype/pipeline/legacy_io.py
+++ b/openpype/pipeline/legacy_io.py
@@ -144,3 +144,12 @@ def parenthood(*args, **kwargs):
@requires_install
def bulk_write(*args, **kwargs):
return _connection_object.bulk_write(*args, **kwargs)
+
+
+@requires_install
+def active_project(*args, **kwargs):
+ return _connection_object.active_project(*args, **kwargs)
+
+
+def current_project(*args, **kwargs):
+ return Session.get("AVALON_PROJECT")
diff --git a/openpype/pipeline/mongodb.py b/openpype/pipeline/mongodb.py
index 565e26b966..dab5bb9e13 100644
--- a/openpype/pipeline/mongodb.py
+++ b/openpype/pipeline/mongodb.py
@@ -199,6 +199,10 @@ class AvalonMongoDB:
"""Return the name of the active project"""
return self.Session["AVALON_PROJECT"]
+ def current_project(self):
+ """Currently set project in Session without triggering installation."""
+ return self.Session.get("AVALON_PROJECT")
+
@requires_install
@auto_reconnect
def projects(self, projection=None, only_active=True):
diff --git a/openpype/plugins/publish/integrate_new.py b/openpype/plugins/publish/integrate_new.py
index 91f6102501..2471105250 100644
--- a/openpype/plugins/publish/integrate_new.py
+++ b/openpype/plugins/publish/integrate_new.py
@@ -940,9 +940,8 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
families += current_families
# create relative source path for DB
- if "source" in instance.data:
- source = instance.data["source"]
- else:
+ source = instance.data.get("source")
+ if not source:
source = context.data["currentFile"]
anatomy = instance.context.data["anatomy"]
source = self.get_rootless_path(anatomy, source)
diff --git a/openpype/settings/defaults/project_settings/ftrack.json b/openpype/settings/defaults/project_settings/ftrack.json
index 9d59deea3d..831c34835e 100644
--- a/openpype/settings/defaults/project_settings/ftrack.json
+++ b/openpype/settings/defaults/project_settings/ftrack.json
@@ -116,6 +116,15 @@
"Administrator",
"Project manager"
]
+ },
+ "create_daily_review_session": {
+ "enabled": true,
+ "role_list": [
+ "Administrator",
+ "Project Manager"
+ ],
+ "cycle_enabled": false,
+ "review_session_template": "{yy}{mm}{dd}"
}
},
"user_handlers": {
diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json
index 16cab49d5d..f8f9d5093d 100644
--- a/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json
+++ b/openpype/settings/entities/schemas/projects_schema/schema_project_ftrack.json
@@ -388,6 +388,44 @@
"object_type": "text"
}
]
+ },
+ {
+ "key": "create_daily_review_session",
+ "label": "Create daily review session",
+ "type": "dict",
+ "is_group": true,
+ "checkbox_key": "enabled",
+ "children": [
+ {
+ "type": "boolean",
+ "key": "enabled"
+ },
+ {
+ "type": "list",
+ "key": "role_list",
+ "label": "Roles",
+ "object_type": "text",
+ "use_label_wrap": true
+ },
+ {
+ "type": "boolean",
+ "key": "cycle_enabled",
+ "label": "Create daily review session"
+ },
+ {
+ "type": "separator"
+ },
+ {
+ "type": "text",
+ "key": "review_session_template",
+ "label": "ReviewSession template",
+ "placeholder": "Default: {yy}{mm}{dd}"
+ },
+ {
+ "type": "label",
+ "label": "Possible formatting keys in template:
- \"project_name\" - <Name of project>
- \"d\" - <Day of month number> in shortest possible way.
- \"dd\" - <Day of month number> with 2 digits.
- \"ddd\" - <Week day name> shortened week day. e.g.: `Mon`, ...
- \"dddd\" - <Week day name> full name of week day. e.g.: `Monday`, ...
- \"m\" - <Month number> in shortest possible way. e.g.: `1` if January
- \"mm\" - <Month number> with 2 digits.
- \"mmm\" - <Month name> shortened month name. e.g.: `Jan`, ...
- \"mmmm\" -<Month name> full month name. e.g.: `January`, ...
- \"yy\" - <Year number> shortened year. e.g.: `19`, `20`, ...
- \"yyyy\" - <Year number> full year. e.g.: `2019`, `2020`, ..."
+ }
+ ]
}
]
},
diff --git a/openpype/tools/assetlinks/widgets.py b/openpype/tools/assetlinks/widgets.py
index 22e8848a60..1b168e542c 100644
--- a/openpype/tools/assetlinks/widgets.py
+++ b/openpype/tools/assetlinks/widgets.py
@@ -1,10 +1,16 @@
+import collections
+from openpype.client import (
+ get_versions,
+ get_subsets,
+ get_assets,
+ get_output_link_versions,
+)
from Qt import QtWidgets
class SimpleLinkView(QtWidgets.QWidget):
-
- def __init__(self, dbcon, parent=None):
+ def __init__(self, dbcon, parent):
super(SimpleLinkView, self).__init__(parent=parent)
self.dbcon = dbcon
@@ -24,6 +30,11 @@ class SimpleLinkView(QtWidgets.QWidget):
self._in_view = in_view
self._out_view = out_view
+ self._version_doc_to_process = None
+
+ @property
+ def project_name(self):
+ return self.dbcon.current_project()
def clear(self):
self._in_view.clear()
@@ -31,60 +42,114 @@ class SimpleLinkView(QtWidgets.QWidget):
def set_version(self, version_doc):
self.clear()
- if not version_doc or not self.isVisible():
- return
+ self._version_doc_to_process = version_doc
+ if version_doc and self.isVisible():
+ self._fill_values()
- # inputs
- #
+ def showEvent(self, event):
+ super(SimpleLinkView, self).showEvent(event)
+ self._fill_values()
+
+ def _fill_values(self):
+ if self._version_doc_to_process is None:
+ return
+ version_doc = self._version_doc_to_process
+ self._version_doc_to_process = None
+ self._fill_inputs(version_doc)
+ self._fill_outputs(version_doc)
+
+ def _fill_inputs(self, version_doc):
+ version_ids = set()
for link in version_doc["data"].get("inputLinks", []):
# Backwards compatibility for "input" key used as "id"
if "id" not in link:
link_id = link["input"]
else:
link_id = link["id"]
- version = self.dbcon.find_one(
- {"_id": link_id, "type": "version"},
- projection={"name": 1, "parent": 1}
- )
- if not version:
- continue
- subset = self.dbcon.find_one(
- {"_id": version["parent"], "type": "subset"},
- projection={"name": 1, "parent": 1}
- )
- if not subset:
- continue
- asset = self.dbcon.find_one(
- {"_id": subset["parent"], "type": "asset"},
- projection={"name": 1}
- )
+ version_ids.add(link_id)
- self._in_view.addItem("{asset} {subset} v{version:0>3}".format(
- asset=asset["name"],
- subset=subset["name"],
- version=version["name"],
+ version_docs = list(get_versions(
+ self.project_name,
+ version_ids=version_ids,
+ fields=["name", "parent"]
+ ))
+
+ versions_by_subset_id = collections.defaultdict(list)
+ for version_doc in version_docs:
+ subset_id = version_doc["parent"]
+ versions_by_subset_id[subset_id].append(version_doc)
+
+ subset_docs = []
+ if versions_by_subset_id:
+ subset_docs = list(get_subsets(
+ self.project_name,
+ subset_ids=versions_by_subset_id.keys(),
+ fields=["_id", "name", "parent"]
))
- # outputs
- #
- outputs = self.dbcon.find(
- {"type": "version", "data.inputLinks.input": version_doc["_id"]},
- projection={"name": 1, "parent": 1}
- )
- for version in outputs or []:
- subset = self.dbcon.find_one(
- {"_id": version["parent"], "type": "subset"},
- projection={"name": 1, "parent": 1}
- )
- if not subset:
- continue
- asset = self.dbcon.find_one(
- {"_id": subset["parent"], "type": "asset"},
- projection={"name": 1}
- )
+ asset_docs = []
+ subsets_by_asset_id = collections.defaultdict(list)
+ if subset_docs:
+ for subset_doc in subset_docs:
+ asset_id = subset_doc["parent"]
+ subsets_by_asset_id[asset_id].append(subset_doc)
- self._out_view.addItem("{asset} {subset} v{version:0>3}".format(
- asset=asset["name"],
- subset=subset["name"],
- version=version["name"],
+ asset_docs = list(get_assets(
+ self.project_name,
+ asset_ids=subsets_by_asset_id.keys(),
+ fields=["_id", "name"]
))
+
+ for asset_doc in asset_docs:
+ asset_id = asset_doc["_id"]
+ for subset_doc in subsets_by_asset_id[asset_id]:
+ subset_id = subset_doc["_id"]
+ for version_doc in versions_by_subset_id[subset_id]:
+ self._in_view.addItem("{} {} v{:0>3}".format(
+ asset_doc["name"],
+ subset_doc["name"],
+ version_doc["name"],
+ ))
+
+ def _fill_outputs(self, version_doc):
+ version_docs = list(get_output_link_versions(
+ self.project_name,
+ version_doc["_id"],
+ fields=["name", "parent"]
+ ))
+ versions_by_subset_id = collections.defaultdict(list)
+ for version_doc in version_docs:
+ subset_id = version_doc["parent"]
+ versions_by_subset_id[subset_id].append(version_doc)
+
+ subset_docs = []
+ if versions_by_subset_id:
+ subset_docs = list(get_subsets(
+ self.project_name,
+ subset_ids=versions_by_subset_id.keys(),
+ fields=["_id", "name", "parent"]
+ ))
+
+ asset_docs = []
+ subsets_by_asset_id = collections.defaultdict(list)
+ if subset_docs:
+ for subset_doc in subset_docs:
+ asset_id = subset_doc["parent"]
+ subsets_by_asset_id[asset_id].append(subset_doc)
+
+ asset_docs = list(get_assets(
+ self.project_name,
+ asset_ids=subsets_by_asset_id.keys(),
+ fields=["_id", "name"]
+ ))
+
+ for asset_doc in asset_docs:
+ asset_id = asset_doc["_id"]
+ for subset_doc in subsets_by_asset_id[asset_id]:
+ subset_id = subset_doc["_id"]
+ for version_doc in versions_by_subset_id[subset_id]:
+ self._out_view.addItem("{} {} v{:0>3}".format(
+ asset_doc["name"],
+ subset_doc["name"],
+ version_doc["name"],
+ ))
diff --git a/openpype/tools/creator/window.py b/openpype/tools/creator/window.py
index e0c329fb78..a3937d6a40 100644
--- a/openpype/tools/creator/window.py
+++ b/openpype/tools/creator/window.py
@@ -4,6 +4,7 @@ import re
from Qt import QtWidgets, QtCore
+from openpype.client import get_asset_by_name, get_subsets
from openpype import style
from openpype.api import get_current_project_settings
from openpype.tools.utils.lib import qt_app_context
@@ -215,12 +216,12 @@ class CreatorWindow(QtWidgets.QDialog):
self._set_valid_state(False)
return
+ project_name = legacy_io.active_project()
asset_doc = None
if creator_plugin:
# Get the asset from the database which match with the name
- asset_doc = legacy_io.find_one(
- {"name": asset_name, "type": "asset"},
- projection={"_id": 1}
+ asset_doc = get_asset_by_name(
+ project_name, asset_name, fields=["_id"]
)
# Get plugin
@@ -235,7 +236,6 @@ class CreatorWindow(QtWidgets.QDialog):
self._set_valid_state(False)
return
- project_name = legacy_io.Session["AVALON_PROJECT"]
asset_id = asset_doc["_id"]
task_name = legacy_io.Session["AVALON_TASK"]
@@ -269,14 +269,13 @@ class CreatorWindow(QtWidgets.QDialog):
self._subset_name_input.setText(subset_name)
# Get all subsets of the current asset
- subset_docs = legacy_io.find(
- {
- "type": "subset",
- "parent": asset_id
- },
- {"name": 1}
+ subset_docs = get_subsets(
+ project_name, asset_ids=[asset_id], fields=["name"]
)
- existing_subset_names = set(subset_docs.distinct("name"))
+ existing_subset_names = {
+ subset_doc["name"]
+ for subset_doc in subset_docs
+ }
existing_subset_names_low = set(
_name.lower()
for _name in existing_subset_names
diff --git a/openpype/tools/launcher/models.py b/openpype/tools/launcher/models.py
index 13567e7916..3f899cc05e 100644
--- a/openpype/tools/launcher/models.py
+++ b/openpype/tools/launcher/models.py
@@ -9,6 +9,10 @@ import appdirs
from Qt import QtCore, QtGui
import qtawesome
+from openpype.client import (
+ get_project,
+ get_assets,
+)
from openpype.lib import JSONSettingRegistry
from openpype.lib.applications import (
CUSTOM_LAUNCH_APP_GROUPS,
@@ -81,13 +85,11 @@ class ActionModel(QtGui.QStandardItemModel):
def get_application_actions(self):
actions = []
- if not self.dbcon.Session.get("AVALON_PROJECT"):
+ if not self.dbcon.current_project():
return actions
- project_doc = self.dbcon.find_one(
- {"type": "project"},
- {"config.apps": True}
- )
+ project_name = self.dbcon.active_project()
+ project_doc = get_project(project_name, fields=["config.apps"])
if not project_doc:
return actions
@@ -448,7 +450,7 @@ class LauncherModel(QtCore.QObject):
@property
def project_name(self):
"""Current project name."""
- return self._dbcon.Session.get("AVALON_PROJECT")
+ return self._dbcon.current_project()
@property
def refreshing_assets(self):
@@ -649,9 +651,8 @@ class LauncherModel(QtCore.QObject):
self._asset_refresh_thread = None
def _refresh_assets(self):
- asset_docs = list(self._dbcon.find(
- {"type": "asset"},
- self._asset_projection
+ asset_docs = list(get_assets(
+ self._last_project_name, fields=self._asset_projection.keys()
))
if not self._refreshing_assets:
return
diff --git a/openpype/tools/libraryloader/app.py b/openpype/tools/libraryloader/app.py
index 7fda6bd6f9..5f4d10d796 100644
--- a/openpype/tools/libraryloader/app.py
+++ b/openpype/tools/libraryloader/app.py
@@ -3,6 +3,7 @@ import sys
from Qt import QtWidgets, QtCore, QtGui
from openpype import style
+from openpype.client import get_project
from openpype.pipeline import AvalonMongoDB
from openpype.tools.utils import lib as tools_lib
from openpype.tools.loader.widgets import (
@@ -303,14 +304,26 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
families = self._subsets_widget.get_subsets_families()
self._families_filter_view.set_enabled_families(families)
- def set_context(self, context, refresh=True):
- self.echo("Setting context: {}".format(context))
- lib.schedule(
- lambda: self._set_context(context, refresh=refresh),
- 50, channel="mongo"
- )
-
# ------------------------------
+ def set_context(self, context, refresh=True):
+ """Set the selection in the interface using a context.
+ The context must contain `asset` data by name.
+
+ Args:
+ context (dict): The context to apply.
+ Returns:
+ None
+ """
+
+ asset_name = context.get("asset", None)
+ if asset_name is None:
+ return
+
+ if refresh:
+ self._refresh_assets()
+
+ self._assets_widget.select_asset_by_name(asset_name)
+
def _on_family_filter_change(self, families):
self._subsets_widget.set_family_filters(families)
@@ -323,10 +336,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
"""Load assets from database"""
if self.current_project is not None:
# Ensure a project is loaded
- project_doc = self.dbcon.find_one(
- {"type": "project"},
- {"type": 1}
- )
+ project_doc = get_project(self.current_project, fields=["_id"])
assert project_doc, "This is a bug"
self._families_filter_view.set_enabled_families(set())
@@ -371,7 +381,7 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
# Clear the version information on asset change
self._version_info_widget.set_version(None)
- self._thumbnail_widget.set_thumbnail(asset_ids)
+ self._thumbnail_widget.set_thumbnail("asset", asset_ids)
self.data["state"]["assetIds"] = asset_ids
@@ -426,34 +436,17 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
version_doc["_id"]
for version_doc in version_docs
]
+ src_type = "version"
if not thumbnail_src_ids:
+ src_type = "asset"
thumbnail_src_ids = self._assets_widget.get_selected_asset_ids()
- self._thumbnail_widget.set_thumbnail(thumbnail_src_ids)
+ self._thumbnail_widget.set_thumbnail(src_type, thumbnail_src_ids)
version_ids = [doc["_id"] for doc in version_docs or []]
if self._repres_widget:
self._repres_widget.set_version_ids(version_ids)
- def _set_context(self, context, refresh=True):
- """Set the selection in the interface using a context.
- The context must contain `asset` data by name.
-
- Args:
- context (dict): The context to apply.
- Returns:
- None
- """
-
- asset_name = context.get("asset", None)
- if asset_name is None:
- return
-
- if refresh:
- self._refresh_assets()
-
- self._assets_widget.select_asset_by_name(asset_name)
-
def _on_message_timeout(self):
self._message_label.setText("")
diff --git a/openpype/tools/loader/app.py b/openpype/tools/loader/app.py
index bb589c199d..1917f23c60 100644
--- a/openpype/tools/loader/app.py
+++ b/openpype/tools/loader/app.py
@@ -3,6 +3,7 @@ import traceback
from Qt import QtWidgets, QtCore
+from openpype.client import get_projects, get_project
from openpype import style
from openpype.lib import register_event_callback
from openpype.pipeline import (
@@ -39,7 +40,7 @@ class LoaderWindow(QtWidgets.QDialog):
def __init__(self, parent=None):
super(LoaderWindow, self).__init__(parent)
title = "Asset Loader 2.1"
- project_name = legacy_io.Session.get("AVALON_PROJECT")
+ project_name = legacy_io.active_project()
if project_name:
title += " - {}".format(project_name)
self.setWindowTitle(title)
@@ -274,8 +275,9 @@ class LoaderWindow(QtWidgets.QDialog):
"""Load assets from database"""
# Ensure a project is loaded
- project = legacy_io.find_one({"type": "project"}, {"type": 1})
- assert project, "Project was not found! This is a bug"
+ project_name = legacy_io.active_project()
+ project_doc = get_project(project_name, fields=["_id"])
+ assert project_doc, "Project was not found! This is a bug"
self._assets_widget.refresh()
self._assets_widget.setFocus()
@@ -314,7 +316,7 @@ class LoaderWindow(QtWidgets.QDialog):
)
# Clear the version information on asset change
- self._thumbnail_widget.set_thumbnail(asset_ids)
+ self._thumbnail_widget.set_thumbnail("asset", asset_ids)
self._version_info_widget.set_version(None)
self.data["state"]["assetIds"] = asset_ids
@@ -371,10 +373,12 @@ class LoaderWindow(QtWidgets.QDialog):
version_doc["_id"]
for version_doc in version_docs
]
+ source_type = "version"
if not thumbnail_src_ids:
+ source_type = "asset"
thumbnail_src_ids = self._assets_widget.get_selected_asset_ids()
- self._thumbnail_widget.set_thumbnail(thumbnail_src_ids)
+ self._thumbnail_widget.set_thumbnail(source_type, thumbnail_src_ids)
if self._repres_widget is not None:
version_ids = [doc["_id"] for doc in version_docs]
@@ -576,8 +580,7 @@ def show(debug=False, parent=None, use_context=False):
legacy_io.install()
any_project = next(
- project for project in legacy_io.projects()
- if project.get("active", True) is not False
+ project for project in get_projects(fields=["name"])
)
legacy_io.Session["AVALON_PROJECT"] = any_project["name"]
diff --git a/openpype/tools/loader/model.py b/openpype/tools/loader/model.py
index 6f39c428be..b5dc16a680 100644
--- a/openpype/tools/loader/model.py
+++ b/openpype/tools/loader/model.py
@@ -7,6 +7,15 @@ from uuid import uuid4
from Qt import QtCore, QtGui
import qtawesome
+from openpype.client import (
+ get_assets,
+ get_subsets,
+ get_last_versions,
+ get_versions,
+ get_hero_versions,
+ get_version_by_name,
+ get_representations
+)
from openpype.pipeline import (
HeroVersionType,
schema,
@@ -56,7 +65,7 @@ class BaseRepresentationModel(object):
remote_site = remote_provider = None
if not project_name:
- project_name = self.dbcon.Session.get("AVALON_PROJECT")
+ project_name = self.dbcon.active_project()
else:
self.dbcon.Session["AVALON_PROJECT"] = project_name
@@ -197,9 +206,6 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
if subset_doc_projection:
self.subset_doc_projection = subset_doc_projection
- self.asset_doc_projection = asset_doc_projection
- self.subset_doc_projection = subset_doc_projection
-
self.repre_icons = {}
self.sync_server = None
self.active_site = self.active_provider = None
@@ -225,7 +231,7 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
self._doc_fetching_stop = False
self._doc_payload = {}
- self.doc_fetched.connect(self.on_doc_fetched)
+ self.doc_fetched.connect(self._on_doc_fetched)
self.refresh()
@@ -244,7 +250,7 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
def set_grouping(self, state):
self._grouping = state
- self.on_doc_fetched()
+ self._on_doc_fetched()
def get_subsets_families(self):
return self._doc_payload.get("subset_families") or set()
@@ -254,57 +260,61 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
# because it also updates the information in other columns
if index.column() == self.columns_index["version"]:
item = index.internalPointer()
- parent = item["_id"]
+ subset_id = item["_id"]
if isinstance(value, HeroVersionType):
- versions = list(self.dbcon.find({
- "type": {"$in": ["version", "hero_version"]},
- "parent": parent
- }, sort=[("name", -1)]))
-
- version = None
- last_version = None
- for __version in versions:
- if __version["type"] == "hero_version":
- version = __version
- elif last_version is None:
- last_version = __version
-
- if version is not None and last_version is not None:
- break
-
- _version = None
- for __version in versions:
- if __version["_id"] == version["version_id"]:
- _version = __version
- break
-
- version["data"] = _version["data"]
- version["name"] = _version["name"]
- version["is_from_latest"] = (
- last_version["_id"] == _version["_id"]
- )
+ version_doc = self._get_hero_version(subset_id)
else:
- version = self.dbcon.find_one({
- "name": value,
- "type": "version",
- "parent": parent
- })
+ project_name = self.dbcon.active_project()
+ version_doc = get_version_by_name(
+ project_name, value, subset_id
+ )
# update availability on active site when version changes
- if self.sync_server.enabled and version:
- query = self._repre_per_version_pipeline([version["_id"]],
- self.active_site,
- self.remote_site)
+ if self.sync_server.enabled and version_doc:
+ query = self._repre_per_version_pipeline(
+ [version_doc["_id"]],
+ self.active_site,
+ self.remote_site
+ )
docs = list(self.dbcon.aggregate(query))
if docs:
repre = docs.pop()
- version["data"].update(self._get_repre_dict(repre))
+ version_doc["data"].update(self._get_repre_dict(repre))
- self.set_version(index, version)
+ self.set_version(index, version_doc)
return super(SubsetsModel, self).setData(index, value, role)
+ def _get_hero_version(self, subset_id):
+ project_name = self.dbcon.active_project()
+ version_docs = get_versions(
+ project_name, subset_ids=[subset_id], hero=True
+ )
+ standard_versions = []
+ hero_version_doc = None
+ for version_doc in version_docs:
+ if version_doc["type"] == "hero_version":
+ hero_version_doc = version_doc
+ continue
+ standard_versions.append(version_doc)
+
+ src_version_id = hero_version_doc["version_id"]
+ src_version = None
+ is_from_latest = True
+ for version_doc in reversed(sorted(
+ standard_versions, key=lambda item: item["name"]
+ )):
+ if version_doc["_id"] == src_version_id:
+ src_version = version_doc
+ break
+ is_from_latest = False
+
+ hero_version_doc["data"] = src_version["data"]
+ hero_version_doc["name"] = src_version["name"]
+ hero_version_doc["is_from_latest"] = is_from_latest
+ return hero_version_doc
+
def set_version(self, index, version):
"""Update the version data of the given index.
@@ -391,26 +401,25 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
item["repre_info"] = repre_info
def _fetch(self):
- asset_docs = self.dbcon.find(
- {
- "type": "asset",
- "_id": {"$in": self._asset_ids}
- },
- self.asset_doc_projection
+ project_name = self.dbcon.active_project()
+ asset_docs = get_assets(
+ project_name,
+ asset_ids=self._asset_ids,
+ fields=self.asset_doc_projection.keys()
)
+
asset_docs_by_id = {
asset_doc["_id"]: asset_doc
for asset_doc in asset_docs
}
subset_docs_by_id = {}
- subset_docs = self.dbcon.find(
- {
- "type": "subset",
- "parent": {"$in": self._asset_ids}
- },
- self.subset_doc_projection
+ subset_docs = get_subsets(
+ project_name,
+ asset_ids=self._asset_ids,
+ fields=self.subset_doc_projection.keys()
)
+
subset_families = set()
for subset_doc in subset_docs:
if self._doc_fetching_stop:
@@ -423,37 +432,13 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
subset_docs_by_id[subset_doc["_id"]] = subset_doc
subset_ids = list(subset_docs_by_id.keys())
- _pipeline = [
- # Find all versions of those subsets
- {"$match": {
- "type": "version",
- "parent": {"$in": subset_ids}
- }},
- # Sorting versions all together
- {"$sort": {"name": 1}},
- # Group them by "parent", but only take the last
- {"$group": {
- "_id": "$parent",
- "_version_id": {"$last": "$_id"},
- "name": {"$last": "$name"},
- "type": {"$last": "$type"},
- "data": {"$last": "$data"},
- "locations": {"$last": "$locations"},
- "schema": {"$last": "$schema"}
- }}
- ]
- last_versions_by_subset_id = dict()
- for doc in self.dbcon.aggregate(_pipeline):
- if self._doc_fetching_stop:
- return
- doc["parent"] = doc["_id"]
- doc["_id"] = doc.pop("_version_id")
- last_versions_by_subset_id[doc["parent"]] = doc
+ last_versions_by_subset_id = get_last_versions(
+ project_name,
+ subset_ids,
+ fields=["_id", "parent", "name", "type", "data", "schema"]
+ )
- hero_versions = self.dbcon.find({
- "type": "hero_version",
- "parent": {"$in": subset_ids}
- })
+ hero_versions = get_hero_versions(project_name, subset_ids=subset_ids)
missing_versions = []
for hero_version in hero_versions:
version_id = hero_version["version_id"]
@@ -462,10 +447,9 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
missing_versions_by_id = {}
if missing_versions:
- missing_version_docs = self.dbcon.find({
- "type": "version",
- "_id": {"$in": missing_versions}
- })
+ missing_version_docs = get_versions(
+ project_name, version_ids=missing_versions
+ )
missing_versions_by_id = {
missing_version_doc["_id"]: missing_version_doc
for missing_version_doc in missing_version_docs
@@ -488,23 +472,16 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
last_versions_by_subset_id[subset_id] = hero_version
- self._doc_payload = {
- "asset_docs_by_id": asset_docs_by_id,
- "subset_docs_by_id": subset_docs_by_id,
- "subset_families": subset_families,
- "last_versions_by_subset_id": last_versions_by_subset_id
- }
-
+ repre_info = {}
if self.sync_server.enabled:
version_ids = set()
for _subset_id, doc in last_versions_by_subset_id.items():
version_ids.add(doc["_id"])
- query = self._repre_per_version_pipeline(list(version_ids),
- self.active_site,
- self.remote_site)
+ query = self._repre_per_version_pipeline(
+ list(version_ids), self.active_site, self.remote_site
+ )
- repre_info = {}
for doc in self.dbcon.aggregate(query):
if self._doc_fetching_stop:
return
@@ -512,7 +489,13 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
doc["remote_provider"] = self.remote_provider
repre_info[doc["_id"]] = doc
- self._doc_payload["repre_info_by_version_id"] = repre_info
+ self._doc_payload = {
+ "asset_docs_by_id": asset_docs_by_id,
+ "subset_docs_by_id": subset_docs_by_id,
+ "subset_families": subset_families,
+ "last_versions_by_subset_id": last_versions_by_subset_id,
+ "repre_info_by_version_id": repre_info
+ }
self.doc_fetched.emit()
@@ -545,7 +528,7 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
self.fetch_subset_and_version()
- def on_doc_fetched(self):
+ def _on_doc_fetched(self):
self.clear()
self._items_by_id = {}
self.beginResetModel()
@@ -1036,7 +1019,6 @@ class RepresentationSortProxyModel(GroupMemberFilterProxyModel):
class RepresentationModel(TreeModel, BaseRepresentationModel):
-
doc_fetched = QtCore.Signal()
refreshed = QtCore.Signal(bool)
@@ -1062,33 +1044,43 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
"remote_site": "Remote"
}
- def __init__(self, dbcon, header, version_ids):
+ repre_projection = {
+ "_id": 1,
+ "name": 1,
+ "context.subset": 1,
+ "context.asset": 1,
+ "context.version": 1,
+ "context.representation": 1,
+ 'files.sites': 1
+ }
+
+ def __init__(self, dbcon, header):
super(RepresentationModel, self).__init__()
self.dbcon = dbcon
self._data = []
self._header = header
- self.version_ids = version_ids
+ self._version_ids = []
manager = ModulesManager()
sync_server = active_site = remote_site = None
active_provider = remote_provider = None
- project = dbcon.Session["AVALON_PROJECT"]
- if project:
+ project_name = dbcon.current_project()
+ if project_name:
sync_server = manager.modules_by_name["sync_server"]
- active_site = sync_server.get_active_site(project)
- remote_site = sync_server.get_remote_site(project)
+ active_site = sync_server.get_active_site(project_name)
+ remote_site = sync_server.get_remote_site(project_name)
# TODO refactor
- active_provider = \
- sync_server.get_provider_for_site(project,
- active_site)
+ active_provider = sync_server.get_provider_for_site(
+ project_name, active_site
+ )
if active_site == 'studio':
active_provider = 'studio'
- remote_provider = \
- sync_server.get_provider_for_site(project,
- remote_site)
+ remote_provider = sync_server.get_provider_for_site(
+ project_name, remote_site
+ )
if remote_site == 'studio':
remote_provider = 'studio'
@@ -1099,7 +1091,7 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
self.remote_site = remote_site
self.remote_provider = remote_provider
- self.doc_fetched.connect(self.on_doc_fetched)
+ self.doc_fetched.connect(self._on_doc_fetched)
self._docs = {}
self._icons = lib.get_repre_icons()
@@ -1110,7 +1102,7 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
self._items_by_id = {}
def set_version_ids(self, version_ids):
- self.version_ids = version_ids
+ self._version_ids = version_ids
self.refresh()
def data(self, index, role):
@@ -1127,8 +1119,7 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
if index.column() == self.Columns.index("name"):
if item.get("isMerged"):
return item["icon"]
- else:
- return self._icons["repre"]
+ return self._icons["repre"]
active_index = self.Columns.index("active_site")
remote_index = self.Columns.index("remote_site")
@@ -1144,12 +1135,12 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
# site added, sync in progress
progress_str = "not avail."
if progress >= 0:
- # progress == 0 for isMerged is unavailable
if progress == 0 and item.get("isMerged"):
progress_str = "not avail."
else:
- progress_str = "{}% {}".format(int(progress * 100),
- label)
+ progress_str = "{}% {}".format(
+ int(progress * 100), label
+ )
return progress_str
@@ -1179,7 +1170,7 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
return super(RepresentationModel, self).data(index, role)
- def on_doc_fetched(self):
+ def _on_doc_fetched(self):
self.clear()
self.beginResetModel()
subsets = set()
@@ -1189,10 +1180,9 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
group = None
self._items_by_id = {}
for doc in self._docs:
- if len(self.version_ids) > 1:
+ if len(self._version_ids) > 1:
group = repre_groups.get(doc["name"])
if not group:
-
group_item = Item()
item_id = str(uuid4())
group_item.update({
@@ -1213,9 +1203,9 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
repre_groups_items[doc["name"]] = 0
group = group_item
- progress = lib.get_progress_for_repre(doc,
- self.active_site,
- self.remote_site)
+ progress = lib.get_progress_for_repre(
+ doc, self.active_site, self.remote_site
+ )
active_site_icon = self._icons.get(self.active_provider)
remote_site_icon = self._icons.get(self.remote_provider)
@@ -1248,9 +1238,9 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
'remote_site_progress': progress[self.remote_site]
}
if group:
- group = self._sum_group_progress(doc["name"], group,
- current_progress,
- repre_groups_items)
+ group = self._sum_group_progress(
+ doc["name"], group, current_progress, repre_groups_items
+ )
self.add_child(item, group)
@@ -1269,47 +1259,39 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
return self._items_by_id.get(item_id)
def refresh(self):
- docs = []
- session_project = self.dbcon.Session['AVALON_PROJECT']
- if not session_project:
+ project_name = self.dbcon.current_project()
+ if not project_name:
return
- if self.version_ids:
+ repre_docs = []
+ if self._version_ids:
# Simple find here for now, expected to receive lower number of
# representations and logic could be in Python
- docs = list(self.dbcon.find(
- {"type": "representation", "parent": {"$in": self.version_ids},
- "files.sites.name": {"$exists": 1}}, self.projection()))
- self._docs = docs
+ repre_docs = list(get_representations(
+ project_name,
+ version_ids=self._version_ids,
+ fields=self.repre_projection.keys()
+ ))
+
+ self._docs = repre_docs
self.doc_fetched.emit()
- @classmethod
- def projection(cls):
- return {
- "_id": 1,
- "name": 1,
- "context.subset": 1,
- "context.asset": 1,
- "context.version": 1,
- "context.representation": 1,
- 'files.sites': 1
- }
+ def _sum_group_progress(
+ self, repre_name, group, current_item_progress, repre_groups_items
+ ):
+ """Update final group progress
- def _sum_group_progress(self, repre_name, group, current_item_progress,
- repre_groups_items):
- """
- Update final group progress
- Called after every item in group is added
+ Called after every item in group is added
- Args:
- repre_name(string)
- group(dict): info about group of selected items
- current_item_progress(dict): {'active_site_progress': XX,
- 'remote_site_progress': YY}
- repre_groups_items(dict)
- Returns:
- (dict): updated group info
+ Args:
+ repre_name(string)
+ group(dict): info about group of selected items
+ current_item_progress(dict): {'active_site_progress': XX,
+ 'remote_site_progress': YY}
+ repre_groups_items(dict)
+ Returns:
+ (dict): updated group info
"""
repre_groups_items[repre_name] += 1
diff --git a/openpype/tools/loader/widgets.py b/openpype/tools/loader/widgets.py
index 42fb62b632..0482bad642 100644
--- a/openpype/tools/loader/widgets.py
+++ b/openpype/tools/loader/widgets.py
@@ -7,6 +7,16 @@ import collections
from Qt import QtWidgets, QtCore, QtGui
+from openpype.client import (
+ get_subset_families,
+ get_subset_by_id,
+ get_subsets,
+ get_version_by_id,
+ get_versions,
+ get_representations,
+ get_thumbnail_id_from_source,
+ get_thumbnail,
+)
from openpype.api import Anatomy
from openpype.pipeline import HeroVersionType
from openpype.pipeline.thumbnail import get_thumbnail_binary
@@ -237,8 +247,7 @@ class SubsetWidget(QtWidgets.QWidget):
self.model = model
self.view = view
- actual_project = dbcon.Session["AVALON_PROJECT"]
- self.on_project_change(actual_project)
+ self.on_project_change(dbcon.current_project())
view.customContextMenuRequested.connect(self.on_context_menu)
@@ -302,33 +311,23 @@ class SubsetWidget(QtWidgets.QWidget):
item["version_document"]
)
- subset_docs = list(self.dbcon.find(
- {
- "_id": {"$in": list(version_docs_by_subset_id.keys())},
- "type": "subset"
- },
- {
- "schema": 1,
- "data.families": 1
- }
+ project_name = self.dbcon.active_project()
+ subset_docs = list(get_subsets(
+ project_name,
+ subset_ids=version_docs_by_subset_id.keys(),
+ fields=["schema", "data.families"]
))
subset_docs_by_id = {
subset_doc["_id"]: subset_doc
for subset_doc in subset_docs
}
version_ids = list(version_docs_by_id.keys())
- repre_docs = self.dbcon.find(
- # Query all representations for selected versions at once
- {
- "type": "representation",
- "parent": {"$in": version_ids}
- },
- # Query only name and parent from representation
- {
- "name": 1,
- "parent": 1
- }
+ repre_docs = get_representations(
+ project_name,
+ version_ids=version_ids,
+ fields=["name", "parent"]
)
+
repre_docs_by_version_id = {
version_id: []
for version_id in version_ids
@@ -566,28 +565,42 @@ class SubsetWidget(QtWidgets.QWidget):
# same representation available
# Trigger
- repre_ids = []
+ project_name = self.dbcon.active_project()
+ subset_names_by_version_id = collections.defaultdict(set)
for item in items:
- representation = self.dbcon.find_one(
- {
- "type": "representation",
- "name": representation_name,
- "parent": item["version_document"]["_id"]
- },
- {"_id": 1}
- )
- if not representation:
- self.echo("Subset '{}' has no representation '{}'".format(
- item["subset"], representation_name
- ))
- continue
- repre_ids.append(representation["_id"])
+ version_id = item["version_document"]["_id"]
+ subset_names_by_version_id[version_id].add(item["subset"])
+
+ version_ids = set(subset_names_by_version_id.keys())
+ repre_docs = get_representations(
+ project_name,
+ representation_names=[representation_name],
+ version_ids=version_ids,
+ fields=["_id", "parent"]
+ )
+
+ repre_ids = []
+ for repre_doc in repre_docs:
+ repre_ids.append(repre_doc["_id"])
+
+ version_id = repre_doc["parent"]
+ if version_id not in version_ids:
+ version_ids.remove(version_id)
+
+ for version_id in version_ids:
+ joined_subset_names = ", ".join([
+ '"{}"'.format(subset)
+ for subset in subset_names_by_version_id[version_id]
+ ])
+ self.echo("Subsets {} don't have representation '{}'".format(
+ joined_subset_names, representation_name
+ ))
# get contexts only for selected menu option
repre_contexts = get_repres_contexts(repre_ids, self.dbcon)
- options = lib.get_options(action, loader, self,
- list(repre_contexts.values()))
-
+ options = lib.get_options(
+ action, loader, self, list(repre_contexts.values())
+ )
error_info = _load_representations_by_loader(
loader, repre_contexts, options=options
)
@@ -661,27 +674,21 @@ class VersionTextEdit(QtWidgets.QTextEdit):
print("Querying..")
+ project_name = self.dbcon.active_project()
if not version_doc:
- version_doc = self.dbcon.find_one({
- "_id": version_id,
- "type": {"$in": ["version", "hero_version"]}
- })
+ version_doc = get_version_by_id(project_name, version_id)
assert version_doc, "Not a valid version id"
if version_doc["type"] == "hero_version":
- _version_doc = self.dbcon.find_one({
- "_id": version_doc["version_id"],
- "type": "version"
- })
+ _version_doc = get_version_by_id(
+ project_name, version_doc["version_id"]
+ )
version_doc["data"] = _version_doc["data"]
version_doc["name"] = HeroVersionType(
_version_doc["name"]
)
- subset = self.dbcon.find_one({
- "_id": version_doc["parent"],
- "type": "subset"
- })
+ subset = get_subset_by_id(project_name, version_doc["parent"])
assert subset, "No valid subset parent for version"
# Define readable creation timestamp
@@ -752,7 +759,7 @@ class VersionTextEdit(QtWidgets.QTextEdit):
if not source:
return
- project_name = self.dbcon.Session["AVALON_PROJECT"]
+ project_name = self.dbcon.current_project()
if self._anatomy is None or self._anatomy.project_name != project_name:
self._anatomy = Anatomy(project_name)
@@ -833,24 +840,19 @@ class ThumbnailWidget(QtWidgets.QLabel):
QtCore.Qt.SmoothTransformation
)
- def set_thumbnail(self, doc_id=None):
- if not doc_id:
+ def set_thumbnail(self, src_type, doc_ids):
+ if not doc_ids:
self.set_pixmap()
return
- if isinstance(doc_id, (list, tuple)):
- if len(doc_id) < 1:
- self.set_pixmap()
- return
- doc_id = doc_id[0]
+ src_id = doc_ids[0]
- doc = self.dbcon.find_one(
- {"_id": doc_id},
- {"data.thumbnail_id"}
+ project_name = self.dbcon.active_project()
+ thumbnail_id = get_thumbnail_id_from_source(
+ project_name,
+ src_type,
+ src_id,
)
- thumbnail_id = None
- if doc:
- thumbnail_id = doc.get("data", {}).get("thumbnail_id")
if thumbnail_id == self.current_thumb_id:
if self.current_thumbnail is None:
self.set_pixmap()
@@ -861,9 +863,7 @@ class ThumbnailWidget(QtWidgets.QLabel):
self.set_pixmap()
return
- thumbnail_ent = self.dbcon.find_one(
- {"type": "thumbnail", "_id": thumbnail_id}
- )
+ thumbnail_ent = get_thumbnail(project_name, thumbnail_id)
if not thumbnail_ent:
return
@@ -917,21 +917,9 @@ class FamilyModel(QtGui.QStandardItemModel):
def refresh(self):
families = set()
- if self.dbcon.Session.get("AVALON_PROJECT"):
- result = list(self.dbcon.aggregate([
- {"$match": {
- "type": "subset"
- }},
- {"$project": {
- "family": {"$arrayElemAt": ["$data.families", 0]}
- }},
- {"$group": {
- "_id": "family_group",
- "families": {"$addToSet": "$family"}
- }}
- ]))
- if result:
- families = set(result[0]["families"])
+ project_name = self.dbcon.current_project()
+ if project_name:
+ families = get_subset_families(project_name)
root_item = self.invisibleRootItem()
@@ -1176,7 +1164,7 @@ class RepresentationWidget(QtWidgets.QWidget):
headers = [item[0] for item in self.default_widths]
- model = RepresentationModel(self.dbcon, headers, [])
+ model = RepresentationModel(self.dbcon, headers)
proxy_model = RepresentationSortProxyModel(self)
proxy_model.setSourceModel(model)
@@ -1213,8 +1201,8 @@ class RepresentationWidget(QtWidgets.QWidget):
self.proxy_model = proxy_model
self.sync_server_enabled = False
- actual_project = dbcon.Session["AVALON_PROJECT"]
- self.on_project_change(actual_project)
+
+ self.on_project_change(dbcon.current_project())
self.model.refresh()
@@ -1243,23 +1231,18 @@ class RepresentationWidget(QtWidgets.QWidget):
for item in items:
repre_ids.append(item["_id"])
- repre_docs = list(self.dbcon.find(
- {
- "type": "representation",
- "_id": {"$in": repre_ids}
- },
- {
- "name": 1,
- "parent": 1
- }
+ project_name = self.dbcon.active_project()
+ repre_docs = list(get_representations(
+ project_name,
+ representation_ids=repre_ids,
+ fields=["name", "parent"]
))
+
version_ids = [
repre_doc["parent"]
for repre_doc in repre_docs
]
- version_docs = self.dbcon.find({
- "_id": {"$in": version_ids}
- })
+ version_docs = get_versions(project_name, version_ids=version_ids)
version_docs_by_id = {}
version_docs_by_subset_id = collections.defaultdict(list)
@@ -1269,15 +1252,10 @@ class RepresentationWidget(QtWidgets.QWidget):
version_docs_by_id[version_id] = version_doc
version_docs_by_subset_id[subset_id].append(version_doc)
- subset_docs = list(self.dbcon.find(
- {
- "_id": {"$in": list(version_docs_by_subset_id.keys())},
- "type": "subset"
- },
- {
- "schema": 1,
- "data.families": 1
- }
+ subset_docs = list(get_subsets(
+ project_name,
+ subset_ids=version_docs_by_subset_id.keys(),
+ fields=["schema", "data.families"]
))
subset_docs_by_id = {
subset_doc["_id"]: subset_doc
@@ -1446,13 +1424,12 @@ class RepresentationWidget(QtWidgets.QWidget):
self._process_action(items, menu, point)
def _process_action(self, items, menu, point):
- """
- Show the context action menu and process selected
+ """Show the context action menu and process selected
- Args:
- items(dict): menu items
- menu(OptionalMenu)
- point(PointIndex)
+ Args:
+ items(dict): menu items
+ menu(OptionalMenu)
+ point(PointIndex)
"""
global_point = self.tree_view.mapToGlobal(point)
action = menu.exec_(global_point)
@@ -1468,21 +1445,23 @@ class RepresentationWidget(QtWidgets.QWidget):
data_by_repre_id = {}
selected_side = action_representation.get("selected_side")
+ is_sync_loader = tools_lib.is_sync_loader(loader)
for item in items:
- if tools_lib.is_sync_loader(loader):
- site_name = "{}_site_name".format(selected_side)
- data = {
- "_id": item.get("_id"),
- "site_name": item.get(site_name),
- "project_name": self.dbcon.Session["AVALON_PROJECT"]
- }
+ item_id = item.get("_id")
+ repre_ids.append(item_id)
+ if not is_sync_loader:
+ continue
- if not data["site_name"]:
- continue
+ site_name = "{}_site_name".format(selected_side)
+ data_site_name = item.get(site_name)
+ if not data_site_name:
+ continue
- data_by_repre_id[data["_id"]] = data
-
- repre_ids.append(item.get("_id"))
+ data_by_repre_id[item_id] = {
+ "_id": item_id,
+ "site_name": data_site_name,
+ "project_name": self.dbcon.active_project()
+ }
repre_contexts = get_repres_contexts(repre_ids, self.dbcon)
options = lib.get_options(action, loader, self,
diff --git a/openpype/tools/mayalookassigner/app.py b/openpype/tools/mayalookassigner/app.py
index 1b6cad77a8..5665acea42 100644
--- a/openpype/tools/mayalookassigner/app.py
+++ b/openpype/tools/mayalookassigner/app.py
@@ -4,6 +4,7 @@ import logging
from Qt import QtWidgets, QtCore
+from openpype.client import get_last_version_by_subset_id
from openpype import style
from openpype.pipeline import legacy_io
from openpype.tools.utils.lib import qt_app_context
@@ -211,6 +212,7 @@ class MayaLookAssignerWindow(QtWidgets.QWidget):
selection = self.assign_selected.isChecked()
asset_nodes = self.asset_outliner.get_nodes(selection=selection)
+ project_name = legacy_io.active_project()
start = time.time()
for i, (asset, item) in enumerate(asset_nodes.items()):
@@ -222,23 +224,20 @@ class MayaLookAssignerWindow(QtWidgets.QWidget):
assign_look = next((subset for subset in item["looks"]
if subset["name"] in looks), None)
if not assign_look:
- self.echo("{} No matching selected "
- "look for {}".format(prefix, asset))
+ self.echo(
+ "{} No matching selected look for {}".format(prefix, asset)
+ )
continue
# Get the latest version of this asset's look subset
- version = legacy_io.find_one(
- {
- "type": "version",
- "parent": assign_look["_id"]
- },
- sort=[("name", -1)]
+ version = get_last_version_by_subset_id(
+ project_name, assign_look["_id"], fields=["_id"]
)
subset_name = assign_look["name"]
- self.echo("{} Assigning {} to {}\t".format(prefix,
- subset_name,
- asset))
+ self.echo("{} Assigning {} to {}\t".format(
+ prefix, subset_name, asset
+ ))
nodes = item["nodes"]
if cmds.pluginInfo('vrayformaya', query=True, loaded=True):
diff --git a/openpype/tools/mayalookassigner/commands.py b/openpype/tools/mayalookassigner/commands.py
index d41d8ca5a2..2e7a51efde 100644
--- a/openpype/tools/mayalookassigner/commands.py
+++ b/openpype/tools/mayalookassigner/commands.py
@@ -2,9 +2,9 @@ from collections import defaultdict
import logging
import os
-from bson.objectid import ObjectId
import maya.cmds as cmds
+from openpype.client import get_asset_by_id
from openpype.pipeline import (
legacy_io,
remove_container,
@@ -159,11 +159,9 @@ def create_items_from_nodes(nodes):
log.warning("No id hashes")
return asset_view_items
+ project_name = legacy_io.active_project()
for _id, id_nodes in id_hashes.items():
- asset = legacy_io.find_one(
- {"_id": ObjectId(_id)},
- projection={"name": True}
- )
+ asset = get_asset_by_id(project_name, _id, fields=["name"])
# Skip if asset id is not found
if not asset:
@@ -180,10 +178,12 @@ def create_items_from_nodes(nodes):
namespace = get_namespace_from_node(node)
namespaces.add(namespace)
- asset_view_items.append({"label": asset["name"],
- "asset": asset,
- "looks": looks,
- "namespaces": namespaces})
+ asset_view_items.append({
+ "label": asset["name"],
+ "asset": asset,
+ "looks": looks,
+ "namespaces": namespaces
+ })
return asset_view_items
diff --git a/openpype/tools/mayalookassigner/vray_proxies.py b/openpype/tools/mayalookassigner/vray_proxies.py
index 3523b24bf3..889396e555 100644
--- a/openpype/tools/mayalookassigner/vray_proxies.py
+++ b/openpype/tools/mayalookassigner/vray_proxies.py
@@ -6,11 +6,14 @@ import logging
import json
import six
-from bson.objectid import ObjectId
import alembic.Abc
from maya import cmds
+from openpype.client import (
+ get_representation_by_name,
+ get_last_version_by_subset_name,
+)
from openpype.pipeline import (
legacy_io,
load_container,
@@ -155,13 +158,12 @@ def get_look_relationships(version_id):
Returns:
dict: Dictionary of relations.
-
"""
- json_representation = legacy_io.find_one({
- "type": "representation",
- "parent": version_id,
- "name": "json"
- })
+
+ project_name = legacy_io.active_project()
+ json_representation = get_representation_by_name(
+ project_name, representation_name="json", version_id=version_id
+ )
# Load relationships
shader_relation = get_representation_path(json_representation)
@@ -184,12 +186,12 @@ def load_look(version_id):
list of shader nodes.
"""
+
+ project_name = legacy_io.active_project()
# Get representations of shader file and relationships
- look_representation = legacy_io.find_one({
- "type": "representation",
- "parent": version_id,
- "name": "ma"
- })
+ look_representation = get_representation_by_name(
+ project_name, representation_name="ma", version_id=version_id
+ )
# See if representation is already loaded, if so reuse it.
host = registered_host()
@@ -220,42 +222,6 @@ def load_look(version_id):
return shader_nodes
-def get_latest_version(asset_id, subset):
- # type: (str, str) -> dict
- """Get latest version of subset.
-
- Args:
- asset_id (str): Asset ID
- subset (str): Subset name.
-
- Returns:
- Latest version
-
- Throws:
- RuntimeError: When subset or version doesn't exist.
-
- """
- subset = legacy_io.find_one({
- "name": subset,
- "parent": ObjectId(asset_id),
- "type": "subset"
- })
- if not subset:
- raise RuntimeError("Subset does not exist: %s" % subset)
-
- version = legacy_io.find_one(
- {
- "type": "version",
- "parent": subset["_id"]
- },
- sort=[("name", -1)]
- )
- if not version:
- raise RuntimeError("Version does not exist.")
-
- return version
-
-
def vrayproxy_assign_look(vrayproxy, subset="lookDefault"):
# type: (str, str) -> None
"""Assign look to vray proxy.
@@ -281,13 +247,20 @@ def vrayproxy_assign_look(vrayproxy, subset="lookDefault"):
asset_id = node_id.split(":", 1)[0]
node_ids_by_asset_id[asset_id].add(node_id)
+ project_name = legacy_io.active_project()
for asset_id, node_ids in node_ids_by_asset_id.items():
# Get latest look version
- try:
- version = get_latest_version(asset_id, subset=subset)
- except RuntimeError as exc:
- print(exc)
+ version = get_last_version_by_subset_name(
+ project_name,
+ subset_name=subset,
+ asset_id=asset_id,
+ fields=["_id"]
+ )
+ if not version:
+ print("Didn't find last version for subset name {}".format(
+ subset
+ ))
continue
relationships = get_look_relationships(version["_id"])
diff --git a/openpype/tools/project_manager/project_manager/model.py b/openpype/tools/project_manager/project_manager/model.py
index 223cfa629d..c5bde5aaec 100644
--- a/openpype/tools/project_manager/project_manager/model.py
+++ b/openpype/tools/project_manager/project_manager/model.py
@@ -7,6 +7,11 @@ from pymongo import UpdateOne, DeleteOne
from Qt import QtCore, QtGui
+from openpype.client import (
+ get_project,
+ get_assets,
+ get_asset_ids_with_subsets,
+)
from openpype.lib import (
CURRENT_DOC_SCHEMAS,
PypeLogger,
@@ -255,10 +260,11 @@ class HierarchyModel(QtCore.QAbstractItemModel):
return
# Find project'd document
- project_doc = self.dbcon.database[project_name].find_one(
- {"type": "project"},
- ProjectItem.query_projection
+ project_doc = get_project(
+ project_name,
+ fields=list(ProjectItem.query_projection.keys())
)
+
# Skip if project document does not exist
# - this shouldn't happen using only UI elements
if not project_doc:
@@ -269,9 +275,8 @@ class HierarchyModel(QtCore.QAbstractItemModel):
self.add_item(project_item)
# Query all assets of the project
- asset_docs = self.dbcon.database[project_name].find(
- {"type": "asset"},
- AssetItem.query_projection
+ asset_docs = get_assets(
+ project_name, fields=AssetItem.query_projection.keys()
)
asset_docs_by_id = {
asset_doc["_id"]: asset_doc
@@ -282,31 +287,16 @@ class HierarchyModel(QtCore.QAbstractItemModel):
# if asset item can be modified (name and hierarchy change)
# - the same must be applied to all it's parents
asset_ids = list(asset_docs_by_id.keys())
- result = []
+ asset_ids_with_subsets = []
if asset_ids:
- result = self.dbcon.database[project_name].aggregate([
- {
- "$match": {
- "type": "subset",
- "parent": {"$in": asset_ids}
- }
- },
- {
- "$group": {
- "_id": "$parent",
- "count": {"$sum": 1}
- }
- }
- ])
+ asset_ids_with_subsets = get_asset_ids_with_subsets(
+ project_name, asset_ids=asset_ids
+ )
asset_modifiable = {
- asset_id: True
+ asset_id: asset_id not in asset_ids_with_subsets
for asset_id in asset_docs_by_id.keys()
}
- for item in result:
- asset_id = item["_id"]
- count = item["count"]
- asset_modifiable[asset_id] = count < 1
# Store assets by their visual parent to be able create their hierarchy
asset_docs_by_parent_id = collections.defaultdict(list)
diff --git a/openpype/tools/project_manager/project_manager/view.py b/openpype/tools/project_manager/project_manager/view.py
index a16def276d..cca892ef72 100644
--- a/openpype/tools/project_manager/project_manager/view.py
+++ b/openpype/tools/project_manager/project_manager/view.py
@@ -3,6 +3,7 @@ from queue import Queue
from Qt import QtWidgets, QtCore, QtGui
+from openpype.client import get_project
from .delegates import (
NumberDelegate,
NameDelegate,
@@ -47,12 +48,8 @@ class ProjectDocCache:
def set_project(self, project_name):
self.project_doc = None
- if not project_name:
- return
-
- self.project_doc = self.dbcon.database[project_name].find_one(
- {"type": "project"}
- )
+ if project_name:
+ self.project_doc = get_project(project_name)
class ToolsCache:
diff --git a/openpype/tools/project_manager/project_manager/widgets.py b/openpype/tools/project_manager/project_manager/widgets.py
index dc75b30bd7..371d1ba2ef 100644
--- a/openpype/tools/project_manager/project_manager/widgets.py
+++ b/openpype/tools/project_manager/project_manager/widgets.py
@@ -1,5 +1,6 @@
import re
+from openpype.client import get_projects
from .constants import (
NAME_ALLOWED_SYMBOLS,
NAME_REGEX
@@ -272,15 +273,9 @@ class CreateProjectDialog(QtWidgets.QDialog):
def _get_existing_projects(self):
project_names = set()
project_codes = set()
- for project_name in self.dbcon.database.collection_names():
- # Each collection will have exactly one project document
- project_doc = self.dbcon.database[project_name].find_one(
- {"type": "project"},
- {"name": 1, "data.code": 1}
- )
- if not project_doc:
- continue
-
+ for project_doc in get_projects(
+ inactive=True, fields=["name", "data.code"]
+ ):
project_name = project_doc.get("name")
if not project_name:
continue
diff --git a/openpype/tools/publisher/control.py b/openpype/tools/publisher/control.py
index 2973d6a5bb..915fb7f32e 100644
--- a/openpype/tools/publisher/control.py
+++ b/openpype/tools/publisher/control.py
@@ -13,6 +13,7 @@ except Exception:
import pyblish.api
+from openpype.client import get_assets
from openpype.pipeline import (
PublishValidationError,
registered_host,
@@ -116,10 +117,10 @@ class AssetDocsCache:
def _query(self):
if self._asset_docs is None:
- asset_docs = list(self.dbcon.find(
- {"type": "asset"},
- self.projection
- ))
+ project_name = self.dbcon.active_project()
+ asset_docs = get_assets(
+ project_name, fields=self.projection.keys()
+ )
task_names_by_asset_name = {}
for asset_doc in asset_docs:
asset_name = asset_doc["name"]
diff --git a/openpype/tools/publisher/widgets/create_dialog.py b/openpype/tools/publisher/widgets/create_dialog.py
index 9e357f3a56..53bbef8b75 100644
--- a/openpype/tools/publisher/widgets/create_dialog.py
+++ b/openpype/tools/publisher/widgets/create_dialog.py
@@ -9,6 +9,8 @@ try:
except Exception:
commonmark = None
from Qt import QtWidgets, QtCore, QtGui
+
+from openpype.client import get_asset_by_name, get_subsets
from openpype.lib import TaskNotSetError
from openpype.pipeline.create import (
CreatorError,
@@ -647,21 +649,19 @@ class CreateDialog(QtWidgets.QDialog):
if asset_name is None:
return
- asset_doc = self.dbcon.find_one({
- "type": "asset",
- "name": asset_name
- })
+ project_name = self.dbcon.active_project()
+ asset_doc = get_asset_by_name(project_name, asset_name)
self._asset_doc = asset_doc
if asset_doc:
- subset_docs = self.dbcon.find(
- {
- "type": "subset",
- "parent": asset_doc["_id"]
- },
- {"name": 1}
+ asset_id = asset_doc["_id"]
+ subset_docs = get_subsets(
+ project_name, asset_ids=[asset_id], fields=["name"]
)
- self._subset_names = set(subset_docs.distinct("name"))
+ self._subset_names = {
+ subset_doc["name"]
+ for subset_doc in subset_docs
+ }
if not asset_doc:
self.subset_name_input.setText("< Asset is not set >")
diff --git a/openpype/tools/sceneinventory/model.py b/openpype/tools/sceneinventory/model.py
index 8d72020c98..0bb9c4a658 100644
--- a/openpype/tools/sceneinventory/model.py
+++ b/openpype/tools/sceneinventory/model.py
@@ -5,8 +5,14 @@ from collections import defaultdict
from Qt import QtCore, QtGui
import qtawesome
-from bson.objectid import ObjectId
+from openpype.client import (
+ get_asset_by_id,
+ get_subset_by_id,
+ get_version_by_id,
+ get_last_version_by_subset_id,
+ get_representation_by_id,
+)
from openpype.pipeline import (
legacy_io,
schema,
@@ -55,7 +61,7 @@ class InventoryModel(TreeModel):
if not self.sync_enabled:
return
- project_name = legacy_io.Session["AVALON_PROJECT"]
+ project_name = legacy_io.current_project()
active_site = sync_server.get_active_site(project_name)
remote_site = sync_server.get_remote_site(project_name)
@@ -192,12 +198,12 @@ class InventoryModel(TreeModel):
self.clear()
if self._hierarchy_view and selected:
-
if not hasattr(host.pipeline, "update_hierarchy"):
# If host doesn't support hierarchical containers, then
# cherry-pick only.
self.add_items((item for item in items
if item["objectName"] in selected))
+ return
# Update hierarchy info for all containers
items_by_name = {item["objectName"]: item
@@ -291,6 +297,9 @@ class InventoryModel(TreeModel):
node.Item: root node which has children added based on the data
"""
+ # NOTE: @iLLiCiTiT this need refactor
+ project_name = legacy_io.active_project()
+
self.beginResetModel()
# Group by representation
@@ -304,32 +313,36 @@ class InventoryModel(TreeModel):
for repre_id, group_dict in sorted(grouped.items()):
group_items = group_dict["items"]
# Get parenthood per group
- representation = legacy_io.find_one({"_id": ObjectId(repre_id)})
+ representation = get_representation_by_id(
+ project_name, repre_id
+ )
if not representation:
not_found["representation"].append(group_items)
not_found_ids.append(repre_id)
continue
- version = legacy_io.find_one({"_id": representation["parent"]})
+ version = get_version_by_id(
+ project_name, representation["parent"]
+ )
if not version:
not_found["version"].append(group_items)
not_found_ids.append(repre_id)
continue
elif version["type"] == "hero_version":
- _version = legacy_io.find_one({
- "_id": version["version_id"]
- })
+ _version = get_version_by_id(
+ project_name, version["version_id"]
+ )
version["name"] = HeroVersionType(_version["name"])
version["data"] = _version["data"]
- subset = legacy_io.find_one({"_id": version["parent"]})
+ subset = get_subset_by_id(project_name, version["parent"])
if not subset:
not_found["subset"].append(group_items)
not_found_ids.append(repre_id)
continue
- asset = legacy_io.find_one({"_id": subset["parent"]})
+ asset = get_asset_by_id(project_name, subset["parent"])
if not asset:
not_found["asset"].append(group_items)
not_found_ids.append(repre_id)
@@ -390,10 +403,9 @@ class InventoryModel(TreeModel):
# Store the highest available version so the model can know
# whether current version is currently up-to-date.
- highest_version = legacy_io.find_one({
- "type": "version",
- "parent": version["parent"]
- }, sort=[("name", -1)])
+ highest_version = get_last_version_by_subset_id(
+ project_name, version["parent"]
+ )
# create the group header
group_node = Item()
diff --git a/openpype/tools/sceneinventory/switch_dialog.py b/openpype/tools/sceneinventory/switch_dialog.py
index b2d770330f..1d1d5cbb91 100644
--- a/openpype/tools/sceneinventory/switch_dialog.py
+++ b/openpype/tools/sceneinventory/switch_dialog.py
@@ -4,6 +4,16 @@ from Qt import QtWidgets, QtCore
import qtawesome
from bson.objectid import ObjectId
+from openpype.client import (
+ get_asset_by_name,
+ get_assets,
+ get_subset_by_name,
+ get_subsets,
+ get_versions,
+ get_hero_versions,
+ get_last_versions,
+ get_representations,
+)
from openpype.pipeline import legacy_io
from openpype.pipeline.load import (
discover_loader_plugins,
@@ -144,6 +154,9 @@ class SwitchAssetDialog(QtWidgets.QDialog):
self._prepare_content_data()
self.refresh(True)
+ def active_project(self):
+ return legacy_io.active_project()
+
def _prepare_content_data(self):
repre_ids = set()
content_loaders = set()
@@ -151,10 +164,12 @@ class SwitchAssetDialog(QtWidgets.QDialog):
repre_ids.add(ObjectId(item["representation"]))
content_loaders.add(item["loader"])
- repres = list(legacy_io.find({
- "type": {"$in": ["representation", "archived_representation"]},
- "_id": {"$in": list(repre_ids)}
- }))
+ project_name = self.active_project()
+ repres = list(get_representations(
+ project_name,
+ representation_ids=repre_ids,
+ archived=True
+ ))
repres_by_id = {repre["_id"]: repre for repre in repres}
# stash context values, works only for single representation
@@ -179,10 +194,11 @@ class SwitchAssetDialog(QtWidgets.QDialog):
content_repres[repre_id] = repres_by_id[repre_id]
version_ids.append(repre["parent"])
- versions = legacy_io.find({
- "type": {"$in": ["version", "hero_version"]},
- "_id": {"$in": list(set(version_ids))}
- })
+ versions = get_versions(
+ project_name,
+ version_ids=set(version_ids),
+ hero=True
+ )
content_versions = {}
hero_version_ids = set()
for version in versions:
@@ -198,10 +214,9 @@ class SwitchAssetDialog(QtWidgets.QDialog):
else:
subset_ids.append(content_versions[version_id]["parent"])
- subsets = legacy_io.find({
- "type": {"$in": ["subset", "archived_subset"]},
- "_id": {"$in": subset_ids}
- })
+ subsets = get_subsets(
+ project_name, subset_ids=subset_ids, archived=True
+ )
subsets_by_id = {sub["_id"]: sub for sub in subsets}
asset_ids = []
@@ -220,10 +235,7 @@ class SwitchAssetDialog(QtWidgets.QDialog):
asset_ids.append(subset["parent"])
content_subsets[subset_id] = subset
- assets = legacy_io.find({
- "type": {"$in": ["asset", "archived_asset"]},
- "_id": {"$in": list(asset_ids)}
- })
+ assets = get_assets(project_name, asset_ids=asset_ids, archived=True)
assets_by_id = {asset["_id"]: asset for asset in assets}
missing_assets = []
@@ -472,9 +484,10 @@ class SwitchAssetDialog(QtWidgets.QDialog):
# Prepare asset document if asset is selected
asset_doc = None
if selected_asset:
- asset_doc = legacy_io.find_one(
- {"type": "asset", "name": selected_asset},
- {"_id": True}
+ asset_doc = get_asset_by_name(
+ self.active_project(),
+ selected_asset,
+ fields=["_id"]
)
if not asset_doc:
return []
@@ -523,38 +536,35 @@ class SwitchAssetDialog(QtWidgets.QDialog):
def _get_current_output_repre_ids_xxx(
self, asset_doc, selected_subset, selected_repre
):
- subset_doc = legacy_io.find_one(
- {
- "type": "subset",
- "name": selected_subset,
- "parent": asset_doc["_id"]
- },
- {"_id": True}
+ project_name = self.active_project()
+ subset_doc = get_subset_by_name(
+ project_name,
+ selected_subset,
+ asset_doc["_id"],
+ fields=["_id"]
)
+
subset_id = subset_doc["_id"]
last_versions_by_subset_id = self.find_last_versions([subset_id])
version_doc = last_versions_by_subset_id.get(subset_id)
if not version_doc:
return []
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "parent": version_doc["_id"],
- "name": selected_repre
- },
- {"_id": True}
+ repre_docs = get_representations(
+ project_name,
+ version_ids=[version_doc["_id"]],
+ representation_names=[selected_repre],
+ fields=["_id"]
)
return [repre_doc["_id"] for repre_doc in repre_docs]
def _get_current_output_repre_ids_xxo(self, asset_doc, selected_subset):
- subset_doc = legacy_io.find_one(
- {
- "type": "subset",
- "parent": asset_doc["_id"],
- "name": selected_subset
- },
- {"_id": True}
+ project_name = self.active_project()
+ subset_doc = get_subset_by_name(
+ project_name,
+ selected_subset,
+ asset_doc["_id"],
+ fields=["_id"]
)
if not subset_doc:
return []
@@ -563,41 +573,51 @@ class SwitchAssetDialog(QtWidgets.QDialog):
for repre_doc in self.content_repres.values():
repre_names.add(repre_doc["name"])
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "parent": subset_doc["_id"],
- "name": {"$in": list(repre_names)}
- },
- {"_id": True}
+ # TODO where to take version ids?
+ version_ids = []
+ repre_docs = get_representations(
+ project_name,
+ representation_names=repre_names,
+ version_ids=version_ids,
+ fields=["_id"]
)
return [repre_doc["_id"] for repre_doc in repre_docs]
def _get_current_output_repre_ids_xox(self, asset_doc, selected_repre):
- susbet_names = set()
+ subset_names = set()
for subset_doc in self.content_subsets.values():
- susbet_names.add(subset_doc["name"])
+ subset_names.add(subset_doc["name"])
- subset_docs = legacy_io.find(
- {
- "type": "subset",
- "name": {"$in": list(susbet_names)},
- "parent": asset_doc["_id"]
- },
- {"_id": True}
+ project_name = self.active_project()
+ subset_docs = get_subsets(
+ project_name,
+ asset_ids=[asset_doc["_id"]],
+ subset_names=subset_names,
+ fields=["_id", "name"]
)
- subset_ids = [subset_doc["_id"] for subset_doc in subset_docs]
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "parent": {"$in": subset_ids},
- "name": selected_repre
- },
- {"_id": True}
+ subset_name_by_id = {
+ subset_doc["_id"]: subset_doc["name"]
+ for subset_doc in subset_docs
+ }
+ subset_ids = list(subset_name_by_id.keys())
+ last_versions_by_subset_id = self.find_last_versions(subset_ids)
+ last_version_id_by_subset_name = {}
+ for subset_id, last_version in last_versions_by_subset_id.items():
+ subset_name = subset_name_by_id[subset_id]
+ last_version_id_by_subset_name[subset_name] = (
+ last_version["_id"]
+ )
+
+ repre_docs = get_representations(
+ project_name,
+ version_ids=last_version_id_by_subset_name.values(),
+ representation_names=[selected_repre],
+ fields=["_id"]
)
return [repre_doc["_id"] for repre_doc in repre_docs]
def _get_current_output_repre_ids_xoo(self, asset_doc):
+ project_name = self.active_project()
repres_by_subset_name = collections.defaultdict(set)
for repre_doc in self.content_repres.values():
repre_name = repre_doc["name"]
@@ -606,13 +626,11 @@ class SwitchAssetDialog(QtWidgets.QDialog):
subset_name = subset_doc["name"]
repres_by_subset_name[subset_name].add(repre_name)
- subset_docs = list(legacy_io.find(
- {
- "type": "subset",
- "parent": asset_doc["_id"],
- "name": {"$in": list(repres_by_subset_name.keys())}
- },
- {"_id": True, "name": True}
+ subset_docs = list(get_subsets(
+ project_name,
+ asset_ids=[asset_doc["_id"]],
+ subset_names=repres_by_subset_name.keys(),
+ fields=["_id", "name"]
))
subset_name_by_id = {
subset_doc["_id"]: subset_doc["name"]
@@ -627,60 +645,59 @@ class SwitchAssetDialog(QtWidgets.QDialog):
last_version["_id"]
)
- repre_or_query = []
+ repre_names_by_version_id = {}
for subset_name, repre_names in repres_by_subset_name.items():
version_id = last_version_id_by_subset_name.get(subset_name)
# This should not happen but why to crash?
- if version_id is None:
- continue
- repre_or_query.append({
- "parent": version_id,
- "name": {"$in": list(repre_names)}
- })
- repre_docs = legacy_io.find(
- {"$or": repre_or_query},
- {"_id": True}
+ if version_id is not None:
+ repre_names_by_version_id[version_id] = list(repre_names)
+
+ repre_docs = get_representations(
+ project_name,
+ names_by_version_ids=repre_names_by_version_id,
+ fields=["_id"]
)
return [repre_doc["_id"] for repre_doc in repre_docs]
def _get_current_output_repre_ids_oxx(
self, selected_subset, selected_repre
):
- subset_docs = list(legacy_io.find({
- "type": "subset",
- "parent": {"$in": list(self.content_assets.keys())},
- "name": selected_subset
- }))
+ project_name = self.active_project()
+ subset_docs = get_subsets(
+ project_name,
+ asset_ids=self.content_assets.keys(),
+ subset_names=[selected_subset],
+ fields=["_id"]
+ )
subset_ids = [subset_doc["_id"] for subset_doc in subset_docs]
last_versions_by_subset_id = self.find_last_versions(subset_ids)
last_version_ids = [
last_version["_id"]
for last_version in last_versions_by_subset_id.values()
]
- repre_docs = legacy_io.find({
- "type": "representation",
- "parent": {"$in": last_version_ids},
- "name": selected_repre
- })
-
+ repre_docs = get_representations(
+ project_name,
+ version_ids=last_version_ids,
+ representation_names=[selected_repre],
+ fields=["_id"]
+ )
return [repre_doc["_id"] for repre_doc in repre_docs]
def _get_current_output_repre_ids_oxo(self, selected_subset):
- subset_docs = list(legacy_io.find(
- {
- "type": "subset",
- "parent": {"$in": list(self.content_assets.keys())},
- "name": selected_subset
- },
- {"_id": True, "parent": True}
- ))
- if not subset_docs:
- return list()
-
+ project_name = self.active_project()
+ subset_docs = get_subsets(
+ project_name,
+ asset_ids=self.content_assets.keys(),
+ subset_names=[selected_subset],
+ fields=["_id", "parent"]
+ )
subset_docs_by_id = {
subset_doc["_id"]: subset_doc
for subset_doc in subset_docs
}
+ if not subset_docs:
+ return list()
+
last_versions_by_subset_id = self.find_last_versions(
subset_docs_by_id.keys()
)
@@ -702,56 +719,44 @@ class SwitchAssetDialog(QtWidgets.QDialog):
asset_id = asset_doc["_id"]
repre_names_by_asset_id[asset_id].add(repre_name)
- repre_or_query = []
+ repre_names_by_version_id = {}
for last_version_id, subset_id in subset_id_by_version_id.items():
subset_doc = subset_docs_by_id[subset_id]
asset_id = subset_doc["parent"]
repre_names = repre_names_by_asset_id.get(asset_id)
if not repre_names:
continue
- repre_or_query.append({
- "parent": last_version_id,
- "name": {"$in": list(repre_names)}
- })
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "$or": repre_or_query
- },
- {"_id": True}
- )
+ repre_names_by_version_id[last_version_id] = repre_names
+ repre_docs = get_representations(
+ project_name,
+ names_by_version_ids=repre_names_by_version_id,
+ fields=["_id"]
+ )
return [repre_doc["_id"] for repre_doc in repre_docs]
def _get_current_output_repre_ids_oox(self, selected_repre):
- repre_docs = legacy_io.find(
- {
- "name": selected_repre,
- "parent": {"$in": list(self.content_versions.keys())}
- },
- {"_id": True}
+ project_name = self.active_project()
+ repre_docs = get_representations(
+ project_name,
+ representation_names=[selected_repre],
+ version_ids=self.content_versions.keys(),
+ fields=["_id"]
)
return [repre_doc["_id"] for repre_doc in repre_docs]
def _get_asset_box_values(self):
- asset_docs = legacy_io.find(
- {"type": "asset"},
- {"_id": 1, "name": 1}
- )
+ project_name = self.active_project()
+ asset_docs = get_assets(project_name, fields=["_id", "name"])
asset_names_by_id = {
asset_doc["_id"]: asset_doc["name"]
for asset_doc in asset_docs
}
- subsets = legacy_io.find(
- {
- "type": "subset",
- "parent": {"$in": list(asset_names_by_id.keys())}
- },
- {
- "parent": 1
- }
+ subsets = get_subsets(
+ project_name,
+ asset_ids=asset_names_by_id.keys(),
+ fields=["parent"]
)
-
filtered_assets = []
for subset in subsets:
asset_name = asset_names_by_id[subset["parent"]]
@@ -760,25 +765,20 @@ class SwitchAssetDialog(QtWidgets.QDialog):
return sorted(filtered_assets)
def _get_subset_box_values(self):
+ project_name = self.active_project()
selected_asset = self._assets_box.get_valid_value()
if selected_asset:
- asset_doc = legacy_io.find_one({
- "type": "asset",
- "name": selected_asset
- })
+ asset_doc = get_asset_by_name(
+ project_name, selected_asset, fields=["_id"]
+ )
asset_ids = [asset_doc["_id"]]
else:
asset_ids = list(self.content_assets.keys())
- subsets = legacy_io.find(
- {
- "type": "subset",
- "parent": {"$in": asset_ids}
- },
- {
- "parent": 1,
- "name": 1
- }
+ subsets = get_subsets(
+ project_name,
+ asset_ids=asset_ids,
+ fields=["parent", "name"]
)
subset_names_by_parent_id = collections.defaultdict(set)
@@ -800,6 +800,7 @@ class SwitchAssetDialog(QtWidgets.QDialog):
def _representations_box_values(self):
# NOTE hero versions are not used because it is expected that
# hero version has same representations as latests
+ project_name = self.active_project()
selected_asset = self._assets_box.currentText()
selected_subset = self._subsets_box.currentText()
@@ -807,16 +808,11 @@ class SwitchAssetDialog(QtWidgets.QDialog):
# [ ] [ ] [?]
if not selected_asset and not selected_subset:
# Find all representations of selection's subsets
- possible_repres = list(legacy_io.find(
- {
- "type": "representation",
- "parent": {"$in": list(self.content_versions.keys())}
- },
- {
- "parent": 1,
- "name": 1
- }
- ))
+ possible_repres = get_representations(
+ project_name,
+ version_ids=self.content_versions.keys(),
+ fields=["parent", "name"]
+ )
possible_repres_by_parent = collections.defaultdict(set)
for repre in possible_repres:
@@ -836,29 +832,23 @@ class SwitchAssetDialog(QtWidgets.QDialog):
# [x] [x] [?]
if selected_asset and selected_subset:
- asset_doc = legacy_io.find_one(
- {"type": "asset", "name": selected_asset},
- {"_id": 1}
+ asset_doc = get_asset_by_name(
+ project_name, selected_asset, fields=["_id"]
)
- subset_doc = legacy_io.find_one(
- {
- "type": "subset",
- "name": selected_subset,
- "parent": asset_doc["_id"]
- },
- {"_id": 1}
+ subset_doc = get_subset_by_name(
+ project_name,
+ selected_subset,
+ asset_doc["_id"],
+ fields=["_id"]
)
+
subset_id = subset_doc["_id"]
last_versions_by_subset_id = self.find_last_versions([subset_id])
version_doc = last_versions_by_subset_id.get(subset_id)
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "parent": version_doc["_id"]
- },
- {
- "name": 1
- }
+ repre_docs = get_representations(
+ project_name,
+ version_ids=[version_doc["_id"]],
+ fields=["name"]
)
return [
repre_doc["name"]
@@ -868,9 +858,8 @@ class SwitchAssetDialog(QtWidgets.QDialog):
# [x] [ ] [?]
# If asset only is selected
if selected_asset:
- asset_doc = legacy_io.find_one(
- {"type": "asset", "name": selected_asset},
- {"_id": 1}
+ asset_doc = get_asset_by_name(
+ project_name, selected_asset, fields=["_id"]
)
if not asset_doc:
return list()
@@ -879,13 +868,12 @@ class SwitchAssetDialog(QtWidgets.QDialog):
subset_names = set()
for subset_doc in self.content_subsets.values():
subset_names.add(subset_doc["name"])
- subset_docs = legacy_io.find(
- {
- "type": "subset",
- "parent": asset_doc["_id"],
- "name": {"$in": list(subset_names)}
- },
- {"_id": 1}
+
+ subset_docs = get_subsets(
+ project_name,
+ asset_ids=[asset_doc["_id"]],
+ subset_names=subset_names,
+ fields=["_id"]
)
subset_ids = [
subset_doc["_id"]
@@ -903,15 +891,10 @@ class SwitchAssetDialog(QtWidgets.QDialog):
if not subset_id_by_version_id:
return list()
- repre_docs = list(legacy_io.find(
- {
- "type": "representation",
- "parent": {"$in": list(subset_id_by_version_id.keys())}
- },
- {
- "name": 1,
- "parent": 1
- }
+ repre_docs = list(get_representations(
+ project_name,
+ version_ids=subset_id_by_version_id.keys(),
+ fields=["name", "parent"]
))
if not repre_docs:
return list()
@@ -933,13 +916,11 @@ class SwitchAssetDialog(QtWidgets.QDialog):
return list(available_repres)
# [ ] [x] [?]
- subset_docs = list(legacy_io.find(
- {
- "type": "subset",
- "parent": {"$in": list(self.content_assets.keys())},
- "name": selected_subset
- },
- {"_id": 1, "parent": 1}
+ subset_docs = list(get_subsets(
+ project_name,
+ asset_ids=self.content_assets.keys(),
+ subset_names=[selected_subset],
+ fields=["_id", "parent"]
))
if not subset_docs:
return list()
@@ -960,16 +941,13 @@ class SwitchAssetDialog(QtWidgets.QDialog):
if not subset_id_by_version_id:
return list()
- repre_docs = list(legacy_io.find(
- {
- "type": "representation",
- "parent": {"$in": list(subset_id_by_version_id.keys())}
- },
- {
- "name": 1,
- "parent": 1
- }
- ))
+ repre_docs = list(
+ get_representations(
+ project_name,
+ version_ids=subset_id_by_version_id.keys(),
+ fields=["name", "parent"]
+ )
+ )
if not repre_docs:
return list()
@@ -1016,14 +994,14 @@ class SwitchAssetDialog(QtWidgets.QDialog):
return
# [x] [ ] [?]
- asset_doc = legacy_io.find_one(
- {"type": "asset", "name": selected_asset},
- {"_id": 1}
+ project_name = self.active_project()
+ asset_doc = get_asset_by_name(
+ project_name, selected_asset, fields=["_id"]
)
- subset_docs = legacy_io.find(
- {"type": "subset", "parent": asset_doc["_id"]},
- {"name": 1}
+ subset_docs = get_subsets(
+ project_name, asset_ids=[asset_doc["_id"]], fields=["name"]
)
+
subset_names = set(
subset_doc["name"]
for subset_doc in subset_docs
@@ -1035,27 +1013,12 @@ class SwitchAssetDialog(QtWidgets.QDialog):
break
def find_last_versions(self, subset_ids):
- _pipeline = [
- # Find all versions of those subsets
- {"$match": {
- "type": "version",
- "parent": {"$in": list(subset_ids)}
- }},
- # Sorting versions all together
- {"$sort": {"name": 1}},
- # Group them by "parent", but only take the last
- {"$group": {
- "_id": "$parent",
- "_version_id": {"$last": "$_id"},
- "type": {"$last": "$type"}
- }}
- ]
- last_versions_by_subset_id = dict()
- for doc in legacy_io.aggregate(_pipeline):
- doc["parent"] = doc["_id"]
- doc["_id"] = doc.pop("_version_id")
- last_versions_by_subset_id[doc["parent"]] = doc
- return last_versions_by_subset_id
+ project_name = self.active_project()
+ return get_last_versions(
+ project_name,
+ subset_ids=subset_ids,
+ fields=["_id", "parent", "type"]
+ )
def _is_repre_ok(self, validation_state):
selected_asset = self._assets_box.get_valid_value()
@@ -1078,33 +1041,28 @@ class SwitchAssetDialog(QtWidgets.QDialog):
return
# [x] [x] [ ]
+ project_name = self.active_project()
if selected_asset is not None and selected_subset is not None:
- asset_doc = legacy_io.find_one(
- {"type": "asset", "name": selected_asset},
- {"_id": 1}
+ asset_doc = get_asset_by_name(
+ project_name, selected_asset, fields=["_id"]
)
- subset_doc = legacy_io.find_one(
- {
- "type": "subset",
- "parent": asset_doc["_id"],
- "name": selected_subset
- },
- {"_id": 1}
+ subset_doc = get_subset_by_name(
+ project_name,
+ selected_subset,
+ asset_doc["_id"],
+ fields=["_id"]
)
- last_versions_by_subset_id = self.find_last_versions(
- [subset_doc["_id"]]
- )
- last_version = last_versions_by_subset_id.get(subset_doc["_id"])
+ subset_id = subset_doc["_id"]
+ last_versions_by_subset_id = self.find_last_versions([subset_id])
+ last_version = last_versions_by_subset_id.get(subset_id)
if not last_version:
validation_state.repre_ok = False
return
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "parent": last_version["_id"]
- },
- {"name": 1}
+ repre_docs = get_representations(
+ project_name,
+ version_ids=[last_version["_id"]],
+ fields=["name"]
)
repre_names = set(
@@ -1119,16 +1077,13 @@ class SwitchAssetDialog(QtWidgets.QDialog):
# [x] [ ] [ ]
if selected_asset is not None:
- asset_doc = legacy_io.find_one(
- {"type": "asset", "name": selected_asset},
- {"_id": 1}
+ asset_doc = get_asset_by_name(
+ project_name, selected_asset, fields=["_id"]
)
- subset_docs = list(legacy_io.find(
- {
- "type": "subset",
- "parent": asset_doc["_id"]
- },
- {"_id": 1, "name": 1}
+ subset_docs = list(get_subsets(
+ project_name,
+ asset_ids=[asset_doc["_id"]],
+ fields=["_id", "name"]
))
subset_name_by_id = {}
@@ -1145,15 +1100,10 @@ class SwitchAssetDialog(QtWidgets.QDialog):
version_id = last_version["_id"]
subset_id_by_version_id[version_id] = subset_id
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "parent": {"$in": list(subset_id_by_version_id.keys())}
- },
- {
- "name": 1,
- "parent": 1
- }
+ repre_docs = get_representations(
+ project_name,
+ version_ids=subset_id_by_version_id.keys(),
+ fields=["name", "parent"]
)
repres_by_subset_name = {}
for repre_doc in repre_docs:
@@ -1176,15 +1126,12 @@ class SwitchAssetDialog(QtWidgets.QDialog):
# [ ] [x] [ ]
# Subset documents
- subset_docs = legacy_io.find(
- {
- "type": "subset",
- "parent": {"$in": list(self.content_assets.keys())},
- "name": selected_subset
- },
- {"_id": 1, "name": 1, "parent": 1}
+ subset_docs = get_subsets(
+ project_name,
+ asset_ids=self.content_assets.keys(),
+ subset_names=[selected_subset],
+ fields=["_id", "name", "parent"]
)
-
subset_docs_by_id = {}
for subset_doc in subset_docs:
subset_docs_by_id[subset_doc["_id"]] = subset_doc
@@ -1197,15 +1144,10 @@ class SwitchAssetDialog(QtWidgets.QDialog):
version_id = last_version["_id"]
subset_id_by_version_id[version_id] = subset_id
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "parent": {"$in": list(subset_id_by_version_id.keys())}
- },
- {
- "name": 1,
- "parent": 1
- }
+ repre_docs = get_representations(
+ project_name,
+ version_ids=subset_id_by_version_id.keys(),
+ fields=["name", "parent"]
)
repres_by_asset_id = {}
for repre_doc in repre_docs:
@@ -1245,11 +1187,9 @@ class SwitchAssetDialog(QtWidgets.QDialog):
selected_subset = self._subsets_box.get_valid_value()
selected_representation = self._representations_box.get_valid_value()
+ project_name = self.active_project()
if selected_asset:
- asset_doc = legacy_io.find_one({
- "type": "asset",
- "name": selected_asset
- })
+ asset_doc = get_asset_by_name(project_name, selected_asset)
asset_docs_by_id = {asset_doc["_id"]: asset_doc}
else:
asset_docs_by_id = self.content_assets
@@ -1259,16 +1199,15 @@ class SwitchAssetDialog(QtWidgets.QDialog):
for asset_doc in asset_docs_by_id.values()
}
- asset_ids = list(asset_docs_by_id.keys())
-
- subset_query = {
- "type": "subset",
- "parent": {"$in": asset_ids}
- }
+ subset_names = None
if selected_subset:
- subset_query["name"] = selected_subset
+ subset_names = [selected_subset]
- subset_docs = list(legacy_io.find(subset_query))
+ subset_docs = list(get_subsets(
+ project_name,
+ subset_names=subset_names,
+ asset_ids=asset_docs_by_id.keys()
+ ))
subset_ids = []
subset_docs_by_parent_and_name = collections.defaultdict(dict)
for subset in subset_docs:
@@ -1278,15 +1217,14 @@ class SwitchAssetDialog(QtWidgets.QDialog):
subset_docs_by_parent_and_name[parent_id][name] = subset
# versions
- version_docs = list(legacy_io.find({
- "type": "version",
- "parent": {"$in": subset_ids}
- }, sort=[("name", -1)]))
+ _version_docs = get_versions(project_name, subset_ids=subset_ids)
+ version_docs = list(reversed(
+ sorted(_version_docs, key=lambda item: item["name"])
+ ))
- hero_version_docs = list(legacy_io.find({
- "type": "hero_version",
- "parent": {"$in": subset_ids}
- }))
+ hero_version_docs = list(get_hero_versions(
+ project_name, subset_ids=subset_ids
+ ))
version_ids = list()
@@ -1303,10 +1241,7 @@ class SwitchAssetDialog(QtWidgets.QDialog):
parent_id = hero_version_doc["parent"]
hero_version_docs_by_parent_id[parent_id] = hero_version_doc
- repre_docs = legacy_io.find({
- "type": "representation",
- "parent": {"$in": version_ids}
- })
+ repre_docs = get_representations(project_name, version_ids=version_ids)
repre_docs_by_parent_id_by_name = collections.defaultdict(dict)
for repre_doc in repre_docs:
parent_id = repre_doc["parent"]
diff --git a/openpype/tools/sceneinventory/view.py b/openpype/tools/sceneinventory/view.py
index 448e3f4e6f..63d181b2d6 100644
--- a/openpype/tools/sceneinventory/view.py
+++ b/openpype/tools/sceneinventory/view.py
@@ -6,6 +6,13 @@ from Qt import QtWidgets, QtCore
import qtawesome
from bson.objectid import ObjectId
+from openpype.client import (
+ get_version_by_id,
+ get_versions,
+ get_hero_versions,
+ get_representation_by_id,
+ get_representations,
+)
from openpype import style
from openpype.pipeline import (
legacy_io,
@@ -83,12 +90,9 @@ class SceneInventoryView(QtWidgets.QTreeView):
if item_id not in repre_ids:
repre_ids.append(item_id)
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "_id": {"$in": repre_ids}
- },
- {"parent": 1}
+ project_name = legacy_io.active_project()
+ repre_docs = get_representations(
+ project_name, representation_ids=repre_ids, fields=["parent"]
)
version_ids = []
@@ -97,10 +101,9 @@ class SceneInventoryView(QtWidgets.QTreeView):
if version_id not in version_ids:
version_ids.append(version_id)
- loaded_versions = legacy_io.find({
- "_id": {"$in": version_ids},
- "type": {"$in": ["version", "hero_version"]}
- })
+ loaded_versions = get_versions(
+ project_name, version_ids=version_ids, hero=True
+ )
loaded_hero_versions = []
versions_by_parent_id = collections.defaultdict(list)
@@ -114,10 +117,9 @@ class SceneInventoryView(QtWidgets.QTreeView):
if parent_id not in version_parents:
version_parents.append(parent_id)
- all_versions = legacy_io.find({
- "type": {"$in": ["hero_version", "version"]},
- "parent": {"$in": version_parents}
- })
+ all_versions = get_versions(
+ project_name, subset_ids=version_parents, hero=True
+ )
hero_versions = []
versions = []
for version in all_versions:
@@ -150,12 +152,10 @@ class SceneInventoryView(QtWidgets.QTreeView):
if item_id not in repre_ids:
repre_ids.append(item_id)
- repre_docs = legacy_io.find(
- {
- "type": "representation",
- "_id": {"$in": repre_ids}
- },
- {"parent": 1}
+ repre_docs = get_representations(
+ project_name,
+ representation_ids=repre_ids,
+ fields=["parent"]
)
version_ids = []
@@ -165,13 +165,13 @@ class SceneInventoryView(QtWidgets.QTreeView):
version_id_by_repre_id[repre_doc["_id"]] = version_id
if version_id not in version_ids:
version_ids.append(version_id)
- hero_versions = legacy_io.find(
- {
- "_id": {"$in": version_ids},
- "type": "hero_version"
- },
- {"version_id": 1}
+
+ hero_versions = get_hero_versions(
+ project_name,
+ version_ids=version_ids,
+ fields=["version_id"]
)
+
version_ids = set()
for hero_version in hero_versions:
version_id = hero_version["version_id"]
@@ -183,12 +183,10 @@ class SceneInventoryView(QtWidgets.QTreeView):
if current_version_id == hero_version_id:
version_id_by_repre_id[_repre_id] = version_id
- version_docs = legacy_io.find(
- {
- "_id": {"$in": list(version_ids)},
- "type": "version"
- },
- {"name": 1}
+ version_docs = get_versions(
+ project_name,
+ version_ids=version_ids,
+ fields=["name"]
)
version_name_by_id = {}
for version_doc in version_docs:
@@ -370,10 +368,9 @@ class SceneInventoryView(QtWidgets.QTreeView):
active_site = self.sync_server.get_active_site(project_name)
remote_site = self.sync_server.get_remote_site(project_name)
- repre_docs = legacy_io.find({
- "type": "representation",
- "_id": {"$in": repre_ids}
- })
+ repre_docs = get_representations(
+ project_name, representation_ids=repre_ids
+ )
repre_docs_by_id = {
repre_doc["_id"]: repre_doc
for repre_doc in repre_docs
@@ -658,25 +655,35 @@ class SceneInventoryView(QtWidgets.QTreeView):
active = items[-1]
+ project_name = legacy_io.active_project()
# Get available versions for active representation
- representation_id = ObjectId(active["representation"])
- representation = legacy_io.find_one({"_id": representation_id})
- version = legacy_io.find_one({
- "_id": representation["parent"]
- })
+ repre_doc = get_representation_by_id(
+ project_name,
+ active["representation"],
+ fields=["parent"]
+ )
- versions = list(legacy_io.find(
- {
- "parent": version["parent"],
- "type": "version"
- },
- sort=[("name", 1)]
+ repre_version_doc = get_version_by_id(
+ project_name,
+ repre_doc["parent"],
+ fields=["parent"]
+ )
+
+ version_docs = list(get_versions(
+ project_name,
+ subset_ids=[repre_version_doc["parent"]],
+ hero=True
+ ))
+ hero_version = None
+ standard_versions = []
+ for version_doc in version_docs:
+ if version_doc["type"] == "hero_version":
+ hero_version = version_doc
+ else:
+ standard_versions.append(version_doc)
+ versions = list(reversed(
+ sorted(standard_versions, key=lambda item: item["name"])
))
-
- hero_version = legacy_io.find_one({
- "parent": version["parent"],
- "type": "hero_version"
- })
if hero_version:
_version_id = hero_version["version_id"]
for _version in versions:
@@ -703,7 +710,7 @@ class SceneInventoryView(QtWidgets.QTreeView):
all_versions = []
if hero_version:
all_versions.append(hero_version)
- all_versions.extend(reversed(versions))
+ all_versions.extend(versions)
if current_item:
index = all_versions.index(current_item)
diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py
index 44ec09b2ca..6def284a83 100644
--- a/openpype/tools/settings/settings/base.py
+++ b/openpype/tools/settings/settings/base.py
@@ -1,7 +1,9 @@
+import os
import sys
import json
import traceback
import functools
+import datetime
from Qt import QtWidgets, QtGui, QtCore
@@ -10,7 +12,66 @@ from openpype.tools.settings import CHILD_OFFSET
from .widgets import ExpandingWidget
from .lib import create_deffered_value_change_timer
-from .constants import DEFAULT_PROJECT_LABEL
+from .constants import (
+ DEFAULT_PROJECT_LABEL,
+ SETTINGS_PATH_KEY,
+ ROOT_KEY,
+ VALUE_KEY,
+ SAVE_TIME_KEY,
+ PROJECT_NAME_KEY,
+)
+
+_MENU_SEPARATOR_REQ = object()
+
+
+class ExtractHelper:
+ _last_save_dir = os.path.expanduser("~")
+
+ @classmethod
+ def get_last_save_dir(cls):
+ return cls._last_save_dir
+
+ @classmethod
+ def set_last_save_dir(cls, save_dir):
+ cls._last_save_dir = save_dir
+
+ @classmethod
+ def ask_for_save_filepath(cls, parent):
+ dialog = QtWidgets.QFileDialog(
+ parent,
+ "Save settings values",
+ cls.get_last_save_dir(),
+ "Values (*.json)"
+ )
+ # dialog.setOption(dialog.DontUseNativeDialog)
+ dialog.setAcceptMode(dialog.AcceptSave)
+ if dialog.exec() != dialog.Accepted:
+ return
+
+ selected_urls = dialog.selectedUrls()
+ if not selected_urls:
+ return
+
+ filepath = selected_urls[0].toLocalFile()
+ if not filepath:
+ return
+
+ if not filepath.lower().endswith(".json"):
+ filepath += ".json"
+ return filepath
+
+ @classmethod
+ def extract_settings_to_json(cls, filepath, settings_data, project_name):
+ now = datetime.datetime.now()
+ settings_data[SAVE_TIME_KEY] = now.strftime("%Y-%m-%d %H:%M:%S")
+ if project_name != 0:
+ settings_data[PROJECT_NAME_KEY] = project_name
+
+ with open(filepath, "w") as stream:
+ json.dump(settings_data, stream, indent=4)
+
+ new_dir = os.path.dirname(filepath)
+ cls.set_last_save_dir(new_dir)
class BaseWidget(QtWidgets.QWidget):
@@ -190,24 +251,29 @@ class BaseWidget(QtWidgets.QWidget):
actions_mapping[action] = remove_from_project_override
menu.addAction(action)
+ def _get_mime_data_from_entity(self):
+ if self.entity.is_dynamic_item or self.entity.is_in_dynamic_item:
+ entity_path = None
+ else:
+ entity_path = "/".join(
+ [self.entity.root_key, self.entity.path]
+ )
+
+ value = self.entity.value
+
+ # Copy for settings tool
+ return {
+ VALUE_KEY: value,
+ ROOT_KEY: self.entity.root_key,
+ SETTINGS_PATH_KEY: entity_path
+ }
+
def _copy_value_actions(self, menu):
def copy_value():
mime_data = QtCore.QMimeData()
- if self.entity.is_dynamic_item or self.entity.is_in_dynamic_item:
- entity_path = None
- else:
- entity_path = "/".join(
- [self.entity.root_key, self.entity.path]
- )
-
- value = self.entity.value
# Copy for settings tool
- settings_data = {
- "root_key": self.entity.root_key,
- "value": value,
- "path": entity_path
- }
+ settings_data = self._get_mime_data_from_entity()
settings_encoded_data = QtCore.QByteArray()
settings_stream = QtCore.QDataStream(
settings_encoded_data, QtCore.QIODevice.WriteOnly
@@ -218,6 +284,7 @@ class BaseWidget(QtWidgets.QWidget):
)
# Copy as json
+ value = settings_data[VALUE_KEY]
json_encoded_data = None
if isinstance(value, (dict, list)):
json_encoded_data = QtCore.QByteArray()
@@ -241,25 +308,87 @@ class BaseWidget(QtWidgets.QWidget):
action = QtWidgets.QAction("Copy", menu)
return [(action, copy_value)]
+ def _extract_to_file(self):
+ filepath = ExtractHelper.ask_for_save_filepath(self)
+ if not filepath:
+ return
+
+ settings_data = self._get_mime_data_from_entity()
+ project_name = 0
+ if hasattr(self.category_widget, "project_name"):
+ project_name = self.category_widget.project_name
+
+ ExtractHelper.extract_settings_to_json(
+ filepath, settings_data, project_name
+ )
+
+ def _extract_value_to_file_actions(self, menu):
+ extract_action = QtWidgets.QAction("Extract to file", menu)
+ return [
+ _MENU_SEPARATOR_REQ,
+ (extract_action, self._extract_to_file)
+ ]
+
+ def _parse_source_data_for_paste(self, data):
+ settings_path = None
+ root_key = None
+ if isinstance(data, dict):
+ data.pop(SAVE_TIME_KEY, None)
+ data.pop(PROJECT_NAME_KEY, None)
+ settings_path = data.pop(SETTINGS_PATH_KEY, settings_path)
+ root_key = data.pop(ROOT_KEY, root_key)
+ data = data.pop(VALUE_KEY, data)
+
+ return {
+ VALUE_KEY: data,
+ SETTINGS_PATH_KEY: settings_path,
+ ROOT_KEY: root_key
+ }
+
+ def _get_value_from_clipboard(self):
+ clipboard = QtWidgets.QApplication.clipboard()
+ mime_data = clipboard.mimeData()
+ app_value = mime_data.data("application/copy_settings_value")
+ if app_value:
+ settings_stream = QtCore.QDataStream(
+ app_value, QtCore.QIODevice.ReadOnly
+ )
+ mime_data_value_str = settings_stream.readQString()
+ return json.loads(mime_data_value_str)
+
+ if mime_data.hasUrls():
+ for url in mime_data.urls():
+ local_file = url.toLocalFile()
+ try:
+ with open(local_file, "r") as stream:
+ value = json.load(stream)
+ except Exception:
+ continue
+ if value:
+ return self._parse_source_data_for_paste(value)
+
+ if mime_data.hasText():
+ text = mime_data.text()
+ try:
+ value = json.loads(text)
+ except Exception:
+ try:
+ value = self.entity.convert_to_valid_type(text)
+ except Exception:
+ return None
+ return self._parse_source_data_for_paste(value)
+
def _paste_value_actions(self, menu):
output = []
# Allow paste of value only if were copied from this UI
- clipboard = QtWidgets.QApplication.clipboard()
- mime_data = clipboard.mimeData()
- mime_value = mime_data.data("application/copy_settings_value")
+ mime_data_value = self._get_value_from_clipboard()
# Skip if there is nothing to do
- if not mime_value:
+ if not mime_data_value:
return output
- settings_stream = QtCore.QDataStream(
- mime_value, QtCore.QIODevice.ReadOnly
- )
- mime_data_value_str = settings_stream.readQString()
- mime_data_value = json.loads(mime_data_value_str)
-
- value = mime_data_value["value"]
- path = mime_data_value["path"]
- root_key = mime_data_value["root_key"]
+ value = mime_data_value[VALUE_KEY]
+ path = mime_data_value[SETTINGS_PATH_KEY]
+ root_key = mime_data_value[ROOT_KEY]
# Try to find matching entity to be able paste values to same spot
# - entity can't by dynamic or in dynamic item
@@ -391,10 +520,19 @@ class BaseWidget(QtWidgets.QWidget):
ui_actions.extend(self._copy_value_actions(menu))
ui_actions.extend(self._paste_value_actions(menu))
if ui_actions:
- menu.addSeparator()
- for action, callback in ui_actions:
- menu.addAction(action)
- actions_mapping[action] = callback
+ ui_actions.insert(0, _MENU_SEPARATOR_REQ)
+
+ ui_actions.extend(self._extract_value_to_file_actions(menu))
+
+ for item in ui_actions:
+ if item is _MENU_SEPARATOR_REQ:
+ if len(menu.actions()) > 0:
+ menu.addSeparator()
+ continue
+
+ action, callback = item
+ menu.addAction(action)
+ actions_mapping[action] = callback
if not actions_mapping:
action = QtWidgets.QAction("< No action >")
diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py
index c8ade5fcdb..764f42f1a3 100644
--- a/openpype/tools/settings/settings/categories.py
+++ b/openpype/tools/settings/settings/categories.py
@@ -45,8 +45,15 @@ from .breadcrumbs_widget import (
SystemSettingsBreadcrumbs,
ProjectSettingsBreadcrumbs
)
-
-from .base import GUIWidget
+from .constants import (
+ SETTINGS_PATH_KEY,
+ ROOT_KEY,
+ VALUE_KEY,
+)
+from .base import (
+ ExtractHelper,
+ GUIWidget,
+)
from .list_item_widget import ListWidget
from .list_strict_widget import ListStrictWidget
from .dict_mutable_widget import DictMutableKeysWidget
@@ -627,11 +634,35 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
self._on_context_version_trigger
)
submenu.addAction(action)
+
menu.addMenu(submenu)
+ extract_action = QtWidgets.QAction("Extract to file", menu)
+ extract_action.triggered.connect(self._on_extract_to_file)
+
+ menu.addAction(extract_action)
+
def _on_context_version_trigger(self, version):
self._on_source_version_change(version)
+ def _on_extract_to_file(self):
+ filepath = ExtractHelper.ask_for_save_filepath(self)
+ if not filepath:
+ return
+
+ settings_data = {
+ SETTINGS_PATH_KEY: self.entity.root_key,
+ ROOT_KEY: self.entity.root_key,
+ VALUE_KEY: self.entity.value
+ }
+ project_name = 0
+ if hasattr(self, "project_name"):
+ project_name = self.project_name
+
+ ExtractHelper.extract_settings_to_json(
+ filepath, settings_data, project_name
+ )
+
def _on_reset_crash(self):
self.save_btn.setEnabled(False)
diff --git a/openpype/tools/settings/settings/constants.py b/openpype/tools/settings/settings/constants.py
index 9d6d7904d7..d98d18c8bf 100644
--- a/openpype/tools/settings/settings/constants.py
+++ b/openpype/tools/settings/settings/constants.py
@@ -7,6 +7,12 @@ PROJECT_IS_ACTIVE_ROLE = QtCore.Qt.UserRole + 2
PROJECT_IS_SELECTED_ROLE = QtCore.Qt.UserRole + 3
PROJECT_VERSION_ROLE = QtCore.Qt.UserRole + 4
+# Save/Extract keys
+SETTINGS_PATH_KEY = "__settings_path__"
+ROOT_KEY = "__root_key__"
+VALUE_KEY = "__value__"
+SAVE_TIME_KEY = "__extracted__"
+PROJECT_NAME_KEY = "__project_name__"
__all__ = (
"DEFAULT_PROJECT_LABEL",
@@ -15,4 +21,11 @@ __all__ = (
"PROJECT_IS_ACTIVE_ROLE",
"PROJECT_IS_SELECTED_ROLE",
"PROJECT_VERSION_ROLE",
+
+ "SETTINGS_PATH_KEY",
+ "ROOT_KEY",
+ "SETTINGS_PATH_KEY",
+ "VALUE_KEY",
+ "SAVE_TIME_KEY",
+ "PROJECT_NAME_KEY",
)
diff --git a/openpype/tools/standalonepublish/app.py b/openpype/tools/standalonepublish/app.py
index 1ad5cd119e..3ceeb3ad48 100644
--- a/openpype/tools/standalonepublish/app.py
+++ b/openpype/tools/standalonepublish/app.py
@@ -6,6 +6,8 @@ import signal
from bson.objectid import ObjectId
from Qt import QtWidgets, QtCore, QtGui
+from openpype.client import get_asset_by_id
+
from .widgets import (
AssetWidget, FamilyWidget, ComponentsWidget, ShadowWidget
)
@@ -126,17 +128,6 @@ class Window(QtWidgets.QDialog):
if event:
super().resizeEvent(event)
- def get_avalon_parent(self, entity):
- ''' Avalon DB entities helper - get all parents (exclude project).
- '''
- parent_id = entity['data']['visualParent']
- parents = []
- if parent_id is not None:
- parent = self.db.find_one({'_id': parent_id})
- parents.extend(self.get_avalon_parent(parent))
- parents.append(parent['name'])
- return parents
-
def on_project_change(self, project_name):
self.widget_family.refresh()
@@ -152,7 +143,10 @@ class Window(QtWidgets.QDialog):
]
if len(selected) == 1:
self.valid_parent = True
- asset = self.db.find_one({"_id": selected[0], "type": "asset"})
+ project_name = self.db.active_project()
+ asset = get_asset_by_id(
+ project_name, selected[0], fields=["name"]
+ )
self.widget_family.change_asset(asset['name'])
else:
self.valid_parent = False
diff --git a/openpype/tools/standalonepublish/widgets/model_asset.py b/openpype/tools/standalonepublish/widgets/model_asset.py
index 02e9073555..abfc0a2145 100644
--- a/openpype/tools/standalonepublish/widgets/model_asset.py
+++ b/openpype/tools/standalonepublish/widgets/model_asset.py
@@ -4,6 +4,7 @@ import collections
from Qt import QtCore, QtGui
import qtawesome
+from openpype.client import get_assets
from openpype.style import (
get_default_entity_icon_color,
get_deprecated_entity_font_color,
@@ -104,17 +105,18 @@ class AssetModel(TreeModel):
def refresh(self):
"""Refresh the data for the model."""
+ project_name = self.dbcon.active_project()
self.clear()
- if (
- self.dbcon.active_project() is None or
- self.dbcon.active_project() == ''
- ):
+ if not project_name:
return
self.beginResetModel()
# Get all assets in current project sorted by name
- db_assets = self.dbcon.find({"type": "asset"}).sort("name", 1)
+ asset_docs = get_assets(project_name)
+ db_assets = list(
+ sorted(asset_docs, key=lambda item: item["name"])
+ )
# Group the assets by their visual parent's id
assets_by_parent = collections.defaultdict(list)
diff --git a/openpype/tools/standalonepublish/widgets/widget_asset.py b/openpype/tools/standalonepublish/widgets/widget_asset.py
index 8b43cd7cf8..73114f7960 100644
--- a/openpype/tools/standalonepublish/widgets/widget_asset.py
+++ b/openpype/tools/standalonepublish/widgets/widget_asset.py
@@ -2,6 +2,10 @@ import contextlib
from Qt import QtWidgets, QtCore
import qtawesome
+from openpype.client import (
+ get_project,
+ get_asset_by_id,
+)
from openpype.tools.utils import PlaceholderLineEdit
from openpype.style import get_default_tools_icon_color
@@ -218,7 +222,8 @@ class AssetWidget(QtWidgets.QWidget):
self.view = view
def collect_data(self):
- project = self.dbcon.find_one({'type': 'project'})
+ project_name = self.dbcon.active_project()
+ project = get_project(project_name, fields=["name"])
asset = self.get_active_asset()
try:
@@ -241,9 +246,16 @@ class AssetWidget(QtWidgets.QWidget):
return ent_parents
output = []
- if entity.get('data', {}).get('visualParent', None) is None:
+ parent_asset_id = entity.get('data', {}).get('visualParent', None)
+ if parent_asset_id is None:
return output
- parent = self.dbcon.find_one({'_id': entity['data']['visualParent']})
+
+ project_name = self.dbcon.active_project()
+ parent = get_asset_by_id(
+ project_name,
+ parent_asset_id,
+ fields=["name", "data.visualParent"]
+ )
output.append(parent['name'])
output.extend(self.get_parents(parent))
return output
@@ -349,9 +361,10 @@ class AssetWidget(QtWidgets.QWidget):
tasks = []
selected = self.get_selected_assets()
if len(selected) == 1:
- asset = self.dbcon.find_one({
- "_id": selected[0], "type": "asset"
- })
+ project_name = self.dbcon.active_project()
+ asset = get_asset_by_id(
+ project_name, selected[0], fields=["data.tasks"]
+ )
if asset:
tasks = asset.get('data', {}).get('tasks', [])
self.task_model.set_tasks(tasks)
@@ -400,7 +413,7 @@ class AssetWidget(QtWidgets.QWidget):
# Select
mode = selection_model.Select | selection_model.Rows
- for index in lib.iter_model_rows(
+ for index in _iter_model_rows(
self.proxy, column=0, include_root=False
):
# stop iteration if there are no assets to process
diff --git a/openpype/tools/standalonepublish/widgets/widget_family.py b/openpype/tools/standalonepublish/widgets/widget_family.py
index 08cd45bbf2..1736be84ab 100644
--- a/openpype/tools/standalonepublish/widgets/widget_family.py
+++ b/openpype/tools/standalonepublish/widgets/widget_family.py
@@ -1,14 +1,21 @@
import re
from Qt import QtWidgets, QtCore
-from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole
-from . import FamilyDescriptionWidget
+from openpype.client import (
+ get_asset_by_name,
+ get_subset_by_name,
+ get_subsets,
+ get_last_version_by_subset_id,
+)
from openpype.api import get_project_settings
from openpype.pipeline import LegacyCreator
from openpype.lib import TaskNotSetError
from openpype.pipeline.create import SUBSET_NAME_ALLOWED_SYMBOLS
+from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole
+from . import FamilyDescriptionWidget
+
class FamilyWidget(QtWidgets.QWidget):
@@ -180,12 +187,9 @@ class FamilyWidget(QtWidgets.QWidget):
asset_doc = None
if asset_name != self.NOT_SELECTED:
# Get the assets from the database which match with the name
- asset_doc = self.dbcon.find_one(
- {
- "type": "asset",
- "name": asset_name
- },
- {"_id": 1}
+ project_name = self.dbcon.active_project()
+ asset_doc = get_asset_by_name(
+ project_name, asset_name, fields=["_id"]
)
# Get plugin and family
@@ -200,14 +204,13 @@ class FamilyWidget(QtWidgets.QWidget):
return
# Get the asset from the database which match with the name
- asset_doc = self.dbcon.find_one(
- {"name": asset_name, "type": "asset"},
- projection={"_id": 1}
+ project_name = self.dbcon.active_project()
+ asset_doc = get_asset_by_name(
+ project_name, asset_name, fields=["_id"]
)
# Get plugin
plugin = item.data(PluginRole)
if asset_doc and plugin:
- project_name = self.dbcon.Session["AVALON_PROJECT"]
asset_id = asset_doc["_id"]
task_name = self.dbcon.Session["AVALON_TASK"]
@@ -231,14 +234,14 @@ class FamilyWidget(QtWidgets.QWidget):
self.input_result.setText("Select task please")
# Get all subsets of the current asset
- subset_docs = self.dbcon.find(
- {
- "type": "subset",
- "parent": asset_id
- },
- {"name": 1}
+ subset_docs = get_subsets(
+ project_name, asset_ids=[asset_id], fields=["name"]
)
- existing_subset_names = set(subset_docs.distinct("name"))
+
+ existing_subset_names = {
+ subset_doc["name"]
+ for subset_doc in subset_docs
+ }
# Defaults to dropdown
defaults = []
@@ -296,47 +299,37 @@ class FamilyWidget(QtWidgets.QWidget):
if not auto_version:
return
+ project_name = self.dbcon.active_project()
asset_name = self.asset_name
subset_name = self.input_result.text()
version = 1
asset_doc = None
subset_doc = None
- versions = None
if (
asset_name != self.NOT_SELECTED and
subset_name.strip() != ''
):
- asset_doc = self.dbcon.find_one(
- {
- 'type': 'asset',
- 'name': asset_name
- },
- {"_id": 1}
+ asset_doc = get_asset_by_name(
+ project_name, asset_name, fields=["_id"]
)
if asset_doc:
- subset_doc = self.dbcon.find_one(
- {
- 'type': 'subset',
- 'parent': asset_doc['_id'],
- 'name': subset_name
- },
- {"_id": 1}
+ subset_doc = get_subset_by_name(
+ project_name,
+ subset_name,
+ asset_doc['_id'],
+ fields=["_id"]
)
if subset_doc:
- versions = self.dbcon.find(
- {
- 'type': 'version',
- 'parent': subset_doc['_id']
- },
- {"name": 1}
- ).distinct("name")
-
- if versions:
- versions = sorted(versions)
- version = int(versions[-1]) + 1
+ last_version = get_last_version_by_subset_id(
+ project_name,
+ subset_doc["_id"],
+ fields=["name"]
+ )
+ if last_version:
+ version = last_version["name"] + 1
self.version_spinbox.setValue(version)
diff --git a/openpype/tools/texture_copy/app.py b/openpype/tools/texture_copy/app.py
index fd8d6dc02e..746a72b3ec 100644
--- a/openpype/tools/texture_copy/app.py
+++ b/openpype/tools/texture_copy/app.py
@@ -4,6 +4,7 @@ import click
import speedcopy
+from openpype.client import get_project, get_asset_by_name
from openpype.lib import Terminal
from openpype.api import Anatomy
from openpype.pipeline import legacy_io
@@ -29,20 +30,6 @@ class TextureCopy:
if os.path.splitext(x)[1].lower() in texture_extensions)
return textures
- def _get_project(self, project_name):
- project = legacy_io.find_one({
- 'type': 'project',
- 'name': project_name
- })
- return project
-
- def _get_asset(self, asset_name):
- asset = legacy_io.find_one({
- 'type': 'asset',
- 'name': asset_name
- })
- return asset
-
def _get_destination_path(self, asset, project):
project_name = project["name"]
hierarchy = ""
@@ -88,11 +75,12 @@ class TextureCopy:
t.echo("!!! {}".format(e))
exit(1)
- def process(self, asset, project, path):
+ def process(self, asset_name, project_name, path):
"""
Process all textures found in path and copy them to asset under
project.
"""
+
t.echo(">>> Looking for textures ...")
textures = self._get_textures(path)
if len(textures) < 1:
@@ -101,14 +89,14 @@ class TextureCopy:
else:
t.echo(">>> Found {} textures ...".format(len(textures)))
- project = self._get_project(project)
+ project = get_project(project_name)
if not project:
- t.echo("!!! Project name [ {} ] not found.".format(project))
+ t.echo("!!! Project name [ {} ] not found.".format(project_name))
exit(1)
- asset = self._get_asset(asset)
- if not project:
- t.echo("!!! Asset [ {} ] not found in project".format(asset))
+ asset = get_asset_by_name(project_name, asset_name)
+ if not asset:
+ t.echo("!!! Asset [ {} ] not found in project".format(asset_name))
exit(1)
t.echo((">>> Project [ {} ] and "
"asset [ {} ] seems to be OK ...").format(project['name'],
diff --git a/openpype/tools/utils/assets_widget.py b/openpype/tools/utils/assets_widget.py
index 82bdcd63a2..772946e9e1 100644
--- a/openpype/tools/utils/assets_widget.py
+++ b/openpype/tools/utils/assets_widget.py
@@ -5,6 +5,10 @@ import Qt
from Qt import QtWidgets, QtCore, QtGui
import qtawesome
+from openpype.client import (
+ get_project,
+ get_assets,
+)
from openpype.style import (
get_objected_colors,
get_default_tools_icon_color,
@@ -525,21 +529,18 @@ class AssetModel(QtGui.QStandardItemModel):
self._doc_fetched.emit()
def _fetch_asset_docs(self):
- if not self.dbcon.Session.get("AVALON_PROJECT"):
+ project_name = self.dbcon.current_project()
+ if not project_name:
return []
- project_doc = self.dbcon.find_one(
- {"type": "project"},
- {"_id": True}
- )
+ project_doc = get_project(project_name, fields=["_id"])
if not project_doc:
return []
# Get all assets sorted by name
- return list(self.dbcon.find(
- {"type": "asset"},
- self._asset_projection
- ))
+ return list(
+ get_assets(project_name, fields=self._asset_projection.keys())
+ )
def _stop_fetch_thread(self):
self._refreshing = False
diff --git a/openpype/tools/utils/delegates.py b/openpype/tools/utils/delegates.py
index 71f817a1d7..d6c2d69e76 100644
--- a/openpype/tools/utils/delegates.py
+++ b/openpype/tools/utils/delegates.py
@@ -6,15 +6,19 @@ import numbers
import Qt
from Qt import QtWidgets, QtGui, QtCore
-from openpype.pipeline import HeroVersionType
-from .models import TreeModel
-from . import lib
-
if Qt.__binding__ == "PySide":
from PySide.QtGui import QStyleOptionViewItemV4
elif Qt.__binding__ == "PyQt4":
from PyQt4.QtGui import QStyleOptionViewItemV4
+from openpype.client import (
+ get_versions,
+ get_hero_versions,
+)
+from openpype.pipeline import HeroVersionType
+from .models import TreeModel
+from . import lib
+
log = logging.getLogger(__name__)
@@ -114,26 +118,24 @@ class VersionDelegate(QtWidgets.QStyledItemDelegate):
"Version is not integer"
)
+ project_name = self.dbcon.active_project()
# Add all available versions to the editor
parent_id = item["version_document"]["parent"]
- version_docs = list(self.dbcon.find(
- {
- "type": "version",
- "parent": parent_id
- },
- sort=[("name", 1)]
+ version_docs = list(sorted(
+ get_versions(project_name, subset_ids=[parent_id]),
+ key=lambda item: item["name"]
))
- hero_version_doc = self.dbcon.find_one(
- {
- "type": "hero_version",
- "parent": parent_id
- }, {
- "name": 1,
- "data.tags": 1,
- "version_id": 1
- }
+ hero_versions = list(
+ get_hero_versions(
+ project_name,
+ subset_ids=[parent_id],
+ fields=["name", "data.tags", "version_id"]
+ )
)
+ hero_version_doc = None
+ if hero_versions:
+ hero_version_doc = hero_versions[0]
doc_for_hero_version = None
diff --git a/openpype/tools/utils/lib.py b/openpype/tools/utils/lib.py
index 20fea6600b..ea1362945f 100644
--- a/openpype/tools/utils/lib.py
+++ b/openpype/tools/utils/lib.py
@@ -6,6 +6,10 @@ import collections
from Qt import QtWidgets, QtCore, QtGui
import qtawesome
+from openpype.client import (
+ get_project,
+ get_asset_by_name,
+)
from openpype.style import (
get_default_entity_icon_color,
get_objected_colors,
@@ -430,9 +434,8 @@ class FamilyConfigCache:
database = getattr(self.dbcon, "database", None)
if database is None:
database = self.dbcon._database
- asset_doc = database[project_name].find_one(
- {"type": "asset", "name": asset_name},
- {"data.tasks": True}
+ asset_doc = get_asset_by_name(
+ project_name, asset_name, fields=["data.tasks"]
) or {}
tasks_info = asset_doc.get("data", {}).get("tasks") or {}
task_type = tasks_info.get(task_name, {}).get("type")
@@ -500,10 +503,7 @@ class GroupsConfig:
project_name = self.dbcon.Session.get("AVALON_PROJECT")
if project_name:
# Get pre-defined group name and appearance from project config
- project_doc = self.dbcon.find_one(
- {"type": "project"},
- projection={"config.groups": True}
- )
+ project_doc = get_project(project_name, fields=["config.groups"])
if project_doc:
group_configs = project_doc["config"].get("groups") or []
diff --git a/openpype/tools/utils/tasks_widget.py b/openpype/tools/utils/tasks_widget.py
index eab183d5f3..0353f3dd2f 100644
--- a/openpype/tools/utils/tasks_widget.py
+++ b/openpype/tools/utils/tasks_widget.py
@@ -1,6 +1,10 @@
from Qt import QtWidgets, QtCore, QtGui
import qtawesome
+from openpype.client import (
+ get_project,
+ get_asset_by_id,
+)
from openpype.style import get_disabled_entity_icon_color
from openpype.tools.utils.lib import get_task_icon
@@ -47,7 +51,8 @@ class TasksModel(QtGui.QStandardItemModel):
# Get the project configured icons from database
project_doc = {}
if self._context_is_valid():
- project_doc = self.dbcon.find_one({"type": "project"})
+ project_name = self.dbcon.active_project()
+ project_doc = get_project(project_name)
self._loaded_project_name = self._get_current_project()
self._project_doc = project_doc
@@ -71,9 +76,9 @@ class TasksModel(QtGui.QStandardItemModel):
def set_asset_id(self, asset_id):
asset_doc = None
if self._context_is_valid():
- asset_doc = self.dbcon.find_one(
- {"_id": asset_id},
- {"data.tasks": True}
+ project_name = self._get_current_project()
+ asset_doc = get_asset_by_id(
+ project_name, asset_id, fields=["data.tasks"]
)
self._set_asset(asset_doc)
diff --git a/openpype/tools/workfiles/files_widget.py b/openpype/tools/workfiles/files_widget.py
index 977111b71b..68fe8301c9 100644
--- a/openpype/tools/workfiles/files_widget.py
+++ b/openpype/tools/workfiles/files_widget.py
@@ -5,6 +5,7 @@ import shutil
import Qt
from Qt import QtWidgets, QtCore
+from openpype.client import get_asset_by_id
from openpype.tools.utils import PlaceholderLineEdit
from openpype.tools.utils.delegates import PrettyTimeDelegate
from openpype.lib import (
@@ -384,7 +385,9 @@ class FilesWidget(QtWidgets.QWidget):
return None
if self._asset_doc is None:
- self._asset_doc = legacy_io.find_one({"_id": self._asset_id})
+ project_name = legacy_io.active_project()
+ self._asset_doc = get_asset_by_id(project_name, self._asset_id)
+
return self._asset_doc
def _get_session(self):
diff --git a/openpype/tools/workfiles/model.py b/openpype/tools/workfiles/model.py
index 8f9dd8c6ba..d5b7cef339 100644
--- a/openpype/tools/workfiles/model.py
+++ b/openpype/tools/workfiles/model.py
@@ -4,6 +4,11 @@ import logging
from Qt import QtCore, QtGui
import qtawesome
+from openpype.client import (
+ get_subsets,
+ get_versions,
+ get_representations,
+)
from openpype.style import (
get_default_entity_icon_color,
get_disabled_entity_icon_color,
@@ -215,6 +220,7 @@ class PublishFilesModel(QtGui.QStandardItemModel):
self._dbcon = dbcon
self._anatomy = anatomy
+
self._file_extensions = extensions
self._invalid_context_item = None
@@ -234,6 +240,10 @@ class PublishFilesModel(QtGui.QStandardItemModel):
self._asset_id = None
self._task_name = None
+ @property
+ def project_name(self):
+ return self._dbcon.Session["AVALON_PROJECT"]
+
def _set_item_invalid(self, item):
item.setFlags(QtCore.Qt.NoItemFlags)
item.setData(self._invalid_icon, QtCore.Qt.DecorationRole)
@@ -285,15 +295,11 @@ class PublishFilesModel(QtGui.QStandardItemModel):
def _get_workfie_representations(self):
output = []
# Get subset docs of asset
- subset_docs = self._dbcon.find(
- {
- "type": "subset",
- "parent": self._asset_id
- },
- {
- "_id": True,
- "name": True
- }
+ subset_docs = get_subsets(
+ self.project_name,
+ asset_ids=[self._asset_id],
+ fields=["_id", "name"]
+
)
subset_ids = [subset_doc["_id"] for subset_doc in subset_docs]
@@ -301,17 +307,12 @@ class PublishFilesModel(QtGui.QStandardItemModel):
return output
# Get version docs of subsets with their families
- version_docs = self._dbcon.find(
- {
- "type": "version",
- "parent": {"$in": subset_ids}
- },
- {
- "_id": True,
- "data.families": True,
- "parent": True
- }
+ version_docs = get_versions(
+ self.project_name,
+ subset_ids=subset_ids,
+ fields=["_id", "parent", "data.families"]
)
+
# Filter versions if they contain 'workfile' family
filtered_versions = []
for version_doc in version_docs:
@@ -327,13 +328,10 @@ class PublishFilesModel(QtGui.QStandardItemModel):
# Query representations of filtered versions and add filter for
# extension
extensions = [ext.replace(".", "") for ext in self._file_extensions]
- repre_docs = self._dbcon.find(
- {
- "type": "representation",
- "parent": {"$in": version_ids},
- "context.ext": {"$in": extensions}
- }
+ repre_docs = get_representations(
+ self.project_name, version_ids, extensions
)
+
# Filter queried representations by task name if task is set
filtered_repre_docs = []
for repre_doc in repre_docs:
diff --git a/openpype/tools/workfiles/save_as_dialog.py b/openpype/tools/workfiles/save_as_dialog.py
index 3e97d6c938..b62fd2c889 100644
--- a/openpype/tools/workfiles/save_as_dialog.py
+++ b/openpype/tools/workfiles/save_as_dialog.py
@@ -5,6 +5,10 @@ import logging
from Qt import QtWidgets, QtCore
+from openpype.client import (
+ get_project,
+ get_asset_by_name,
+)
from openpype.lib import (
get_last_workfile_with_version,
get_workdir_data,
@@ -22,29 +26,19 @@ def build_workfile_data(session):
"""Get the data required for workfile formatting from avalon `session`"""
# Set work file data for template formatting
+ project_name = session["AVALON_PROJECT"]
asset_name = session["AVALON_ASSET"]
task_name = session["AVALON_TASK"]
host_name = session["AVALON_APP"]
- project_doc = legacy_io.find_one(
- {"type": "project"},
- {
- "name": True,
- "data.code": True,
- "config.tasks": True,
- }
+ project_doc = get_project(
+ project_name, fields=["name", "data.code", "config.tasks"]
+ )
+ asset_doc = get_asset_by_name(
+ project_name,
+ asset_name,
+ fields=["name", "data.tasks", "data.parents"]
)
- asset_doc = legacy_io.find_one(
- {
- "type": "asset",
- "name": asset_name
- },
- {
- "name": True,
- "data.tasks": True,
- "data.parents": True
- }
- )
data = get_workdir_data(project_doc, asset_doc, task_name, host_name)
data.update({
"version": 1,
diff --git a/openpype/tools/workfiles/window.py b/openpype/tools/workfiles/window.py
index 02a22af26c..9f4cea2f8a 100644
--- a/openpype/tools/workfiles/window.py
+++ b/openpype/tools/workfiles/window.py
@@ -2,6 +2,7 @@ import os
import datetime
from Qt import QtCore, QtWidgets
+from openpype.client import get_asset_by_id, get_asset_by_name
from openpype import style
from openpype.lib import (
get_workfile_doc,
@@ -223,6 +224,10 @@ class Window(QtWidgets.QMainWindow):
self._first_show = True
self._context_to_set = None
+ @property
+ def project_name(self):
+ return legacy_io.Session["AVALON_PROJECT"]
+
def showEvent(self, event):
super(Window, self).showEvent(event)
if self._first_show:
@@ -296,7 +301,8 @@ class Window(QtWidgets.QMainWindow):
if not workfile_doc:
workdir, filename = os.path.split(filepath)
asset_id = self.assets_widget.get_selected_asset_id()
- asset_doc = legacy_io.find_one({"_id": asset_id})
+ project_name = legacy_io.active_project()
+ asset_doc = get_asset_by_id(project_name, asset_id)
task_name = self.tasks_widget.get_selected_task_name()
create_workfile_doc(
asset_doc, task_name, filename, workdir, legacy_io
@@ -322,14 +328,13 @@ class Window(QtWidgets.QMainWindow):
self._context_to_set, context = None, self._context_to_set
if "asset" in context:
- asset_doc = legacy_io.find_one(
- {
- "name": context["asset"],
- "type": "asset"
- },
- {"_id": 1}
- ) or {}
- asset_id = asset_doc.get("_id")
+ asset_doc = get_asset_by_name(
+ self.project_name, context["asset"], fields=["_id"]
+ )
+
+ asset_id = None
+ if asset_doc:
+ asset_id = asset_doc["_id"]
# Select the asset
self.assets_widget.select_asset(asset_id)
self.tasks_widget.set_asset_id(asset_id)