diff --git a/flattentool/schema.py b/flattentool/schema.py index 396c1e57..d472f0d6 100644 --- a/flattentool/schema.py +++ b/flattentool/schema.py @@ -372,9 +372,14 @@ def parse_schema_dict( ) ) elif "string" in property_type_set or not property_type_set: - self.flattened[ - parent_path.replace("/0/", "/") + property_name - ] = "string" + if property_schema_dict.get("format") == "date": + self.flattened[ + parent_path.replace("/0/", "/") + property_name + ] = "date" + else: + self.flattened[ + parent_path.replace("/0/", "/") + property_name + ] = "string" yield property_name, title elif "number" in property_type_set: self.flattened[ diff --git a/flattentool/tests/test_input_SpreadsheetInput_unflatten.py b/flattentool/tests/test_input_SpreadsheetInput_unflatten.py index d9e1e1c7..99f637ed 100644 --- a/flattentool/tests/test_input_SpreadsheetInput_unflatten.py +++ b/flattentool/tests/test_input_SpreadsheetInput_unflatten.py @@ -7,6 +7,7 @@ from __future__ import unicode_literals from collections import OrderedDict +import datetime from decimal import Decimal import pytest @@ -48,6 +49,7 @@ def inject_root_id(root_id, d): [{"ROOT_ID": "1", "id": 2, "testA": 3}], [], True, + True, ), ( "Basic with float", @@ -58,6 +60,7 @@ def inject_root_id(root_id, d): [{"ROOT_ID": "1", "id": 2, "testA": 3}], [], True, + True, ), ( "Basic with zero", @@ -65,6 +68,23 @@ def inject_root_id(root_id, d): [{"ROOT_ID": "1", "id": 2, "testA": 0}], [], True, + True, + ), + ( + "Basic with date-time", + [{"ROOT_ID": "1", "id": 2, "testDateTime": datetime.datetime(2020, 1, 1)}], + [{"ROOT_ID": "1", "id": 2, "testDateTime": '2020-01-01T00:00:00+00:00'}], + [], + False, + True, + ), + ( + "Basic with date", + [{"ROOT_ID": "1", "id": 2, "testDate": datetime.datetime(2020, 1, 1)}], + [{"ROOT_ID": "1", "id": 2, "testDate": '2020-01-01'}], + [], + False, + False, ), ( "Nested", @@ -72,6 +92,7 @@ def inject_root_id(root_id, d): [{"ROOT_ID": "1", "id": 2, "testO": {"testB": 3, "testC": 4}}], [], True, + True, ), ( "Unicode", @@ -79,6 +100,7 @@ def inject_root_id(root_id, d): [{"ROOT_ID": UNICODE_TEST_STRING, "testU": UNICODE_TEST_STRING}], [], True, + True, ), ( "Single item array", @@ -86,6 +108,7 @@ def inject_root_id(root_id, d): [{"ROOT_ID": "1", "id": 2, "testL": [{"id": 3, "testB": 4}],}], [], False, + True, ), ( "Single item array without parent ID", @@ -93,6 +116,7 @@ def inject_root_id(root_id, d): [{"ROOT_ID": "1", "testL": [{"id": "2", "testB": "3"}],}], [], False, + True, ), ( "Empty", @@ -110,6 +134,7 @@ def inject_root_id(root_id, d): [], [], False, + True, ), ( "Empty except for root id", @@ -127,6 +152,7 @@ def inject_root_id(root_id, d): [{"ROOT_ID": 1}], [], False, + True, ), # Previously this caused the error: TypeError: unorderable types: str() < int() # Now one of the columns is ignored @@ -142,6 +168,7 @@ def inject_root_id(root_id, d): "Column newtest/0/a has been ignored, because it treats newtest as an array, but another column does not." ], False, + True, ), # Previously this caused the error: TypeError: unorderable types: str() < int() # Now one of the columns is ignored @@ -157,6 +184,7 @@ def inject_root_id(root_id, d): "Column newtest/a has been ignored, because it treats newtest as an object, but another column does not." ], False, + True, ), # Previously this caused the error: 'Cell' object has no attribute 'get' # Now one of the columns is ignored @@ -168,6 +196,7 @@ def inject_root_id(root_id, d): "Column newtest/0/a has been ignored, because it treats newtest as an array, but another column does not." ], False, + True, ), ( "str / object mixing", @@ -177,6 +206,7 @@ def inject_root_id(root_id, d): "Column newtest/a has been ignored, because it treats newtest as an object, but another column does not." ], False, + True, ), ( "array / str mixing", @@ -195,6 +225,7 @@ def inject_root_id(root_id, d): "Column nest/newtest has been ignored, because another column treats it as an array or object" ], False, + True, ), ( "object / str mixing", @@ -204,6 +235,7 @@ def inject_root_id(root_id, d): "Column newtest has been ignored, because another column treats it as an array or object" ], False, + True, ), ( "Mismatch of object/array for field not in schema (multiline)", @@ -216,6 +248,7 @@ def inject_root_id(root_id, d): "Column nest/newtest/0/a has been ignored, because it treats newtest as an array, but another column does not" ], False, + True, ), # Previously this caused the error: TypeError: unorderable types: str() < int() # Now one of the columns is ignored @@ -230,6 +263,7 @@ def inject_root_id(root_id, d): "Column newtest/a has been ignored, because it treats newtest as an object, but another column does not" ], False, + True, ), # Previously this caused the error: 'Cell' object has no attribute 'get' # Now one of the columns is ignored @@ -252,6 +286,7 @@ def inject_root_id(root_id, d): "Column nest/newtest/0/b has been ignored, because it treats newtest as an array, but another column does not", ], False, + True, ), ( "array / str mixing multiline", @@ -265,6 +300,7 @@ def inject_root_id(root_id, d): "Column nest/newtest has been ignored, because another column treats it as an array or object" ], False, + True, ), # WARNING: Conflict when merging field "newtest" for id "2" in sheet custom_main: "3" ( @@ -281,6 +317,7 @@ def inject_root_id(root_id, d): "Column newtest/b has been ignored, because it treats newtest as an object, but another column does not", ], False, + True, ), ( "object / str mixing multiline", @@ -293,6 +330,7 @@ def inject_root_id(root_id, d): "Column newtest has been ignored, because another column treats it as an array or object" ], False, + True, ), # Previously this caused the error: KeyError('ocid',) # Now it works, but probably not as intended @@ -304,6 +342,7 @@ def inject_root_id(root_id, d): [{"id": 2, "testA": 3}], [], False, + True, ), # We should be able to handle numbers as column headings ( @@ -329,6 +368,7 @@ def inject_root_id(root_id, d): 'Column "4" has been ignored because it is a number.', ], False, + True, ), ] @@ -377,6 +417,8 @@ def create_schema(root_id): "properties": { "id": {"title": "Identifier", "type": "integer",}, "testA": {"title": "A title", "type": "integer",}, + "testDateTime": {"title": "A title", "type": "string", "format": "date-time"}, + "testDate": {"title": "A title", "type": "string", "format": "date"}, "testB": { "title": "B title", "type": "object", @@ -685,7 +727,7 @@ def create_schema(root_id): @pytest.mark.parametrize("use_schema", [True, False]) @pytest.mark.parametrize("root_id,root_id_kwargs", ROOT_ID_PARAMS) @pytest.mark.parametrize( - "comment,input_list,expected_output_list,warning_messages,reversible", testdata + "comment,input_list,expected_output_list,warning_messages,reversible,works_without_schema", testdata ) def test_unflatten( convert_titles, @@ -698,7 +740,11 @@ def test_unflatten( comment, warning_messages, reversible, + works_without_schema, ): + if not use_schema and not works_without_schema: + pytest.skip() + # Not sure why, but this seems to be necessary to have warnings picked up # on Python 2.7 and 3.3, but 3.4 and 3.5 are fine without it import warnings @@ -764,6 +810,7 @@ def test_unflatten_pointer( comment=comment, warning_messages=warning_messages, reversible=False, + works_without_schema=True, ) @@ -802,4 +849,5 @@ def test_unflatten_titles( comment=comment, warning_messages=warning_messages, reversible=reversible, + works_without_schema=True, ) diff --git a/flattentool/tests/test_json_input_is_unflatten_reversed.py b/flattentool/tests/test_json_input_is_unflatten_reversed.py index 257881b0..cdd6a9a5 100644 --- a/flattentool/tests/test_json_input_is_unflatten_reversed.py +++ b/flattentool/tests/test_json_input_is_unflatten_reversed.py @@ -32,7 +32,7 @@ @pytest.mark.parametrize("root_id,root_id_kwargs", ROOT_ID_PARAMS) @pytest.mark.parametrize( "comment,expected_output_list,input_list,warning_messages,reversible", - [x for x in testdata if x[4]], + [x[:5] for x in testdata if x[4]], ) def test_flatten( use_titles,