Pull in _NodeBase from actorgraph; include short-hash in repr

This commit is contained in:
Karl Kroening 2017-07-04 17:45:07 -06:00
parent dcebe917a7
commit fc946be164
2 changed files with 80 additions and 18 deletions

View File

@ -1,25 +1,72 @@
from __future__ import unicode_literals
from builtins import object
import copy
import hashlib
import json
class Node(object):
"""Node base"""
def __init__(self, parents, name, *args, **kwargs):
def _recursive_repr(item):
"""Hack around python `repr` to deterministically represent dictionaries.
This is able to represent more things than json.dumps, since it does not require things to be JSON serializable
(e.g. datetimes).
"""
if isinstance(item, basestring):
result = str(item)
elif isinstance(item, list):
result = '[{}]'.format(', '.join([_recursive_repr(x) for x in item]))
elif isinstance(item, dict):
kv_pairs = ['{}: {}'.format(_recursive_repr(k), _recursive_repr(item[k])) for k in sorted(item)]
result = '{' + ', '.join(kv_pairs) + '}'
else:
result = repr(item)
return result
def _create_hash(item):
hasher = hashlib.sha224()
repr_ = _recursive_repr(item)
hasher.update(repr_.encode('utf-8'))
return hasher.hexdigest()
class _NodeBase(object):
@property
def hash(self):
if self._hash is None:
self._update_hash()
return self._hash
def __init__(self, parents, name):
parent_hashes = [hash(parent) for parent in parents]
assert len(parent_hashes) == len(set(parent_hashes)), 'Same node cannot be included as parent multiple times'
self._parents = parents
self._hash = None
self._name = name
self._args = args
self._kwargs = kwargs
def _transplant(self, new_parents):
other = copy.copy(self)
other._parents = copy.copy(new_parents)
return other
@property
def _repr_args(self):
raise NotImplementedError()
@property
def _repr_kwargs(self):
raise NotImplementedError()
@property
def _short_hash(self):
return '{:x}'.format(abs(hash(self)))[:12]
def __repr__(self):
formatted_props = ['{}'.format(arg) for arg in self._args]
formatted_props += ['{}={!r}'.format(key, self._kwargs[key]) for key in sorted(self._kwargs)]
return '{}({})'.format(self._name, ','.join(formatted_props))
args = self._repr_args
kwargs = self._repr_kwargs
formatted_props = ['{!r}'.format(arg) for arg in args]
formatted_props += ['{}={!r}'.format(key, kwargs[key]) for key in sorted(kwargs)]
return '{}({}) <{}>'.format(self._name, ', '.join(formatted_props), self._short_hash)
def __hash__(self):
if self._hash is None:
@ -30,9 +77,8 @@ class Node(object):
return hash(self) == hash(other)
def _update_hash(self):
props = {'args': self._args, 'kwargs': self._kwargs}
props_str = json.dumps(props, sort_keys=True).encode('utf-8')
my_hash = hashlib.md5(props_str).hexdigest()
props = {'args': self._repr_args, 'kwargs': self._repr_kwargs}
my_hash = _create_hash(props)
parent_hashes = [str(hash(parent)) for parent in self._parents]
hashes = parent_hashes + [my_hash]
hashes_str = ','.join(hashes).encode('utf-8')
@ -40,6 +86,22 @@ class Node(object):
self._hash = int(hash_str, base=16)
class Node(_NodeBase):
"""Node base"""
def __init__(self, parents, name, *args, **kwargs):
super(Node, self).__init__(parents, name)
self._args = args
self._kwargs = kwargs
@property
def _repr_args(self):
return self._args
@property
def _repr_kwargs(self):
return self._kwargs
class InputNode(Node):
"""InputNode type"""
def __init__(self, name, *args, **kwargs):

View File

@ -73,12 +73,12 @@ def test_repr():
trim3 = ffmpeg.trim(in_file, start_frame=50, end_frame=60)
concatted = ffmpeg.concat(trim1, trim2, trim3)
output = ffmpeg.output(concatted, 'dummy2.mp4')
assert repr(in_file) == "input(filename={!r})".format('dummy.mp4')
assert repr(trim1) == "trim(end_frame=20,start_frame=10)"
assert repr(trim2) == "trim(end_frame=40,start_frame=30)"
assert repr(trim3) == "trim(end_frame=60,start_frame=50)"
assert repr(concatted) == "concat(n=3)"
assert repr(output) == "output(filename={!r})".format('dummy2.mp4')
assert repr(in_file) == "input(filename={!r}) <{}>".format('dummy.mp4', in_file._short_hash)
assert repr(trim1) == "trim(end_frame=20, start_frame=10) <{}>".format(trim1._short_hash)
assert repr(trim2) == "trim(end_frame=40, start_frame=30) <{}>".format(trim2._short_hash)
assert repr(trim3) == "trim(end_frame=60, start_frame=50) <{}>".format(trim3._short_hash)
assert repr(concatted) == "concat(n=3) <{}>".format(concatted._short_hash)
assert repr(output) == "output(filename={!r}) <{}>".format('dummy2.mp4', output._short_hash)
def test_get_args_simple():