From 09e15d29b432adb22adaff1a461a55e5a8ceef5d Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 12:52:09 -0300 Subject: [PATCH 01/17] Force flattened record according to provided flattened schema --- singer_sdk/helpers/_flattening.py | 11 ++++++--- tests/core/test_flattening.py | 40 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 tests/core/test_flattening.py diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 77e3935b9..968a5f785 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -361,8 +361,8 @@ def _key_func(item: tuple[str, dict]) -> str: def flatten_record( record: dict, - flattened_schema: dict, - max_level: int, + flattened_schema: dict | None = None, + max_level: int | None = None, separator: str = "__", ) -> dict: """Flatten a record up to max_level. @@ -376,6 +376,9 @@ def flatten_record( Returns: A flattened version of the record. """ + assert (flattened_schema is not None) or (max_level is not None), "flattened_schema or max_level must be provided" + max_level = max_level or 0 + return _flatten_record( record_node=record, flattened_schema=flattened_schema, @@ -415,7 +418,9 @@ def _flatten_record( items: list[tuple[str, t.Any]] = [] for k, v in record_node.items(): new_key = flatten_key(k, parent_key, separator) - if isinstance(v, collections.abc.MutableMapping) and level < max_level: + if (isinstance(v, MutableMapping) and + ((flattened_schema and new_key not in flattened_schema.get('properties', {})) or + (not flattened_schema and level < max_level))): items.extend( _flatten_record( v, diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py new file mode 100644 index 000000000..8b5f52de7 --- /dev/null +++ b/tests/core/test_flattening.py @@ -0,0 +1,40 @@ +from singer_sdk._flattening import flatten_record + + +@pytest.mark.parametrize("flattened_schema, max_level, expected, expected_exception", [ + pytest.param({ + 'properties': { + 'key_1': {'type': ['null', 'integer']}, + 'key_2__key_3': {'type': ['null', 'string']}, + 'key_2__key_4': {'type': ['null', 'object']}, + } + }, None, {'key_1': 1, 'key_2__key_3': 'value', 'key_2__key_4': '{"key_5": 1, "key_6": ["a", "b"]}'}, None, + id='flattened schema provided'), + pytest.param(None, 99, + {'key_1': 1, + 'key_2__key_3': 'value', + 'key_2__key_4__key_5': 1, + 'key_2__key_4__key_6': '["a", "b"]'}, None, + id='flattened schema not provided'), + pytest.param(None, None, None, AssertionError, + id='no schema or max level provided'), +]) +def test_flatten_record(flattened_schema, max_level, expected, expected_exception): + """Test flatten_record to obey the max_level and flattened_schema parameters.""" + record = { + 'key_1': 1, + 'key_2': { + 'key_3': 'value', + 'key_4': { + 'key_5': 1, + 'key_6': ['a', 'b'] + } + } + } + if expected_exception: + with pytest.raises(expected_exception): + flatten_record(record, max_level=max_level, flattened_schema=flattened_schema) + else: + result = flatten_record(record, max_level=max_level, flattened_schema=flattened_schema) + print(result) + assert expected == result From 2fe8de32c7b6fad58fc6c36bd145c889f6825b81 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Feb 2024 16:02:34 +0000 Subject: [PATCH 02/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- singer_sdk/helpers/_flattening.py | 12 ++--- tests/core/test_flattening.py | 75 +++++++++++++++++++------------ 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 968a5f785..476d7561d 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -2,7 +2,6 @@ from __future__ import annotations -import collections import itertools import re import typing as t @@ -376,7 +375,9 @@ def flatten_record( Returns: A flattened version of the record. """ - assert (flattened_schema is not None) or (max_level is not None), "flattened_schema or max_level must be provided" + assert (flattened_schema is not None) or ( + max_level is not None + ), "flattened_schema or max_level must be provided" max_level = max_level or 0 return _flatten_record( @@ -418,9 +419,10 @@ def _flatten_record( items: list[tuple[str, t.Any]] = [] for k, v in record_node.items(): new_key = flatten_key(k, parent_key, separator) - if (isinstance(v, MutableMapping) and - ((flattened_schema and new_key not in flattened_schema.get('properties', {})) or - (not flattened_schema and level < max_level))): + if isinstance(v, MutableMapping) and ( + (flattened_schema and new_key not in flattened_schema.get("properties", {})) + or (not flattened_schema and level < max_level) + ): items.extend( _flatten_record( v, diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index 8b5f52de7..4d6219f40 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -1,40 +1,59 @@ +from __future__ import annotations + from singer_sdk._flattening import flatten_record -@pytest.mark.parametrize("flattened_schema, max_level, expected, expected_exception", [ - pytest.param({ - 'properties': { - 'key_1': {'type': ['null', 'integer']}, - 'key_2__key_3': {'type': ['null', 'string']}, - 'key_2__key_4': {'type': ['null', 'object']}, - } - }, None, {'key_1': 1, 'key_2__key_3': 'value', 'key_2__key_4': '{"key_5": 1, "key_6": ["a", "b"]}'}, None, - id='flattened schema provided'), - pytest.param(None, 99, - {'key_1': 1, - 'key_2__key_3': 'value', - 'key_2__key_4__key_5': 1, - 'key_2__key_4__key_6': '["a", "b"]'}, None, - id='flattened schema not provided'), - pytest.param(None, None, None, AssertionError, - id='no schema or max level provided'), -]) +@pytest.mark.parametrize( + "flattened_schema, max_level, expected, expected_exception", + [ + pytest.param( + { + "properties": { + "key_1": {"type": ["null", "integer"]}, + "key_2__key_3": {"type": ["null", "string"]}, + "key_2__key_4": {"type": ["null", "object"]}, + } + }, + None, + { + "key_1": 1, + "key_2__key_3": "value", + "key_2__key_4": '{"key_5": 1, "key_6": ["a", "b"]}', + }, + None, + id="flattened schema provided", + ), + pytest.param( + None, + 99, + { + "key_1": 1, + "key_2__key_3": "value", + "key_2__key_4__key_5": 1, + "key_2__key_4__key_6": '["a", "b"]', + }, + None, + id="flattened schema not provided", + ), + pytest.param( + None, None, None, AssertionError, id="no schema or max level provided" + ), + ], +) def test_flatten_record(flattened_schema, max_level, expected, expected_exception): """Test flatten_record to obey the max_level and flattened_schema parameters.""" record = { - 'key_1': 1, - 'key_2': { - 'key_3': 'value', - 'key_4': { - 'key_5': 1, - 'key_6': ['a', 'b'] - } - } + "key_1": 1, + "key_2": {"key_3": "value", "key_4": {"key_5": 1, "key_6": ["a", "b"]}}, } if expected_exception: with pytest.raises(expected_exception): - flatten_record(record, max_level=max_level, flattened_schema=flattened_schema) + flatten_record( + record, max_level=max_level, flattened_schema=flattened_schema + ) else: - result = flatten_record(record, max_level=max_level, flattened_schema=flattened_schema) + result = flatten_record( + record, max_level=max_level, flattened_schema=flattened_schema + ) print(result) assert expected == result From 0d945650896ca6bfc367d8d9030b5a3f35a98d06 Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:32:43 -0300 Subject: [PATCH 03/17] fix import --- tests/core/test_flattening.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index 4d6219f40..3cb87c6ad 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -1,6 +1,8 @@ from __future__ import annotations -from singer_sdk._flattening import flatten_record +import pytest + +from singer_sdk.helpers._flattening import flatten_record @pytest.mark.parametrize( From 3a3532af534d6feb2fe5460b5e0b41bee7bc699b Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:34:00 -0300 Subject: [PATCH 04/17] fix --- singer_sdk/helpers/_flattening.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 476d7561d..475233387 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -419,7 +419,7 @@ def _flatten_record( items: list[tuple[str, t.Any]] = [] for k, v in record_node.items(): new_key = flatten_key(k, parent_key, separator) - if isinstance(v, MutableMapping) and ( + if isinstance(v, t.MutableMapping) and ( (flattened_schema and new_key not in flattened_schema.get("properties", {})) or (not flattened_schema and level < max_level) ): From dbdd0115fdef1cb58f8fb8a980a48c22b3865530 Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:37:06 -0300 Subject: [PATCH 05/17] revert collections change --- singer_sdk/helpers/_flattening.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 475233387..18de38b68 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -2,6 +2,7 @@ from __future__ import annotations +import collections import itertools import re import typing as t @@ -419,7 +420,7 @@ def _flatten_record( items: list[tuple[str, t.Any]] = [] for k, v in record_node.items(): new_key = flatten_key(k, parent_key, separator) - if isinstance(v, t.MutableMapping) and ( + if isinstance(v, collections.abc.MutableMapping) and ( (flattened_schema and new_key not in flattened_schema.get("properties", {})) or (not flattened_schema and level < max_level) ): From 2d39177ddabd4ee7aef5fc877214d94ac524b6b2 Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:52:27 -0300 Subject: [PATCH 06/17] ruff linter fixes --- singer_sdk/exceptions.py | 4 ++++ singer_sdk/helpers/_flattening.py | 7 ++++--- tests/core/test_flattening.py | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/singer_sdk/exceptions.py b/singer_sdk/exceptions.py index 03b06a7c0..4befe36ee 100644 --- a/singer_sdk/exceptions.py +++ b/singer_sdk/exceptions.py @@ -157,3 +157,7 @@ def __init__(self, error_message: str, record: dict) -> None: super().__init__(f"Record Message Validation Error: {error_message}") self.error_message = error_message self.record = record + + +class InvalidFlatteningRecordsParameter(Exception): + """Raised when the flattening_records parameter is invalid.""" diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 18de38b68..58ed68ab3 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -11,6 +11,8 @@ import inflection import simplejson as json +from exceptions import InvalidFlatteningRecordsParameter + DEFAULT_FLATTENING_SEPARATOR = "__" @@ -376,9 +378,8 @@ def flatten_record( Returns: A flattened version of the record. """ - assert (flattened_schema is not None) or ( - max_level is not None - ), "flattened_schema or max_level must be provided" + if (flattened_schema is not None) or (max_level is not None): + raise InvalidFlatteningRecordsParameter("flattened_schema or max_level must be provided") max_level = max_level or 0 return _flatten_record( diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index 3cb87c6ad..f62afd02d 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -2,6 +2,7 @@ import pytest +from exceptions import InvalidFlatteningRecordsParameter from singer_sdk.helpers._flattening import flatten_record @@ -38,7 +39,7 @@ id="flattened schema not provided", ), pytest.param( - None, None, None, AssertionError, id="no schema or max level provided" + None, None, None, InvalidFlatteningRecordsParameter, id="no schema or max level provided" ), ], ) @@ -57,5 +58,4 @@ def test_flatten_record(flattened_schema, max_level, expected, expected_exceptio result = flatten_record( record, max_level=max_level, flattened_schema=flattened_schema ) - print(result) assert expected == result From f51aae8b01a61c6bf31fe2156db498521958c64c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Feb 2024 16:54:35 +0000 Subject: [PATCH 07/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- singer_sdk/helpers/_flattening.py | 4 +++- tests/core/test_flattening.py | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 58ed68ab3..e188e59e1 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -379,7 +379,9 @@ def flatten_record( A flattened version of the record. """ if (flattened_schema is not None) or (max_level is not None): - raise InvalidFlatteningRecordsParameter("flattened_schema or max_level must be provided") + raise InvalidFlatteningRecordsParameter( + "flattened_schema or max_level must be provided" + ) max_level = max_level or 0 return _flatten_record( diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index f62afd02d..37e63ff6b 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -39,7 +39,11 @@ id="flattened schema not provided", ), pytest.param( - None, None, None, InvalidFlatteningRecordsParameter, id="no schema or max level provided" + None, + None, + None, + InvalidFlatteningRecordsParameter, + id="no schema or max level provided", ), ], ) From 77620d37931ab8aa8b869bf3e9e558a07b4dee4d Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:56:31 -0300 Subject: [PATCH 08/17] ruff linter fixes --- singer_sdk/helpers/_flattening.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 58ed68ab3..7ddeb4bcb 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -379,7 +379,8 @@ def flatten_record( A flattened version of the record. """ if (flattened_schema is not None) or (max_level is not None): - raise InvalidFlatteningRecordsParameter("flattened_schema or max_level must be provided") + msg = "flattened_schema or max_level must be provided" + raise InvalidFlatteningRecordsParameter(msg) max_level = max_level or 0 return _flatten_record( From 947b7a5f7dfff3952642578f657b3b6c55dd6560 Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:07:28 -0300 Subject: [PATCH 09/17] fix --- singer_sdk/helpers/_flattening.py | 2 +- tests/core/test_flattening.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 7ddeb4bcb..34f2e4cc5 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -11,7 +11,7 @@ import inflection import simplejson as json -from exceptions import InvalidFlatteningRecordsParameter +from singer_sdk.exceptions import InvalidFlatteningRecordsParameter DEFAULT_FLATTENING_SEPARATOR = "__" diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index 37e63ff6b..60d60ea55 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -2,7 +2,7 @@ import pytest -from exceptions import InvalidFlatteningRecordsParameter +from singer_sdk.exceptions import InvalidFlatteningRecordsParameter from singer_sdk.helpers._flattening import flatten_record From f31b49986393d23d53a1a42425a0a2de231aeaa1 Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:09:23 -0300 Subject: [PATCH 10/17] fix --- singer_sdk/helpers/_flattening.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 34f2e4cc5..bb8a21fd1 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -378,7 +378,7 @@ def flatten_record( Returns: A flattened version of the record. """ - if (flattened_schema is not None) or (max_level is not None): + if flattened_schema is None and max_level is None: msg = "flattened_schema or max_level must be provided" raise InvalidFlatteningRecordsParameter(msg) max_level = max_level or 0 From 2eb84ca0053d78aea90c225d90acf96241501437 Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:18:46 -0300 Subject: [PATCH 11/17] add test --- tests/core/test_flattening.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index 60d60ea55..6d0af0820 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -38,6 +38,16 @@ None, id="flattened schema not provided", ), + pytest.param( + None, + 1, + { + 'key_1': 1, + 'key_2__key_3': 'value', + 'key_2__key_4': '{"key_5": 1, "key_6": ["a", "b"]}' + }, + None, + id='limited by max_level 2'), pytest.param( None, None, From 2173ca17e0f5b43f4b827ec8567667e8f81127c5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:19:31 +0000 Subject: [PATCH 12/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/core/test_flattening.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index 6d0af0820..51a027ed6 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -42,12 +42,13 @@ None, 1, { - 'key_1': 1, - 'key_2__key_3': 'value', - 'key_2__key_4': '{"key_5": 1, "key_6": ["a", "b"]}' + "key_1": 1, + "key_2__key_3": "value", + "key_2__key_4": '{"key_5": 1, "key_6": ["a", "b"]}', }, None, - id='limited by max_level 2'), + id="limited by max_level 2", + ), pytest.param( None, None, From 454758c9c9246dc3e7025920634fbd02e4a11c16 Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:21:03 -0300 Subject: [PATCH 13/17] removing None option for flatten schema and max level --- singer_sdk/exceptions.py | 4 -- singer_sdk/helpers/_flattening.py | 17 +++------ tests/core/test_flattening.py | 62 +++++++++++++++---------------- 3 files changed, 35 insertions(+), 48 deletions(-) diff --git a/singer_sdk/exceptions.py b/singer_sdk/exceptions.py index 4befe36ee..03b06a7c0 100644 --- a/singer_sdk/exceptions.py +++ b/singer_sdk/exceptions.py @@ -157,7 +157,3 @@ def __init__(self, error_message: str, record: dict) -> None: super().__init__(f"Record Message Validation Error: {error_message}") self.error_message = error_message self.record = record - - -class InvalidFlatteningRecordsParameter(Exception): - """Raised when the flattening_records parameter is invalid.""" diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index bb8a21fd1..1ce64969b 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -11,8 +11,6 @@ import inflection import simplejson as json -from singer_sdk.exceptions import InvalidFlatteningRecordsParameter - DEFAULT_FLATTENING_SEPARATOR = "__" @@ -363,8 +361,8 @@ def _key_func(item: tuple[str, dict]) -> str: def flatten_record( record: dict, - flattened_schema: dict | None = None, - max_level: int | None = None, + flattened_schema: dict, + max_level: int, separator: str = "__", ) -> dict: """Flatten a record up to max_level. @@ -378,11 +376,6 @@ def flatten_record( Returns: A flattened version of the record. """ - if flattened_schema is None and max_level is None: - msg = "flattened_schema or max_level must be provided" - raise InvalidFlatteningRecordsParameter(msg) - max_level = max_level or 0 - return _flatten_record( record_node=record, flattened_schema=flattened_schema, @@ -394,7 +387,7 @@ def flatten_record( def _flatten_record( record_node: t.MutableMapping[t.Any, t.Any], *, - flattened_schema: dict | None = None, + flattened_schema: dict, parent_key: list[str] | None = None, separator: str = "__", level: int = 0, @@ -423,8 +416,8 @@ def _flatten_record( for k, v in record_node.items(): new_key = flatten_key(k, parent_key, separator) if isinstance(v, collections.abc.MutableMapping) and ( - (flattened_schema and new_key not in flattened_schema.get("properties", {})) - or (not flattened_schema and level < max_level) + (new_key not in flattened_schema.get("properties", {})) + and (level < max_level) ): items.extend( _flatten_record( diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index 6d0af0820..8e19a4d3e 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -2,12 +2,11 @@ import pytest -from singer_sdk.exceptions import InvalidFlatteningRecordsParameter from singer_sdk.helpers._flattening import flatten_record @pytest.mark.parametrize( - "flattened_schema, max_level, expected, expected_exception", + "flattened_schema, max_level, expected", [ pytest.param( { @@ -17,17 +16,23 @@ "key_2__key_4": {"type": ["null", "object"]}, } }, - None, + 99, { "key_1": 1, "key_2__key_3": "value", "key_2__key_4": '{"key_5": 1, "key_6": ["a", "b"]}', }, - None, - id="flattened schema provided", + id="flattened schema limiting the max level", ), pytest.param( - None, + { + "properties": { + "key_1": {"type": ["null", "integer"]}, + "key_2__key_3": {"type": ["null", "string"]}, + "key_2__key_4__key_5": {"type": ["null", "integer"]}, + "key_2__key_4__key_6": {"type": ["null", "array"]}, + } + }, 99, { "key_1": 1, @@ -35,41 +40,34 @@ "key_2__key_4__key_5": 1, "key_2__key_4__key_6": '["a", "b"]', }, - None, - id="flattened schema not provided", + id="flattened schema not limiting the max level", ), pytest.param( - None, + { + "properties": { + "key_1": {"type": ["null", "integer"]}, + "key_2__key_3": {"type": ["null", "string"]}, + "key_2__key_4__key_5": {"type": ["null", "integer"]}, + "key_2__key_4__key_6": {"type": ["null", "array"]}, + } + }, 1, { - 'key_1': 1, - 'key_2__key_3': 'value', - 'key_2__key_4': '{"key_5": 1, "key_6": ["a", "b"]}' + "key_1": 1, + "key_2__key_3": "value", + "key_2__key_4": '{"key_5": 1, "key_6": ["a", "b"]}', }, - None, - id='limited by max_level 2'), - pytest.param( - None, - None, - None, - InvalidFlatteningRecordsParameter, - id="no schema or max level provided", - ), + id="max level limiting flattened schema") ], ) -def test_flatten_record(flattened_schema, max_level, expected, expected_exception): +def test_flatten_record(flattened_schema, max_level, expected): """Test flatten_record to obey the max_level and flattened_schema parameters.""" record = { "key_1": 1, "key_2": {"key_3": "value", "key_4": {"key_5": 1, "key_6": ["a", "b"]}}, } - if expected_exception: - with pytest.raises(expected_exception): - flatten_record( - record, max_level=max_level, flattened_schema=flattened_schema - ) - else: - result = flatten_record( - record, max_level=max_level, flattened_schema=flattened_schema - ) - assert expected == result + + result = flatten_record( + record, max_level=max_level, flattened_schema=flattened_schema + ) + assert expected == result From f6988977c8d059fc38cda3bd14fab6c637e7ceff Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:22:51 +0000 Subject: [PATCH 14/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/core/test_flattening.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/core/test_flattening.py b/tests/core/test_flattening.py index 8e19a4d3e..73169eab3 100644 --- a/tests/core/test_flattening.py +++ b/tests/core/test_flattening.py @@ -57,7 +57,8 @@ "key_2__key_3": "value", "key_2__key_4": '{"key_5": 1, "key_6": ["a", "b"]}', }, - id="max level limiting flattened schema") + id="max level limiting flattened schema", + ), ], ) def test_flatten_record(flattened_schema, max_level, expected): From 35e191be8e72f2b7f3ada6332e29e48fa5dcd5ea Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:23:22 -0300 Subject: [PATCH 15/17] revert typing --- singer_sdk/helpers/_flattening.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 1ce64969b..580a31b16 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -387,7 +387,7 @@ def flatten_record( def _flatten_record( record_node: t.MutableMapping[t.Any, t.Any], *, - flattened_schema: dict, + flattened_schema: dict | None = None, parent_key: list[str] | None = None, separator: str = "__", level: int = 0, From 73b881b08ee5e3bf354b823b9d5a8f44a6ddd65b Mon Sep 17 00:00:00 2001 From: Joao Amaral <7281460+joaopamaral@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:28:40 -0300 Subject: [PATCH 16/17] fix check --- singer_sdk/helpers/_flattening.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 580a31b16..d5bc4afff 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -416,7 +416,7 @@ def _flatten_record( for k, v in record_node.items(): new_key = flatten_key(k, parent_key, separator) if isinstance(v, collections.abc.MutableMapping) and ( - (new_key not in flattened_schema.get("properties", {})) + (flattened_schema and new_key not in flattened_schema.get("properties", {})) and (level < max_level) ): items.extend( From 938d15e69196ea8af3b7105bce66772fb2eeafc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Thu, 15 Feb 2024 16:24:02 -0600 Subject: [PATCH 17/17] Add a short comment --- singer_sdk/helpers/_flattening.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index d5bc4afff..2a3e194d0 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -415,8 +415,12 @@ def _flatten_record( items: list[tuple[str, t.Any]] = [] for k, v in record_node.items(): new_key = flatten_key(k, parent_key, separator) - if isinstance(v, collections.abc.MutableMapping) and ( - (flattened_schema and new_key not in flattened_schema.get("properties", {})) + # If the value is a dictionary, and the key is not in the schema, and the + # level is less than the max level, then we should continue to flatten. + if ( + isinstance(v, collections.abc.MutableMapping) + and flattened_schema + and new_key not in flattened_schema.get("properties", {}) and (level < max_level) ): items.extend(