Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
da6b8d2
Fixed Jupyter Labs rendering.
hcpchris Mar 31, 2023
071ccce
Fixed timestamp serialization of timezone naive datetime objects.
hcpchris Mar 31, 2023
be8a714
Bumped version number.
hcpchris Mar 31, 2023
79a8cf7
Fixed JS literal serialization bug when string contains JS placeholder.
hcpchris Mar 31, 2023
e5b6c15
Fixed typo in plot_bands serialization.
hcpchris Mar 31, 2023
929b46d
Added null support to color validation.
hcpchris Mar 31, 2023
ddba847
Fixed style deserialization.
hcpchris Mar 31, 2023
e457dc1
Added empty value handling.
hcpchris Apr 1, 2023
33e4a67
Added bool value handling.
hcpchris Apr 1, 2023
73a04fc
Added naive timezone handling for SeriesBase.point_start.
hcpchris Apr 1, 2023
89df485
Fixed .from_array() 1D data handling bug.
hcpchris Apr 1, 2023
7483cb6
Fixed JSON deserialization error in RangeData.from_array()
hcpchris Apr 1, 2023
ebb66ff
Fixed NaN handling bug in .load_from_pandas().
hcpchris Apr 1, 2023
d09c474
Fixed typo.
hcpchris Apr 1, 2023
60a9d21
Modified attribute setting sequence.
hcpchris Apr 1, 2023
d6cafb0
Added Highcharts Error #13 handling to Jupyter JS.
hcpchris Apr 1, 2023
a0218e0
Fixed JSON deserialization in *.from_array()
hcpchris Apr 1, 2023
d23b92c
Fixed module inclusions.
hcpchris Apr 1, 2023
405733e
Fixed validation error.
hcpchris Apr 1, 2023
b9f29f3
Cleaned up the JavaScript imports.
hcpchris Apr 1, 2023
97056c2
Added support for stylesheet links in Jupyter Lbas.
hcpchris Apr 1, 2023
944b90d
Fixed JS literal serialization.
hcpchris Apr 2, 2023
35f3657
Merge branch 'develop' of github.com:highcharts-for-python/highcharts…
hcpchris Apr 2, 2023
3f64c73
Updated change history.
hcpchris Apr 2, 2023
856080d
Merge branch 'master' into develop
hcpchris Apr 2, 2023
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
Release 1.0.0-rc5
=========================================

* Bug fixes to Jupyter Labs rendering.
* Bug fix for timestamp serialization of timezone-naive ``datetime`` objects.
* Bug fix: typo in Plot Bands serialization.
* Added null support to color validation.
* Bug fix in ``style`` deserialization.
* Bug fix in ``CartesianData.from_array()``.
* Fixed ``NaN`` handling in ``.load_from_pandas()``.
* Fixed JSON deserialization in ``.from_array()``.
* Added support for stylesheet links in Jupyter Labs context.
* Several bug fixes in JS literal serialization.
* Major improvements to JavaScript module inclusion.

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

