📝 some fixes, mostly docstrings

This commit is contained in:
Ondřej Samohel 2025-05-14 18:50:39 +02:00
parent 0508b841d0
commit 4d6f5be7f5
No known key found for this signature in database
GPG key ID: 02376E18990A97C6
10 changed files with 126 additions and 97 deletions

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -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:

View file

@ -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.

View file

@ -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

View file

@ -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:

View file

@ -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")