__author__ = 'Robert Meyer'
from collections import Sequence, Mapping, Set
import numpy as np
import pandas as pd
import pypet
import itertools as it
import pypet.pypetconstants as pypetconstants
[docs]def results_equal(a,b):
"""Compares two result instances
Checks full name and all data. Does not consider the comment.
:return: True or False
:raises: ValueError if both inputs are no result instances
"""
if not isinstance(a, pypet.parameter.Result) and not isinstance(b, pypet.parameter.Result):
raise ValueError('Both inputs are not results.')
if not isinstance(a, pypet.parameter.Result) or not isinstance(b, pypet.parameter.Result):
return False
if not a.v_name==b.v_name:
return False
if not a.v_location==b.v_location:
return False
if not a.v_full_name == b.v_full_name:
return False
akeyset = set(a._data.keys())
bkeyset = set(b._data.keys())
if akeyset != bkeyset:
return False
for key, val in a._data.iteritems():
bval = b._data[key]
if not nested_equal(val,bval):
return False
return True
[docs]def parameters_equal(a,b):
"""Compares two parameter instances
Checks full name, data, and ranges. Does not consider the comment.
:return: True or False
:raises: ValueError if both inputs are no parameter instances
"""
if not isinstance(b, pypet.parameter.BaseParameter) and not isinstance(a, pypet.parameter.BaseParameter):
raise ValueError('Both inputs are not parameters')
if not isinstance(b, pypet.parameter.BaseParameter) or not isinstance(a, pypet.parameter.BaseParameter):
return False
if not a.v_name==b.v_name:
return False
if not a.v_location==b.v_location:
return False
if not a.v_full_name == b.v_full_name:
return False
# I allow different comments for now
# if not a.get_comment() == b.get_comment():
# return False
if not a._values_of_same_type(a.f_get(),b.f_get()):
return False
if not a._equal_values(a.f_get(),b.f_get()):
return False
if not len(a) == len(b):
return False
if a.f_has_range():
for myitem, bitem in it.izip(a.f_get_range(),b.f_get_range()):
if not a._values_of_same_type(myitem,bitem):
return False
if not a._equal_values(myitem,bitem):
return False
return True
[docs]def nested_equal(a, b):
"""Compares two objects recursively by their elements, also handling numpy objects.
Assumes hashable items are not mutable in a way that affects equality.
Based on the suggestion from HERE_, thanks again Lauritz V. Thaulow :-)
.. _HERE: http://stackoverflow.com/questions/18376935/best-practice-for-equality-in-python
"""
if id(a) == id(b):
return True
# for types that support __eq__
if hasattr(a,'__eq__'):
try:
custom_eq= a == b
if isinstance(custom_eq,bool):
return custom_eq
except ValueError:
pass
#Check equality according to type type [sic].
if a is None:
return b is None
if isinstance(a, basestring):
return a == b
if isinstance(a, pypetconstants.PARAMETER_SUPPORTED_DATA):
return a==b
if isinstance(a, np.ndarray):
return np.all(a==b)
if isinstance(a, (pd.Panel, pd.Panel4D)):
return nested_equal(a.to_frame(), b.to_frame())
if isinstance(a, pd.DataFrame):
try:
new_frame = a == b
new_frame = new_frame |( pd.isnull(a) & pd.isnull(b))
return np.all(new_frame.as_matrix())
except ValueError:
# The Value Error can happen if the data frame is of dtype=object and contains
# numpy arrays. Numpy array comparisons do not evaluate to a single truth value
for name, cola in a.iteritems():
if not name in b:
return False
colb = b[name]
if not len(cola)==len(colb):
return False
for idx,itema in enumerate(cola):
itemb = colb[idx]
if not nested_equal(itema,itemb):
return False
return True
if isinstance(a, Sequence):
return all(nested_equal(x, y) for x, y in zip(a, b))
if isinstance(a, Mapping):
if set(a.keys()) != set(b.keys()):
return False
return all(nested_equal(a[k], b[k]) for k in a.keys())
if isinstance(a, Set):
return a == b
if hasattr(a,'__dict__'):
if not hasattr(b,'__dict__'):
return False
if set(a.__dict__.keys()) != set(b.__dict__.keys()):
return False
return all(nested_equal(a.__dict__[k], b.__dict__[k]) for k in a.__dict__.keys())
return id(a) == id(b)