Release 1.0.0-rc4
=========================================

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.0.0-rc4'
__version__ = '1.0.0-rc5'
111 changes: 91 additions & 20 deletions highcharts_core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,37 +31,108 @@ def __eq__(self, other):
'https://code.highcharts.com/highcharts-3d.js',
'https://code.highcharts.com/modules/accessibility.js',
'https://code.highcharts.com/modules/annotations.js',
'https://code.highcharts.com/modules/annotations-advanced.js',
'https://code.highcharts.com/modules/sankey.js',
'https://code.highcharts.com/modules/arc-diagram.js',
'https://code.highcharts.com/modules/boost.js',
'https://code.highcharts.com/modules/broken-axis.js',
'https://code.highcharts.com/modules/bullet.js',
'https://code.highcharts.com/modules/cylinder.js',
'https://code.highcharts.com/modules/data.js',
'https://code.highcharts.com/modules/exporting.js',
'https://code.highcharts.com/modules/datagrouping.js',
'https://code.highcharts.com/modules/debugger.js',
'https://code.highcharts.com/modules/dependency-wheel.js',
'https://code.highcharts.com/modules/drag-panes.js',
'https://code.highcharts.com/modules/draggable-points.js',
'https://code.highcharts.com/modules/drilldown.js',
'https://code.highcharts.com/modules/dumbbell.js',
'https://code.highcharts.com/modules/export-data.js',
'https://code.highcharts.com/modules/exporting.js',
'https://code.highcharts.com/modules/funnel.js',
'https://code.highcharts.com/modules/funnel3d.js',
'https://code.highcharts.com/modules/heatmap.js',
'https://code.highcharts.com/modules/item-series.js',
'https://code.highcharts.com/modules/lollipop.js',
'https://code.highcharts.com/modules/networkgraph.js',
'https://code.highcharts.com/modules/no-data-to-display.js',
'https://code.highcharts.com/modules/offline-exporting.js',
'https://code.highcharts.com/modules/solid-gauge.js',
'https://code.highcharts.com/modules/oldie.js',
'https://code.highcharts.com/modules/organization.js',
'https://code.highcharts.com/modules/parallel-coordinates.js',
'https://code.highcharts.com/modules/pareto.js',
'https://code.highcharts.com/modules/pyramid3d.js',
'https://code.highcharts.com/modules/series-label.js',
'https://code.highcharts.com/modules/treemap.js'
'https://code.highcharts.com/modules/series-on-point.js',
'https://code.highcharts.com/modules/solid-gauge.js',
'https://code.highcharts.com/modules/streamgraph.js',
'https://code.highcharts.com/modules/sunburst.js',
'https://code.highcharts.com/modules/tilemap.js',
'https://code.highcharts.com/modules/timeline.js',
'https://code.highcharts.com/modules/treegraph.js',
'https://code.highcharts.com/modules/treemap.js',
'https://code.highcharts.com/modules/variable-pie.js',
'https://code.highcharts.com/modules/variwide.js',
'https://code.highcharts.com/modules/vector.js',
'https://code.highcharts.com/modules/venn.js',
'https://code.highcharts.com/modules/windbarb.js',
'https://code.highcharts.com/modules/wordcloud.js',
'https://code.highcharts.com/modules/xrange.js',
]

