From 3baeb1793f8d1c98747d9f11a3fcf7aeeb081117 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 11:35:21 +0900 Subject: [PATCH 01/19] Extract shared base class --- dataproperty/_data_property.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index 1314a6f..5229d41 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -34,7 +34,24 @@ def default_datetime_converter(value): return value -class DataProperty(DataPeropertyInterface): +class DataPeropertyBase(DataPeropertyInterface): + __slots__ = () + + @property + def format_str(self): + if self.typecode == Typecode.INT: + return "d" + + if self.typecode == Typecode.FLOAT: + if is_nan(self.decimal_places): + return "f" + + return ".%df" % (self.decimal_places) + + return "s" + + +class DataProperty(DataPeropertyBase): __slots__ = ( "__data", "__typecode", @@ -83,19 +100,6 @@ def typecode(self): return self.__typecode - @property - def format_str(self): - if self.typecode == Typecode.INT: - return "d" - - if self.typecode == Typecode.FLOAT: - if is_nan(self.decimal_places): - return "f" - - return ".%df" % (self.decimal_places) - - return "s" - @property def data(self): """ @@ -241,7 +245,7 @@ def __replace_tabs(self, replace_tabs_with_spaces, tab_length): pass -class ColumnDataProperty(DataPeropertyInterface): +class ColumnDataProperty(DataPeropertyBase): __slots__ = ( "__typecode_bitmap", "__str_len", From e2b691810f9d9a33f054bf245f1429d6999338a6 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 11:36:16 +0900 Subject: [PATCH 02/19] Delete property from the interface class --- dataproperty/_interface.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dataproperty/_interface.py b/dataproperty/_interface.py index dc68a7b..dfbec08 100644 --- a/dataproperty/_interface.py +++ b/dataproperty/_interface.py @@ -28,16 +28,3 @@ def decimal_places(self): # pragma: no cover @abc.abstractproperty def typecode(self): # pragma: no cover pass - - @property - def format_str(self): - if self.typecode == Typecode.INT: - return "d" - - if self.typecode == Typecode.FLOAT: - if is_nan(self.decimal_places): - return "f" - - return ".%df" % (self.decimal_places) - - return "s" From aa730ed1ba0f054bd61ae388a320b408b1148cd9 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 12:39:03 +0900 Subject: [PATCH 03/19] Modification to return format string of format method of string class --- dataproperty/_data_property.py | 4 +++- test/test_property_extractor.py | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index 5229d41..d19e30b 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -41,8 +41,10 @@ class DataPeropertyBase(DataPeropertyInterface): def format_str(self): if self.typecode == Typecode.INT: return "d" + elif self.typecode == Typecode.BOOL: + return "" - if self.typecode == Typecode.FLOAT: + if self.typecode in (Typecode.FLOAT, Typecode.INFINITY, Typecode.NAN): if is_nan(self.decimal_places): return "f" diff --git a/test/test_property_extractor.py b/test/test_property_extractor.py index bde7a0a..7ee0193 100644 --- a/test/test_property_extractor.py +++ b/test/test_property_extractor.py @@ -107,7 +107,7 @@ def test_normal( assert prop.align.align_string == Align.LEFT.align_string assert prop.str_len == 3 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "f" prop = prop_matrix[2][1] assert prop.data == "Infinity" @@ -116,7 +116,7 @@ def test_normal( assert prop.align.align_string == Align.LEFT.align_string assert prop.str_len == 8 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "f" prop = prop_matrix[3][0] assert prop.data == "false" @@ -125,7 +125,7 @@ def test_normal( assert prop.align.align_string == Align.LEFT.align_string assert prop.str_len == 5 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "" prop = prop_matrix[3][1] assert prop.data == "20170101 000000" @@ -227,7 +227,7 @@ def test_normal(self, prop_extractor, header_list, value): assert prop.align.align_string == Align.LEFT.align_string assert prop.padding_len == 5 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "" prop = col_prop_list[6] assert prop.typecode == Typecode.INFINITY @@ -235,7 +235,7 @@ def test_normal(self, prop_extractor, header_list, value): assert prop.align.align_string == Align.LEFT.align_string assert prop.padding_len == 3 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "f" prop = col_prop_list[7] assert prop.typecode == Typecode.NAN @@ -243,7 +243,7 @@ def test_normal(self, prop_extractor, header_list, value): assert prop.align.align_string == Align.LEFT.align_string assert prop.padding_len == 3 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "f" prop = col_prop_list[8] assert prop.typecode == Typecode.DATETIME From 8de55a296593a843909c96bd83c6a18566312048 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 12:45:42 +0900 Subject: [PATCH 04/19] Change string formatter to format method --- dataproperty/_data_property.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index d19e30b..3b11fe7 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -160,8 +160,16 @@ def __init__( self.__str_len = self.__get_str_len() def __repr__(self): - return ", ".join([ - ("data=%" + self.format_str) % (self.data), + element_list = [] + + if self.typecode == Typecode.DATETIME: + element_list.append( + "data={:s}".format(str(self.data))) + else: + element_list.append( + ("data={:" + self.format_str + "}").format(self.data)) + + element_list.extend([ "typename=" + Typecode.get_typename(self.typecode), "align=" + str(self.align), "str_len=" + str(self.str_len), @@ -170,6 +178,8 @@ def __repr__(self): "additional_format_len=" + str(self.additional_format_len), ]) + return ", ".join(element_list) + def __get_additional_format_len(self): if not FloatTypeChecker(self.data).is_type(): return 0 From ebc8bce73fd784f721355a2f0b166d4579329db7 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 13:32:25 +0900 Subject: [PATCH 05/19] Add StringConverter class --- dataproperty/converter/_core.py | 6 ++++++ test/test_converter.py | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/dataproperty/converter/_core.py b/dataproperty/converter/_core.py index f6f5dc1..b62a33b 100644 --- a/dataproperty/converter/_core.py +++ b/dataproperty/converter/_core.py @@ -37,6 +37,12 @@ def convert(self): return self._value +class StringConverter(ValueConverter): + + def convert(self): + return str(self._value) + + class IntegerConverter(ValueConverter): def convert(self): diff --git a/test/test_converter.py b/test/test_converter.py index 4452081..5c93e9e 100644 --- a/test/test_converter.py +++ b/test/test_converter.py @@ -31,6 +31,21 @@ def test_normal(self, value, expected): assert dpcc.NopConverter(value).convert() == expected +class Test_StringConverter_convert: + + @pytest.mark.parametrize(["value", "expected"], [ + [None, "None"], + [six.MAXSIZE, str(six.MAXSIZE)], + [-six.MAXSIZE, str(-six.MAXSIZE)], + [inf, "inf"], + [nan, "nan"], + [True, "True"], + [datetime.datetime(2017, 1, 2, 3, 4, 5), "2017-01-02 03:04:05"], + ]) + def test_normal(self, value, expected): + assert dpcc.StringConverter(value).convert() == expected + + class Test_IntegerConverter_convert: @pytest.mark.parametrize(["value", "expected"], [ From fb09d58b5c883cce8f8b552c1833e30e3b5b138e Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 13:36:09 +0900 Subject: [PATCH 06/19] Add StringConverterCreator class --- dataproperty/converter/__init__.py | 1 + dataproperty/converter/_creator.py | 7 +++++++ test/test_converter_creator.py | 1 + 3 files changed, 9 insertions(+) diff --git a/dataproperty/converter/__init__.py b/dataproperty/converter/__init__.py index 11a9c71..69561e0 100644 --- a/dataproperty/converter/__init__.py +++ b/dataproperty/converter/__init__.py @@ -7,6 +7,7 @@ from __future__ import absolute_import from ._creator import NopConverterCreator +from ._creator import StringConverterCreator from ._creator import IntegerConverterCreator from ._creator import FloatConverterCreator from ._creator import BoolConverterCreator diff --git a/dataproperty/converter/_creator.py b/dataproperty/converter/_creator.py index 2287b15..a5feae0 100644 --- a/dataproperty/converter/_creator.py +++ b/dataproperty/converter/_creator.py @@ -10,6 +10,7 @@ import six from ._core import NopConverter +from ._core import StringConverter from ._core import IntegerConverter from ._core import FloatConverter from ._core import BoolConverter @@ -30,6 +31,12 @@ def create(self, value): return NopConverter(value) +class StringConverterCreator(ValueConverterCreatorInterface): + + def create(self, value): + return StringConverter(value) + + class IntegerConverterCreator(ValueConverterCreatorInterface): def create(self, value): diff --git a/test/test_converter_creator.py b/test/test_converter_creator.py index f34fbfd..b503142 100644 --- a/test/test_converter_creator.py +++ b/test/test_converter_creator.py @@ -16,6 +16,7 @@ class Test_ConverterCreator(object): @pytest.mark.parametrize(["value", "expected"], [ [dpc.NopConverterCreator, dpcc.NopConverter], + [dpc.StringConverterCreator, dpcc.StringConverter], [dpc.IntegerConverterCreator, dpcc.IntegerConverter], [dpc.FloatConverterCreator, dpcc.FloatConverter], [dpc.BoolConverterCreator, dpcc.BoolConverter], From cbf434600ff487bfddbee1425bf49fc3d4ebed1f Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 13:46:17 +0900 Subject: [PATCH 07/19] Add StringTypeChecker class --- dataproperty/_type_checker.py | 18 ++++++++++++++++++ test/test_type_checker.py | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/dataproperty/_type_checker.py b/dataproperty/_type_checker.py index 2f4da9a..5eae3a4 100644 --- a/dataproperty/_type_checker.py +++ b/dataproperty/_type_checker.py @@ -11,6 +11,7 @@ import six from .converter import NopConverterCreator +from .converter import StringConverterCreator from .converter import IntegerConverterCreator from .converter import FloatConverterCreator from .converter import BoolConverterCreator @@ -95,6 +96,23 @@ def _is_valid_after_convert(self): return self._value is None +class StringTypeChecker(TypeChecker): + + @property + def typecode(self): + return Typecode.STRING + + @property + def _converter_creator(self): + return StringConverterCreator() + + def _is_instance(self): + return isinstance(self._value, six.string_types) + + def _is_valid_after_convert(self): + return isinstance(self._converted_value, six.string_types) + + class IntegerTypeChecker(TypeChecker): @property diff --git a/test/test_type_checker.py b/test/test_type_checker.py index e8e4e06..cb00eec 100644 --- a/test/test_type_checker.py +++ b/test/test_type_checker.py @@ -39,6 +39,28 @@ def test_normal_true(self, value, is_convert, expected): assert type_checker.typecode == Typecode.NONE +class Test_StringTypeChecker: + + @pytest.mark.parametrize(["value", "is_convert", "expected"], [ + [None, True, True], + [None, False, False], + [six.MAXSIZE, True, True], + [six.MAXSIZE, False, False], + [inf, True, True], + [inf, False, False], + ] + list( + itertools.product( + ["None"], + [True, False], + [True] + )) + ) + def test_normal_true(self, value, is_convert, expected): + type_checker = tc.StringTypeChecker(value, is_convert) + assert type_checker.is_type() == expected + assert type_checker.typecode == Typecode.STRING + + class Test_IntegerTypeChecker: @pytest.mark.parametrize(["value", "is_convert"], [ From 3349dd846094f843afc2897a34d557d3305128db Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 13:46:43 +0900 Subject: [PATCH 08/19] Add StringTypeCheckerCreator class --- dataproperty/_type_checker_creator.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dataproperty/_type_checker_creator.py b/dataproperty/_type_checker_creator.py index 77923df..5e50f16 100644 --- a/dataproperty/_type_checker_creator.py +++ b/dataproperty/_type_checker_creator.py @@ -10,6 +10,7 @@ import six from ._type_checker import NoneTypeChecker +from ._type_checker import StringTypeChecker from ._type_checker import IntegerTypeChecker from ._type_checker import FloatTypeChecker from ._type_checker import BoolTypeChecker @@ -32,6 +33,12 @@ def create(self, value, is_convert): return NoneTypeChecker(value, is_convert) +class StringTypeCheckerCreator(TypeCheckerCreatorInterface): + + def create(self, value, is_convert): + return StringTypeChecker(value, is_convert) + + class IntegerTypeCheckerCreator(TypeCheckerCreatorInterface): def create(self, value, is_convert): From 0f5defb5872f8f3d954d6df49f3ad4a73d7909d1 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 13:59:14 +0900 Subject: [PATCH 09/19] Add StringTypeFactory class --- dataproperty/_factory.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dataproperty/_factory.py b/dataproperty/_factory.py index 2b9fa65..66169be 100644 --- a/dataproperty/_factory.py +++ b/dataproperty/_factory.py @@ -10,11 +10,13 @@ import six from .converter import NopConverterCreator +from .converter import StringConverterCreator from .converter import IntegerConverterCreator from .converter import FloatConverterCreator from .converter import BoolConverterCreator from .converter import DateTimeConverterCreator from ._type_checker_creator import NoneTypeCheckerCreator +from ._type_checker_creator import StringTypeCheckerCreator from ._type_checker_creator import IntegerTypeCheckerCreator from ._type_checker_creator import FloatTypeCheckerCreator from ._type_checker_creator import BoolTypeCheckerCreator @@ -49,6 +51,17 @@ def value_converter_factory(self): return NopConverterCreator() +class StringTypeFactory(TypeConverterFactoryInterface): + + @property + def type_checker_factory(self): + return StringTypeCheckerCreator() + + @property + def value_converter_factory(self): + return StringConverterCreator() + + class IntegerTypeFactory(TypeConverterFactoryInterface): @property From 7d6fd6ff7ebfcdfd430b5fb6c2fd8bbad92717d8 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 14:24:18 +0900 Subject: [PATCH 10/19] Add error message --- dataproperty/converter/_core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dataproperty/converter/_core.py b/dataproperty/converter/_core.py index b62a33b..b2aecd1 100644 --- a/dataproperty/converter/_core.py +++ b/dataproperty/converter/_core.py @@ -49,7 +49,7 @@ def convert(self): try: return int(self._value) except (TypeError, ValueError, OverflowError): - raise TypeConversionError + raise TypeConversionError("failed to convert: " + str(self._value)) class FloatConverter(ValueConverter): @@ -63,7 +63,7 @@ def convert(self): try: return decimal.Decimal(self._value) except (TypeError, ValueError, decimal.InvalidOperation): - raise TypeConversionError + raise TypeConversionError("failed to convert: " + str(self._value)) class BoolConverter(ValueConverter): @@ -74,7 +74,7 @@ def convert(self): try: return strict_strtobool(self._value) except ValueError: - raise TypeConversionError + raise TypeConversionError("failed to convert: " + str(self._value)) class DateTimeConverter(ValueConverter): From ed9744e8be2d381a043e7746230d0f74918a43fa Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 15:47:32 +0900 Subject: [PATCH 11/19] Modify to use StringTypeFactory class --- dataproperty/_data_property.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index 3b11fe7..5a243f6 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -18,6 +18,7 @@ from ._function import get_text_len from ._factory import NoneTypeFactory +from ._factory import StringTypeFactory from ._factory import IntegerTypeFactory from ._factory import FloatTypeFactory from ._factory import BoolTypeFactory @@ -72,6 +73,7 @@ class DataProperty(DataPeropertyBase): FloatTypeFactory(), BoolTypeFactory(), DateTimeTypeFactory(), + StringTypeFactory(), ] @property @@ -238,8 +240,8 @@ def __set_data( return - self.__typecode = Typecode.STRING - self.__data = str(data) + raise TypeConversionError( + "failed to convert: " + Typecode.get_typename(self.__typecode)) def __convert_data(self, bool_converter, datetime_converter): if self.typecode == Typecode.BOOL: From fc77a821b39f4767e85c06e5fbcb816c66bea7e5 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 15:50:50 +0900 Subject: [PATCH 12/19] Modify to use StringTypeFactory class --- dataproperty/_data_property.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index 5a243f6..06c7902 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -9,6 +9,7 @@ from ._align_getter import align_getter from ._container import MinMaxContainer +from ._error import TypeConversionError from ._interface import DataPeropertyInterface from ._typecode import Typecode from ._type_checker import FloatTypeChecker From b6941764bf4cf9037aa6070ff13b21ce689eebbc Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 15:53:30 +0900 Subject: [PATCH 13/19] Add type_factory property --- dataproperty/_data_property.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index 06c7902..a7e76ab 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -270,6 +270,17 @@ class ColumnDataProperty(DataPeropertyBase): "__data_prop_list", ) + __FACTORY_TABLE = { + Typecode.NONE: NoneTypeFactory(), + Typecode.STRING: StringTypeFactory(), + Typecode.INT: IntegerTypeFactory(), + Typecode.INFINITY: InfinityTypeFactory(), + Typecode.NAN: NanTypeFactory(), + Typecode.FLOAT: FloatTypeFactory(), + Typecode.BOOL: BoolTypeFactory(), + Typecode.DATETIME: DateTimeTypeFactory(), + } + @property def align(self): return align_getter.get_align_from_typecode(self.typecode) @@ -323,6 +334,10 @@ def minmax_decimal_places(self): def minmax_additional_format_len(self): return self.__minmax_additional_format_len + @property + def type_factory(self): + return self.__FACTORY_TABLE.get(self.typecode) + def __init__(self, min_padding_len=0): self.__typecode_bitmap = Typecode.NONE self.__str_len = min_padding_len From 6f30c3146fd401bf1621f2ace61834875d95b892 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 16:06:37 +0900 Subject: [PATCH 14/19] Add support for datetime format string --- dataproperty/_data_property.py | 27 ++++++++++++++++++++------- test/test_property_extractor.py | 4 ++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index a7e76ab..2519027 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -37,14 +37,18 @@ def default_datetime_converter(value): class DataPeropertyBase(DataPeropertyInterface): - __slots__ = () + __slots__ = ("__datetime_format_str") @property def format_str(self): - if self.typecode == Typecode.INT: - return "d" - elif self.typecode == Typecode.BOOL: - return "" + format_str = { + Typecode.INT: "d", + Typecode.BOOL: "", + Typecode.DATETIME: self.__datetime_format_str, + }.get(self.typecode) + + if format_str is not None: + return format_str if self.typecode in (Typecode.FLOAT, Typecode.INFINITY, Typecode.NAN): if is_nan(self.decimal_places): @@ -54,6 +58,9 @@ def format_str(self): return "s" + def __init__(self, datetime_format_str): + self.__datetime_format_str = datetime_format_str + class DataProperty(DataPeropertyBase): __slots__ = ( @@ -143,9 +150,10 @@ def __init__( none_value=None, inf_value=float("inf"), nan_value=float("nan"), bool_converter=default_bool_converter, datetime_converter=default_datetime_converter, + datetime_format_str="%Y-%m-%dT%H:%M:%S%z", is_convert=True, replace_tabs_with_spaces=True, tab_length=2): - super(DataProperty, self).__init__() + super(DataProperty, self).__init__(datetime_format_str) self.__set_data(data, none_value, inf_value, nan_value, is_convert) self.__convert_data(bool_converter, datetime_converter) @@ -338,7 +346,12 @@ def minmax_additional_format_len(self): def type_factory(self): return self.__FACTORY_TABLE.get(self.typecode) - def __init__(self, min_padding_len=0): + def __init__( + self, + min_padding_len=0, + datetime_format_str="%Y-%m-%dT%H:%M:%S%z"): + super(ColumnDataProperty, self).__init__(datetime_format_str) + self.__typecode_bitmap = Typecode.NONE self.__str_len = min_padding_len self.__minmax_integer_digits = MinMaxContainer() diff --git a/test/test_property_extractor.py b/test/test_property_extractor.py index 7ee0193..bd1ee69 100644 --- a/test/test_property_extractor.py +++ b/test/test_property_extractor.py @@ -134,7 +134,7 @@ def test_normal( assert prop.align.align_string == Align.LEFT.align_string assert prop.str_len == 15 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "%Y-%m-%dT%H:%M:%S%z" @pytest.mark.parametrize(["value", "expected"], [ [None, TypeError], @@ -251,7 +251,7 @@ def test_normal(self, prop_extractor, header_list, value): assert prop.align.align_string == Align.LEFT.align_string assert prop.padding_len == 25 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "%Y-%m-%dT%H:%M:%S%z" @pytest.mark.parametrize(["header_list", "value", "expected"], [ [ From 93a4f92b232692a674dba6d7c0c53262f932c2ec Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 18:55:14 +0900 Subject: [PATCH 15/19] Fix str_len of datetime type --- dataproperty/_data_property.py | 5 ++++ dataproperty/_property_extractor.py | 5 +++- test/test_property.py | 38 +++++++++++++++++++++++------ test/test_property_extractor.py | 5 ++-- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index 2519027..da43fed 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -221,6 +221,11 @@ def __get_str_len(self): if self.typecode == Typecode.FLOAT: return self.__get_base_float_len() + self.additional_format_len + if self.typecode == Typecode.DATETIME: + full_format_str = "{:" + self.format_str + "}" + print full_format_str, self.data, type(self.data) + return len(full_format_str.format(self.data)) + return get_text_len(self.data) def __set_data( diff --git a/dataproperty/_property_extractor.py b/dataproperty/_property_extractor.py index 7a104d3..c2ee141 100644 --- a/dataproperty/_property_extractor.py +++ b/dataproperty/_property_extractor.py @@ -24,6 +24,7 @@ def __init__(self): self.nan_value = float("nan") self.bool_converter = default_bool_converter self.datetime_converter = default_datetime_converter + self.datetime_format_str = "%Y-%m-%dT%H:%M:%S%z" self.is_convert = True def extract_data_property_matrix(self): @@ -39,7 +40,8 @@ def extract_column_property_list(self): for col_idx, col_prop_list in enumerate(zip(*data_prop_matrix)): column_prop = ColumnDataProperty( - min_padding_len=self.min_padding_len) + min_padding_len=self.min_padding_len, + datetime_format_str=self.datetime_format_str) if is_not_empty_list_or_tuple(header_prop_list): header_prop = header_prop_list[col_idx] @@ -64,6 +66,7 @@ def __extract_data_property_list(self, data_list): nan_value=self.nan_value, bool_converter=self.bool_converter, datetime_converter=self.datetime_converter, + datetime_format_str=self.datetime_format_str, is_convert=self.is_convert) for data in data_list ] diff --git a/test/test_property.py b/test/test_property.py index 292c83c..c2b17fa 100644 --- a/test/test_property.py +++ b/test/test_property.py @@ -109,14 +109,18 @@ def bool_converter_test(value): return "false value" -def datetime_converter_test_0(value): +def datetime_converter_tostr_0(value): return value.strftime("%Y-%m-%d %H:%M:%S%z") -def datetime_converter_test_1(value): +def datetime_converter_tostr_1(value): return value.strftime("%Y/%m/%d %H:%M:%S") +def datetime_converter_test_raw(value): + return value + + class Test_DataPeroperty_set_data: @pytest.mark.parametrize( @@ -177,27 +181,40 @@ def test_special_bool( assert dp.data == expected @pytest.mark.parametrize( - ["value", "datetime_converter", "is_convert", "expected"], + [ + "value", "datetime_converter", "datetime_format_str", + "is_convert", "expected", + ], [ [ - DATATIME_DATA, datetime_converter_test_0, + DATATIME_DATA, datetime_converter_tostr_0, + "s", True, "2017-01-02 03:04:05", ], [ - "2017-01-01 00:00:00", datetime_converter_test_1, + "2017-01-01 00:00:00", datetime_converter_tostr_1, + "s", True, "2017/01/01 00:00:00", ], [ - "2017-01-01", datetime_converter_test_0, - False, "2017-01-01", + "2017-01-01 00:00:00", datetime_converter_test_raw, + "%Y-%m-%dT%H:%M:%S", + True, datetime.datetime(2017, 1, 1, 0, 0, 0), + ], + [ + "2017-01-01 00:00:00", datetime_converter_test_raw, + "s", + False, "2017-01-01 00:00:00", ], ] ) def test_special_datetime( - self, value, datetime_converter, is_convert, expected): + self, value, datetime_converter, datetime_format_str, + is_convert, expected): dp = DataProperty( value, datetime_converter=datetime_converter, + datetime_format_str=datetime_format_str, is_convert=is_convert) assert dp.data == expected @@ -402,6 +419,11 @@ class Test_DataPeroperty_repr: "data=2017-01-02 03:04:05, typename=DATETIME, align=left, str_len=19, " "integer_digits=nan, decimal_places=nan, additional_format_len=0", ], + [ + "2017-01-02 03:04:05+0900", + "data=2017-01-02 03:04:05+09:00, typename=DATETIME, align=left, str_len=24, " + "integer_digits=nan, decimal_places=nan, additional_format_len=0", + ], [ inf, "data=inf, typename=INFINITY, align=left, str_len=3, " diff --git a/test/test_property_extractor.py b/test/test_property_extractor.py index bd1ee69..9c3833b 100644 --- a/test/test_property_extractor.py +++ b/test/test_property_extractor.py @@ -60,6 +60,7 @@ def test_normal( prop_extractor.nan_value = nan_value prop_extractor.bool_converter = bool_converter_test prop_extractor.datetime_converter = datetime_converter + prop_extractor.datetime_format_str = "s" prop_matrix = prop_extractor.extract_data_property_matrix() assert len(prop_matrix) == 4 @@ -134,7 +135,7 @@ def test_normal( assert prop.align.align_string == Align.LEFT.align_string assert prop.str_len == 15 assert is_nan(prop.decimal_places) - assert prop.format_str == "%Y-%m-%dT%H:%M:%S%z" + assert prop.format_str == "s" @pytest.mark.parametrize(["value", "expected"], [ [None, TypeError], @@ -249,7 +250,7 @@ def test_normal(self, prop_extractor, header_list, value): assert prop.typecode == Typecode.DATETIME assert prop.align.align_code == Align.LEFT.align_code assert prop.align.align_string == Align.LEFT.align_string - assert prop.padding_len == 25 + assert prop.padding_len == 24 assert is_nan(prop.decimal_places) assert prop.format_str == "%Y-%m-%dT%H:%M:%S%z" From 2286ace96dfbc9200e00e85edfeab8a4a6f8f6e3 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 19:07:51 +0900 Subject: [PATCH 16/19] Delete unnecessary line --- dataproperty/_data_property.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index da43fed..3299116 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -223,7 +223,6 @@ def __get_str_len(self): if self.typecode == Typecode.DATETIME: full_format_str = "{:" + self.format_str + "}" - print full_format_str, self.data, type(self.data) return len(full_format_str.format(self.data)) return get_text_len(self.data) From f110214374e2b096bbf2e76e5d6c313534ca8f72 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 19:14:43 +0900 Subject: [PATCH 17/19] Fix for format string of NONE type --- dataproperty/_data_property.py | 1 + test/test_property_extractor.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dataproperty/_data_property.py b/dataproperty/_data_property.py index 3299116..90e92b5 100644 --- a/dataproperty/_data_property.py +++ b/dataproperty/_data_property.py @@ -42,6 +42,7 @@ class DataPeropertyBase(DataPeropertyInterface): @property def format_str(self): format_str = { + Typecode.NONE: "", Typecode.INT: "d", Typecode.BOOL: "", Typecode.DATETIME: self.__datetime_format_str, diff --git a/test/test_property_extractor.py b/test/test_property_extractor.py index 9c3833b..4b5a485 100644 --- a/test/test_property_extractor.py +++ b/test/test_property_extractor.py @@ -72,7 +72,7 @@ def test_normal( assert prop.align.align_string == Align.LEFT.align_string assert prop.str_len == 4 assert is_nan(prop.decimal_places) - assert prop.format_str == "s" + assert prop.format_str == "" prop = prop_matrix[0][1] assert prop.data == 1 From 0f30ffdda44d98a0461b2c53dd2650d0bf58d5f1 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 20:35:35 +0900 Subject: [PATCH 18/19] Bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c3d7375..bb2fb24 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ setuptools.setup( name=project_name, - version="0.6.0", + version="0.7.0", url="https://github.com/thombashi/" + project_name, bugtrack_url="https://github.com/thombashi/%s/issues" % (project_name), From 2ad1887287b8254bc28705a802b948ba99da00a4 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Hombashi Date: Sat, 9 Jul 2016 20:50:18 +0900 Subject: [PATCH 19/19] Drop support for Python 2.6 --- .travis.yml | 2 -- setup.py | 1 - tox.ini | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 99b9f5e..985ce24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: python matrix: include: - - python: 2.6 - env: TOXENV=python2.6 - python: 2.7 env: TOXENV=python2.7 - python: 3.3 diff --git a/setup.py b/setup.py index bb2fb24..73ae84e 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,6 @@ "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", diff --git a/tox.ini b/tox.ini index e05f6e6..1f7e009 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = python{2.6,2.7,3.3,3.4,3.5} +envlist = python{2.7,3.3,3.4,3.5} [testenv] deps =