Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: openedx/openedx-events
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: d00b0d5d7bafaf54744dc8d8fe1d6a0efc1434fa
Choose a base ref
..
head repository: openedx/openedx-events
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f28f4a8cd4f780cdbc1a88d708ae4d7537239172
Choose a head ref
Showing with 29 additions and 8 deletions.
  1. +7 −7 openedx_events/event_bus/avro/deserializer.py
  2. +1 −1 openedx_events/event_bus/avro/schema.py
  3. +21 −0 openedx_events/event_bus/avro/tests/test_deserializer.py
14 changes: 7 additions & 7 deletions openedx_events/event_bus/avro/deserializer.py
Original file line number Diff line number Diff line change
@@ -41,26 +41,26 @@ def _deserialized_avro_record_dict_to_object(data: dict, data_type, deserializer
elif data_type in PYTHON_TYPE_TO_AVRO_MAPPING:
return data
elif data_type_origin == list:
# returns types of list contents
# if data_type == List[int], arg_data_type = (int,)
# Returns types of list contents.
# Example: if data_type == List[int], arg_data_type = (int,)
arg_data_type = get_args(data_type)
if not arg_data_type:
raise TypeError(
"List without annotation type is not supported. The argument should be a type, for eg., List[int]"
)
# check whether list items type is in basic types.
# Check whether list items type is in basic types.
if arg_data_type[0] in SIMPLE_PYTHON_TYPE_TO_AVRO_MAPPING:
return data
elif data_type_origin == dict:
# returns types of dict contents
# if data_type == Dict[str, int], arg_data_type = (str, int)
# Returns types of dict contents.
# Example: if data_type == Dict[str, int], arg_data_type = (str, int)
arg_data_type = get_args(data_type)
if not arg_data_type:
raise TypeError(
"Dict without annotation type is not supported. The argument should be a type, for eg., Dict[str, int]"
)
# check whether dict items type is in basic types.
if arg_data_type[1] in SIMPLE_PYTHON_TYPE_TO_AVRO_MAPPING:
# Check whether dict items type is in basic types.
if all(arg in SIMPLE_PYTHON_TYPE_TO_AVRO_MAPPING for arg in arg_data_type):
return data
elif hasattr(data_type, "__attrs_attrs__"):
transformed = {}
2 changes: 1 addition & 1 deletion openedx_events/event_bus/avro/schema.py
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ def _create_avro_field_definition(data_key, data_type, previously_seen_types,
field["type"] = field_type
# Case 2: data_type is a simple type that can be converted directly to an Avro type
elif data_type in PYTHON_TYPE_TO_AVRO_MAPPING:
if PYTHON_TYPE_TO_AVRO_MAPPING[data_type] in ["record", "map", "array"]:
if PYTHON_TYPE_TO_AVRO_MAPPING[data_type] in ["map", "array"]:
# pylint: disable-next=broad-exception-raised
raise Exception("Unable to generate Avro schema for dict or array fields without annotation types.")
avro_type = PYTHON_TYPE_TO_AVRO_MAPPING[data_type]
21 changes: 21 additions & 0 deletions openedx_events/event_bus/avro/tests/test_deserializer.py
Original file line number Diff line number Diff line change
@@ -298,6 +298,27 @@ def test_deserialization_of_dict_without_annotation(self):
with self.assertRaises(TypeError):
deserializer.from_dict(initial_dict)

def test_deserialization_of_dict_with_complex_types_fails(self):
SIGNAL = create_simple_signal({"dict_input": Dict[str, list]})
with self.assertRaises(TypeError):
AvroSignalDeserializer(SIGNAL)
initial_dict = {"dict_input": {"key1": [1, 3], "key2": [4, 5]}}
# create dummy signal to bypass schema check while initializing deserializer
# This allows us to test whether correct exceptions are raised while deserializing data
DUMMY_SIGNAL = create_simple_signal({"dict_input": Dict[str, int]})
deserializer = AvroSignalDeserializer(DUMMY_SIGNAL)
# Update signal with incorrect type info
deserializer.signal = SIGNAL
with self.assertRaises(TypeError):
deserializer.from_dict(initial_dict)

def test_deserialization_of_dicts_with_keys_of_complex_types_fails(self):
SIGNAL = create_simple_signal({"dict_input": Dict[CourseKey, int]})
deserializer = AvroSignalDeserializer(SIGNAL)
initial_dict = {"dict_input": {CourseKey.from_string("course-v1:edX+DemoX.1+2014"): 1}}
with self.assertRaises(TypeError):
deserializer.from_dict(initial_dict)

def test_deserialization_of_nested_list_fails(self):
"""
Check that deserialization raises error when nested list data is passed.