INCLUDE_STR = """<script src="https://code.highcharts.com/highcharts.js"/>
<script src="https://code.highcharts.com/highcharts-more.js"/>
<script src="https://code.highcharts.com/highcharts-3d.js"/>
<script src="https://code.highcharts.com/modules/accessibility.js"/>
<script src="https://code.highcharts.com/modules/annotations.js"/>
<script src="https://code.highcharts.com/modules/boost.js"/>
<script src="https://code.highcharts.com/modules/broken-axis.js"/>
<script src="https://code.highcharts.com/modules/data.js"/>
<script src="https://code.highcharts.com/modules/exporting.js"/>
<script src="https://code.highcharts.com/modules/drilldown.js"/>
<script src="https://code.highcharts.com/modules/funnel.js"/>
<script src="https://code.highcharts.com/modules/heatmap.js"/>
<script src="https://code.highcharts.com/modules/no-data-to-display.js"/>
<script src="https://code.highcharts.com/modules/offline-exporting.js"/>
<script src="https://code.highcharts.com/modules/solid-gauge.js"/>
<script src="https://code.highcharts.com/modules/treemap.js"/>
<script src="https://code.highcharts.com/modules/series-label.js"/>
INCLUDE_STR = """
<script src="https://code.highcharts.com/highcharts.js"/>
<script src="https://code.highcharts.com/highcharts-more.js"/>
<script src="https://code.highcharts.com/highcharts-3d.js"/>
<script src="https://code.highcharts.com/modules/accessibility.js"/>
<script src="https://code.highcharts.com/modules/annotations.js"/>
<script src="https://code.highcharts.com/modules/annotations-advanced.js"/>
<script src="https://code.highcharts.com/modules/arc-diagram.js"/>
<script src="https://code.highcharts.com/modules/bellcurve.js"/>
<script src="https://code.highcharts.com/modules/boost.js"/>
<script src="https://code.highcharts.com/modules/broken-axis.js"/>
<script src="https://code.highcharts.com/modules/bullet.js"/>
<script src="https://code.highcharts.com/modules/cylinder.js"/>
<script src="https://code.highcharts.com/modules/data.js"/>
<script src="https://code.highcharts.com/modules/datagrouping.js"/>
<script src="https://code.highcharts.com/modules/debugger.js"/>
<script src="https://code.highcharts.com/modules/dependency-wheel.js"/>
<script src="https://code.highcharts.com/modules/drag-panes'
<script src="https://code.highcharts.com/modules/draggable-points.js"/>
<script src="https://code.highcharts.com/modules/drilldown.js"/>
<script src="https://code.highcharts.com/modules/dumbbell.js"/>
<script src="https://code.highcharts.com/modules/export-data.js"/>
<script src="https://code.highcharts.com/modules/exporting.js"/>
<script src="https://code.highcharts.com/modules/full-screen.js"/>
<script src="https://code.highcharts.com/modules/funnel.js"/>
<script src="https://code.highcharts.com/modules/funnel3d.js"/>
<script src="https://code.highcharts.com/modules/histogram.js"/>
<script src="https://code.highcharts.com/modules/item-series.js"/>
<script src="https://code.highcharts.com/modules/lollipop.js"/>
<script src="https://code.highcharts.com/modules/networkgraph.js"/>
<script src="https://code.highcharts.com/modules/no-data-to-display.js"/>
<script src="https://code.highcharts.com/modules/offline-exporting.js"/>
<script src="https://code.highcharts.com/modules/oldie.js"/>
<script src="https://code.highcharts.com/modules/organization.js"/>
<script src="https://code.highcharts.com/modules/parallel-coordinates.js"/>
<script src="https://code.highcharts.com/modules/pareto.js"/>
<script src="https://code.highcharts.com/modules/pyramid3d.js"/>
<script src="https://code.highcharts.com/modules/sankey.js"/>
<script src="https://code.highcharts.com/modules/series-label.js"/>
<script src="https://code.highcharts.com/modules/series-on-point.js"/>
<script src="https://code.highcharts.com/modules/solid-gauge.js"/>
<script src="https://code.highcharts.com/modules/streamgraph.js"/>
<script src="https://code.highcharts.com/modules/sunburst.js"/>
<script src="https://code.highcharts.com/modules/tilemap.js"/>
<script src="https://code.highcharts.com/modules/timeline.js"/>
<script src="https://code.highcharts.com/modules/treegraph.js"/>
<script src="https://code.highcharts.com/modules/treemap.js"/>
<script src="https://code.highcharts.com/modules/variable-pie.js"/>
<script src="https://code.highcharts.com/modules/variwide.js"/>
<script src="https://code.highcharts.com/modules/vector.js"/>
<script src="https://code.highcharts.com/modules/venn.js"/>
<script src="https://code.highcharts.com/modules/windbarb.js"/>
<script src="https://code.highcharts.com/modules/wordcloud.js"/>
<script src="https://code.highcharts.com/modules/xrange.js"/>
"""

AXIS_TYPES = [
Expand Down
2 changes: 1 addition & 1 deletion highcharts_core/global_options/language/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,7 @@ def style(self) -> Optional[str]:

@style.setter
def style(self, value):
self._style = validators.string(value, allow_empty = True)
self._style = validators.string(value, allow_empty = True, coerce_value = True)

@property
def time_cycles(self) -> Optional[str]:
Expand Down
50 changes: 48 additions & 2 deletions highcharts_core/js_literal_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def serialize_to_js_literal(item, encoding = 'utf-8') -> Optional[str]:
elif isinstance(item, bool):
return item
elif checkers.is_string(item):
return item
return_value = item.replace("'", "\\'")
return return_value
elif checkers.is_numeric(item) and not isinstance(item, Decimal):
return item
elif isinstance(item, Decimal):
Expand All @@ -46,6 +47,8 @@ def serialize_to_js_literal(item, encoding = 'utf-8') -> Optional[str]:
as_dict[key] = serialize_to_js_literal(item[key], encoding = encoding)
return str(as_dict)
elif checkers.is_datetime(item):
if not item.tzinfo:
item = item.replace(tzinfo = datetime.timezone.utc)
return item.timestamp()
elif checkers.is_date(item):
return f'Date.UTC({item.year}, {item.month - 1}, {item.day})'
Expand All @@ -57,6 +60,41 @@ def serialize_to_js_literal(item, encoding = 'utf-8') -> Optional[str]:
return None


def is_js_object(as_str):
"""Determine whether ``as_str`` is a JavaScript object.

