Skip to content

Commit 22e9919

Browse files
authored
Merge pull request #36 from highcharts-for-python/develop
PR for v.1.0.1
2 parents 738dbfa + 02954ab commit 22e9919

File tree

11 files changed

+168
-39
lines changed

11 files changed

+168
-39
lines changed

CHANGES.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
Release 1.0.1
2+
=========================================
3+
4+
* **BUGFIX**: Fixed a bug encountered when parsing CSV data (issue #32).
5+
* **ENHANCEMENT**: Added a catch for when trying to set ``Chart.options`` to a ``SharedOptions`` instance (issue #34).
6+
* Fixed a broken link in the documentation.
7+
8+
---------------
9+
110
Release 1.0.0
211
=========================================
312

docs/api.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,9 @@ Core Components
337337
:class:`SolidGaugeOptions <highcharts_core.options.plot_options.gauge.SolidGaugeOptions>`
338338
* - :mod:`.options.plot_options.generic <highcharts_core.options.plot_options.generic>`
339339
- :class:`GenericTypeOptions <highcharts_core.options.plot_options.generic.GenericTypeOptions>`
340-
* - :mod:`.options.plot_options.Heatmap <highcharts_core.options.plot_options.Heatmap>`
341-
- :class:`HeatmapOptions <highcharts_core.options.plot_options.Heatmap.HeatmapOptions>`
342-
:class:`TilemapOptions <highcharts_core.options.plot_options.Tilemap.TilemapOptions>`
340+
* - :mod:`.options.plot_options.heatmap <highcharts_core.options.plot_options.heatmap>`
341+
- :class:`HeatmapOptions <highcharts_core.options.plot_options.heatmap.HeatmapOptions>`
342+
:class:`TilemapOptions <highcharts_core.options.plot_options.heatmap.TilemapOptions>`
343343
* - :mod:`.options.plot_options.histogram <highcharts_core.options.plot_options.histogram>`
344344
- :class:`HistogramOptions <highcharts_core.options.plot_options.histogram.HistogramOptions>`
345345
* - :mod:`.options.plot_options.item <highcharts_core.options.plot_options.item>`

docs/api/options/index.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,9 @@ Sub-components
265265
:class:`SolidGaugeOptions <highcharts_core.options.plot_options.gauge.SolidGaugeOptions>`
266266
* - :mod:`.options.plot_options.generic <highcharts_core.options.plot_options.generic>`
267267
- :class:`GenericTypeOptions <highcharts_core.options.plot_options.generic.GenericTypeOptions>`
268-
* - :mod:`.options.plot_options.Heatmap <highcharts_core.options.plot_options.Heatmap>`
269-
- :class:`HeatmapOptions <highcharts_core.options.plot_options.Heatmap.HeatmapOptions>`
270-
:class:`TilemapOptions <highcharts_core.options.plot_options.Tilemap.TilemapOptions>`
268+
* - :mod:`.options.plot_options.heatmap <highcharts_core.options.plot_options.heatmap>`
269+
- :class:`HeatmapOptions <highcharts_core.options.plot_options.heatmap.HeatmapOptions>`
270+
:class:`TilemapOptions <highcharts_core.options.plot_options.heatmap.TilemapOptions>`
271271
* - :mod:`.options.plot_options.histogram <highcharts_core.options.plot_options.histogram>`
272272
- :class:`HistogramOptions <highcharts_core.options.plot_options.histogram.HistogramOptions>`
273273
* - :mod:`.options.plot_options.item <highcharts_core.options.plot_options.item>`

docs/api/options/plot_options/index.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ Sub-components
139139
:class:`SolidGaugeOptions <highcharts_core.options.plot_options.gauge.SolidGaugeOptions>`
140140
* - :mod:`.options.plot_options.generic <highcharts_core.options.plot_options.generic>`
141141
- :class:`GenericTypeOptions <highcharts_core.options.plot_options.generic.GenericTypeOptions>`
142-
* - :mod:`.options.plot_options.Heatmap <highcharts_core.options.plot_options.Heatmap>`
143-
- :class:`HeatmapOptions <highcharts_core.options.plot_options.Heatmap.HeatmapOptions>`
144-
:class:`TilemapOptions <highcharts_core.options.plot_options.Tilemap.TilemapOptions>`
142+
* - :mod:`.options.plot_options.heatmap <highcharts_core.options.plot_options.heatmap>`
143+
- :class:`HeatmapOptions <highcharts_core.options.plot_options.heatmap.HeatmapOptions>`
144+
:class:`TilemapOptions <highcharts_core.options.plot_options.heatmap.TilemapOptions>`
145145
* - :mod:`.options.plot_options.histogram <highcharts_core.options.plot_options.histogram>`
146146
- :class:`HistogramOptions <highcharts_core.options.plot_options.histogram.HistogramOptions>`
147147
* - :mod:`.options.plot_options.item <highcharts_core.options.plot_options.item>`

highcharts_core/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.0.0'
1+
__version__ = '1.0.1'

highcharts_core/chart.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,18 @@ def options(self) -> Optional[HighchartsOptions]:
185185
return self._options
186186

187187
@options.setter
188-
@class_sensitive(HighchartsOptions)
189188
def options(self, value):
189+
if not value:
190+
self._options = None
191+
elif isinstance(value, SharedOptions):
192+
raise errors.HighchartsValueError('Chart.options expects a HighchartsOptions instance '
193+
'or a valid descendent. However, the value you supplied '
194+
'is a SharedOptions instance, which wil a descendent is not '
195+
'valid for this parameter.')
196+
else:
197+
value = validate_types(value,
198+
types = HighchartsOptions)
199+
190200
self._options = value
191201

192202
@property

highcharts_core/options/series/base.py

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -440,12 +440,6 @@ def load_from_csv(self,
440440
except AttributeError:
441441
pass
442442

443-
if checkers.is_file_on_filesystem(as_string_or_file):
444-
with open(as_string_or_file, 'r') as file_:
445-
as_str = file_.read()
446-
else:
447-
as_str = as_string_or_file
448-
449443
property_column_map = validators.dict(property_column_map, allow_empty = False)
450444
cleaned_column_map = {}
451445
for key in property_column_map:
@@ -464,17 +458,32 @@ def load_from_csv(self,
464458
f'instead.')
465459
cleaned_column_map[key] = map_value
466460

467-
columns, csv_records = utility_functions.parse_csv(
468-
as_str,
469-
has_header_row = has_header_row,
470-
delimiter = delimiter,
471-
null_text = null_text,
472-
wrapper_character = wrapper_character,
473-
line_terminator = line_terminator,
474-
wrap_all_strings = False,
475-
double_wrapper_character_when_nested = False,
476-
escape_character = "\\"
477-
)
461+
if not checkers.is_on_filesystem(as_string_or_file):
462+
as_str = as_string_or_file
463+
columns, csv_records = utility_functions.parse_csv(
464+
as_str,
465+
has_header_row = has_header_row,
466+
delimiter = delimiter,
467+
null_text = null_text,
468+
wrapper_character = wrapper_character,
469+
line_terminator = line_terminator,
470+
wrap_all_strings = False,
471+
double_wrapper_character_when_nested = False,
472+
escape_character = "\\"
473+
)
474+
else:
475+
with open(as_string_or_file, 'r', newline = '') as file_:
476+
columns, csv_records = utility_functions.parse_csv(
477+
file_,
478+
has_header_row = has_header_row,
479+
delimiter = delimiter,
480+
null_text = null_text,
481+
wrapper_character = wrapper_character,
482+
line_terminator = line_terminator,
483+
wrap_all_strings = False,
484+
double_wrapper_character_when_nested = False,
485+
escape_character = "\\"
486+
)
478487

479488
for key in cleaned_column_map:
480489
map_value = cleaned_column_map[key]
@@ -495,7 +504,14 @@ def load_from_csv(self,
495504
data_point_dict = {}
496505
for key in cleaned_column_map:
497506
map_value = cleaned_column_map[key]
498-
data_point_dict[key] = record.get(map_value, None)
507+
value = record.get(map_value, None)
508+
if value and isinstance(value, str) and ',' in value:
509+
test_value = value.replace(delimiter, '')
510+
if checkers.is_numeric(test_value):
511+
value = test_value
512+
513+
data_point_dict[key] = value
514+
499515
data_point_dicts.append(data_point_dict)
500516

501517
self.data = data_point_dicts
@@ -650,14 +666,14 @@ def from_csv(cls,
650666
instance = cls(**series_kwargs)
651667
instance.load_from_csv(as_string_or_file,
652668
property_column_map,
653-
has_header_row = True,
654-
delimiter = ',',
655-
null_text = 'None',
656-
wrapper_character = "'",
657-
line_terminator = '\r\n',
658-
wrap_all_strings = False,
659-
double_wrapper_character_when_nested = False,
660-
escape_character = "\\")
669+
has_header_row = has_header_row,
670+
delimiter = delimiter,
671+
null_text = null_text,
672+
wrapper_character = wrapper_character,
673+
line_terminator = line_terminator,
674+
wrap_all_strings = wrap_all_strings,
675+
double_wrapper_character_when_nested = double_wrapper_character_when_nested,
676+
escape_character = escape_character)
661677

662678
return instance
663679

highcharts_core/utility_functions.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,12 +279,14 @@ def parse_csv(csv_data,
279279
:rtype: :class:`tuple <python:tuple>` of a :class:`list <python:list>` of column names
280280
and :class:`list <python:list>` of :class:`dict <python:dict>`
281281
"""
282-
csv_data = validators.string(csv_data, allow_empty = True)
283282
if not csv_data:
284283
return [], []
285284

285+
if isinstance(csv_data, str):
286+
csv_data = csv_data.split(line_terminator)
287+
286288
if not wrapper_character:
287-
wrapper_character = '\''
289+
wrapper_character = "'"
288290

289291
if wrap_all_strings:
290292
quoting = csv.QUOTE_NONNUMERIC

tests/options/series/test_area.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import datetime
66
from json.decoder import JSONDecodeError
77

8+
from validator_collection import checkers
9+
810
from highcharts_core.options.series.area import AreaSeries as cls
911
from highcharts_core.options.series.area import AreaRangeSeries as cls2
1012
from highcharts_core.options.series.area import AreaSplineSeries as cls3
@@ -2764,6 +2766,64 @@ def test_LineSeries_from_pandas(input_files, filename, property_map, error):
27642766
with pytest.raises(error):
27652767
result = cls5.from_pandas(df, property_map = property_map)
27662768

2769+
2770+
@pytest.mark.parametrize('kwargs, error', [
2771+
({
2772+
'as_string_or_file': "'Date','HeadCount'\r\n'01/01/2023','2'\r\n'01/02/2023','4'\r\n'01/03/2023','8'",
2773+
'property_column_map': {'x': 'Date', 'y': 'HeadCount', 'id': 'Date'}
2774+
}, None),
2775+
({
2776+
'as_string_or_file': "Date,HeadCount\r\n01/01/2023,2\r\n01/02/2023,4\r\n01/03/2023,8",
2777+
'property_column_map': {'x': 'Date', 'y': 'HeadCount', 'id': 'Date'}
2778+
}, None),
2779+
2780+
])
2781+
def test_bugfix32_LineSeries_from_csv(kwargs, error):
2782+
if not error:
2783+
result = cls5.from_csv(**kwargs)
2784+
assert result is not None
2785+
assert isinstance(result, cls5) is True
2786+
assert result.data is not None
2787+
assert isinstance(result.data, list) is True
2788+
for item in result.data:
2789+
assert item.x is not None
2790+
assert item.y is not None
2791+
2792+
2793+
@pytest.mark.parametrize('filename, property_map, kwargs, error', [
2794+
('test-data-files/nst-est2019-01.csv', {}, {}, ValueError),
2795+
('test-data-files/nst-est2019-01.csv',
2796+
{
2797+
'name': 'Geographic Area',
2798+
'x': 'Geographic Area',
2799+
'y': '2010'
2800+
},
2801+
{
2802+
'wrapper_character': '"'
2803+
},
2804+
None),
2805+
2806+
])
2807+
def test_LineSeries_from_csv(input_files, filename, property_map, kwargs, error):
2808+
input_file = check_input_file(input_files, filename)
2809+
2810+
if not error:
2811+
result = cls5.from_csv(input_file,
2812+
property_column_map = property_map,
2813+
**kwargs)
2814+
assert result is not None
2815+
assert isinstance(result, cls5)
2816+
assert result.data is not None
2817+
for item in result.data:
2818+
for key in property_map:
2819+
assert getattr(item, key, None) is not None
2820+
else:
2821+
with pytest.raises(error):
2822+
result = cls5.from_csv(input_file,
2823+
property_column_map = property_map,
2824+
**kwargs)
2825+
2826+
27672827
#### NEXT CLASS
27682828

27692829
@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS)

tests/test_chart.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from json.decoder import JSONDecodeError
66

77
from highcharts_core.chart import Chart as cls
8+
from highcharts_core.global_options.shared_options import SharedOptions
89
from highcharts_core import errors
910
from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \
1011
Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \
@@ -20,6 +21,19 @@ def test__init__(kwargs, error):
2021
Class__init__(cls, kwargs, error)
2122

2223

24+
@pytest.mark.parametrize('kwargs, error', [
25+
({}, errors.HighchartsValueError),
26+
])
27+
def test_bugfix34_SharedOptions_error(kwargs, error):
28+
shared_options = SharedOptions()
29+
instance = cls(**kwargs)
30+
if not error:
31+
instance.options = shared_options
32+
else:
33+
with pytest.raises(error):
34+
instance.options = shared_options
35+
36+
2337
@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS)
2438
def test__to_untrimmed_dict(kwargs, error):
2539
Class__to_untrimmed_dict(cls, kwargs, error)

0 commit comments

Comments
 (0)