Skip to content

Commit

Permalink
make Schema.__eq__ deterministic (#316)
Browse files Browse the repository at this point in the history
* add test for schema equality and fix Schema.__eq__ to deal with dicts properly (fixes #315)

* add negative equality tests, implement Schema.__ne__ method to support != operator

This fills in missing test coverage to ensure the __eq__ method does not
return True in some potentially unexpected cases (these tests would fail
before be867c5).

Previously only the __eq__ method was implemented, which could lead to
surprising behavior e.g.:

    Schema('foo') == Schema('foo')  # True
    Schema('foo') != Schema('foo')  # True

This adds the __ne__ method so that these operators are complementary as
one might expect.
  • Loading branch information
dtao authored and tusharmakkar08 committed Dec 7, 2017
1 parent 9204e83 commit d82601e
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 5 deletions.
10 changes: 6 additions & 4 deletions voluptuous/schema_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,12 @@ def value_to_schema_type(value):
return cls(value_to_schema_type(data), **kwargs)

def __eq__(self, other):
if str(other) == str(self.schema):
# Because repr is combination mixture of object and schema
return True
return False
if not isinstance(other, Schema):
return False
return other.schema == self.schema

def __ne__(self, other):
return not (self == other)

def __str__(self):
return str(self.schema)
Expand Down
65 changes: 64 additions & 1 deletion voluptuous/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
import sys

from nose.tools import assert_equal, assert_raises, assert_true
from nose.tools import assert_equal, assert_false, assert_raises, assert_true

from voluptuous import (
Schema, Required, Exclusive, Optional, Extra, Invalid, In, Remove, Literal,
Expand Down Expand Up @@ -410,6 +410,69 @@ def test_subschema_extension():
assert_equal(extended.schema, {'a': {'b': str, 'c': float, 'e': int}, 'd': str})


def test_equality():
assert_equal(Schema('foo'), Schema('foo'))

assert_equal(Schema(['foo', 'bar', 'baz']),
Schema(['foo', 'bar', 'baz']))

# Ensure two Schemas w/ two equivalent dicts initialized in a different
# order are considered equal.
dict_a = {}
dict_a['foo'] = 1
dict_a['bar'] = 2
dict_a['baz'] = 3

dict_b = {}
dict_b['baz'] = 3
dict_b['bar'] = 2
dict_b['foo'] = 1

assert_equal(Schema(dict_a), Schema(dict_b))


def test_equality_negative():
"""Verify that Schema objects are not equal to string representations"""
assert_false(Schema('foo') == 'foo')

assert_false(Schema(['foo', 'bar']) == "['foo', 'bar']")
assert_false(Schema(['foo', 'bar']) == Schema("['foo', 'bar']"))

assert_false(Schema({'foo': 1, 'bar': 2}) == "{'foo': 1, 'bar': 2}")
assert_false(Schema({'foo': 1, 'bar': 2}) == Schema("{'foo': 1, 'bar': 2}"))


def test_inequality():
assert_true(Schema('foo') != 'foo')

assert_true(Schema(['foo', 'bar']) != "['foo', 'bar']")
assert_true(Schema(['foo', 'bar']) != Schema("['foo', 'bar']"))

assert_true(Schema({'foo': 1, 'bar': 2}) != "{'foo': 1, 'bar': 2}")
assert_true(Schema({'foo': 1, 'bar': 2}) != Schema("{'foo': 1, 'bar': 2}"))


def test_inequality_negative():
assert_false(Schema('foo') != Schema('foo'))

assert_false(Schema(['foo', 'bar', 'baz']) !=
Schema(['foo', 'bar', 'baz']))

# Ensure two Schemas w/ two equivalent dicts initialized in a different
# order are considered equal.
dict_a = {}
dict_a['foo'] = 1
dict_a['bar'] = 2
dict_a['baz'] = 3

dict_b = {}
dict_b['baz'] = 3
dict_b['bar'] = 2
dict_b['foo'] = 1

assert_false(Schema(dict_a) != Schema(dict_b))


def test_repr():
"""Verify that __repr__ returns valid Python expressions"""
match = Match('a pattern', msg='message')
Expand Down

0 comments on commit d82601e

Please sign in to comment.