From bbc2ef4284378867147a7a6febdec6897d529ad6 Mon Sep 17 00:00:00 2001 From: Rico Koschmitzky Date: Wed, 5 Jul 2023 18:33:42 +0200 Subject: [PATCH 1/3] add DEFAULT_PROJECTIONS_RESOLVER fix logger initialization --- src/trackteroid/configuration.py | 3 ++ src/trackteroid/entities/base.py | 20 +++++--- src/trackteroid/entities/entities.py | 76 ++++++++++------------------ 3 files changed, 41 insertions(+), 58 deletions(-) diff --git a/src/trackteroid/configuration.py b/src/trackteroid/configuration.py index 9cee961..82db7e7 100644 --- a/src/trackteroid/configuration.py +++ b/src/trackteroid/configuration.py @@ -113,12 +113,15 @@ def _override_configuration(): # deletion for and resolves to True or False. ALLOWED_FOR_DELETION_RESOLVER = lambda session, type_name: True +DEFAULT_PROJECTIONS_RESOLVER = lambda type_name: [] + WARN_ON_INJECT = False ############################################################################################ _LOG = logging.getLogger(f"{LOGGING_NAMESPACE}.configuration") _CALLABLES_REQUIRE_FALLBACK = [ "RELATIONSHIPS_RESOLVER", + "DEFAULT_PROJECTIONS_RESOLVER" ] _override_configuration() diff --git a/src/trackteroid/entities/base.py b/src/trackteroid/entities/base.py index 26a57c1..d2b5acb 100644 --- a/src/trackteroid/entities/base.py +++ b/src/trackteroid/entities/base.py @@ -56,6 +56,7 @@ from ..configuration import ( LOGGING_NAMESPACE, ALLOWED_FOR_DELETION_RESOLVER, + DEFAULT_PROJECTIONS_RESOLVER, WARN_ON_INJECT ) @@ -1660,11 +1661,9 @@ def delete(self): class _EntityBase(object, metaclass=ForwardDeclareCompare): + _ftrack_entity = None relationship = Relationship() - projections = ["id"] - _ftrack_entity = None - log = None def __new__(cls, *args, **kwargs): """ make it possible to swap the Entity class with the given class @@ -1678,7 +1677,6 @@ def __new__(cls, *args, **kwargs): """ if kwargs.get("_cls"): cls = kwargs["_cls"] - cls.log = logging.getLogger("{}.entities.{}".format(cls.__name__, LOGGING_NAMESPACE)) del kwargs["_cls"] if cls and args and isinstance(args[0], (EntityCollection, EmptyCollection)): @@ -1720,10 +1718,6 @@ def __new__(cls, *args, **kwargs): def __init__(self, _cls=None, ftrack_entity=None, **kwargs): self.ftrack_entity = ftrack_entity - if not _cls: - self.log = logging.getLogger( - "{}.entities.{}".format(self.__class__.__name__, LOGGING_NAMESPACE) - ) def __getitem__(self, item): return self.ftrack_entity.get(item) @@ -1763,6 +1757,16 @@ def __cmp__(self, other): else: return 1 + @classmethod + @property + def projections(cls): + return DEFAULT_PROJECTIONS_RESOLVER(type_name=cls.__name__) + + @classmethod + @property + def log(cls): + return logging.getLogger(f"{LOGGING_NAMESPACE}.entities.{cls.__name__}") + def pre_create(self, **kwargs): return kwargs diff --git a/src/trackteroid/entities/entities.py b/src/trackteroid/entities/entities.py index 1d9610f..574b95d 100644 --- a/src/trackteroid/entities/entities.py +++ b/src/trackteroid/entities/entities.py @@ -41,7 +41,6 @@ class AssetVersion(Entity): - projections = ["id", "asset.name", "version"] relationship = Relationship() relationship.parent = "asset" @@ -140,7 +139,6 @@ def by_publish_state(self, target, publish_state): class TypedContext(Entity): - projections = ["id", "name"] relationship = Relationship() # only for autocompletion @@ -300,7 +298,6 @@ class AssetGroup(TypedContext): class Component(Entity): - projections = ["id", "name"] relationship = Relationship() relationship.parent = "version" @@ -361,19 +358,19 @@ def by_size(self, target, minimum=0, maximum=0): class FileComponent(Component): - projections = ["id", "name"] + pass class ContainerComponent(Component): - projections = ["id", "name"] + pass class NoteComponent(Component): - projections = ["note_id", "component_id", "component"] + pass class Project(Entity): - projections = ["id", "name"] + pass @Criteria.supported_targets(Entity) def by_name(self, target, *names): @@ -423,7 +420,6 @@ def create(self, name, project_schema, **kwargs): pass class ComponentLocation(Entity): - projections = ["id", "resource_identifier"] relationship = Relationship() relationship.parent = "component" @@ -456,7 +452,6 @@ def by_resource_identifier(self, target, *resource_identifiers): class Asset(Entity): - projections = ["id", "name"] relationship = Relationship() @@ -496,7 +491,6 @@ def create(self, name, type, **kwargs): pass class Status(Entity): - projections = ["id", "name"] relationship = Relationship() @@ -507,21 +501,19 @@ def by_name(self, target, *names): class State(Entity): - projections = ["id", "name"] relationship = Relationship() class AssetVersionLink(Entity): - projections = ["id", "from_id", "to_id"] + pass class ProjectSchema(Entity): - projections = ["id", "name"] + pass class User(Entity): - projections = ["id", "username", "is_active"] relationship = Relationship() @@ -540,7 +532,6 @@ def by_name(self, target, *names): class Timelog(Entity): - projections =["id", "comment", "start", "duration"] relationship = Relationship() relationship.parent = "user" @@ -567,19 +558,18 @@ def by_lifespan(self, target, start=None, end=None): class UserSecurityRole(Entity): - projections = ["id", "security_role", "projects"] + pass class UserSecurityRoleProject(Entity): - projections = ["id", "project"] + pass class SecurityRole(Entity): - projections = ["id", "name", "type"] + pass class Appointment(Entity): - projections = ["id", "resource", "resource.name"] relationship = Relationship() relationship.parent = "context" @@ -599,19 +589,19 @@ def pre_create(self, **kwargs): class ObjectType(Entity): - projections = ["id"] + pass class Context(Entity): - projections = ["id"] + pass class AssetType(Entity): - projections = ["id", "name"] + pass class Event(Entity): - projections = ["id", "action", "user", "data"] + pass relationship = Relationship() @@ -632,23 +622,23 @@ def by_data(self, target, *datas): class TypedContextLink(Entity): - projections = ["id", "from_id", "to_id"] + pass class TaskTypeSchema(Entity): - projections = ["id", "types.name"] + pass class Type(Entity): - projections = ["id", "name"] + pass class Metadata(Entity): - projections = ["id", "key", "value"] + pass class NoteCategory(Entity): - projections = ["id", "name"] + pass @Criteria.supported_targets() def by_name(self, target, *names): @@ -657,7 +647,7 @@ def by_name(self, target, *names): class Note(Entity): - projections = ["id", "content"] + relationship = Relationship() # FIX: why do we need to set a parent if the precreate set @@ -728,7 +718,7 @@ def by_id(self, target, *ids): class ReviewSession(Entity): - projections = ["id", "name"] + relationship = Relationship() def pre_create(self, **kwargs): @@ -748,7 +738,7 @@ def by_name(self, target, *names): class ReviewSessionObject(Entity): - projections = ["id", "name"] + relationship = Relationship() relationship.parent = "review_session" @@ -762,7 +752,7 @@ def pre_create(self, **kwargs): class ReviewSessionInvitee(Entity): - projections = ["id", "name", "email"] + relationship = Relationship() # TEST: Check if this is needed or how it is actually used. relationship.parent = "review_session" @@ -773,15 +763,11 @@ def pre_create(self, **kwargs): class ReviewSessionObjectStatus(Entity): - projections = ["id", "status"] + pass class Recipient(Entity): - # recipients are only used in notes and thus we can simply project - # everything - projections = ["resource_id", "note", "note_id", "recipient", "user"] - - relationship = Relationship() + pass class EntitySetting(Entity): @@ -789,7 +775,6 @@ class EntitySetting(Entity): class Group(Entity): - projections = ["id", "name"] @Criteria.supported_targets() def by_name(self, target, *names): @@ -798,9 +783,6 @@ def by_name(self, target, *names): class Job(Entity): - projections = ["id", "status", "data"] - - relationship = Relationship() @Criteria.supported_targets(Entity) def by_name(self, target, *names): @@ -876,11 +858,10 @@ def by_finish_date(self, target, finish_date): class Membership(Entity): - projections = ["id", "group"] + pass class Location(Entity): - projections = ["id", "name"] @Criteria.supported_targets() def by_name(self, target, *names): @@ -889,7 +870,6 @@ def by_name(self, target, *names): class List(Entity): - projections = ["id", "name"] relationship = Relationship() @@ -941,9 +921,6 @@ def create(self, task, **kwargs): pass class ListCategory(Entity): - projections = ["id", "name"] - - relationship = Relationship() @Criteria.supported_targets() def by_name(self, target, *names): @@ -956,7 +933,6 @@ class WorkflowSchema(Entity): class NoteLabel(Entity): - projections = ["id", "name"] @Criteria.supported_targets(Entity) def by_name(self, target, *names): @@ -971,4 +947,4 @@ class Resource(Entity): # automatically declare classes for all TypedContext objects for _type in OBJECT_TYPES.types: if _type not in locals() or issubclass(locals().get(_type, None), ForwardDeclaration): - locals()[_type] = type(str(_type), (TypedContext,), {"projections": ['id', 'name']}) + locals()[_type] = type(str(_type), (TypedContext,), {}) From c2174d8db2f663ef05e3e9c100d6103633386602 Mon Sep 17 00:00:00 2001 From: Rico Koschmitzky Date: Fri, 7 Jul 2023 12:55:40 +0200 Subject: [PATCH 2/3] keep ftracks default projections intact --- src/trackteroid/query/query.py | 7 ++----- tests/test_authoring.py | 2 ++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/trackteroid/query/query.py b/src/trackteroid/query/query.py index 48d1693..1481e58 100644 --- a/src/trackteroid/query/query.py +++ b/src/trackteroid/query/query.py @@ -115,7 +115,7 @@ def __init__(self, entity, session=SESSION, schema=SCHEMA.default): self.entity_type.relationship(session=session, schema=schema) - self.primary_key = self.entity_type.projections[0] if len(self.entity_type.projections) else "id" + self.primary_key = session.types[self.entity_type.__class__.__name__].primary_key_attributes[0] self.projections = [] self.criteria = [] self.session = session @@ -157,10 +157,7 @@ def __str__(self): projections = ", ".join(self.projections or self.entity_type.projections) - _query = "select {} from {}".format( - projections, - self.entity_type.__class__.__name__ - ) + _query = (f"select {projections} from " if projections else "") + f"{self.entity_type.__class__.__name__}" if self.criteria: # We sort the criteria based on the distance to the queried entity: diff --git a/tests/test_authoring.py b/tests/test_authoring.py index c34cd5f..1cbf152 100644 --- a/tests/test_authoring.py +++ b/tests/test_authoring.py @@ -1,4 +1,6 @@ +import logging import random +import sys import uuid from collections import OrderedDict From 837045b66f822c189caa6b39559f18ee33b97314 Mon Sep 17 00:00:00 2001 From: Rico Koschmitzky Date: Fri, 7 Jul 2023 17:45:00 +0200 Subject: [PATCH 3/3] make DEFAULT_PROJECTIONS_RESOLVER consuming session --- src/trackteroid/configuration.py | 2 +- src/trackteroid/entities/base.py | 22 ++-------------------- src/trackteroid/query/query.py | 4 ++-- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/trackteroid/configuration.py b/src/trackteroid/configuration.py index 82db7e7..704be90 100644 --- a/src/trackteroid/configuration.py +++ b/src/trackteroid/configuration.py @@ -113,7 +113,7 @@ def _override_configuration(): # deletion for and resolves to True or False. ALLOWED_FOR_DELETION_RESOLVER = lambda session, type_name: True -DEFAULT_PROJECTIONS_RESOLVER = lambda type_name: [] +DEFAULT_PROJECTIONS_RESOLVER = lambda session, type_name: [] WARN_ON_INJECT = False ############################################################################################ diff --git a/src/trackteroid/entities/base.py b/src/trackteroid/entities/base.py index 053420c..4cc0f2e 100644 --- a/src/trackteroid/entities/base.py +++ b/src/trackteroid/entities/base.py @@ -730,22 +730,6 @@ def resolve_subtype(self, entity_type): source=getattr(matched_types, "source", None) ) - def query_children(self, projections=None, session=None): - """Queries and returns the children of the collection. Only supported for - entities that have a "children" relation - - Args: - projections (`list` of `str`): Projections to fetch from the children - session (Session): Optional session to use. - - """ - projections_ = ["children.{}".format(_) for _ in self._entity.projections] - projections_ += ["children.{}".format(x) for x in (projections or [])] - projections_.append("children.object_type.name") - query = self.as_query(use_ids=True) - query.projections = list(set(projections_).union(query.projections)) # update not override - return query.get_all(session=session or self._session).children - # TODO: move to avoid circular import @staticmethod def _make_empty(entity_class, session): @@ -1847,10 +1831,8 @@ def __cmp__(self, other): else: return 1 - @classmethod - @property - def projections(cls): - return DEFAULT_PROJECTIONS_RESOLVER(type_name=cls.__name__) + def projections(self, session): + return DEFAULT_PROJECTIONS_RESOLVER(session=session, type_name=self.__class__.__name__) @classmethod @property diff --git a/src/trackteroid/query/query.py b/src/trackteroid/query/query.py index 1481e58..e048661 100644 --- a/src/trackteroid/query/query.py +++ b/src/trackteroid/query/query.py @@ -155,7 +155,7 @@ def __copy__(self): def __str__(self): """ returns the generated query string """ - projections = ", ".join(self.projections or self.entity_type.projections) + projections = ", ".join(self.projections or self.entity_type.projections(self.session)) _query = (f"select {projections} from " if projections else "") + f"{self.entity_type.__class__.__name__}" @@ -307,7 +307,7 @@ def _set_projections(self, projections): else: _projections.append(projection) # extend default projections - self.projections = list(set(_projections + self.entity_type.__class__.projections)) + self.projections = list(set(_projections + self.entity_type.projections(self.session))) @property def valid(self):