Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Ftrack: Use client query functions #3339

Merged
merged 18 commits into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions openpype/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
get_asset_by_id,
get_asset_by_name,
get_assets,
get_archived_assets,
get_asset_ids_with_subsets,

get_subset_by_id,
Expand Down Expand Up @@ -41,6 +42,7 @@
"get_asset_by_id",
"get_asset_by_name",
"get_assets",
"get_archived_assets",
"get_asset_ids_with_subsets",

"get_subset_by_id",
Expand Down
98 changes: 95 additions & 3 deletions openpype/client/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,16 @@ def get_asset_by_name(project_name, asset_name, fields=None):
return conn.find_one(query_filter, _prepare_fields(fields))


def get_assets(
project_name, asset_ids=None, asset_names=None, archived=False, fields=None
# NOTE this could be just public function?
# - any better variable name instead of 'standard'?
# - same approach can be used for rest of types
def _get_assets(
project_name,
asset_ids=None,
asset_names=None,
standard=True,
archived=False,
fields=None
):
"""Assets for specified project by passed filters.

Expand All @@ -153,6 +161,8 @@ def get_assets(
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.
standard (bool): Query standart assets (type 'asset').
archived (bool): Query archived assets (type 'archived_asset').
fields (list[str]): Fields that should be returned. All fields are
returned if 'None' is passed.

Expand All @@ -161,10 +171,15 @@ def get_assets(
passed filters.
"""

asset_types = ["asset"]
asset_types = []
if standard:
asset_types.append("asset")
if archived:
asset_types.append("archived_asset")

if not asset_types:
return []

if len(asset_types) == 1:
query_filter = {"type": asset_types[0]}
else:
Expand All @@ -186,6 +201,68 @@ def get_assets(
return conn.find(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.
archived (bool): Add also archived assets.
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.
"""

return _get_assets(
project_name, asset_ids, asset_names, True, archived, fields
)


def get_archived_assets(
project_name,
asset_ids=None,
asset_names=None,
fields=None
):
"""Archived assets for specified project by passed filters.

Passed filters (ids and names) are always combined so all conditions must
match.

To receive all archived 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.
"""

return _get_assets(
project_name, asset_ids, asset_names, False, True, fields
)


def get_asset_ids_with_subsets(project_name, asset_ids=None):
"""Find out which assets have existing subsets.

Expand Down Expand Up @@ -432,6 +509,7 @@ def _get_versions(
project_name,
subset_ids=None,
version_ids=None,
versions=None,
standard=True,
hero=False,
fields=None
Expand Down Expand Up @@ -462,6 +540,16 @@ def _get_versions(
return []
query_filter["_id"] = {"$in": version_ids}

if versions is not None:
versions = list(versions)
if not versions:
return []

if len(versions) == 1:
query_filter["name"] = versions[0]
else:
query_filter["name"] = {"$in": versions}

conn = _get_project_connection(project_name)

return conn.find(query_filter, _prepare_fields(fields))
Expand All @@ -471,6 +559,7 @@ def get_versions(
project_name,
version_ids=None,
subset_ids=None,
versions=None,
hero=False,
fields=None
):
Expand All @@ -484,6 +573,8 @@ def get_versions(
Filter ignored if 'None' is passed.
subset_ids (list[str]): Subset ids that will be queried.
Filter ignored if 'None' is passed.
versions (list[int]): Version names (as integers).
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.
Expand All @@ -496,6 +587,7 @@ def get_versions(
project_name,
subset_ids,
version_ids,
versions,
standard=True,
hero=hero,
fields=fields
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import json

from openpype.client import get_project
from openpype.api import ProjectSettings
from openpype.lib import create_project
from openpype.pipeline import AvalonMongoDB
from openpype.settings import SaveWarningExc

from openpype_modules.ftrack.lib import (
Expand Down Expand Up @@ -363,22 +363,16 @@ def launch(self, session, entities, event):
project_name = project_entity["full_name"]

# Try to find project document
dbcon = AvalonMongoDB()
dbcon.install()
dbcon.Session["AVALON_PROJECT"] = project_name
project_doc = dbcon.find_one({
"type": "project"
})
project_doc = get_project(project_name)

# Create project if is not available
# - creation is required to be able set project anatomy and attributes
if not project_doc:
project_code = project_entity["name"]
self.log.info("Creating project \"{} [{}]\"".format(
project_name, project_code
))
create_project(project_name, project_code, dbcon=dbcon)

dbcon.uninstall()
create_project(project_name, project_code)

project_settings = ProjectSettings(project_name)
project_anatomy_settings = project_settings["project_anatomy"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
import arrow
import ftrack_api

from openpype.client import (
get_project,
get_assets,
get_archived_assets,
get_asset_ids_with_subsets
)
from openpype.pipeline import AvalonMongoDB, schema

from openpype_modules.ftrack.lib import (
Expand Down Expand Up @@ -149,12 +155,11 @@ def cust_attr_types_by_id(self):
@property
def avalon_entities(self):
if self._avalon_ents is None:
project_name = self.cur_project["full_name"]
self.dbcon.install()
self.dbcon.Session["AVALON_PROJECT"] = (
self.cur_project["full_name"]
)
avalon_project = self.dbcon.find_one({"type": "project"})
avalon_entities = list(self.dbcon.find({"type": "asset"}))
self.dbcon.Session["AVALON_PROJECT"] = project_name
avalon_project = get_project(project_name)
avalon_entities = list(get_assets(project_name))
self._avalon_ents = (avalon_project, avalon_entities)
return self._avalon_ents

Expand Down Expand Up @@ -284,28 +289,21 @@ def handle_missing_ftrack_id(self, doc):
self._avalon_ents_by_ftrack_id[ftrack_id] = doc

@property
def avalon_subsets_by_parents(self):
if self._avalon_subsets_by_parents is None:
self._avalon_subsets_by_parents = collections.defaultdict(list)
self.dbcon.install()
self.dbcon.Session["AVALON_PROJECT"] = (
self.cur_project["full_name"]
def avalon_asset_ids_with_subsets(self):
if self._avalon_asset_ids_with_subsets is None:
project_name = self.cur_project["full_name"]
self._avalon_asset_ids_with_subsets = get_asset_ids_with_subsets(
project_name
)
for subset in self.dbcon.find({"type": "subset"}):
self._avalon_subsets_by_parents[subset["parent"]].append(
subset
)
return self._avalon_subsets_by_parents

return self._avalon_asset_ids_with_subsets

@property
def avalon_archived_by_id(self):
if self._avalon_archived_by_id is None:
self._avalon_archived_by_id = {}
self.dbcon.install()
self.dbcon.Session["AVALON_PROJECT"] = (
self.cur_project["full_name"]
)
for asset in self.dbcon.find({"type": "archived_asset"}):
project_name = self.cur_project["full_name"]
for asset in get_archived_assets(project_name):
self._avalon_archived_by_id[asset["_id"]] = asset
return self._avalon_archived_by_id

Expand All @@ -327,7 +325,7 @@ def changeability_by_mongo_id(self):
avalon_project, avalon_entities = self.avalon_entities
self._changeability_by_mongo_id[avalon_project["_id"]] = False
self._bubble_changeability(
list(self.avalon_subsets_by_parents.keys())
list(self.avalon_asset_ids_with_subsets)
)

return self._changeability_by_mongo_id
Expand Down Expand Up @@ -449,14 +447,9 @@ def _bubble_changeability(self, unchangeable_ids):
if not entity:
# if entity is not found then it is subset without parent
if entity_id in unchangeable_ids:
_subset_ids = [
str(sub["_id"]) for sub in
self.avalon_subsets_by_parents[entity_id]
]
joined_subset_ids = "| ".join(_subset_ids)
self.log.warning((
"Parent <{}> for subsets <{}> does not exist"
).format(str(entity_id), joined_subset_ids))
"Parent <{}> with subsets does not exist"
).format(str(entity_id)))
else:
self.log.warning((
"In avalon are entities without valid parents that"
Expand All @@ -483,7 +476,7 @@ def reset_variables(self):
self._avalon_ents_by_parent_id = None
self._avalon_ents_by_ftrack_id = None
self._avalon_ents_by_name = None
self._avalon_subsets_by_parents = None
self._avalon_asset_ids_with_subsets = None
self._changeability_by_mongo_id = None
self._avalon_archived_by_id = None
self._avalon_archived_by_name = None
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import re
import subprocess

from openpype.client import get_asset_by_id, get_asset_by_name
from openpype_modules.ftrack.lib import BaseEvent
from openpype_modules.ftrack.lib.avalon_sync import CUST_ATTR_ID_KEY
from openpype.pipeline import AvalonMongoDB

from bson.objectid import ObjectId

from openpype.api import Anatomy, get_project_settings

Expand Down Expand Up @@ -36,8 +34,6 @@ class UserAssigmentEvent(BaseEvent):
3) path to publish files of task user was (de)assigned to
"""

db_con = AvalonMongoDB()

def error(self, *err):
for e in err:
self.log.error(e)
Expand Down Expand Up @@ -101,26 +97,16 @@ def _get_asset(self, task):
:rtype: dict
"""
parent = task['parent']
self.db_con.install()
self.db_con.Session['AVALON_PROJECT'] = task['project']['full_name']

project_name = task["project"]["full_name"]
avalon_entity = None
parent_id = parent['custom_attributes'].get(CUST_ATTR_ID_KEY)
if parent_id:
parent_id = ObjectId(parent_id)
avalon_entity = self.db_con.find_one({
'_id': parent_id,
'type': 'asset'
})
avalon_entity = get_asset_by_id(project_name, parent_id)

if not avalon_entity:
avalon_entity = self.db_con.find_one({
'type': 'asset',
'name': parent['name']
})
avalon_entity = get_asset_by_name(project_name, parent["name"])

if not avalon_entity:
self.db_con.uninstall()
msg = 'Entity "{}" not found in avalon database'.format(
parent['name']
)
Expand All @@ -129,7 +115,6 @@ def _get_asset(self, task):
'success': False,
'message': msg
}
self.db_con.uninstall()
return avalon_entity

def _get_hierarchy(self, asset):
Expand Down
Loading