From 4ccbcb1e616783a151c99b665f0e4b9c160b40a4 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 15:58:53 -0400 Subject: [PATCH 01/18] Remove blank lines --- jsonmodels/collections.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/jsonmodels/collections.py b/jsonmodels/collections.py index 950af96..5ec61aa 100644 --- a/jsonmodels/collections.py +++ b/jsonmodels/collections.py @@ -1,5 +1,3 @@ - - class ModelCollection(list): """`ModelCollection` is list which validates stored values. From 09714104cd73a04e128c2493bea6f70890c78391 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 16:01:26 -0400 Subject: [PATCH 02/18] Add alias for misspelled structure_name method --- jsonmodels/fields.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index 722c833..9bc84d0 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -137,10 +137,14 @@ def _validate_name(self): if not re.match('^[A-Za-z_](([\w\-]*)?\w+)?$', self.name): raise ValueError('Wrong name', self.name) - def structue_name(self, default): + def structure_name(self, default): return self.name if self.name is not None else default + def structue_name(self, default): + return self.structure_name(default) + + class StringField(BaseField): """String field.""" From a141e24f751175aeb19e3ea03a07563bf70ab7f1 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 16:02:20 -0400 Subject: [PATCH 03/18] Clean up if/elif/else logic in parse_value --- jsonmodels/fields.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index 9bc84d0..1bb62e6 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -132,9 +132,7 @@ def get_default_value(self): return self._default if self.has_default else None def _validate_name(self): - if self.name is None: - return - if not re.match('^[A-Za-z_](([\w\-]*)?\w+)?$', self.name): + if self.name is not None and not re.match('^[A-Za-z_](([\w\-]*)?\w+)?$', self.name): raise ValueError('Wrong name', self.name) def structure_name(self, default): @@ -163,7 +161,8 @@ def parse_value(self, value): parsed = super(IntField, self).parse_value(value) if parsed is None: return parsed - return int(parsed) + else: + return int(parsed) class FloatField(BaseField): @@ -248,15 +247,12 @@ def validate_single_value(self, item): def parse_value(self, values): """Cast value to proper collection.""" - result = self.get_default_value() - if not values: - return result - - if not isinstance(values, list): + return self.get_default_value() + elif not isinstance(values, list): return values - - return [self._cast_value(value) for value in values] + else: + return [self._cast_value(value) for value in values] def _cast_value(self, value): if isinstance(value, self.items_types): @@ -334,9 +330,9 @@ def parse_value(self, value): """Parse value to proper model type.""" if not isinstance(value, dict): return value - - embed_type = self._get_embed_type() - return embed_type(**value) + else: + embed_type = self._get_embed_type() + return embed_type(**value) def _get_embed_type(self): if len(self.types) != 1: @@ -423,9 +419,10 @@ def parse_value(self, value): """Parse string into instance of `time`.""" if value is None: return value - if isinstance(value, datetime.time): + elif isinstance(value, datetime.time): return value - return parse(value).timetz() + else: + return parse(value).timetz() class DateField(StringField): @@ -455,9 +452,10 @@ def parse_value(self, value): """Parse string into instance of `date`.""" if value is None: return value - if isinstance(value, datetime.date): + elif isinstance(value, datetime.date): return value - return parse(value).date() + else: + return parse(value).date() class DateTimeField(StringField): @@ -486,7 +484,7 @@ def parse_value(self, value): """Parse string into instance of `datetime`.""" if isinstance(value, datetime.datetime): return value - if value: + elif value: return parse(value) else: return None From b6a71c8c00bb5b62f2c16fc943d9e6940436ce5f Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 16:02:43 -0400 Subject: [PATCH 04/18] Clean --- jsonmodels/fields.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index 1bb62e6..25a5043 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -212,7 +212,7 @@ def _assign_types(self, items_types): try: self.items_types = tuple(items_types) except TypeError: - self.items_types = items_types, + self.items_types = (items_types, ) else: self.items_types = tuple() @@ -271,11 +271,11 @@ def _finish_initialization(self, owner): super(ListField, self)._finish_initialization(owner) types = [] - for type in self.items_types: - if isinstance(type, _LazyType): - types.append(type.evaluate(owner)) + for type_ in self.items_types: + if isinstance(type_, _LazyType): + types.append(type_.evaluate(owner)) else: - types.append(type) + types.append(type_) self.items_types = tuple(types) def _elem_to_struct(self, value): From e5f6759536529467cfc89c54562f1d2ba0675097 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 16:07:39 -0400 Subject: [PATCH 05/18] Fix lint issues --- jsonmodels/fields.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index 25a5043..57b2e63 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -14,6 +14,9 @@ NotSet = object() +_FIELD_NAME_REGEX = re.compile(r'^[A-Za-z_](([\w\-]*)?\w+)?$') + + class BaseField(object): """Base class for all fields.""" @@ -132,15 +135,14 @@ def get_default_value(self): return self._default if self.has_default else None def _validate_name(self): - if self.name is not None and not re.match('^[A-Za-z_](([\w\-]*)?\w+)?$', self.name): + if self.name is not None \ + and not re.match(_FIELD_NAME_REGEX, self.name): raise ValueError('Wrong name', self.name) def structure_name(self, default): return self.name if self.name is not None else default - - def structue_name(self, default): - return self.structure_name(default) + structue_name = structure_name class StringField(BaseField): From f9106510cbc778c5c2b232152d09ec22d4f0490b Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 16:18:51 -0400 Subject: [PATCH 06/18] Clean --- jsonmodels/models.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/jsonmodels/models.py b/jsonmodels/models.py index da4bbac..41377a2 100644 --- a/jsonmodels/models.py +++ b/jsonmodels/models.py @@ -19,10 +19,10 @@ def validate_fields(attributes): } taken_names = set() for name, field in fields.items(): - structue_name = field.structue_name(name) - if structue_name in taken_names: - raise ValueError('Name taken', structue_name, name) - taken_names.add(structue_name) + structure_name = field.structure_name(name) + if structure_name in taken_names: + raise ValueError('Name taken', structure_name, name) + taken_names.add(structure_name) class Base(six.with_metaclass(JsonmodelMeta, object)): @@ -99,7 +99,7 @@ def to_json_schema(cls): def __repr__(self): attrs = {} - for name, _ in self: + for name, field in self: try: attr = getattr(self, name) if attr is not None: @@ -152,3 +152,4 @@ def __ne__(self, other): class _CacheKey(object): """Object to identify model in memory.""" + pass From 7fed7dca5a67ecba8f5eaeedc67e5b84dd40b634 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 16:24:46 -0400 Subject: [PATCH 07/18] Make get_field a classmethod --- jsonmodels/models.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/jsonmodels/models.py b/jsonmodels/models.py index 41377a2..c798b70 100644 --- a/jsonmodels/models.py +++ b/jsonmodels/models.py @@ -44,13 +44,14 @@ def populate(self, **values): if name in values: field.__set__(self, values.pop(name)) - def get_field(self, field_name): + @classmethod + def get_field(cls, field_name): """Get field associated with given attribute.""" - for attr_name, field in self: - if field_name == attr_name: - return field - - raise errors.FieldNotFound('Field not found', field_name) + field = getattr(cls, field_name, None) + if isinstance(field, BaseField): + return field + else: + raise errors.FieldNotFound('Field not found', field_name) def __iter__(self): """Iterate through fields and values.""" From 7c584c73e17657d981ba74be4d02d28d3c661162 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 16:25:35 -0400 Subject: [PATCH 08/18] Clean --- jsonmodels/models.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/jsonmodels/models.py b/jsonmodels/models.py index c798b70..7119028 100644 --- a/jsonmodels/models.py +++ b/jsonmodels/models.py @@ -55,8 +55,7 @@ def get_field(cls, field_name): def __iter__(self): """Iterate through fields and values.""" - for name, field in self.iterate_over_fields(): - yield name, field + yield from self.iterate_over_fields() def validate(self): """Explicitly validate all the fields.""" @@ -72,21 +71,21 @@ def validate(self): @classmethod def iterate_over_fields(cls): """Iterate through fields as `(attribute_name, field_instance)`.""" - for attr in dir(cls): - clsattr = getattr(cls, attr) + for clsname in dir(cls): + clsattr = getattr(cls, clsname) if isinstance(clsattr, BaseField): - yield attr, clsattr + yield clsname, clsattr @classmethod def iterate_with_name(cls): """Iterate over fields, but also give `structure_name`. - Format is `(attribute_name, structue_name, field_instance)`. + Format is `(attribute_name, structure_name, field_instance)`. Structure name is name under which value is seen in structure and schema (in primitives) and only there. """ for attr_name, field in cls.iterate_over_fields(): - structure_name = field.structue_name(attr_name) + structure_name = field.structure_name(attr_name) yield attr_name, structure_name, field def to_struct(self): From c0922df4d1a282f2da3dfed084a2b4b47209f899 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 21:23:24 -0400 Subject: [PATCH 09/18] Simplify populate implementation --- jsonmodels/models.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/jsonmodels/models.py b/jsonmodels/models.py index 7119028..bbc4322 100644 --- a/jsonmodels/models.py +++ b/jsonmodels/models.py @@ -36,13 +36,12 @@ def __init__(self, **kwargs): def populate(self, **values): """Populate values to fields. Skip non-existing.""" values = values.copy() - fields = list(self.iterate_with_name()) - for _, structure_name, field in fields: + for attr_name, structure_name, field in self.iterate_with_name(): + # set field by structure name if structure_name in values: field.__set__(self, values.pop(structure_name)) - for name, _, field in fields: - if name in values: - field.__set__(self, values.pop(name)) + elif attr_name in values: + field.__set__(self, values.pop(attr_name)) @classmethod def get_field(cls, field_name): From 5f75477e182b4501be54d924c28eabc52029e34a Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 21:40:00 -0400 Subject: [PATCH 10/18] Guard against finish_initialization called multiple times --- jsonmodels/fields.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index 57b2e63..390d9fd 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -42,6 +42,8 @@ def __init__( self.validate(default) self._default = default + self._initialized = False + @property def has_default(self): return self._default is not NotSet @@ -52,20 +54,25 @@ def _assign_validators(self, validators): self.validators = validators or [] def __set__(self, instance, value): - self._finish_initialization(type(instance)) + if not self._initialized: + self._finish_initialization(type(instance)) + self._initialized = True value = self.parse_value(value) self.validate(value) self.memory[instance._cache_key] = value def __get__(self, instance, owner=None): + if not self._initialized: + if instance is None: + self._finish_initialization(owner) + else: + self._finish_initialization(type(instance)) + self._initialized = True if instance is None: - self._finish_initialization(owner) return self - - self._finish_initialization(type(instance)) - - self._check_value(instance) - return self.memory[instance._cache_key] + else: + self._check_value(instance) + return self.memory[instance._cache_key] def _finish_initialization(self, owner): pass From cc31ea4b405095249b5dd15771bd4f8481f03e2b Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 21:40:42 -0400 Subject: [PATCH 11/18] Rename iteration vars --- jsonmodels/models.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/jsonmodels/models.py b/jsonmodels/models.py index bbc4322..12f6a1a 100644 --- a/jsonmodels/models.py +++ b/jsonmodels/models.py @@ -58,22 +58,22 @@ def __iter__(self): def validate(self): """Explicitly validate all the fields.""" - for name, field in self: + for attr_name, field in self: try: field.validate_for_object(self) except ValidationError as error: raise ValidationError( - "Error for field '{name}'.".format(name=name), - error, + 'Error for field {attr_name!r}: {error}' + .format(attr_name=attr_name, error=error) ) @classmethod def iterate_over_fields(cls): """Iterate through fields as `(attribute_name, field_instance)`.""" - for clsname in dir(cls): - clsattr = getattr(cls, clsname) - if isinstance(clsattr, BaseField): - yield clsname, clsattr + for attr_name in dir(cls): + field = getattr(cls, attr_name) + if isinstance(field, BaseField): + yield attr_name, field @classmethod def iterate_with_name(cls): @@ -98,11 +98,11 @@ def to_json_schema(cls): def __repr__(self): attrs = {} - for name, field in self: + for attr_name, field in self: try: - attr = getattr(self, name) + attr = getattr(self, attr_name) if attr is not None: - attrs[name] = repr(attr) + attrs[attr_name] = repr(attr) except ValidationError: pass @@ -129,14 +129,14 @@ def __eq__(self, other): if type(other) is not type(self): return False - for name, _ in self.iterate_over_fields(): + for attr_name, _ in self.iterate_over_fields(): try: - our = getattr(self, name) + our = getattr(self, attr_name) except errors.ValidationError: our = None try: - their = getattr(other, name) + their = getattr(other, attr_name) except errors.ValidationError: their = None From d74dff6cc92f16eac7af88d920b311b4ab59c991 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 22:00:17 -0400 Subject: [PATCH 12/18] Add initialize fields --- jsonmodels/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jsonmodels/models.py b/jsonmodels/models.py index 12f6a1a..7322c87 100644 --- a/jsonmodels/models.py +++ b/jsonmodels/models.py @@ -31,8 +31,13 @@ class Base(six.with_metaclass(JsonmodelMeta, object)): def __init__(self, **kwargs): self._cache_key = _CacheKey() + self.initialize_fields() self.populate(**kwargs) + def initialize_fields(self): + for _, _, _ in self.iterate_with_name(): + pass + def populate(self, **values): """Populate values to fields. Skip non-existing.""" values = values.copy() From 8a00ef313ba54013a5aee6f43a21f3ded673b532 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 22:20:54 -0400 Subject: [PATCH 13/18] Use dateutil.parser.parse --- jsonmodels/fields.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index 390d9fd..8e17a8a 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -3,7 +3,7 @@ from weakref import WeakKeyDictionary import six -from dateutil.parser import parse +import dateutil.parser from .errors import ValidationError from .collections import ModelCollection @@ -431,7 +431,7 @@ def parse_value(self, value): elif isinstance(value, datetime.time): return value else: - return parse(value).timetz() + return dateutil.parser.parse(value).timetz() class DateField(StringField): @@ -464,7 +464,7 @@ def parse_value(self, value): elif isinstance(value, datetime.date): return value else: - return parse(value).date() + return dateutil.parser.parse(value).date() class DateTimeField(StringField): @@ -494,6 +494,6 @@ def parse_value(self, value): if isinstance(value, datetime.datetime): return value elif value: - return parse(value) + return dateutil.parser.parse(value) else: return None From 24459bac2cadf9354a9feb58a5097f448a97a453 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 22:21:18 -0400 Subject: [PATCH 14/18] Rename unclear _check_value --- jsonmodels/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index 8e17a8a..caaf9b5 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -71,13 +71,13 @@ def __get__(self, instance, owner=None): if instance is None: return self else: - self._check_value(instance) + self._maybe_assign_default_value(instance) return self.memory[instance._cache_key] def _finish_initialization(self, owner): pass - def _check_value(self, obj): + def _maybe_assign_default_value(self, obj): if obj._cache_key not in self.memory: self.__set__(obj, self.get_default_value()) From dfb74b2fa1b8b67f5f1d91a98b805562bc218a0d Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Sun, 12 Aug 2018 22:22:53 -0400 Subject: [PATCH 15/18] Clean string --- jsonmodels/fields.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index caaf9b5..adfc14b 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -98,10 +98,8 @@ def _check_against_required(self, value): def _validate_against_types(self, value): if value is not None and not isinstance(value, self.types): raise ValidationError( - 'Value is wrong, expected type "{types}"'.format( - types=', '.join([t.__name__ for t in self.types]) - ), - value, + 'Value {value!r} is wrong, expected type {types!r}' + .format(value=value, types=', '.join(t.__name__ for t in self.types)) ) def _check_types(self): From b9a5e142e19560a00fb16b97003978850a683db1 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Tue, 14 Aug 2018 23:08:50 -0400 Subject: [PATCH 16/18] Fix lint issues --- jsonmodels/fields.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jsonmodels/fields.py b/jsonmodels/fields.py index adfc14b..e733273 100644 --- a/jsonmodels/fields.py +++ b/jsonmodels/fields.py @@ -99,7 +99,8 @@ def _validate_against_types(self, value): if value is not None and not isinstance(value, self.types): raise ValidationError( 'Value {value!r} is wrong, expected type {types!r}' - .format(value=value, types=', '.join(t.__name__ for t in self.types)) + .format(value=value, + types=', '.join(t.__name__ for t in self.types)) ) def _check_types(self): From c5568f4664c29481b0e50ba6b7000e39ca0cba02 Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Mon, 17 Dec 2018 20:45:50 -0500 Subject: [PATCH 17/18] Fix W605 warnings with raw strings See https://lintlyci.github.io/Flake8Rules/rules/W605.html --- tests/test_utilities.py | 100 ++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/tests/test_utilities.py b/tests/test_utilities.py index b82d5c6..f9262b1 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -59,56 +59,56 @@ def test_failed_comparison_of_two_dicts(): def test_is_ecma_regex(): - assert utilities.is_ecma_regex('some regex') is False - assert utilities.is_ecma_regex('^some regex$') is False - assert utilities.is_ecma_regex('/^some regex$/') is True - assert utilities.is_ecma_regex('/^some regex$/gim') is True - assert utilities.is_ecma_regex('/^some regex$/trololo') is True + assert utilities.is_ecma_regex(r'some regex') is False + assert utilities.is_ecma_regex(r'^some regex$') is False + assert utilities.is_ecma_regex(r'/^some regex$/') is True + assert utilities.is_ecma_regex(r'/^some regex$/gim') is True + assert utilities.is_ecma_regex(r'/^some regex$/trololo') is True with pytest.raises(ValueError): - utilities.is_ecma_regex('/wrong regex') + utilities.is_ecma_regex(r'/wrong regex') with pytest.raises(ValueError): - utilities.is_ecma_regex('wrong regex/') + utilities.is_ecma_regex(r'wrong regex/') with pytest.raises(ValueError): - utilities.is_ecma_regex('wrong regex/gim') + utilities.is_ecma_regex(r'wrong regex/gim') with pytest.raises(ValueError): - utilities.is_ecma_regex('wrong regex/asdf') + utilities.is_ecma_regex(r'wrong regex/asdf') - assert utilities.is_ecma_regex('/^some regex\/gim') is True + assert utilities.is_ecma_regex(r'/^some regex\/gim') is True - assert utilities.is_ecma_regex('/^some regex\\\\/trololo') is True - assert utilities.is_ecma_regex('/^some regex\\\\\/gim') is True - assert utilities.is_ecma_regex('/\\\\/') is True + assert utilities.is_ecma_regex(r'/^some regex\\/trololo') is True + assert utilities.is_ecma_regex(r'/^some regex\\\/gim') is True + assert utilities.is_ecma_regex(r'/\\/') is True - assert utilities.is_ecma_regex('some /regex/asdf') is False - assert utilities.is_ecma_regex('^some regex$//') is False + assert utilities.is_ecma_regex(r'some /regex/asdf') is False + assert utilities.is_ecma_regex(r'^some regex$//') is False def test_convert_ecma_regex_to_python(): - assert ('some', []) == utilities.convert_ecma_regex_to_python('/some/') + assert ('some', []) == utilities.convert_ecma_regex_to_python(r'/some/') assert ( ('some/pattern', []) == - utilities.convert_ecma_regex_to_python('/some/pattern/') + utilities.convert_ecma_regex_to_python(r'/some/pattern/') ) assert ( - ('^some \d+ pattern$', []) == - utilities.convert_ecma_regex_to_python('/^some \d+ pattern$/') + (r'^some \d+ pattern$', []) == + utilities.convert_ecma_regex_to_python(r'/^some \d+ pattern$/') ) - regex, flags = utilities.convert_ecma_regex_to_python('/^regex \d/i') - assert '^regex \d' == regex + regex, flags = utilities.convert_ecma_regex_to_python(r'/^regex \d/i') + assert r'^regex \d' == regex assert set([re.I]) == set(flags) - result = utilities.convert_ecma_regex_to_python('/^regex \d/m') - assert '^regex \d' == result.regex + result = utilities.convert_ecma_regex_to_python(r'/^regex \d/m') + assert r'^regex \d' == result.regex assert set([re.M]) == set(result.flags) - result = utilities.convert_ecma_regex_to_python('/^regex \d/mi') - assert '^regex \d' == result.regex + result = utilities.convert_ecma_regex_to_python(r'/^regex \d/mi') + assert r'^regex \d' == result.regex assert set([re.M, re.I]) == set(result.flags) with pytest.raises(ValueError): - utilities.convert_ecma_regex_to_python('/regex/wrong') + utilities.convert_ecma_regex_to_python(r'/regex/wrong') assert ( ('python regex', []) == @@ -116,8 +116,8 @@ def test_convert_ecma_regex_to_python(): ) assert ( - ('^another \d python regex$', []) == - utilities.convert_ecma_regex_to_python('^another \d python regex$') + (r'^another \d python regex$', []) == + utilities.convert_ecma_regex_to_python(r'^another \d python regex$') ) result = utilities.convert_ecma_regex_to_python('python regex') @@ -127,61 +127,61 @@ def test_convert_ecma_regex_to_python(): def test_convert_python_regex_to_ecma(): assert ( - '/^some regex$/' == - utilities.convert_python_regex_to_ecma('^some regex$') + r'/^some regex$/' == + utilities.convert_python_regex_to_ecma(r'^some regex$') ) assert ( - '/^some regex$/' == - utilities.convert_python_regex_to_ecma('^some regex$', []) + r'/^some regex$/' == + utilities.convert_python_regex_to_ecma(r'^some regex$', []) ) assert ( - '/pattern \d+/i' == - utilities.convert_python_regex_to_ecma('pattern \d+', [re.I]) + r'/pattern \d+/i' == + utilities.convert_python_regex_to_ecma(r'pattern \d+', [re.I]) ) assert ( - '/pattern \d+/m' == - utilities.convert_python_regex_to_ecma('pattern \d+', [re.M]) + r'/pattern \d+/m' == + utilities.convert_python_regex_to_ecma(r'pattern \d+', [re.M]) ) assert ( - '/pattern \d+/im' == - utilities.convert_python_regex_to_ecma('pattern \d+', [re.I, re.M]) + r'/pattern \d+/im' == + utilities.convert_python_regex_to_ecma(r'pattern \d+', [re.I, re.M]) ) assert ( - '/ecma pattern$/' == - utilities.convert_python_regex_to_ecma('/ecma pattern$/') + r'/ecma pattern$/' == + utilities.convert_python_regex_to_ecma(r'/ecma pattern$/') ) assert ( - '/ecma pattern$/im' == - utilities.convert_python_regex_to_ecma('/ecma pattern$/im') + r'/ecma pattern$/im' == + utilities.convert_python_regex_to_ecma(r'/ecma pattern$/im') ) assert ( - '/ecma pattern$/wrong' == - utilities.convert_python_regex_to_ecma('/ecma pattern$/wrong') + r'/ecma pattern$/wrong' == + utilities.convert_python_regex_to_ecma(r'/ecma pattern$/wrong') ) assert ( - '/ecma pattern$/m' == - utilities.convert_python_regex_to_ecma('/ecma pattern$/m', [re.M]) + r'/ecma pattern$/m' == + utilities.convert_python_regex_to_ecma(r'/ecma pattern$/m', [re.M]) ) def test_converters(): assert ( - '/^ecma \d regex$/im' == + r'/^ecma \d regex$/im' == utilities.convert_python_regex_to_ecma( - *utilities.convert_ecma_regex_to_python('/^ecma \d regex$/im')) + *utilities.convert_ecma_regex_to_python(r'/^ecma \d regex$/im')) ) result = utilities.convert_ecma_regex_to_python( utilities.convert_python_regex_to_ecma( - '^some \w python regex$', [re.I])) + r'^some \w python regex$', [re.I])) - assert '^some \w python regex$' == result.regex + assert r'^some \w python regex$' == result.regex assert [re.I] == result.flags From 58afd9ba1e4412c5cb7e64d33463bc2d411a478c Mon Sep 17 00:00:00 2001 From: Micah Smith Date: Mon, 17 Dec 2018 21:14:46 -0500 Subject: [PATCH 18/18] Avoid yield from for py2 compatibility :( --- jsonmodels/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jsonmodels/models.py b/jsonmodels/models.py index 7322c87..89674f6 100644 --- a/jsonmodels/models.py +++ b/jsonmodels/models.py @@ -59,7 +59,8 @@ def get_field(cls, field_name): def __iter__(self): """Iterate through fields and values.""" - yield from self.iterate_over_fields() + for item in self.iterate_over_fields(): + yield item def validate(self): """Explicitly validate all the fields."""