Skip to content

Commit

Permalink
Make FileSequence perform more accurate equality test using FrameSet …
Browse files Browse the repository at this point in the history
…(refs #131)
  • Loading branch information
justinfx committed Mar 24, 2024
1 parent 3687b38 commit e987948
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 11 deletions.
43 changes: 32 additions & 11 deletions src/fileseq/filesequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
from __future__ import annotations

import dataclasses
import decimal
import fnmatch
import functools
Expand Down Expand Up @@ -55,6 +56,14 @@ class FileSequence:

_DEFAULT_PAD_CHAR = '@'

@dataclasses.dataclass
class _Components:
dir: str
base: str
frameSet: FrameSet|str|None
pad: str|int
ext: str

def __init__(self,
sequence: str,
pad_style: constants._PadStyle = PAD_STYLE_DEFAULT,
Expand Down Expand Up @@ -753,15 +762,9 @@ def __str__(self):
Returns:
str:
"""
frameSet = utils.asString(self._frameSet or "")
parts = [
self._dir,
self._base,
frameSet,
self._pad if frameSet else "",
self._ext,
]
return "".join(parts)
cmpts = self.__components()
cmpts.frameSet = utils.asString(cmpts.frameSet or "")
return "".join(dataclasses.astuple(cmpts))

def __repr__(self):
try:
Expand All @@ -770,10 +773,19 @@ def __repr__(self):
return super(self.__class__, self).__repr__()

def __eq__(self, other):
return str(self) == str(other)
if not isinstance(other, FileSequence):
return str(self) == str(other)

a = self.__components()
b = other.__components()

a.pad = self.getPaddingNum(a.pad)
b.pad = other.getPaddingNum(b.pad)

return a == b

def __ne__(self, other):
return str(self) != str(other)
return not self.__eq__(other)

def __hash__(self):
# TODO: Technically we should be returning None,
Expand All @@ -783,6 +795,15 @@ def __hash__(self):
# For now, preserving the hashing behaviour in py3.
return id(self)

def __components(self):
return self._Components(
self._dir,
self._base,
self._frameSet or "",
self._pad if self._frameSet else "",
self._ext,
)

@classmethod
def yield_sequences_in_list(
cls,
Expand Down
86 changes: 86 additions & 0 deletions test/test_unit.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import annotations

import dataclasses
import warnings

with warnings.catch_warnings():
Expand Down Expand Up @@ -243,6 +246,30 @@ def _iter(): return iter([1, 2, 3, 4, 5, 6, 7])

class TestFrameSet(unittest.TestCase):

def testEqual(self):
@dataclasses.dataclass
class Case:
a: FrameSet|str|None
b: FrameSet|str|None
expect: bool

table = [
Case(a=FrameSet('1-5'), b=FrameSet('1-5'), expect=True),
Case(a=FrameSet('1-5'), b=FrameSet('1,2,3,4,5'), expect=True),
Case(a=FrameSet('1-3,5-8'), b=FrameSet('1,2,3,5,6-8'), expect=True),
Case(a=FrameSet('1-5'), b=FrameSet('1-4,6'), expect=False),

# Automatic casting of other object
Case(a=FrameSet('1-5'), b='1-5', expect=True),
Case(a=FrameSet('1-5'), b='1-4', expect=False),
Case(a=FrameSet('1-5'), b=[1,2,3,4,5], expect=True),
Case(a=FrameSet('1-5'), b=[1,2,3,5], expect=False),
]

for case in table:
fn = self.assertEqual if case.expect else self.assertNotEqual
fn(case.a, case.b)

def testFrameValues(self):
class Case:
def __init__(self, src, expected=None, has_subframes=False, err=None):
Expand Down Expand Up @@ -640,6 +667,65 @@ def __getitem__(self, item):

class TestFileSequence(TestBase):

def testToStr(self):
@dataclasses.dataclass
class Case:
seq: FileSequence
expect: str

FS = FileSequence
table = [
Case(FS("/dir/file.1-5#.ext"), "/dir/file.1-5#.ext"),
Case(FS("/dir/file.0001.ext"), "/dir/file.0001#.ext"),
Case(FS("/dir/file.1.ext"), "/dir/file.1@.ext"),
Case(FS("/dir/file.ext"), "/dir/file.ext"),
Case(FS("/dir/file"), "/dir/file"),
Case(FS("/dir/.ext"), "/dir/.ext"),
Case(FS("file"), "file"),
]

for case in table:
actual = str(case.seq)
self.assertEqual(case.expect, actual)

fs = FS("/dir/file.1.ext")
fs._frameSet = None
actual = str(fs)
self.assertEqual("/dir/file..ext", actual)

def testEqual(self):
@dataclasses.dataclass
class Case:
a: FileSequence|str|None
b: FileSequence|str|None
expect: bool

FS = FileSequence
table = [
Case(a=FS('/dir/file.1-5#.ext'), b=FS('/dir/file.1-5#.ext'), expect=True),
Case(a=FS('/dir/file.1-5#.ext'), b=FS('/dir/file.1-5@@@@.ext'), expect=True),
Case(a=FS('/dir/file.1-5#.ext'), b=FS('/dir/file.1-5@.ext'), expect=False),
Case(a=FS('/dir/file.0001.ext'), b=FS('/dir/file.0001.ext'), expect=True),
Case(a=FS('file.1-5#.ext'), b=FS('file.1-5#.ext'), expect=True),
Case(a=FS('file.1-5#'), b=FS('file.1-5#'), expect=True),
Case(a=FS('file.ext'), b=FS('file.ext'), expect=True),
Case(a=FS('file'), b=FS('file'), expect=True),

Case(a=FS('/dir/file.1-5#.ext'), b=FS('/dir/file.1,2,3,4,5#.ext'), expect=True),
Case(a=FS('/dir/file.1-5#.ext'), b=FS('/dir/file.1,2,3,4,5#.ext'), expect=True),
Case(a=FS('/dir/file.1-3,5-8#.ext'), b=FS('/dir/file.1,2,3,5,6-8#.ext'), expect=True),
Case(a=FS('/dir/file.1-5#.ext'), b=FS('/dir/file.1-4,6#.ext'), expect=False),

# Automatic casting of other object, to string
Case(a=FS('/dir/file.1-5#.ext'), b='/dir/file.1-5#.ext', expect=True),
Case(a=FS('/dir/file.1-5#.ext'), b='/dir/file.1,2,3,4,5#.ext', expect=False),
Case(a=FS('/dir/file.1-5#.ext'), b='/dir/file.1-4#.ext', expect=False),
]

for case in table:
fn = self.assertEqual if case.expect else self.assertNotEqual
fn(case.a, case.b)

def testNativeStr(self):
seq = FileSequence("/foo/boo.1-5#.exr")
self.assertNativeStr(seq.dirname())
Expand Down

0 comments on commit e987948

Please sign in to comment.