:param as_str: The string to evaluate.
:type as_str: :class:`str <python:str>`

:returns: ``True`` if ``as_str`` is a JavaScript function. ``False`` if not.
:rtype: :class:`bool <python:bool>`
"""
expression_item = f'const testName = {as_str}'
try:
parsed = esprima.parseScript(expression_item)
except ParseError:
try:
parsed = esprima.parseModule(expression_item)
except ParseError:
return False

body = parsed.body
if not body:
return False

first_item = body[0]
if first_item.type != 'VariableDeclaration':
return False

init = first_item.declarations[0].init
if not init:
return False
if init.type in ('ObjectExpression'):
return True

return False


def attempt_variable_declaration(as_str):
"""Attempt to coerce ``as_str`` to a JavaScript variable declaration form.

Expand Down Expand Up @@ -160,13 +198,21 @@ def get_js_literal(item) -> str:
subitem_counter = 0
for subitem in subitems:
subitem_counter += 1
if subitem == 'None':
subitem = 'null'
as_str += f"""{subitem}"""
if subitem_counter < len(subitems):
as_str += ',\n'
as_str += ']'
elif checkers.is_string(item):
if item.startswith('{') or item.startswith('[') or item.startswith('Date'):
if item.startswith('[') or item.startswith('Date'):
as_str += f"""{item}"""
elif item.startswith('{') and item.endswith('}'):
if is_js_object(item):
as_str += f"""{item}"""
elif "'" in item:
item = item.replace("'", "\\'")
as_str += f'"{item}"'
elif item in string.whitespace:
as_str += f"""`{item}`"""
elif item.startswith == 'HCP: REPLACE-WITH-':
Expand Down
2 changes: 1 addition & 1 deletion highcharts_core/options/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,14 @@ def __init__(self, **kwargs):
self.navigation = kwargs.get('navigation', None)
self.plot_options = kwargs.get('plot_options', None)
self.responsive = kwargs.get('responsive', None)
self.series = kwargs.get('series', None)
self.subtitle = kwargs.get('subtitle', None)
self.time = kwargs.get('time', None)
self.title = kwargs.get('title', None)
self.tooltip = kwargs.get('tooltip', None)
self.x_axis = kwargs.get('x_axis', None)
self.y_axis = kwargs.get('y_axis', None)

