mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
📝 some fixes, mostly docstrings
This commit is contained in:
parent
0508b841d0
commit
4d6f5be7f5
10 changed files with 126 additions and 97 deletions
|
|
@ -3,12 +3,12 @@
|
|||
## Introduction
|
||||
|
||||
The Representation is the lowest level entity, describing the concrete data chunk that
|
||||
pipeline can act on. It can be specific file or just a set of metadata. Idea is that one
|
||||
pipeline can act on. It can be a specific file or just a set of metadata. Idea is that one
|
||||
product version can have multiple representations - **Image** product can be jpeg or tiff, both formats are representation of the same source.
|
||||
|
||||
### Brief look into the past (and current state)
|
||||
|
||||
So far, representation was defined as dict-like structure:
|
||||
So far, representation was defined as a dict-like structure:
|
||||
```python
|
||||
{
|
||||
"name": "foo",
|
||||
|
|
@ -18,9 +18,9 @@ So far, representation was defined as dict-like structure:
|
|||
}
|
||||
```
|
||||
|
||||
This is minimal form, but it can have additional keys like `frameStart`, `fps`, `resolutionWidth`, and more. Thare is also `tags` key that can hold `review`, `thumbnail`, `delete`, `toScanline` and other tag that are controlling the processing.
|
||||
This is minimal form, but it can have additional keys like `frameStart`, `fps`, `resolutionWidth`, and more. Thare is also `tags` key that can hold `review`, `thumbnail`, `delete`, `toScanline` and other tags that are controlling the processing.
|
||||
|
||||
This will be *"translated"* to similar structure in database:
|
||||
This will be *"translated"* to the similar structure in the database:
|
||||
|
||||
```python
|
||||
{
|
||||
|
|
@ -57,12 +57,12 @@ There are also some assumptions and limitations - like that if `files` in the
|
|||
representation are list they need to be sequence of files (it can't be a bunch of
|
||||
unrelated files).
|
||||
|
||||
This system is very flexible in one way, but it lacks few very important things:
|
||||
This system is very flexible in one way, but it lacks a few very important things:
|
||||
|
||||
- it is not clearly defined - you can add easily keys, values, tags but without
|
||||
- it is not clearly defined — you can add easily keys, values, tags but without
|
||||
unforeseeable
|
||||
consequences
|
||||
- it cannot handle "bundles" - multiple files that needs to be versioned together and
|
||||
- it cannot handle "bundles" — multiple files that need to be versioned together and
|
||||
belong together
|
||||
- it cannot describe important information that you can't get from the file itself, or
|
||||
it is very expensive (like axis orientation and units from alembic files)
|
||||
|
|
@ -70,7 +70,7 @@ it is very expensive (like axis orientation and units from alembic files)
|
|||
|
||||
### New Representation model
|
||||
|
||||
The idea about new representation model is obviously around solving points mentioned
|
||||
The idea about a new representation model is about solving points mentioned
|
||||
above and also adding some benefits, like consistent IDE hints, typing, built-in
|
||||
validators and much more.
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ above and also adding some benefits, like consistent IDE hints, typing, built-in
|
|||
|
||||
The new representation is "just" a dictionary of traits. Trait can be anything provided
|
||||
it is based on `TraitBase`. It shouldn't really duplicate information that is
|
||||
available in a moment of loading (or any usage) by other means. It should contain
|
||||
available at the moment of loading (or any usage) by other means. It should contain
|
||||
information that couldn't be determined by the file, or the AYON context. Some of
|
||||
those traits are aligned with [OpenAssetIO Media Creation](https://github.com/OpenAssetIO/OpenAssetIO-MediaCreation) with hopes of maintained compatibility (it
|
||||
should be easy enough to convert between OpenAssetIO Traits and AYON Traits).
|
||||
|
|
@ -114,18 +114,18 @@ image = rep[Image.id]
|
|||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Trait and their ids - every Trait has its id as a string with
|
||||
> Trait and their ids — every Trait has its id as a string with a
|
||||
> version appended - so **Image** has `ayon.2d.Image.v1`. This is used on
|
||||
> several places (you see its use above for indexing traits). When querying,
|
||||
> you can also omit the version at the end, and it will try its best to find
|
||||
> the latest possible version. More on that in [Traits]()
|
||||
|
||||
You can construct the `Representation` from dictionary (for example
|
||||
You can construct the `Representation` from dictionary (for example,
|
||||
serialized as JSON) using `Representation.from_dict()`, or you can
|
||||
serialize `Representation` to dict to store with `Representation.traits_as_dict()`.
|
||||
|
||||
Every time representation is created, new id is generated. You can pass existing
|
||||
id when creating new representation instance.
|
||||
Every time representation is created, a new id is generated. You can pass existing
|
||||
id when creating the new representation instance.
|
||||
|
||||
##### Equality
|
||||
|
||||
|
|
@ -200,7 +200,7 @@ in the representation if needed.
|
|||
|
||||
## Examples
|
||||
|
||||
Create simple image representation to be integrated by AYON:
|
||||
Create a simple image representation to be integrated by AYON:
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
|
@ -252,8 +252,8 @@ except MissingTraitError:
|
|||
print(f"resolution isn't set on {rep.name}")
|
||||
```
|
||||
|
||||
Accessing non-existent traits will result in exception. To test if
|
||||
representation has some specific trait, you can use `.contains_trait()` method.
|
||||
Accessing non-existent traits will result in an exception. To test if
|
||||
the representation has some specific trait, you can use `.contains_trait()` method.
|
||||
|
||||
|
||||
You can also prepare the whole representation data as a dict and
|
||||
|
|
@ -381,7 +381,7 @@ class AlembicTraitLoader(MayaLoader):
|
|||
|
||||
You can create the representations in the same way as mentioned in the examples above.
|
||||
Straightforward way is to use `Representation` class and add the traits to it. Collect
|
||||
traits in list and then pass them to the `Representation` constructor. You should add
|
||||
traits in the list and then pass them to the `Representation` constructor. You should add
|
||||
the new Representation to the instance data using `add_trait_representations()` function.
|
||||
|
||||
```python
|
||||
|
|
@ -436,8 +436,8 @@ class SomeExtractor(Extractor):
|
|||
|
||||
## Developer notes
|
||||
|
||||
Adding new trait based representations in to publish Instance and working with them is using
|
||||
set of helper function defined in `ayon_core.pipeline.publish` module. These are:
|
||||
Adding new trait-based representations in to the publishing Instance and working with them is using
|
||||
a set of helper function defined in `ayon_core.pipeline.publish` module. These are:
|
||||
|
||||
* add_trait_representations
|
||||
* get_trait_representations
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Color management related traits."""
|
||||
"""Color-management-related traits."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
|
@ -11,7 +11,7 @@ from .trait import TraitBase
|
|||
class ColorManaged(TraitBase):
|
||||
"""Color managed trait.
|
||||
|
||||
Holds color management information. Can be used with Image related
|
||||
Holds color management information. Can be used with Image-related
|
||||
traits to define color space and config.
|
||||
|
||||
Sync with OpenAssetIO MediaCreation Traits.
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class MimeType(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
mime_type (str): Mime type like image/jpeg.
|
||||
"""
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ class LocatableContent(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
location (str): Location.
|
||||
is_templated (Optional[bool]): Is the location templated?
|
||||
Default is None.
|
||||
|
|
@ -82,7 +82,7 @@ class FileLocation(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
file_path (str): File path.
|
||||
file_size (Optional[int]): File size in bytes.
|
||||
file_hash (Optional[str]): File hash.
|
||||
|
|
@ -108,7 +108,7 @@ class FileLocations(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
file_paths (list of FileLocation): File locations.
|
||||
|
||||
"""
|
||||
|
|
@ -136,7 +136,7 @@ class FileLocations(TraitBase):
|
|||
frame: int,
|
||||
sequence_trait: Optional[Sequence] = None,
|
||||
) -> Optional[FileLocation]:
|
||||
"""Get file location for a frame.
|
||||
"""Get a file location for a frame.
|
||||
|
||||
This method will return the file location for a given frame. If the
|
||||
frame is not found in the file paths, it will return None.
|
||||
|
|
@ -166,7 +166,7 @@ class FileLocations(TraitBase):
|
|||
"""Validate the trait.
|
||||
|
||||
This method validates the trait against others in the representation.
|
||||
In particular, it checks that the sequence trait is present and if
|
||||
In particular, it checks that the sequence trait is present, and if
|
||||
so, it will compare the frame range to the file paths.
|
||||
|
||||
Args:
|
||||
|
|
@ -187,8 +187,8 @@ class FileLocations(TraitBase):
|
|||
if not representation.contains_trait(Sequence) \
|
||||
and not representation.contains_trait(UDIM):
|
||||
# we have multiple files, but it is not a sequence
|
||||
# or UDIM tile set what it it then? If the files are not related
|
||||
# to each other then this representation is invalid.
|
||||
# or UDIM tile set what is it then? If the files are not related
|
||||
# to each other, then this representation is invalid.
|
||||
msg = (
|
||||
"Multiple file locations defined, but no Sequence "
|
||||
"or UDIM trait defined. If the files are not related to "
|
||||
|
|
@ -254,7 +254,7 @@ class FileLocations(TraitBase):
|
|||
f"({len(frames_from_spec)})"
|
||||
)
|
||||
raise TraitValidationError(self.name, msg)
|
||||
# if there is frame spec on the Sequence trait
|
||||
# if there is a frame spec on the Sequence trait,
|
||||
# we should not validate the frame range from the files.
|
||||
# the rest is validated by Sequence validators.
|
||||
return
|
||||
|
|
@ -354,7 +354,7 @@ class RootlessLocation(TraitBase):
|
|||
"""RootlessLocation trait model.
|
||||
|
||||
RootlessLocation trait is a trait that represents a file path that is
|
||||
without specific root. To obtain absolute path, the root needs to be
|
||||
without a specific root. To get the absolute path, the root needs to be
|
||||
resolved by AYON. Rootless path can be used on multiple platforms.
|
||||
|
||||
Example::
|
||||
|
|
@ -366,7 +366,7 @@ class RootlessLocation(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
rootless_path (str): Rootless path.
|
||||
"""
|
||||
|
||||
|
|
@ -391,7 +391,7 @@ class Compressed(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
compression_type (str): Compression type.
|
||||
"""
|
||||
|
||||
|
|
@ -431,7 +431,7 @@ class Bundle(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
items (list[list[TraitBase]]): List of representations.
|
||||
"""
|
||||
|
||||
|
|
@ -442,7 +442,7 @@ class Bundle(TraitBase):
|
|||
items: list[list[TraitBase]]
|
||||
|
||||
def to_representations(self) -> Generator[Representation]:
|
||||
"""Convert bundle to representations.
|
||||
"""Convert a bundle to representations.
|
||||
|
||||
Yields:
|
||||
Representation: Representation of the bundle.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class Transient(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with the version
|
||||
"""
|
||||
|
||||
name: ClassVar[str] = "Transient"
|
||||
|
|
@ -50,13 +50,13 @@ class Persistent(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with the version
|
||||
"""
|
||||
|
||||
name: ClassVar[str] = "Persistent"
|
||||
description: ClassVar[str] = "Persistent Trait Model"
|
||||
id: ClassVar[str] = "ayon.lifecycle.Persistent.v1"
|
||||
# note that this affects persistence of the trait itself, not
|
||||
# Note that this affects the persistence of the trait itself, not
|
||||
# the representation. This is a class variable, so it is shared
|
||||
# among all instances of the class.
|
||||
persistent: bool = True
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from .trait import TraitBase
|
|||
class Tagged(TraitBase):
|
||||
"""Tagged trait model.
|
||||
|
||||
This trait can hold list of tags.
|
||||
This trait can hold a list of tags.
|
||||
|
||||
Example::
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ class Tagged(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
tags (List[str]): Tags.
|
||||
"""
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ class TemplatePath(TraitBase):
|
|||
"""TemplatePath trait model.
|
||||
|
||||
This model represents a template path with formatting data.
|
||||
Template path can be Anatomy template and data is used to format it.
|
||||
Template path can be an Anatomy template and data is used to format it.
|
||||
|
||||
Example::
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ class TemplatePath(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
template (str): Template path.
|
||||
data (dict[str]): Formatting data.
|
||||
"""
|
||||
|
|
@ -72,7 +72,7 @@ class Variant(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
variant (str): Variant name.
|
||||
"""
|
||||
|
||||
|
|
@ -115,8 +115,8 @@ class KeepOriginalName(TraitBase):
|
|||
class SourceApplication(TraitBase):
|
||||
"""Metadata about the source (producing) application.
|
||||
|
||||
This can be useful in cases, where this information is
|
||||
needed but it cannot be determined from other means - like
|
||||
This can be useful in cases where this information is
|
||||
needed, but it cannot be determined from other means - like
|
||||
.txt files used for various motion tracking applications that
|
||||
must be interpreted by the loader.
|
||||
|
||||
|
|
@ -147,9 +147,9 @@ class IntendedUse(TraitBase):
|
|||
"""Intended use of the representation.
|
||||
|
||||
This trait describes the intended use of the representation. It
|
||||
can be used in cases, where the other traits are not enough to
|
||||
describe the intended use. For example txt file with tracking
|
||||
points can be used as corner pin in After Effect but not in Nuke.
|
||||
can be used in cases where the other traits are not enough to
|
||||
describe the intended use. For example, a txt file with tracking
|
||||
points can be used as a corner pin in After Effect but not in Nuke.
|
||||
|
||||
Attributes:
|
||||
use (str): Intended use description.
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ T = TypeVar("T", bound="TraitBase")
|
|||
|
||||
|
||||
def _get_version_from_id(_id: str) -> Optional[int]:
|
||||
"""Get version from ID.
|
||||
"""Get the version from ID.
|
||||
|
||||
Args:
|
||||
_id (str): ID.
|
||||
|
|
@ -47,15 +47,16 @@ def _get_version_from_id(_id: str) -> Optional[int]:
|
|||
class Representation(Generic[T]): # noqa: PLR0904
|
||||
"""Representation of products.
|
||||
|
||||
Representation defines collection of individual properties that describe
|
||||
the specific "form" of the product. Each property is represented by a
|
||||
trait therefore the Representation is a collection of traits.
|
||||
Representation defines a collection of individual properties that describe
|
||||
the specific "form" of the product. A trait represents a set of
|
||||
properties therefore, the Representation is a collection of traits.
|
||||
|
||||
It holds methods to add, remove, get, and check for the existence of a
|
||||
trait in the representation. It also provides a method to get all the
|
||||
trait in the representation.
|
||||
|
||||
Note:
|
||||
`PLR0904` is rule for checking number of public methods in a class.
|
||||
`PLR0904` is the rule for checking the number of public methods
|
||||
in a class.
|
||||
|
||||
Arguments:
|
||||
name (str): Representation name. Must be unique within instance.
|
||||
|
|
@ -141,7 +142,7 @@ class Representation(Generic[T]): # noqa: PLR0904
|
|||
trait already exists. Defaults to False.
|
||||
|
||||
Raises:
|
||||
ValueError: If the trait ID is not provided or the trait already
|
||||
ValueError: If the trait ID is not provided, or the trait already
|
||||
exists.
|
||||
|
||||
"""
|
||||
|
|
@ -423,7 +424,7 @@ class Representation(Generic[T]): # noqa: PLR0904
|
|||
@staticmethod
|
||||
def _get_version_from_id(trait_id: str) -> Union[int, None]:
|
||||
# sourcery skip: use-named-expression
|
||||
"""Check if the trait has version specified.
|
||||
"""Check if the trait has a version specified.
|
||||
|
||||
Args:
|
||||
trait_id (str): Trait ID.
|
||||
|
|
@ -498,11 +499,11 @@ class Representation(Generic[T]): # noqa: PLR0904
|
|||
klass = getattr(module, attr_name)
|
||||
if not inspect.isclass(klass):
|
||||
continue
|
||||
# this needs to be done because of the bug? in
|
||||
# This needs to be done because of the bug? In
|
||||
# python ABCMeta, where ``issubclass`` is not working
|
||||
# if it hits the GenericAlias (that is in fact
|
||||
# tuple[int, int]). This is added to the scope by
|
||||
# ``types`` module.
|
||||
# the ``types`` module.
|
||||
if type(klass) is GenericAlias:
|
||||
continue
|
||||
if issubclass(klass, TraitBase) \
|
||||
|
|
@ -518,8 +519,8 @@ class Representation(Generic[T]): # noqa: PLR0904
|
|||
"""Get the trait class with corresponding to given ID.
|
||||
|
||||
This method will search for the trait class in all the modules except
|
||||
the blacklisted modules. There is some issue in Pydantic where
|
||||
``issubclass`` is not working properly so we are excluding explicitly
|
||||
the blocklisted modules. There is some issue in Pydantic where
|
||||
``issubclass`` is not working properly, so we are excluding explicit
|
||||
modules with offending classes. This list can be updated as needed to
|
||||
speed up the search.
|
||||
|
||||
|
|
@ -540,7 +541,7 @@ class Representation(Generic[T]): # noqa: PLR0904
|
|||
|
||||
for trait_class in trait_candidates:
|
||||
if trait_class.id == trait_id:
|
||||
# we found direct match
|
||||
# we found a direct match
|
||||
return trait_class
|
||||
|
||||
# if we didn't find direct match, we will search for the highest
|
||||
|
|
@ -670,7 +671,7 @@ class Representation(Generic[T]): # noqa: PLR0904
|
|||
try:
|
||||
trait_class = cls.get_trait_class_by_trait_id(trait_id)
|
||||
except UpgradableTraitError as e:
|
||||
# we found newer version of trait, we will upgrade the data
|
||||
# we found a newer version of trait, we will upgrade the data
|
||||
if hasattr(e.trait, "upgrade"):
|
||||
traits.append(e.trait.upgrade(value))
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ if TYPE_CHECKING:
|
|||
class GapPolicy(Enum):
|
||||
"""Gap policy enumeration.
|
||||
|
||||
This type defines how to handle gaps in sequence.
|
||||
This type defines how to handle gaps in a sequence.
|
||||
|
||||
Attributes:
|
||||
forbidden (int): Gaps are forbidden.
|
||||
|
|
@ -40,7 +40,7 @@ class GapPolicy(Enum):
|
|||
class FrameRanged(TraitBase):
|
||||
"""Frame ranged trait model.
|
||||
|
||||
Model representing a frame ranged trait.
|
||||
Model representing a frame-ranged trait.
|
||||
|
||||
Sync with OpenAssetIO MediaCreation Traits. For compatibility with
|
||||
OpenAssetIO, we'll need to handle different names of attributes:
|
||||
|
|
@ -52,14 +52,14 @@ class FrameRanged(TraitBase):
|
|||
Note: frames_per_second is a string to allow various precision
|
||||
formats. FPS is a floating point number, but it can be also
|
||||
represented as a fraction (e.g. "30000/1001") or as a decimal
|
||||
or even as irrational number. We need to support all these
|
||||
or even as an irrational number. We need to support all these
|
||||
formats. To work with FPS, we'll need some helper function
|
||||
to convert FPS to Decimal from string.
|
||||
|
||||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with a version
|
||||
frame_start (int): Frame start.
|
||||
frame_end (int): Frame end.
|
||||
frame_in (int): Frame in.
|
||||
|
|
@ -90,7 +90,7 @@ class Handles(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with a version
|
||||
inclusive (bool): Handles are inclusive.
|
||||
frame_start_handle (int): Frame start handle.
|
||||
frame_end_handle (int): Frame end handle.
|
||||
|
|
@ -116,7 +116,7 @@ class Sequence(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with a version
|
||||
gaps_policy (GapPolicy): Gaps policy - how to handle gaps in
|
||||
sequence.
|
||||
frame_padding (int): Frame padding.
|
||||
|
|
@ -162,7 +162,7 @@ class Sequence(TraitBase):
|
|||
"""Validate the trait."""
|
||||
super().validate_trait(representation)
|
||||
|
||||
# if there is FileLocations trait, run validation
|
||||
# if there is a FileLocations trait, run validation
|
||||
# on it as well
|
||||
|
||||
with contextlib.suppress(MissingTraitError):
|
||||
|
|
@ -182,9 +182,9 @@ class Sequence(TraitBase):
|
|||
from .content import FileLocations
|
||||
file_locs: FileLocations = representation.get_trait(
|
||||
FileLocations)
|
||||
# validate if file locations on representation
|
||||
# matches the frame list (if any)
|
||||
# we need to extend the expected frames with Handles
|
||||
# Validate if the file locations on representation
|
||||
# match the frame list (if any).
|
||||
# We need to extend the expected frames with Handles.
|
||||
frame_start = None
|
||||
frame_end = None
|
||||
handles_frame_start = None
|
||||
|
|
@ -192,7 +192,7 @@ class Sequence(TraitBase):
|
|||
with contextlib.suppress(MissingTraitError):
|
||||
handles: Handles = representation.get_trait(Handles)
|
||||
# if handles are inclusive, they should be already
|
||||
# accounted in the FrameRaged frame spec
|
||||
# accounted for in the FrameRaged frame spec
|
||||
if not handles.inclusive:
|
||||
handles_frame_start = handles.frame_start_handle
|
||||
handles_frame_end = handles.frame_end_handle
|
||||
|
|
@ -218,16 +218,16 @@ class Sequence(TraitBase):
|
|||
frame_end: Optional[int] = None,
|
||||
handles_frame_start: Optional[int] = None,
|
||||
handles_frame_end: Optional[int] = None) -> None:
|
||||
"""Validate frame list.
|
||||
"""Validate a frame list.
|
||||
|
||||
This will take FileLocations trait and validate if the
|
||||
file locations match the frame list specification.
|
||||
|
||||
For example, if frame list is "1-10,20-30,40-50", then
|
||||
For example, if the frame list is "1-10,20-30,40-50", then
|
||||
the frame numbers in the file locations should match
|
||||
these frames.
|
||||
|
||||
It will skip the validation if frame list is not provided.
|
||||
It will skip the validation if the frame list is not provided.
|
||||
|
||||
Args:
|
||||
file_locations (FileLocations): File locations trait.
|
||||
|
|
@ -237,7 +237,7 @@ class Sequence(TraitBase):
|
|||
handles_frame_end (Optional[int]): Frame end handle.
|
||||
|
||||
Raises:
|
||||
TraitValidationError: If frame list does not match
|
||||
TraitValidationError: If the frame list does not match
|
||||
the expected frames.
|
||||
|
||||
"""
|
||||
|
|
@ -341,7 +341,7 @@ class Sequence(TraitBase):
|
|||
def _get_collection(
|
||||
file_locations: FileLocations,
|
||||
regex: Optional[Pattern] = None) -> clique.Collection:
|
||||
r"""Get collection from file locations.
|
||||
r"""Get the collection from file locations.
|
||||
|
||||
Args:
|
||||
file_locations (FileLocations): File locations trait.
|
||||
|
|
@ -355,7 +355,7 @@ class Sequence(TraitBase):
|
|||
clique.Collection: Collection instance.
|
||||
|
||||
Raises:
|
||||
ValueError: If zero or multiple collections found.
|
||||
ValueError: If zero or multiple of collections are found.
|
||||
|
||||
"""
|
||||
patterns = [regex] if regex else None
|
||||
|
|
@ -382,7 +382,7 @@ class Sequence(TraitBase):
|
|||
"""
|
||||
src_collection = Sequence._get_collection(file_locations)
|
||||
padding = src_collection.padding
|
||||
# sometimes Clique doens't get the padding right so
|
||||
# sometimes Clique doesn't get the padding right, so
|
||||
# we need to calculate it manually
|
||||
if padding == 0:
|
||||
padding = len(str(max(src_collection.indexes)))
|
||||
|
|
@ -394,7 +394,7 @@ class Sequence(TraitBase):
|
|||
file_locations: FileLocations,
|
||||
regex: Optional[Pattern] = None,
|
||||
) -> list[int]:
|
||||
r"""Get frame list.
|
||||
r"""Get the frame list.
|
||||
|
||||
Args:
|
||||
file_locations (FileLocations): File locations trait.
|
||||
|
|
@ -412,9 +412,9 @@ class Sequence(TraitBase):
|
|||
return list(src_collection.indexes)
|
||||
|
||||
def get_frame_pattern(self) -> Pattern:
|
||||
"""Get frame regex as pattern.
|
||||
"""Get frame regex as a pattern.
|
||||
|
||||
If the regex is string, it will compile it to the pattern.
|
||||
If the regex is a string, it will compile it to the pattern.
|
||||
|
||||
Returns:
|
||||
Pattern: Compiled regex pattern.
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class TraitBase(ABC):
|
|||
@classmethod
|
||||
def get_version(cls) -> Optional[int]:
|
||||
# sourcery skip: use-named-expression
|
||||
"""Get trait version from ID.
|
||||
"""Get a trait version from ID.
|
||||
|
||||
This assumes Trait ID ends with `.v{version}`. If not, it will
|
||||
return None.
|
||||
|
|
@ -71,16 +71,16 @@ class TraitBase(ABC):
|
|||
|
||||
@classmethod
|
||||
def get_versionless_id(cls) -> str:
|
||||
"""Get trait ID without version.
|
||||
"""Get a trait ID without a version.
|
||||
|
||||
Returns:
|
||||
str: Trait ID without version.
|
||||
str: Trait ID without a version.
|
||||
|
||||
"""
|
||||
return re.sub(r"\.v\d+$", "", str(cls.id))
|
||||
|
||||
def as_dict(self) -> dict:
|
||||
"""Return trait as dictionary.
|
||||
"""Return a trait as a dictionary.
|
||||
|
||||
Returns:
|
||||
dict: Trait as dictionary.
|
||||
|
|
@ -101,8 +101,8 @@ class UpgradableTraitError(Exception, Generic[T]):
|
|||
"""Upgradable trait version exception.
|
||||
|
||||
This exception is raised when the trait can upgrade existing data
|
||||
meant for older versions of the trait. It must implement `upgrade`
|
||||
method that will take old trait data as argument to handle the upgrade.
|
||||
meant for older versions of the trait. It must implement an `upgrade`
|
||||
method that will take old trait data as an argument to handle the upgrade.
|
||||
"""
|
||||
|
||||
trait: T
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class Image(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with version
|
||||
"""
|
||||
|
||||
name: ClassVar[str] = "Image"
|
||||
|
|
@ -33,12 +33,12 @@ class Image(TraitBase):
|
|||
class PixelBased(TraitBase):
|
||||
"""PixelBased trait model.
|
||||
|
||||
Pixel related trait for image data.
|
||||
The pixel-related trait for image data.
|
||||
|
||||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with a version
|
||||
display_window_width (int): Width of the image display window.
|
||||
display_window_height (int): Height of the image display window.
|
||||
pixel_aspect_ratio (float): Pixel aspect ratio.
|
||||
|
|
@ -87,7 +87,7 @@ class Deep(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with a version
|
||||
"""
|
||||
|
||||
name: ClassVar[str] = "Deep"
|
||||
|
|
@ -106,7 +106,7 @@ class Overscan(TraitBase):
|
|||
Attributes:
|
||||
name (str): Trait name.
|
||||
description (str): Trait description.
|
||||
id (str): id should be namespaced trait name with version
|
||||
id (str): id should be a namespaced trait name with a version
|
||||
left (int): Left overscan/underscan.
|
||||
right (int): Right overscan/underscan.
|
||||
top (int): Top overscan/underscan.
|
||||
|
|
@ -144,8 +144,8 @@ class UDIM(TraitBase):
|
|||
udim: list[int]
|
||||
udim_regex: Optional[str] = r"(?:\.|_)(?P<udim>\d+)\.\D+\d?$"
|
||||
|
||||
# field validator for udim_regex - this works in pydantic model v2 but not
|
||||
# with the pure data classes
|
||||
# Field validator for udim_regex - this works in the pydantic model v2
|
||||
# but not with the pure data classes.
|
||||
@classmethod
|
||||
def validate_frame_regex(cls, v: Optional[str]) -> Optional[str]:
|
||||
"""Validate udim regex.
|
||||
|
|
@ -177,6 +177,8 @@ class UDIM(TraitBase):
|
|||
Optional[FileLocation]: File location.
|
||||
|
||||
"""
|
||||
if not self.udim_regex:
|
||||
return None
|
||||
pattern = re.compile(self.udim_regex)
|
||||
for location in file_locations.file_paths:
|
||||
result = re.search(pattern, location.file_path.name)
|
||||
|
|
@ -188,7 +190,7 @@ class UDIM(TraitBase):
|
|||
|
||||
def get_udim_from_file_location(
|
||||
self, file_location: FileLocation) -> Optional[int]:
|
||||
"""Get UDIM from file location.
|
||||
"""Get UDIM from the file location.
|
||||
|
||||
Args:
|
||||
file_location (FileLocation): File location.
|
||||
|
|
@ -197,6 +199,8 @@ class UDIM(TraitBase):
|
|||
Optional[int]: UDIM value.
|
||||
|
||||
"""
|
||||
if not self.udim_regex:
|
||||
return None
|
||||
pattern = re.compile(self.udim_regex)
|
||||
result = re.search(pattern, file_location.file_path.name)
|
||||
if result:
|
||||
|
|
|
|||
|
|
@ -378,3 +378,27 @@ def test_representation_equality() -> None:
|
|||
assert rep_d != rep_e
|
||||
# because of the trait difference
|
||||
assert rep_d != rep_f
|
||||
|
||||
def test_get_repre_by_name():
|
||||
"""Test getting representation by name."""
|
||||
rep_a = Representation(name="test_a", traits=[
|
||||
FileLocation(file_path=Path("/path/to/file"), file_size=1024),
|
||||
Image(),
|
||||
PixelBased(
|
||||
display_window_width=1920,
|
||||
display_window_height=1080,
|
||||
pixel_aspect_ratio=1.0),
|
||||
Planar(planar_configuration="RGB"),
|
||||
])
|
||||
rep_b = Representation(name="test_b", traits=[
|
||||
FileLocation(file_path=Path("/path/to/file"), file_size=1024),
|
||||
Image(),
|
||||
PixelBased(
|
||||
display_window_width=1920,
|
||||
display_window_height=1080,
|
||||
pixel_aspect_ratio=1.0),
|
||||
Planar(planar_configuration="RGB"),
|
||||
])
|
||||
|
||||
representations = [rep_a, rep_b]
|
||||
repre = next(rep for rep in representations if rep.name == "test_a")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue