diff --git a/highcharts_core/js_literal_functions.py b/highcharts_core/js_literal_functions.py index 914fba01..51e647c2 100644 --- a/highcharts_core/js_literal_functions.py +++ b/highcharts_core/js_literal_functions.py @@ -25,7 +25,14 @@ 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)): - return [serialize_to_js_literal(x, encoding = encoding) for x in item] + requires_js_objects = all([getattr(x, 'requires_js_object', True) + for x in item]) + if requires_js_objects: + return [serialize_to_js_literal(x, encoding = encoding) + for x in item] + else: + return [serialize_to_js_literal(x.to_array(), encoding = encoding) + for x in item] elif hasattr(item, 'to_js_literal'): return item.to_js_literal(encoding = encoding) elif isinstance(item, constants.EnforcedNullType) or item == 'null': diff --git a/highcharts_core/options/series/data/arcdiagram.py b/highcharts_core/options/series/data/arcdiagram.py index 3a889e9a..064902d3 100644 --- a/highcharts_core/options/series/data/arcdiagram.py +++ b/highcharts_core/options/series/data/arcdiagram.py @@ -1,10 +1,10 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal from collections import UserDict from validator_collection import validators, checkers -from highcharts_core import utility_functions, constants +from highcharts_core import utility_functions, constants, errors from highcharts_core.options.series.data.base import DataBase from highcharts_core.utility_classes.gradients import Gradient from highcharts_core.utility_classes.patterns import Pattern @@ -126,6 +126,17 @@ def from_array(cls, value): return collection + 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 ['from_', + 'to', + 'weight'] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the diff --git a/highcharts_core/options/series/data/bar.py b/highcharts_core/options/series/data/bar.py index 7d6b8840..8c5b7bb3 100644 --- a/highcharts_core/options/series/data/bar.py +++ b/highcharts_core/options/series/data/bar.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal import datetime @@ -376,6 +376,63 @@ def from_array(cls, value): return collection + 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 ['x', 'value', 'direction', 'y', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.x is None and self.name is not None: + x = self.name + elif self.x is not None: + x = self.x + else: + x = constants.EnforcedNull + + if self.y is not None: + y = self.y + else: + y = constants.EnforcedNull + + if self.value is not None: + value = self.value + else: + value = constants.EnforcedNull + + if self.direction is not None: + direction = self.direction + else: + direction = constants.EnforcedNull + + if self.y is None: + return [x, value, direction] + + return [x, value, direction, y] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the diff --git a/highcharts_core/options/series/data/base.py b/highcharts_core/options/series/data/base.py index 5e8af127..6fd178f2 100644 --- a/highcharts_core/options/series/data/base.py +++ b/highcharts_core/options/series/data/base.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal from validator_collection import validators, checkers @@ -304,6 +304,38 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict: return untrimmed + 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 [] + + @property + def requires_js_object(self) -> bool: + """Indicates whether or not the data point *must* be serialized to a JS literal + object or whether it can be serialized to a primitive array. + + :returns: ``True`` if the data point *must* be serialized to a JS literal object. + ``False`` if it can be serialized to an array. + :rtype: :class:`bool ` + """ + from_array_props = [utility_functions.to_camelCase(x) + for x in self._get_props_from_array()] + + as_dict = self.to_dict() + trimmed_dict = self.trim_dict(as_dict) + for prop in from_array_props: + if prop in trimmed_dict: + del trimmed_dict[prop] + + if trimmed_dict: + return True + + return False + @classmethod def from_array(cls, value): """Creates a collection of data point instances, parsing the contents of ``value`` @@ -416,3 +448,27 @@ def from_array(cls, value): collection.append(as_obj) return collection + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + return [getattr(self, x, constants.EnforcedNull) + for x in self._get_props_from_array()] diff --git a/highcharts_core/options/series/data/boxplot.py b/highcharts_core/options/series/data/boxplot.py index 22fbe413..55bf1591 100644 --- a/highcharts_core/options/series/data/boxplot.py +++ b/highcharts_core/options/series/data/boxplot.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal from validator_collection import validators, checkers @@ -290,6 +290,73 @@ def from_array(cls, value): return collection + 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 ['x', 'low', 'q1', 'median', 'q3', 'high', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.x is not None: + x = self.x + elif self.name is not None: + x = self.name + else: + x = constants.EnforcedNull + + if self.low is not None: + low = self.low + else: + low = constants.EnforcedNull + + if self.q1 is not None: + q1 = self.q1 + else: + q1 = constants.EnforcedNull + + if self.median is not None: + median = self.median + else: + median = constants.EnforcedNull + + if self.q3 is not None: + q3 = self.q3 + else: + q3 = constants.EnforcedNull + + if self.high is not None: + high = self.high + else: + high = constants.EnforcedNull + + if self.x is None and self.name is None: + return [low, q1, median, q3, high] + + return [x, low, q1, median, q3, high] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the diff --git a/highcharts_core/options/series/data/bullet.py b/highcharts_core/options/series/data/bullet.py index badc7fc3..01981a1a 100644 --- a/highcharts_core/options/series/data/bullet.py +++ b/highcharts_core/options/series/data/bullet.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal from validator_collection import validators, checkers @@ -99,6 +99,58 @@ def from_array(cls, value): return collection + 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 ['x', 'y', 'target', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.x is not None: + x = self.x + elif self.name is not None: + x = self.name + else: + x = constants.EnforcedNull + + if self.y is not None: + y = self.y + else: + y = constants.EnforcedNull + + if self.target is not None: + target = self.target + else: + target = constants.EnforcedNull + + if self.x is None and self.name is None: + return [y, target] + + return [x, y, target] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the diff --git a/highcharts_core/options/series/data/cartesian.py b/highcharts_core/options/series/data/cartesian.py index 74f30e15..b5b2c666 100644 --- a/highcharts_core/options/series/data/cartesian.py +++ b/highcharts_core/options/series/data/cartesian.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal import datetime @@ -189,6 +189,53 @@ def from_array(cls, value): return collection + 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 ['x', 'y', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.y is not None: + y = self.y + else: + y = constants.EnforcedNull + + if self.x is None and self.name is None: + x = self.x + elif self.name is None: + x = self.x + else: + x = self.name + + if self.x is None and self.name is None: + return [y] + + return [x, y] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the @@ -332,6 +379,57 @@ def from_array(cls, value): return collection + 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 ['x', 'y', 'z', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.y is not None: + y = self.y + else: + y = constants.EnforcedNull + if self.z is not None: + z = self.z + else: + z = constants.EnforcedNull + + if self.x is None and self.name is not None: + x = self.name + elif self.name is None and self.x is not None: + x = self.x + else: + x = constants.EnforcedNull + + if self.x is None and self.name is None: + return [y, z] + + return [x, y, z] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the @@ -492,6 +590,58 @@ def from_array(cls, value): return collection + 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 ['x', 'y', 'value', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.y is not None: + y = self.y + else: + y = constants.EnforcedNull + + if self.value is not None: + value = self.value + else: + value = constants.EnforcedNull + + if self.x is None and self.name is not None: + x = self.name + elif self.x is not None: + x = self.x + else: + x = constants.EnforcedNull + + if self.x is None and self.name is None: + return [y, value] + + return [x, y, value] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the diff --git a/highcharts_core/options/series/data/range.py b/highcharts_core/options/series/data/range.py index 12af2736..2f7e8b8e 100644 --- a/highcharts_core/options/series/data/range.py +++ b/highcharts_core/options/series/data/range.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal import datetime @@ -216,6 +216,58 @@ def from_array(cls, value): return collection + 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 ['x', 'low', 'high', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.x is not None: + x = self.x + elif self.name is not None: + x = self.name + else: + x = constants.EnforcedNull + + if self.low is not None: + low = self.low + else: + low = constants.EnforcedNull + + if self.high is not None: + high = self.high + else: + high = constants.EnforcedNull + + if self.x is None and self.name is None: + return [low, high] + + return [x, low, high] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the diff --git a/highcharts_core/options/series/data/single_point.py b/highcharts_core/options/series/data/single_point.py index ac8b7f6e..5253ed11 100644 --- a/highcharts_core/options/series/data/single_point.py +++ b/highcharts_core/options/series/data/single_point.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal from collections import UserDict @@ -197,6 +197,51 @@ def from_array(cls, value): return collection + 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 ['y', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.y is not None: + y = self.y + else: + y = constants.EnforcedNull + + if self.name is not None: + name = self.name + else: + name = constants.EnforcedNull + + if not self.name: + return [y] + + return [name, y] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the @@ -316,6 +361,43 @@ def from_array(cls, value): return collection + 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 ['value'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.value is not None: + value = self.value + else: + value = constants.EnforcedNull + + return [value] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the @@ -434,6 +516,43 @@ def from_array(cls, value): return collection + 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 ['x'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.x is not None: + x = self.x + else: + x = constants.EnforcedNull + + return [x] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the diff --git a/highcharts_core/options/series/data/vector.py b/highcharts_core/options/series/data/vector.py index 97cdf956..27f13531 100644 --- a/highcharts_core/options/series/data/vector.py +++ b/highcharts_core/options/series/data/vector.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List, Dict from decimal import Decimal from validator_collection import validators, checkers @@ -93,6 +93,63 @@ def from_array(cls, value): return collection + 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 ['x', 'y', 'length', 'direction', 'name'] + + def to_array(self, force_object = False) -> List | Dict: + """Generate the array representation of the data point (the inversion + of + :meth:`.from_array() `). + + .. warning:: + + If the data point *cannot* be serialized to a JavaScript array, + this method will instead return the untrimmed :class:`dict ` + representation of the data point as a fallback. + + :param force_object: if ``True``, forces the return of the instance's + untrimmed :class:`dict ` representation. Defaults to ``False``. + :type force_object: :class:`bool ` + + :returns: The array representation of the data point. + :rtype: :class:`list ` of values or :class:`dict ` + """ + if self.requires_js_object or force_object: + return self._to_untrimmed_dict() + + if self.y is not None: + y = self.y + else: + y = constants.EnforcedNull + + if self.length is not None: + length = self.length + else: + length = constants.EnforcedNull + + if self.direction is not None: + direction = self.direction + else: + direction = constants.EnforcedNull + + if self.x is not None: + x = self.x + elif self.name is not None: + x = self.name + else: + x = constants.EnforcedNull + + if self.x is None and self.name is None: + return [y, length, direction] + + return [x, y, length, direction] + @classmethod def _get_kwargs_from_dict(cls, as_dict): """Convenience method which returns the keyword arguments used to initialize the diff --git a/tests/input_files/series/vector/01.js b/tests/input_files/series/vector/01.js index 4d739d09..f995ddd6 100644 --- a/tests/input_files/series/vector/01.js +++ b/tests/input_files/series/vector/01.js @@ -1,9 +1,6 @@ { data: [ - { - direction: 45, - length: 12 - } + [0, 45, 12] ], cluster: { allowOverlap: true, diff --git a/tests/input_files/series/vector/02.js b/tests/input_files/series/vector/02.js index 192f2e69..b3758cf0 100644 --- a/tests/input_files/series/vector/02.js +++ b/tests/input_files/series/vector/02.js @@ -1,9 +1,6 @@ { data: [ - { - direction: 45, - length: 12 - } + [0, 45, 12] ], cluster: { allowOverlap: true, diff --git a/tests/options/series/data/test_bar.py b/tests/options/series/data/test_bar.py index 542726e6..2aef2592 100644 --- a/tests/options/series/data/test_bar.py +++ b/tests/options/series/data/test_bar.py @@ -324,6 +324,36 @@ def test_BarData_from_array(array, expected, error): with pytest.raises(error): result = cls.from_array(array) + +utc_now = datetime.datetime.utcnow() +today = datetime.date.today() + + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[123, 456], [789, 123]], {}, list, [[123, 456], [789, 123]]), + ([['A', 456], ['B', 123]], {}, list, [['A', 456], ['B', 123]]), + ([[utc_now, 456], [utc_now, 123]], {}, list, [[utc_now, 456], [utc_now, 123]]), + ([[today, 456], [today, 123]], {}, list, [[today, 456], [today, 123]]), + + ([[123, 456], [789, 123]], {'id': 'some_id'}, dict, None), +]) +def test_BarData_to_array(input_array, set_props, expected_type, expected): + iterable = cls.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + + ## NEXT CLASS STANDARD_PARAMS_2 = [ @@ -595,6 +625,31 @@ def test_WaterfallData_to_dict(kwargs, error): def test_WaterfallData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls2, input_files, filename, as_file, error) + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[123, 456], [789, 123]], {}, list, [[123, 456], [789, 123]]), + ([['A', 456], ['B', 123]], {}, list, [['A', 456], ['B', 123]]), + ([[utc_now, 456], [utc_now, 123]], {}, list, [[utc_now, 456], [utc_now, 123]]), + ([[today, 456], [today, 123]], {}, list, [[today, 456], [today, 123]]), + + ([[123, 456], [789, 123]], {'id': 'some_id'}, dict, None), +]) +def test_WaterfallData_to_array(input_array, set_props, expected_type, expected): + iterable = cls.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + ## NEXT CLASS STANDARD_PARAMS_3 = [ @@ -883,6 +938,37 @@ def test_WindBarbData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls3, input_files, filename, as_file, error) +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[123, 456, 789, 987], [789, 123, 456, 789]], {}, list, [[123, 456, 789, 987], [789, 123, 456, 789]]), + ([['A', 456, 789, 987], ['B', 123, 456, 789]], {}, list, [['A', 456, 789, 987], ['B', 123, 456, 789]]), + ([[utc_now, 456, 789, 987], [utc_now, 123, 456, 789]], {}, list, [[utc_now, 456, 789, 987], [utc_now, 123, 456, 789]]), + ([[today, 456, 789, 987], [today, 123, 456, 789]], {}, list, [[today, 456, 789, 987], [today, 123, 456, 789]]), + + ([[123, 456, 789], [789, 123, 456]], {}, list, [[123, 456, 789], [789, 123, 456]]), + ([['A', 456, 789], ['B', 123, 456]], {}, list, [['A', 456, 789], ['B', 123, 456]]), + ([[utc_now, 456, 789], [utc_now, 123, 456]], {}, list, [[utc_now, 456, 789], [utc_now, 123, 456]]), + ([[today, 456, 789], [today, 123, 456]], {}, list, [[today, 456, 789], [today, 123, 456]]), + + ([[123, 456, 789, 987], [789, 123, 456, 789]], {'id': 'some_id'}, dict, None), + ([[123, 456, 789], [789, 123, 456]], {'id': 'some_id'}, dict, None), +]) +def test_WindBarbData_to_array(input_array, set_props, expected_type, expected): + iterable = cls3.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + + ## NEXT CLASS STANDARD_PARAMS_4 = [ diff --git a/tests/options/series/data/test_base.py b/tests/options/series/data/test_base.py index 9d89724d..b0e338aa 100644 --- a/tests/options/series/data/test_base.py +++ b/tests/options/series/data/test_base.py @@ -20,6 +20,11 @@ def from_array(cls, value): cls = NonAbstractDataBase +class RequiringJSObject(NonAbstractDataBase): + def _to_untrimmed_dict(self): + return {'someKey': 123} + + STANDARD_PARAMS = [ ({}, None), ({ @@ -93,3 +98,13 @@ def test_to_dict(kwargs, error): ]) def test_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls, input_files, filename, as_file, error) + + +@pytest.mark.parametrize('cls, expected', [ + (NonAbstractDataBase, False), + (RequiringJSObject, True), + +]) +def test_requires_js_object(cls, expected): + obj = cls() + assert obj.requires_js_object is expected \ No newline at end of file diff --git a/tests/options/series/data/test_boxplot.py b/tests/options/series/data/test_boxplot.py index 396dafc2..96a68f41 100644 --- a/tests/options/series/data/test_boxplot.py +++ b/tests/options/series/data/test_boxplot.py @@ -806,3 +806,37 @@ def test_BoxPlotData_to_dict(kwargs, error): ]) def test_BoxPlotData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls, input_files, filename, as_file, error) + + +utc_now = datetime.datetime.utcnow() +today = datetime.date.today() + + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[123, 456, 789, 987, 654, 321]], {}, list, [[123, 456, 789, 987, 654, 321]]), + ([['A', 456, 789, 987, 654, 321], ['B', 123, 456, 789, 987, 654]], {}, list, [['A', 456, 789, 987, 654, 321], ['B', 123, 456, 789, 987, 654]]), + ([[utc_now, 456, 789, 987, 654, 321]], {}, list, [[utc_now, 456, 789, 987, 654, 321]]), + ([[today, 456, 789, 987, 654, 321]], {}, list, [[today, 456, 789, 987, 654, 321]]), + + ([[456, 789, 987, 654, 321]], {}, list, [[456, 789, 987, 654, 321]]), + ([[456, 789, 987, 654, 321], [123, 456, 789, 987, 654]], {}, list, [[456, 789, 987, 654, 321], [123, 456, 789, 987, 654]]), + ([[456, 789, 987, 654, 321]], {}, list, [[456, 789, 987, 654, 321]]), + + ([[123, 456, 789, 987, 654, 321]], {'id': 'some_id'}, dict, None), + +]) +def test_BoxPlotData_to_array(input_array, set_props, expected_type, expected): + iterable = cls.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected diff --git a/tests/options/series/data/test_bullet.py b/tests/options/series/data/test_bullet.py index fb2db83e..77ff9b16 100644 --- a/tests/options/series/data/test_bullet.py +++ b/tests/options/series/data/test_bullet.py @@ -331,3 +331,33 @@ def test_BulletData_to_dict(kwargs, error): ]) def test_BulletData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls, input_files, filename, as_file, error) + + +utc_now = datetime.datetime.utcnow() +today = datetime.date.today() + + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[321, 123, 456], [123, 789, 123]], {}, list, [[321, 123, 456], [123, 789, 123]]), + ([[123, 456], [789, 123]], {}, list, [[123, 456], [789, 123]]), + ([['A', 123, 456], ['B', 321, 123]], {}, list, [['A', 123, 456], ['B', 321, 123]]), + ([[utc_now, 123, 456], [utc_now, 321, 123]], {}, list, [[utc_now, 123, 456], [utc_now, 321, 123]]), + ([[today, 123, 456], [today, 321, 123]], {}, list, [[today, 123, 456], [today, 321, 123]]), + + ([[123, 456], [789, 123]], {'id': 'some_id'}, dict, None), +]) +def test_BulletData_to_array(input_array, set_props, expected_type, expected): + iterable = cls.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected diff --git a/tests/options/series/data/test_cartesian.py b/tests/options/series/data/test_cartesian.py index 9708e1ba..6041c085 100644 --- a/tests/options/series/data/test_cartesian.py +++ b/tests/options/series/data/test_cartesian.py @@ -746,6 +746,35 @@ def test_CartesianData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls, input_files, filename, as_file, error) +utc_now = datetime.datetime.utcnow() +today = datetime.date.today() + + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[123, 456], [789, 123]], {}, list, [[123, 456], [789, 123]]), + ([['A', 456], ['B', 123]], {}, list, [['A', 456], ['B', 123]]), + ([[utc_now, 456], [utc_now, 123]], {}, list, [[utc_now, 456], [utc_now, 123]]), + ([[today, 456], [today, 123]], {}, list, [[today, 456], [today, 123]]), + + ([[123, 456], [789, 123]], {'id': 'some_id'}, dict, None), +]) +def test_CartesianData_to_array(input_array, set_props, expected_type, expected): + iterable = cls.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + + ## NEXT CLASS STANDARD_PARAMS_2 = [ @@ -1033,6 +1062,33 @@ def test_Cartesian3DData_to_dict(kwargs, error): def test_Cartesian3DData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls2, input_files, filename, as_file, error) + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[321, 123, 456], [123, 789, 123]], {}, list, [[321, 123, 456], [123, 789, 123]]), + ([[123, 456], [789, 123]], {}, list, [[123, 456], [789, 123]]), + ([['A', 123, 456], ['B', 321, 123]], {}, list, [['A', 123, 456], ['B', 321, 123]]), + ([[utc_now, 123, 456], [utc_now, 321, 123]], {}, list, [[utc_now, 123, 456], [utc_now, 321, 123]]), + ([[today, 123, 456], [today, 321, 123]], {}, list, [[today, 123, 456], [today, 321, 123]]), + + ([[123, 456], [789, 123]], {'id': 'some_id'}, dict, None), +]) +def test_Cartesian3DData_to_array(input_array, set_props, expected_type, expected): + iterable = cls2.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + + ## NEXT CLASS STANDARD_PARAMS_3 = [ @@ -1322,3 +1378,29 @@ def test_CartesianValueData_to_dict(kwargs, error): ]) def test_CartesianValueData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls3, input_files, filename, as_file, error) + + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[321, 123, 456], [123, 789, 123]], {}, list, [[321, 123, 456], [123, 789, 123]]), + ([[123, 456], [789, 123]], {}, list, [[123, 456], [789, 123]]), + ([['A', 123, 456], ['B', 321, 123]], {}, list, [['A', 123, 456], ['B', 321, 123]]), + ([[utc_now, 123, 456], [utc_now, 321, 123]], {}, list, [[utc_now, 123, 456], [utc_now, 321, 123]]), + ([[today, 123, 456], [today, 321, 123]], {}, list, [[today, 123, 456], [today, 321, 123]]), + + ([[123, 456], [789, 123]], {'id': 'some_id'}, dict, None), +]) +def test_CartesianValueData_to_array(input_array, set_props, expected_type, expected): + iterable = cls3.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected diff --git a/tests/options/series/data/test_range.py b/tests/options/series/data/test_range.py index 9e512cdc..3e27ecaf 100644 --- a/tests/options/series/data/test_range.py +++ b/tests/options/series/data/test_range.py @@ -1,6 +1,7 @@ """Tests for ``highcharts.no_data``.""" import pytest +import datetime from json.decoder import JSONDecodeError @@ -290,6 +291,36 @@ def test_RangeData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls, input_files, filename, as_file, error) +utc_now = datetime.datetime.utcnow() +today = datetime.date.today() + + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[321, 123, 456], [123, 789, 123]], {}, list, [[321, 123, 456], [123, 789, 123]]), + ([[123, 456], [789, 123]], {}, list, [[123, 456], [789, 123]]), + ([['A', 123, 456], ['B', 321, 123]], {}, list, [['A', 123, 456], ['B', 321, 123]]), + ([[utc_now, 123, 456], [utc_now, 321, 123]], {}, list, [[utc_now, 123, 456], [utc_now, 321, 123]]), + ([[today, 123, 456], [today, 321, 123]], {}, list, [[today, 123, 456], [today, 321, 123]]), + + ([[123, 456], [789, 123]], {'id': 'some_id'}, dict, None), +]) +def test_RangeData_to_array(input_array, set_props, expected_type, expected): + iterable = cls.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + + ## NEXT CLASS STANDARD_PARAMS_2 = [ diff --git a/tests/options/series/data/test_single_point.py b/tests/options/series/data/test_single_point.py index fc9f0a7c..ab6684ea 100644 --- a/tests/options/series/data/test_single_point.py +++ b/tests/options/series/data/test_single_point.py @@ -1,6 +1,7 @@ """Tests for ``highcharts.no_data``.""" import pytest +import datetime from json.decoder import JSONDecodeError @@ -506,6 +507,35 @@ def test_SinglePointData_to_dict(kwargs, error): def test_SinglePointData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls2, input_files, filename, as_file, error) + +utc_now = datetime.datetime.utcnow() +today = datetime.date.today() + + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([['123', 456], ['789', 123]], {}, list, [['123', 456], ['789', 123]]), + ([['A', 456], ['B', 123]], {}, list, [['A', 456], ['B', 123]]), + ([[123], [456]], {}, list, [[123], [456]]), + + ([['123', 456], ['789', 123]], {'id': 'some_id'}, dict, None), +]) +def test_SinglePointData_to_array(input_array, set_props, expected_type, expected): + iterable = cls2.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + + ## NEXT CLASS @@ -756,6 +786,28 @@ def test_SingleValueData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls3, input_files, filename, as_file, error) +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([123, 456], {}, list, [[123], [456]]), + + ([123, 456], {'id': 'some_id'}, dict, None), +]) +def test_SingleValueData_to_array(input_array, set_props, expected_type, expected): + iterable = cls3.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + + ## NEXT CLASS @@ -1006,6 +1058,28 @@ def test_SingleXData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls4, input_files, filename, as_file, error) +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([123, 456], {}, list, [[123], [456]]), + + ([123, 456], {'id': 'some_id'}, dict, None), +]) +def test_SingleXData_to_array(input_array, set_props, expected_type, expected): + iterable = cls4.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected + + ## NEXT CLASS diff --git a/tests/options/series/data/test_vector.py b/tests/options/series/data/test_vector.py index 161993ae..7804322e 100644 --- a/tests/options/series/data/test_vector.py +++ b/tests/options/series/data/test_vector.py @@ -757,3 +757,35 @@ def test_VectorData_to_dict(kwargs, error): ]) def test_VectorData_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls, input_files, filename, as_file, error) + + +utc_now = datetime.datetime.utcnow() +today = datetime.date.today() + + +@pytest.mark.parametrize('input_array, set_props, expected_type, expected', [ + ([], {}, list, []), + ([[123, 456, 789, 987], [789, 123, 456, 789]], {}, list, [[123, 456, 789, 987], [789, 123, 456, 789]]), + ([['A', 456, 789, 987], ['B', 123, 456, 789]], {}, list, [['A', 456, 789, 987], ['B', 123, 456, 789]]), + ([[utc_now, 456, 789, 987], [utc_now, 123, 456, 789]], {}, list, [[utc_now, 456, 789, 987], [utc_now, 123, 456, 789]]), + ([[today, 456, 789, 987], [today, 123, 456, 789]], {}, list, [[today, 456, 789, 987], [today, 123, 456, 789]]), + + ([[123, 456, 789], [789, 123, 456]], {}, list, [[123, 456, 789], [789, 123, 456]]), + + ([[123, 456, 789, 987], [789, 123, 456, 789]], {'id': 'some_id'}, dict, None), + ([[123, 456, 789], [789, 123, 456]], {'id': 'some_id'}, dict, None), +]) +def test_VectorData_to_array(input_array, set_props, expected_type, expected): + iterable = cls.from_array(input_array) + for data_point in iterable: + for key in set_props: + setattr(data_point, key, set_props[key]) + + results = [] + for data_point in iterable: + result = data_point.to_array() + assert isinstance(result, expected_type) is True + results.append(result) + + if expected_type == list: + assert results == expected