self.series = kwargs.get('series', None)
@property
def accessibility(self) -> Optional[Accessibility]:
"""Options for configuring accessibility for the chart.
Expand Down
4 changes: 2 additions & 2 deletions highcharts_core/options/annotations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ def draggable(self, value):
if value is None:
self._draggable = None
else:
value = validators.string(value, allow_empty = True)
value = validators.string(value, allow_empty = True) or ''
value = value.lower()
if value not in ['x', 'xy', 'y']:
if value not in ['x', 'xy', 'y', '']:
raise errors.HighchartsValueError(f'draggable must be "x", "xy", "y", '
f'or "". Was: {value}')
self._draggable = value
Expand Down
2 changes: 1 addition & 1 deletion highcharts_core/options/annotations/label_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ def style(self) -> Optional[str]:

@style.setter
def style(self, value):
self._style = validators.string(value, allow_empty = True)
self._style = validators.string(value, allow_empty = True, coerce_value = True)

@property
def text(self) -> Optional[str]:
Expand Down
8 changes: 6 additions & 2 deletions highcharts_core/options/axes/labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,9 @@ def style(self) -> Optional[str]:

@style.setter
def style(self, value):
self._style = validators.string(value, allow_empty = True)
self._style = validators.string(value,
allow_empty = True,
coerce_value = True)

@property
def use_html(self) -> Optional[bool]:
Expand Down Expand Up @@ -632,7 +634,9 @@ def style(self) -> Optional[str]:

@style.setter
def style(self, value):
self._style = validators.string(value, allow_empty = True)
self._style = validators.string(value,
allow_empty = True,
coerce_value = True)

@property
def text(self) -> Optional[str]:
Expand Down
4 changes: 2 additions & 2 deletions highcharts_core/options/axes/numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def categories(self, value):
if not value:
self._categories = None
else:
self._categories = [validators.string(x) for x in validators.iterable(value)]
self._categories = [validators.string(x, allow_empty = True) or '' for x in validators.iterable(value)]

@property
def date_time_label_formats(self) -> Optional[DateTimeLabelFormats]:
Expand Down Expand Up @@ -541,7 +541,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
'opposite': self.opposite,
'pane': self.pane,
'panningEnabled': self.panning_enabled,
'plotPands': self.plot_bands,
'plotBands': self.plot_bands,
'plotLines': self.plot_lines,
'reversed': self.reversed,
'reversedStacks': self.reversed_stacks,
Expand Down
11 changes: 7 additions & 4 deletions highcharts_core/options/axes/title.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from validator_collection import validators

from highcharts_core import errors
from highcharts_core import errors, constants
from highcharts_core.metaclasses import HighchartsMeta


Expand Down Expand Up @@ -208,10 +208,10 @@ def style(self) -> Optional[str]:

@style.setter
def style(self, value):
self._style = validators.string(value, allow_empty = True)
self._style = validators.string(value, allow_empty = True, coerce_value = True)

@property
def text(self) -> Optional[str]:
def text(self) -> Optional[str | constants.EnforcedNullType]:
"""The actual text of the title.

.. note::
Expand All @@ -225,7 +225,10 @@ def text(self) -> Optional[str]:

@text.setter
def text(self, value):
self._text = validators.string(value, allow_empty = True)
if isinstance(value, constants.EnforcedNullType):
self._text = constants.EnforcedNull
else:
self._text = validators.string(value, allow_empty = True)

@property
def text_align(self) -> Optional[str]:
Expand Down
10 changes: 7 additions & 3 deletions highcharts_core/options/axes/x_axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from validator_collection import validators

from highcharts_core import errors
from highcharts_core.decorators import class_sensitive
from highcharts_core.decorators import class_sensitive, validate_types
from highcharts_core.utility_classes.gradients import Gradient
from highcharts_core.utility_classes.patterns import Pattern

Expand Down Expand Up @@ -49,9 +49,13 @@ def crosshair(self) -> Optional[CrosshairOptions]:
return self._crosshair

@crosshair.setter
@class_sensitive(CrosshairOptions)
def crosshair(self, value):
self._crosshair = value
if isinstance(value, bool):
value = {
'enabled': value
}

self._crosshair = validate_types(value, CrosshairOptions)

@property
def height(self) -> Optional[str | int | float | Decimal]:
Expand Down
4 changes: 3 additions & 1 deletion highcharts_core/options/caption.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ def style(self) -> Optional[str]:

@style.setter
def style(self, value):
self._style = validators.string(value, allow_empty = True)
self._style = validators.string(value,
allow_empty = True,
coerce_value = True)

@property
def text(self) -> Optional[str]:
Expand Down
Loading