Skip to content

Commit

Permalink
Merge pull request #189 from highcharts-for-python/develop
Browse files Browse the repository at this point in the history
PR for v.1.9.0
  • Loading branch information
hcpchris authored Jul 16, 2024
2 parents fec60b3 + 10c3786 commit edb52c5
Show file tree
Hide file tree
Showing 17 changed files with 435 additions and 15 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,6 @@ dmypy.json
# temp files
~$*.*
tests/input_files/headless_export/output/

# VSCode Settings
.vscode/
17 changes: 17 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@

Release 1.9.0
=========================================

* **BUGFIX:** Fixed missing serialization/de-serialization of ``ChartEvents.render``.
* **BUGFIX:** Added new ``utility_classes.data_labels.PieDataLabel`` class to ensure support for
the ``.distance`` property on Pie-chart (and descended) data labels. Closes #183.
* **BUGFIX:** Fixed ``options.chart.height`` type validation to accept string values as per JS API.
(Issue reported in #184).
* **BUGFIX:** Added missing support for ``options.plot_options.sunburst.SunburstOptions.border_radius``
(issue reported in #184).
* **BUGFIX:** Added support for concatenation via `+` operator in JS literal strings when parsed by
``.from_js_literal()``. Closes #185.
* **ENHANCEMENT:** Added support for ``utility_classes.border_radius.BorderRadius`` object.

----


Release 1.8.2
=========================================

Expand Down
3 changes: 3 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,8 @@ Core Components
:class:`ASTNode <highcharts_core.utility_classes.ast.ASTNode>`
:class:`TextPath <highcharts_core.utility_classes.ast.TextPath>`
:class:`AttributeObject <highcharts_core.utility_classes.ast.AttributeObject>`
* - :mod:`.utility_classes.border_radius <highcharts_core.utility_classes.border_radius>`
- :class:`BorderRadius <highcharts_core.utility_classes.border_radius.BorderRadius>`
* - :mod:`.utility_classes.breadcrumbs <highcharts_core.utility_classes.breadcrumbs>`
- :class:`BreadcrumbOptions <highcharts_core.utility_classes.breadcrumbs.BreadcrumbOptions>`
:class:`Separator <highcharts_core.utility_classes.breadcrumbs.Separator>`
Expand All @@ -638,6 +640,7 @@ Core Components
- :class:`DataGroupingOptions <highcharts_core.utility_classes.data_grouping.DataGroupingOptions>`
* - :mod:`.utility_classes.data_labels <highcharts_core.utility_classes.data_labels>`
- :class:`DataLabel <highcharts_core.utility_classes.data_labels.DataLabel>`
:class:`PieDataLabel <highcharts_core.utility_classes.data_labels.PieDataLabel>`
:class:`SunburstDataLabel <highcharts_core.utility_classes.data_labels.SunburstDataLabel>`
:class:`OrganizationDataLabel <highcharts_core.utility_classes.data_labels.OrganizationDataLabel>`
:class:`NodeDataLabel <highcharts_core.utility_classes.data_labels.NodeDataLabel>`
Expand Down
29 changes: 29 additions & 0 deletions docs/api/utility_classes/border_radius.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
##########################################################################################
:mod:`.border_radius <highcharts_core.utility_classes.border_radius>`
##########################################################################################

.. contents:: Module Contents
:local:
:depth: 3
:backlinks: entry

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

.. module:: highcharts_core.utility_classes.border_radius

********************************************************************************************************************
class: :class:`BorderRadius <highcharts_core.utility_classes.border_radius.BorderRadius>`
********************************************************************************************************************

.. autoclass:: BorderRadius
:members:
:inherited-members:

.. collapse:: Class Inheritance

.. inheritance-diagram:: BorderRadius
:top-classes: highcharts_core.metaclasses.HighchartsMeta
:parts: -1

|
18 changes: 18 additions & 0 deletions docs/api/utility_classes/data_labels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ class: :class:`OrganizationDataLabel <highcharts_core.utility_classes.data_label
-----------------

********************************************************************************************************************
class: :class:`PieDataLabel <highcharts_core.utility_classes.data_labels.PieDataLabel>`
********************************************************************************************************************

.. autoclass:: PieDataLabel
:members:
:inherited-members:

.. collapse:: Class Inheritance

.. inheritance-diagram:: PieDataLabel
:top-classes: highcharts_core.metaclasses.HighchartsMeta
:parts: -1

|
-----------------

********************************************************************************************************************
class: :class:`SunburstDataLabel <highcharts_core.utility_classes.data_labels.SunburstDataLabel>`
********************************************************************************************************************
Expand Down
3 changes: 3 additions & 0 deletions docs/api/utility_classes/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ Sub-components
:class:`ASTNode <highcharts_core.utility_classes.ast.ASTNode>`
:class:`TextPath <highcharts_core.utility_classes.ast.TextPath>`
:class:`AttributeObject <highcharts_core.utility_classes.ast.AttributeObject>`
* - :mod:`.utility_classes.border_radius <highcharts_core.utility_classes.border_radius>`
- :class:`BorderRadius <highcharts_core.utility_classes.border_radius.BorderRadius>`
* - :mod:`.utility_classes.breadcrumbs <highcharts_core.utility_classes.breadcrumbs>`
- :class:`BreadcrumbOptions <highcharts_core.utility_classes.breadcrumbs.BreadcrumbOptions>`
:class:`Separator <highcharts_core.utility_classes.breadcrumbs.Separator>`
Expand All @@ -68,6 +70,7 @@ Sub-components
- :class:`DataGroupingOptions <highcharts_core.utility_classes.data_grouping.DataGroupingOptions>`
* - :mod:`.utility_classes.data_labels <highcharts_core.utility_classes.data_labels>`
- :class:`DataLabel <highcharts_core.utility_classes.data_labels.DataLabel>`
:class:`PieDataLabel <highcharts_core.utility_classes.data_labels.PieDataLabel>`
:class:`SunburstDataLabel <highcharts_core.utility_classes.data_labels.SunburstDataLabel>`
:class:`OrganizationDataLabel <highcharts_core.utility_classes.data_labels.OrganizationDataLabel>`
:class:`NodeDataLabel <highcharts_core.utility_classes.data_labels.NodeDataLabel>`
Expand Down
2 changes: 1 addition & 1 deletion highcharts_core/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.8.2'
__version__ = '1.9.0'
20 changes: 20 additions & 0 deletions highcharts_core/js_literal_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,25 @@ def convert_js_property_to_python(property_definition, original_str = None):
elif property_definition.value.type == 'ClassExpression':
return JavaScriptClass._convert_from_js_ast(property_definition.value,
original_str)
elif property_definition.value.type == 'BinaryExpression':
property_value = property_definition.value
operator = property_value.operator
left, right = property_value.left, property_value.right
left_type, right_type = left.type, right.type

if (left_type not in ['Literal']) or (right_type not in ['Literal']):
raise errors.HighchartsParseError(f'unable to find two Literal values within'
f'a Binary expression. Found: '
f'{left_type, right_type}')

left_value, right_value = left.value, right.value
if operator not in ['+', '-', '/']:
raise errors.HighchartsParseError(f'operator "{operator}" not supported within '
f'Binary expression parsing')
left_value = validators.string(left_value, allow_empty = False)
right_value = validators.string(right_value, allow_empty = False)

return left_value + right_value
elif property_definition.value.type == 'CallExpression':
expression = property_definition.value
try:
Expand Down Expand Up @@ -650,6 +669,7 @@ def convert_js_to_python(javascript, original_str = None):
'ObjectExpression',
'ArrayExpression',
'UnaryExpression',
'BinaryExpression',
'FunctionExpression'):
raise errors.HighchartsParseError(f'javascript should contain a '
f'Property, Literal, ObjectExpression, '
Expand Down
2 changes: 1 addition & 1 deletion highcharts_core/options/chart/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ def height(self, value):
self._height = validators.numeric(value,
allow_empty = False,
minimum = 0)
except ValueError:
except (ValueError, TypeError):
self._height = validators.string(value,
allow_empty = False)
except ValueError:
Expand Down
28 changes: 24 additions & 4 deletions highcharts_core/options/plot_options/bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from highcharts_core.utility_classes.patterns import Pattern
from highcharts_core.utility_classes.data_grouping import DataGroupingOptions
from highcharts_core.utility_classes.partial_fill import PartialFillOptions
from highcharts_core.utility_classes.border_radius import BorderRadius


class BaseBarOptions(SeriesOptions):
Expand Down Expand Up @@ -61,7 +62,7 @@ def border_color(self, value):
self._border_color = utility_functions.validate_color(value)

@property
def border_radius(self) -> Optional[int | float | Decimal]:
def border_radius(self) -> Optional[int | float | Decimal | str | BorderRadius]:
"""The corner radius of the border surrounding each column or bar. Defaults to
``0``.
Expand All @@ -71,9 +72,28 @@ def border_radius(self) -> Optional[int | float | Decimal]:

@border_radius.setter
def border_radius(self, value):
self._border_radius = validators.numeric(value,
allow_empty = True,
minimum = 0)
if value is None:
self._border_radius = None
else:
try:
self._border_radius = validators.numeric(value,
allow_empty = True,
minimum = 0)
except (ValueError, TypeError):
try:
self._border_radius = validate_types(value, BorderRadius)
except (ValueError, TypeError):
if not isinstance(value, str):
raise errors.HighchartsValueError(f'border_radius must be a numeric value, '
f'a string, or an instance of BorderRadius. '
f'Received {value.__class__.__name__}.')
if not value.endswith(('%', 'px', 'em')):
raise errors.HighchartsValueError(f'border_radius must be a numeric value, '
f'a percentage string, a pixel measurement, '
f'or an instance of BorderRadius. '
f'Received: "{value}".')

self._border_radius = value

@property
def border_width(self) -> Optional[int | float | Decimal]:
Expand Down
53 changes: 45 additions & 8 deletions highcharts_core/options/plot_options/pie.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
from typing import Optional, List
from decimal import Decimal

from validator_collection import validators
from validator_collection import validators, checkers

from highcharts_core import constants, errors, utility_functions
from highcharts_core.options.plot_options.generic import GenericTypeOptions
from highcharts_core.utility_classes.gradients import Gradient
from highcharts_core.utility_classes.patterns import Pattern
from highcharts_core.utility_classes.data_labels import PieDataLabel
from highcharts_core.utility_classes.border_radius import BorderRadius
from highcharts_core.decorators import validate_types


class PieOptions(GenericTypeOptions):
Expand Down Expand Up @@ -93,7 +96,7 @@ def border_color(self, value):
self._border_color = utility_functions.validate_color(value)

@property
def border_radius(self) -> Optional[str | int | float | Decimal]:
def border_radius(self) -> Optional[str | int | float | Decimal | BorderRadius]:
"""
.. versionadded:: Highcharts Core for Python v.1.1.0 / Highcharts Core (JS) v.11.0.0
Expand All @@ -104,7 +107,9 @@ def border_radius(self) -> Optional[str | int | float | Decimal]:
A numerical value signifies the value is expressed in pixels. A percentage string like `50%`
signifies a size relative to the radius and the inner radius.
:rtype: numeric, :class:`str <python:str>` or :obj:`None <python:None>`
:rtype: numeric, :class:`str <python:str>`,
:class:`BorderRadius <highcharts_core.utility_classes.border_radius.BorderRadius>` or
:obj:`None <python:None>`
"""
return self._border_radius

Expand All @@ -114,11 +119,14 @@ def border_radius(self, value):
self._border_radius = None
else:
try:
value = validators.string(value)
if '%' not in value:
raise ValueError
except (TypeError, ValueError):
value = validators.numeric(value, minimum = 0)
value = validate_types(value, types = BorderRadius)
except (ValueError, TypeError):
try:
value = validators.string(value)
if '%' not in value:
raise ValueError
except (TypeError, ValueError):
value = validators.numeric(value, minimum = 0)

self._border_radius = value

Expand Down Expand Up @@ -265,6 +273,35 @@ def colors(self, value):
value = validators.iterable(value)
self._colors = [utility_functions.validate_color(x) for x in value]

@property
def data_labels(self) -> Optional[PieDataLabel | List[PieDataLabel]]:
"""Options for the series data labels, appearing next to each data point.
.. note::
To have multiple data labels per data point, you can also supply a collection of
:class:`DataLabel` configuration settings.
:rtype: :class:`PieDataLabel`, :class:`list <python:list>` of :class:`PieDataLabel`, or
:obj:`None <python:None>`
"""
return self._data_labels

@data_labels.setter
def data_labels(self, value):
if not value:
self._data_labels = None
else:
if checkers.is_iterable(value):
self._data_labels = validate_types(value,
types = PieDataLabel,
allow_none = False,
force_iterable = True)
else:
self._data_labels = validate_types(value,
types = PieDataLabel,
allow_none = False)

@property
def depth(self) -> Optional[int | float | Decimal]:
"""The thickness of a 3D pie. Defaults to ``0``.
Expand Down
34 changes: 34 additions & 0 deletions highcharts_core/options/plot_options/sunburst.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from highcharts_core.utility_classes.breadcrumbs import BreadcrumbOptions
from highcharts_core.utility_classes.shadows import ShadowOptions
from highcharts_core.utility_classes.data_labels import SunburstDataLabel
from highcharts_core.utility_classes.border_radius import BorderRadius


class SunburstOptions(GenericTypeOptions):
Expand All @@ -28,6 +29,7 @@ class SunburstOptions(GenericTypeOptions):
"""

def __init__(self, **kwargs):
self._border_radius = None
self._color_index = None
self._crisp = None
self._shadow = None
Expand All @@ -46,6 +48,7 @@ def __init__(self, **kwargs):
self._sliced_offset = None
self._start_angle = None

self.border_radius = kwargs.get('border_radius', None)
self.color_index = kwargs.get('color_index', None)
self.crisp = kwargs.get('crisp', None)
self.shadow = kwargs.get('shadow', None)
Expand Down Expand Up @@ -117,6 +120,35 @@ def border_width(self, value):
allow_empty = True,
minimum = 0)

@property
def border_radius(self) -> Optional[int | float | Decimal | str | BorderRadius]:
"""The corner radius of the border surrounding each column or bar. Defaults to
``0``.
:rtype: numeric or :obj:`None <python:None>`
"""
return self._border_radius

@border_radius.setter
def border_radius(self, value):
if value is None:
self._border_radius = None
else:
try:
self._border_radius = validators.numeric(value,
allow_empty = True,
minimum = 0)
except (ValueError, TypeError):
try:
self._border_radius = validate_types(value, BorderRadius)
except (ValueError, TypeError):
if not isinstance(value, str):
raise errors.HighchartsValueError(f'border_radius must be a numeric value, '
f'a string, or an instance of BorderRadius. '
f'Received {value.__class__.__name__}.')

self._border_radius = value

@property
def breadcrumbs(self) -> Optional[BreadcrumbOptions]:
"""Options for the breadcrumbs, the navigation at the top leading the way up
Expand Down Expand Up @@ -468,6 +500,7 @@ def _get_kwargs_from_dict(cls, as_dict):
'allow_traversing_tree': as_dict.get('allowTraversingTree', None),
'border_color': as_dict.get('borderColor', None),
'border_width': as_dict.get('borderWidth', None),
'border_radius': as_dict.get('borderRadius', None),
'breadcrumbs': as_dict.get('breadcrumbs', None),
'center': as_dict.get('center', None),
'color_by_point': as_dict.get('colorByPoint', None),
Expand All @@ -491,6 +524,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
'allowTraversingTree': self.allow_traversing_tree,
'borderColor': self.border_color,
'borderWidth': self.border_width,
'borderRadius': self.border_radius,
'breadcrumbs': self.breadcrumbs,
'center': self.center,
'colorByPoint': self.color_by_point,
Expand Down
Loading

0 comments on commit edb52c5

Please sign in to comment.