Skip to content

Commit

Permalink
Merge branch 'feature/color_correction_reference' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
shidarin committed Jun 10, 2014
2 parents f844ea9 + 4996253 commit 675b6eb
Show file tree
Hide file tree
Showing 4 changed files with 334 additions and 1 deletion.
183 changes: 183 additions & 0 deletions cdl_convert/cdl_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@
# If id given to ColorCorrection is blank, will set to number of CCs
# When determining if a non-existent directory referenced by MediaRef
# contains an image sequence, will just return False.
# If attempting to retrieve a referenced ColorCorrection whose id doesn't
# exist.
# If attempting to set a ColorCorrectionReference to a ColorCorrection whose
# id doesn't exist. (Other than first creation)
HALT_ON_ERROR = False

# ==============================================================================
Expand All @@ -126,6 +130,7 @@
'AscXMLBase',
'ColorCollection',
'ColorCorrection',
'ColorCorrectionReference',
'ColorDecision',
'ColorNodeBase',
'MediaRef',
Expand Down Expand Up @@ -716,6 +721,183 @@ def reset_members(cls):
# ==============================================================================


class ColorCorrectionReference(AscXMLBase):
"""Reference marker to a full color correction
Description
~~~~~~~~~~~
This is a fairly basic class that simply contains a reference to a full
:class:`ColorCorrection` . The ``ref`` attribute must match the
``id`` attribute in order for this class to function fully.
When writing to a format that allows empty references (like ``cdl``),
the reference can write correctly without breaking. However, if writing to
a format that does not support reference objects at all (like ``ccc``),
attempting to write an empty reference will result in a ``ValueError`` (if
``HALT_ON_ERROR`` is set to ``True``, or simply skip past the reference
entirely.
**Class Attributes:**
members : {str: [:class`ColorCorrectionReference`]}
All instanced :class:`ColorCorrectionReference` are added to this
member dictionary. Multiple :class:`ColorCorrectionReference` can
share the same reference id, therefore for each reference id key,
the members dictionary stores a list of
:class:`ColorCorrectionReference` instances that share that ``ref``
value.
**Attributes:**
cc : (:class:`ColorCorrection`)
If the stored reference resolves to an existing
:class:`ColorCorrection`, this attribute will return that node
using the ``resolve_reference`` method. This attribute is the same
as calling that method.
parent : (:class:`ColorDecision`)
The parent :class:`ColorDecision` that contains this node.
ref : (str)
The :class:`ColorCorrection` id that this reference refers to. If
``HALT_ON_ERROR`` is set to ``True``, will raise a ``ValueError``
if set to a :class:`ColorCorrection` ``id`` value that doesn't
yet exist.
xml : (str)
A nicely formatted XML string representing the node. Inherited from
:class:`AscXMLBase`.
xml_root : (str)
A nicely formatted XML, ready to write to file string representing
the node. Formatted as an XML root, it includes the xml version and
encoding tags on the first line. Inherited from
:class:`AscXMLBase`.
**Public Methods:**
build_element()
Builds an ElementTree XML Element for this node and all nodes it
contains. ``element``, ``xml``, and ``xml_root`` attributes use
this to build the XML. This function is identical to calling the
``element`` attribute. Overrides inherited placeholder method
from :class:`AscXMLBase` .
reset_members()
Resets the class level members list.
resolve_reference()
Attempts to return the :class:`ColorCorrection` that this
reference is supposed to refer to.
If ``HALT_ON_ERROR`` is set to ``True``, resolving a bad reference
will raise a ``ValueError`` exception. If not set, it will simply
return None.
Otherwise (if the ``ref`` attribute matches a known
:class:`ColorCorrection` ``id``, the :class:`ColorCorrection` will
be returned.
"""

members = {}

def __init__(self, ref):
super(ColorCorrectionReference, self).__init__()
self._ref = None
# Bypass cc id existence checks on first set by calling private
# method directly.
self._set_ref(ref)

# While all ColorCorrectionReferences should be under a
# ColorDecision node, we won't strictly enforce that a
# parent must exist.
self.parent = None

# Properties ==============================================================

@property
def cc(self):
"""Returns the referenced ColorCorrection"""
return self.resolve_reference()

@property
def ref(self):
"""Returns the reference id"""
return self._ref

@ref.setter
def ref(self, ref_id):
"""Sets the reference id"""
if ref_id not in ColorCorrection.members and HALT_ON_ERROR:
raise ValueError(
"Reference id '{id}' does not match any existing "
"ColorCorrection id in ColorCorrection.members "
"dictionary.".format(
id=ref_id
)
)

self._set_ref(ref_id)

# Private Methods =========================================================

def _set_ref(self, new_ref):
"""Changes the ref field and updates members dictionary"""
# The only time it won't be in here is if this is the first time
# we set it.
if self.ref in ColorCorrectionReference.members:
ColorCorrectionReference.members[self.ref].remove(self)
# If the remaining list is empty, we'll pop it out
if not ColorCorrectionReference.members[self.ref]:
ColorCorrectionReference.members.pop(self.ref)

# Check if this ref is already registered
if new_ref in ColorCorrectionReference.members:
ColorCorrectionReference.members[new_ref].append(self)
else:
ColorCorrectionReference.members[new_ref] = [self]

self._ref = new_ref

# Public Methods ==========================================================

def build_element(self):
"""Builds an ElementTree XML element representing this reference"""
cc_ref_xml = ElementTree.Element('ColorCorrectionRef')
cc_ref_xml.attrib = {'ref': self.ref}

return cc_ref_xml

# =========================================================================

@classmethod
def reset_members(cls):
"""Resets the member list"""
cls.members = {}

# =========================================================================

