Skip to content

Commit

Permalink
Merge pull request #50 from highcharts-for-python/develop
Browse files Browse the repository at this point in the history
PR for v.1.4.6
  • Loading branch information
hcpchris authored Oct 25, 2023
2 parents 6b72e57 + 52923e1 commit a9911ff
Show file tree
Hide file tree
Showing 4 changed files with 270 additions and 64 deletions.
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
Release 1.4.6
=========================================

* **BUGFIX**: Fixed ``FlagData`` and ``FlagDataCollection`` serialization bug (#49).

---------------------

Release 1.4.5
=========================================

Expand Down
2 changes: 1 addition & 1 deletion highcharts_stock/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.4.5'
__version__ = '1.4.6'
65 changes: 2 additions & 63 deletions highcharts_stock/options/series/data/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,6 @@ def from_list(cls, value):
as_obj = cls(x = None)
elif checkers.is_numeric(item):
as_obj = cls(x = item)
elif checkers.is_iterable(item):
if len(item) == 2:
as_obj = cls(x = item[0], title = item[1])
elif len(item) == 1:
as_obj = cls(x = item[0])
else:
raise errors.HighchartsValueError(f'data expects either a 1D or 2D '
f'collection. Collection received '
f'had {len(item)} dimensions.')
else:
raise errors.HighchartsValueError(f'each data point supplied must either '
f'be a Flag Data Point or be '
Expand All @@ -81,55 +72,14 @@ def from_ndarray(cls, value):
:rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
"""
return FlagDataCollection.from_ndarray(value)

@classmethod
def _get_supported_dimensions(cls) -> List[int]:
"""Returns a list of the supported dimensions for the data point.
:rtype: :class:`list <python:list>` of :class:`int <python:int>`
"""
return [1, 2]

@classmethod
def _get_props_from_array(cls, length = None) -> List[str]:
"""Returns a list of the property names that can be set using the
:meth:`.from_array() <highcharts_core.options.series.data.base.DataBase.from_array>`
method.
:param length: The length of the array, which may determine the properties to
parse. Defaults to :obj:`None <python:None>`, which returns the full list of
properties.
:type length: :class:`int <python:int>` or :obj:`None <python:None>`
:rtype: :class:`list <python:list>` of :class:`str <python:str>`
"""
prop_list = {
None: ['x', 'title'],
1: ['x'],
2: ['x', 'title']
}

return cls._get_props_from_array_helper(prop_list, length)

def to_array(self, force_object = False) -> List | Dict:
"""Generate the array representation of the data point (the inversion
of
:meth:`.from_array() <highcharts_core.options.series.data.base.DataBase.from_array>`).
.. warning::
If the data point *cannot* be serialized to a JavaScript array,
this method will instead return the untrimmed :class:`dict <python:dict>`
representation of the data point as a fallback.
:param force_object: if ``True``, forces the return of the instance's
untrimmed :class:`dict <python:dict>` representation. Defaults to ``False``.
:type force_object: :class:`bool <python:bool>`
:returns: The array representation of the data point.
:rtype: :class:`list <python:list>` of values or :class:`dict <python:dict>`
"""
return self._to_untrimmed_dict()
return [1]

@classmethod
def _get_kwargs_from_dict(cls, as_dict):
Expand Down Expand Up @@ -198,17 +148,6 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:

class FlagDataCollection(DataPointCollection):

@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 <python:bool>`
"""
return True

@classmethod
def _get_data_point_class(cls):
"""The Python class to use as the underlying data point within the Collection.
Expand Down
260 changes: 260 additions & 0 deletions tests/options/series/data/test_flags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
"""Tests for ``highcharts.no_data``."""

import pytest

from json.decoder import JSONDecodeError

from highcharts_stock.options.series.data.flags import FlagData as cls4
from highcharts_stock import errors
from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \
Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \
Class_from_js_literal

STANDARD_PARAMS_4 = [
({}, None),
({
'title': 'Test Title',
'x': 123,

'data_labels': {
'align': 'center',
'allowOverlap': True,
'animation': {
'defer': 5
},
'backgroundColor': {
'linearGradient': {
'x1': 0.123,
'x2': 0.234,
'y1': 0.345,
'y2': 0.456
},
'stops': [
[0.12, '#999'],
[0.34, '#fff']
]
},
'borderColor': '#999999',
'borderRadius': 24,
'borderWidth': 1,
'className': 'some-class-name',
'color': '#000000',
'crop': True,
'defer': False,
'enabled': True,
'filter': {
'operator': '>=',
'property': 'some_property',
'value': 123
},
'format': 'some format',
'formatter': """function() { return true; }""",
'inside': True,
'nullFormat': 'some format',
'nullFormatter': """function() { return true; }""",
'overflow': 'none',
'padding': 12,
'position': 'center',
'rotation': 0,
'shadow': False,
'shape': 'rect',
'style': 'style goes here',
'useHTML': False,
'verticalAlign': 'top',
'x': 10,
'y': 20,
'z': 0
},
'drag_drop': {
'draggableX': True,
'draggableY': True,
'dragHandle': {
'className': 'draghandle-classname-goes-here',
'color': '#ccc',
'cursor': 'alias',
'lineColor': '#ddd',
'lineWidth': 2,
'pathFormatter': """function() { return true; }""",
'zIndex': 10
},
'dragMaxX': 3456,
'dragMaxY': 6532,
'dragMinX': 123,
'dragMinY': 321,
'dragPrecisionX': 5,
'dragPrecisionY': 5,
'dragSensitivity': 2,
'groupBy': 'some-property-name',
'guideBox': {
'default': {
'className': 'some-classname-goes-here',
'color': '#999',
'cursor': 'pointer',
'lineColor': '#ccc',
'lineWidth': 2,
'zIndex': 100
}
},
'liveRedraw': True
},
'drilldown': 'some-id-goes-here'
}, None),
# + DataBase
({
'title': 'test title',
'x': 123,

'data_labels': {
'align': 'center',
'allowOverlap': True,
'animation': {
'defer': 5
},
'backgroundColor': {
'linearGradient': {
'x1': 0.123,
'x2': 0.234,
'y1': 0.345,
'y2': 0.456
},
'stops': [
[0.12, '#999'],
[0.34, '#fff']
]
},
'borderColor': '#999999',
'borderRadius': 24,
'borderWidth': 1,
'className': 'some-class-name',
'color': '#000000',
'crop': True,
'defer': False,
'enabled': True,
'filter': {
'operator': '>=',
'property': 'some_property',
'value': 123
},
'format': 'some format',
'formatter': """function() { return true; }""",
'inside': True,
'nullFormat': 'some format',
'nullFormatter': """function() { return true; }""",
'overflow': 'none',
'padding': 12,
'position': 'center',
'rotation': 0,
'shadow': False,
'shape': 'rect',
'style': 'style goes here',
'useHTML': False,
'verticalAlign': 'top',
'x': 10,
'y': 20,
'z': 0
},
'drag_drop': {
'draggableX': True,
'draggableY': True,
'dragHandle': {
'className': 'draghandle-classname-goes-here',
'color': '#ccc',
'cursor': 'alias',
'lineColor': '#ddd',
'lineWidth': 2,
'pathFormatter': """function() { return true; }""",
'zIndex': 10
},
'dragMaxX': 3456,
'dragMaxY': 6532,
'dragMinX': 123,
'dragMinY': 321,
'dragPrecisionX': 5,
'dragPrecisionY': 5,
'dragSensitivity': 2,
'groupBy': 'some-property-name',
'guideBox': {
'default': {
'className': 'some-classname-goes-here',
'color': '#999',
'cursor': 'pointer',
'lineColor': '#ccc',
'lineWidth': 2,
'zIndex': 100
}
},
'liveRedraw': True
},
'drilldown': 'some-id-goes-here',

'accessibility': {
'description': 'Some description goes here',
'enabled': True
},
'class_name': 'some-class-name',
'color': '#ccc',
'color_index': 2,
'custom': {
'some_key': 123,
'other_key': 456
},
'description': 'Some description goes here',
'events': {
'click': """function(event) { return true; }""",
'drag': """function(event) { return true; }""",
'drop': """function(event) { return true; }""",
'mouseOut': """function(event) { return true; }"""
},
'id': 'some-id-goes-here',
'label_rank': 3,
'name': 'Some Name Goes here',
'selected': False
}, None),
]


@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS_4)
def test_FlagData__init__(kwargs, error):
Class__init__(cls4, kwargs, error)


@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS_4)
def test_FlagData__to_untrimmed_dict(kwargs, error):
Class__to_untrimmed_dict(cls4, kwargs, error)


@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS_4)
def test_FlagData_from_dict(kwargs, error):
Class_from_dict(cls4, kwargs, error)


@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS_4)
def test_FlagData_to_dict(kwargs, error):
Class_to_dict(cls4, kwargs, error)


@pytest.mark.parametrize('filename, as_file, error', [
('series/data/single_point/04.js', False, None),
('series/data/single_point/error-04.js',
False,
(errors.HighchartsValueError,
errors.HighchartsParseError,
JSONDecodeError,
TypeError,
ValueError)),
('series/data/single_point/04.js', True, None),
('series/data/single_point/error-04.js',
True,
(errors.HighchartsValueError,
errors.HighchartsParseError,
JSONDecodeError,
TypeError,
ValueError)),
])
def test_FlagData_from_js_literal(input_files, filename, as_file, error):
Class_from_js_literal(cls4, input_files, filename, as_file, error)

0 comments on commit a9911ff

Please sign in to comment.