Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API] Get abstract paths with a different sequence key format #783

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
33 changes: 25 additions & 8 deletions python/tank/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .errors import TankError, TankMultipleMatchingTemplatesError
from .path_cache import PathCache
from .template import read_templates
from .templatekey import SequenceKey
from . import constants
from . import pipelineconfig
from . import pipelineconfig_utils
Expand Down Expand Up @@ -528,9 +529,12 @@ def paths_from_template(
:returns: Matching file paths
:rtype: List of strings.
"""
skip_keys = skip_keys or []
if isinstance(skip_keys, six.string_types):
skip_keys = [skip_keys]
elif isinstance(skip_keys, list):
skip_keys = list(skip_keys)
else:
skip_keys = []

# construct local fields dictionary that doesn't include any skip keys:
local_fields = dict(
Expand Down Expand Up @@ -681,12 +685,25 @@ def abstract_paths_from_template(self, template, fields):
if skip_leaf_level:
search_template = template.parent

# now carry out a regular search based on the template
found_files = self.paths_from_template(search_template, fields)
st_abstract_keys = [k for k in search_template.keys.values() if k.is_abstract]

# skip abstract SequenceKey declared as format_spec_format: "FORMAT:"
# then we can list properly existing paths
skip_keys = []
for k in st_abstract_keys:
key_name = k.name
if key_name not in fields:
continue
if not isinstance(k, SequenceKey):
continue
if not k.is_framespec_format(fields[key_name]):
continue
skip_keys.append(key_name)

st_abstract_key_names = [
k.name for k in search_template.keys.values() if k.is_abstract
]
# now carry out a regular search based on the template
found_files = self.paths_from_template(
search_template, fields, skip_keys=skip_keys
)

# now collapse down the search matches for any abstract fields,
# and add the leaf level if necessary
Expand All @@ -703,8 +720,8 @@ def abstract_paths_from_template(self, template, fields):
# by deleting all eye values they will be replaced by %V
# as the template is applied.
#
for abstract_key_name in st_abstract_key_names:
del cur_fields[abstract_key_name]
for abstract_key in st_abstract_keys:
del cur_fields[abstract_key.name]

# pass 2 - if we ignored the leaf level, add those fields back
# note that there is no risk that we add abstract fields at this point
Expand Down
18 changes: 8 additions & 10 deletions python/tank/templatekey.py
Original file line number Diff line number Diff line change
Expand Up @@ -1112,9 +1112,7 @@ def validate(self, value):
error_msg += "Valid frame specs: %s\n" % str(self._frame_specs)
error_msg += "Valid format strings: %s\n" % full_format_strings

if isinstance(value, six.string_types) and value.startswith(
self.FRAMESPEC_FORMAT_INDICATOR
):
if self.is_framespec_format(value):
# FORMAT: YXZ string - check that XYZ is in VALID_FORMAT_STRINGS
pattern = self._extract_format_string(value)
if pattern in self.VALID_FORMAT_STRINGS:
Expand Down Expand Up @@ -1142,11 +1140,13 @@ def validate(self, value):
else:
return super(SequenceKey, self).validate(value)

def _as_string(self, value):

if isinstance(value, six.string_types) and value.startswith(
def is_framespec_format(self, value):
return isinstance(value, six.string_types) and value.startswith(
self.FRAMESPEC_FORMAT_INDICATOR
):
)

def _as_string(self, value):
if self.is_framespec_format(value):
# this is a FORMAT: XYZ - convert it to the proper resolved frame spec
pattern = self._extract_format_string(value)
return self._resolve_frame_spec(pattern, self.format_spec)
Expand Down Expand Up @@ -1180,9 +1180,7 @@ def _extract_format_string(self, value):
"""
Returns XYZ given the string "FORMAT: XYZ"
"""
if isinstance(value, six.string_types) and value.startswith(
self.FRAMESPEC_FORMAT_INDICATOR
):
if self.is_framespec_format(value):
pattern = value.replace(self.FRAMESPEC_FORMAT_INDICATOR, "").strip()
else:
# passthrough
Expand Down
10 changes: 10 additions & 0 deletions tests/core_tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,16 @@ def test_specify_name(self):
)
self.assertEqual(set(expected), set(result))

def test_sequence_format(self):
expected = [
os.path.join(self.shot_a_path, "%V", "filename.$F4.exr"),
os.path.join(self.shot_b_path, "%V", "filename.$F4.exr"),
]
result = self.tk.abstract_paths_from_template(
self.template, {"name": "filename", "SEQ": "FORMAT: $F"}
)
self.assertEqual(set(expected), set(result))


class TestPathsFromTemplateGlob(TankTestBase):
"""Tests for Tank.paths_from_template method which check the string sent to glob.glob."""
Expand Down