diff --git a/CHANGES.rst b/CHANGES.rst index e11f0e8a..05cef5f7 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,4 +1,12 @@ +Release 1.3.7 +========================================= + +* **BUGFIX:** Fixed bug in ``HighchartsMeta.copy()`` (#98). +* **BUGFIX:** Fixed bug in data point serialization to primitive array. + +--------------------- + Release 1.3.6 ========================================= diff --git a/highcharts_core/__version__.py b/highcharts_core/__version__.py index 2686689d..83ad9b45 100644 --- a/highcharts_core/__version__.py +++ b/highcharts_core/__version__.py @@ -1 +1 @@ -__version__ = '1.3.6' \ No newline at end of file +__version__ = '1.3.7' \ No newline at end of file diff --git a/highcharts_core/js_literal_functions.py b/highcharts_core/js_literal_functions.py index 51e647c2..088273ba 100644 --- a/highcharts_core/js_literal_functions.py +++ b/highcharts_core/js_literal_functions.py @@ -25,7 +25,7 @@ def serialize_to_js_literal(item, encoding = 'utf-8') -> Optional[str]: :rtype: :class:`str ` or :obj:`None ` """ if checkers.is_iterable(item, forbid_literals = (str, bytes, dict, UserDict)): - requires_js_objects = all([getattr(x, 'requires_js_object', True) + requires_js_objects = any([getattr(x, 'requires_js_object', True) for x in item]) if requires_js_objects: return [serialize_to_js_literal(x, encoding = encoding) diff --git a/highcharts_core/metaclasses.py b/highcharts_core/metaclasses.py index 46fd54c8..43418704 100644 --- a/highcharts_core/metaclasses.py +++ b/highcharts_core/metaclasses.py @@ -664,8 +664,14 @@ def _copy_dict_key(cls, :returns: The value that should be placed in ``other`` for ``key``. """ + if not isinstance(original, (dict, UserDict)): + return original + original_value = original[key] - other_value = other.get(key, None) + if other is None: + other_value = None + else: + other_value = other.get(key, None) if isinstance(original_value, (dict, UserDict)): new_value = {} diff --git a/tests/options/series/data/test_base.py b/tests/options/series/data/test_base.py index b0e338aa..5ea1755d 100644 --- a/tests/options/series/data/test_base.py +++ b/tests/options/series/data/test_base.py @@ -1,6 +1,7 @@ """Tests for ``highcharts.no_data``.""" import pytest +from typing import List from json.decoder import JSONDecodeError @@ -17,6 +18,17 @@ class NonAbstractDataBase(DataBase): def from_array(cls, value): pass + def _get_props_from_array(self) -> List[str]: + """Returns a list of the property names that can be set using the + :meth:`.from_array() ` + method. + + :rtype: :class:`list ` of :class:`str ` + """ + return ['fromArrayProp1', 'fromArrayProp2'] + + + cls = NonAbstractDataBase @@ -24,6 +36,20 @@ class RequiringJSObject(NonAbstractDataBase): def _to_untrimmed_dict(self): return {'someKey': 123} +class NotRequiringJSObject(NonAbstractDataBase): + def _to_untrimmed_dict(self): + return { + 'fromArrayProp1': 456, + 'fromArrayProp2': 789 + } + + +class RequiringJSObject2(NonAbstractDataBase): + def _to_untrimmed_dict(self): + return {'someKey': 123, + 'fromArrayProp1': 456, + 'fromArrayProp2': 789} + STANDARD_PARAMS = [ ({}, None), @@ -102,8 +128,10 @@ def test_from_js_literal(input_files, filename, as_file, error): @pytest.mark.parametrize('cls, expected', [ (NonAbstractDataBase, False), + (NotRequiringJSObject, False), (RequiringJSObject, True), - + (RequiringJSObject2, True) + ]) def test_requires_js_object(cls, expected): obj = cls() diff --git a/tests/test_metaclasses.py b/tests/test_metaclasses.py index e8198d8c..e264cb54 100644 --- a/tests/test_metaclasses.py +++ b/tests/test_metaclasses.py @@ -232,6 +232,26 @@ def test_trim_iterable(untrimmed, expected_type, expected_length, error): with pytest.raises(error): result = TestClass.trim_iterable(untrimmed) + +@pytest.mark.parametrize('instance, error', [ + (test_class_instance, None), + (test_class_trimmed_instance, None), + (test_class_iterable, None), + (test_class_none_iterable, None), +]) +def test_copy(instance, error): + if not error: + result = instance.copy() + assert result is not None + assert isinstance(result, instance.__class__) is True + result_as_dict = result.to_dict() + instance_as_dict = instance.to_dict() + assert checkers.are_dicts_equivalent(result_as_dict, instance_as_dict) is True + else: + with pytest.raises(error): + result = instance.copy() + + """ @pytest.mark.parametrize('error', [ (None),