From cfc85365915b9aa07b4e5dda0d2626d0e742b5df Mon Sep 17 00:00:00 2001 From: Dan Girellini Date: Sun, 9 Oct 2016 15:14:23 -0700 Subject: [PATCH] Validate namedtuples as tuples namedtuples can't be initialized with a tuple. Detect that datatype and initialize it with *args notation. Resolves #230 --- voluptuous/schema_builder.py | 10 +++++++++- voluptuous/tests/tests.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/voluptuous/schema_builder.py b/voluptuous/schema_builder.py index 053d951..9e4b622 100644 --- a/voluptuous/schema_builder.py +++ b/voluptuous/schema_builder.py @@ -106,6 +106,10 @@ def iteritems(d): REMOVE_EXTRA = 2 # extra keys not in schema will be excluded from output +def _isnamedtuple(obj): + return isinstance(obj, tuple) and hasattr(obj, '_fields') + + class Undefined(object): def __nonzero__(self): return False @@ -557,7 +561,11 @@ def validate_sequence(path, data): errors.append(invalid) if errors: raise er.MultipleInvalid(errors) - return type(data)(out) + + if _isnamedtuple(data): + return type(data)(*out) + else: + return type(data)(out) return validate_sequence diff --git a/voluptuous/tests/tests.py b/voluptuous/tests/tests.py index 8759b13..7ddd092 100644 --- a/voluptuous/tests/tests.py +++ b/voluptuous/tests/tests.py @@ -1,4 +1,5 @@ import copy +import collections from nose.tools import assert_equal, assert_raises, assert_true from voluptuous import ( @@ -699,3 +700,14 @@ def test_number_validation_with_valid_precision_scale_yield_decimal_false(): schema = Schema({"number" : Number(precision=6, scale=2, yield_decimal=False)}) out_ = schema({"number": '1234.00'}) assert_equal(out_.get("number"), '1234.00') + + +def test_named_tuples_validate_as_tuples(): + NT = collections.namedtuple('NT', ['a', 'b']) + nt = NT(1, 2) + t = (1, 2) + + Schema((int, int))(nt) + Schema((int, int))(t) + Schema(NT(int, int))(nt) + Schema(NT(int, int))(t)