def resolve_reference(self):
"""Returns the ColorCorrection this reference points to"""
if self.ref in ColorCorrection.members:
return ColorCorrection.members[self.ref]
else:
if HALT_ON_ERROR:
raise ValueError(
"Cannot resolve ColorCorrectionReference with reference "
"id of '{id}' because no ColorCorrection with that id "
"can be found.".format(
id=self.ref
)
)
else:
return None

# ==============================================================================


class ColorDecision(AscXMLBase): # pylint: disable=R0903
"""Contains a media ref and a ColorCorrection or reference to CC.
Expand Down Expand Up @@ -2717,6 +2899,7 @@ def build_cc(line_id, edl_path, sop_dict, sat_value, title_line):
def reset_all():
"""Resets all class level member lists and dictionaries"""
ColorCorrection.reset_members()
ColorCorrectionReference.reset_members()
ColorCollection.reset_members()
MediaRef.reset_members()

Expand Down
7 changes: 6 additions & 1 deletion docs/cdl_convert.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ AscXMLBase
.. autoclass:: cdl_convert.AscXMLBase

ColorCollection
-------------------
---------------

.. warning::
Functionality described below relating to ``cdl`` type collections
Expand Down Expand Up @@ -106,6 +106,11 @@ function, see :doc:`usage` for a walkthrough.

.. autoclass:: cdl_convert.ColorCorrection

ColorCorrectionReference
------------------------

.. autoclass:: cdl_convert.ColorCorrectionReference

ColorDecision
-------------

Expand Down
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and ``.flex`` files now return a collection.
- Adds ``parse_ccc`` which returns a :class:`ColorCollection` .
- Adds ``write_ccc`` which writes a :class:`ColorCollection` as a ``ccc`` file.
- :class:`ColorCollection` is now a fully functional container class, with many attributes and methods.
- Added :class:`ColorCorrectionReference` , which stores a reference to a :class:`ColorCorrection`
- Added ``parent`` attribute to :class:`ColorCorrection` .
- Calling ``sop_node`` or ``sat_node`` on a :class:`ColorCorrection` before attempting to set a SOP or Sat power now works.
- :class:`ColorCorrection` ``cdl_file`` init argument renamed to ``input_file``, which is now optional and able to be set after init.
Expand Down
144 changes: 144 additions & 0 deletions tests/test_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,150 @@ def testDetermineDest(self):
self.cc.file_out
)

# ColorCorrection =============================================================


class TestColorCorrectionReference(unittest.TestCase):
"""Tests the ColorCorrectionReference class"""

#==========================================================================
# SETUP & TEARDOWN
#==========================================================================

def setUp(self):
# Note that the file doesn't really need to exist for our test purposes
self.cc = cdl_convert.ColorCorrection(
id='uniqueId', input_file='../testcdl.cc'
)

self.ccr = cdl_convert.ColorCorrectionReference(ref='uniqueId')
self.ccr_bad = cdl_convert.ColorCorrectionReference(ref='oldId')

def tearDown(self):
# We need to clear the ColorCorrection member dictionary so we don't
# have to worry about non-unique ids.
cdl_convert.reset_all()
cdl_convert.HALT_ON_ERROR = False

#==========================================================================
# TESTS
#==========================================================================

def testCC(self):
"""Tests that a CC is returned correctly"""
self.assertEqual(
self.cc,
self.ccr.cc
)

self.assertEqual(
None,
self.ccr_bad.cc
)

#==========================================================================

def testCCHalt(self):
"""Tests trying to get a CC reference with Halt set"""
cdl_convert.HALT_ON_ERROR = True

def getCC():
self.ccr_bad.cc

self.assertRaises(
ValueError,
getCC
)

#==========================================================================

def testRef(self):
"""Tests that ref is returned correctly"""
self.assertEqual(
'uniqueId',
self.ccr.ref
)

self.assertEqual(
'oldId',
self.ccr_bad.ref
)

#==========================================================================

def testMembers(self):
"""Tests that the member's dictionary looks like it should"""
self.assertEqual(
{'uniqueId': [self.ccr], 'oldId': [self.ccr_bad]},
cdl_convert.ColorCorrectionReference.members
)

#==========================================================================

def testChangeRef(self):
"""Tests changing a reference id"""
self.ccr.ref = 'blahblahblah'

self.assertEqual(
{'blahblahblah': [self.ccr], 'oldId': [self.ccr_bad]},
cdl_convert.ColorCorrectionReference.members
)

#==========================================================================

def testChangeRefAppend(self):
"""Tests changing a reference id"""
self.ccr.ref = 'oldId'

self.assertEqual(
{'oldId': [self.ccr_bad, self.ccr]},
cdl_convert.ColorCorrectionReference.members
)

#==========================================================================

def testChangeRefHALT(self):
"""Tests changing a reference id if halt on error true"""
def setRef():
self.ccr.ref = 'blahblahblah'

cdl_convert.HALT_ON_ERROR = True

self.assertRaises(
ValueError,
setRef
)

self.assertEqual(
'uniqueId',
self.ccr.ref
)

self.assertEqual(
{'uniqueId': [self.ccr], 'oldId': [self.ccr_bad]},
cdl_convert.ColorCorrectionReference.members
)

#==========================================================================

def testBuildElement(self):
"""Tests that build element works correctly"""
self.assertEqual(
b'<ColorCorrectionRef ref="uniqueId"/>\n',
self.ccr.xml
)

#==========================================================================

def testResetMembers(self):
"""Tests resetting the member dict"""
cdl_convert.ColorCorrectionReference.reset_members()

self.assertEqual(
{},
cdl_convert.ColorCorrectionReference.members
)

# ColorNodeBase ===============================================================


Expand Down

0 comments on commit 675b6eb

Please sign in to comment.