Skip to content

Commit

Permalink
Merge pull request #126 from highcharts-for-python/develop
Browse files Browse the repository at this point in the history
PR for v.1.4.3
  • Loading branch information
hcpchris authored Nov 1, 2023
2 parents cfbcf5e + 1c0eb74 commit 8dfe76a
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 15 deletions.
9 changes: 9 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@

Release 1.4.3
=========================================

* **BUGFIX:** Fixed edge case error when deserializing ``ChartOptions`` using ``.from_dict()``
with a ``dict`` that had been serialized using ``.to_dict()`` which errored on ``.margin``
and ``.spacing`` (#124).

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

Release 1.4.2
=========================================

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.4.2'
__version__ = '1.4.3'
62 changes: 48 additions & 14 deletions highcharts_core/options/chart/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,10 +592,22 @@ def margin(self, value):
f'or an iterable of four values. '
f'Received an iterable of {len(value)} '
f'values ({value})')
self.margin_top = value[0]
self.margin_right = value[1]
self.margin_bottom = value[2]
self.margin_left = value[3]
if value[0] == 'null':
self.margin_top = None
else:
self.margin_top = value[0]
if value[1] == 'null':
self.margin_right = None
else:
self.margin_right = value[1]
if value[2] == 'null':
self.margin_bottom = None
else:
self.margin_bottom = value[2]
if value[3] == 'null':
self.margin_left = None
else:
self.margin_left = value[3]
else:
self.margin_top = value
self.margin_right = value
Expand All @@ -620,7 +632,10 @@ def margin_bottom(self) -> Optional[int | float | Decimal]:

@margin_bottom.setter
def margin_bottom(self, value):
self._margin_bottom = validators.numeric(value, allow_empty = True)
if value is None or isinstance(value, constants.EnforcedNullType):
self._margin_bottom = None
else:
self._margin_bottom = validators.numeric(value)

@property
def margin_left(self) -> Optional[int | float | Decimal]:
Expand All @@ -640,7 +655,10 @@ def margin_left(self) -> Optional[int | float | Decimal]:

@margin_left.setter
def margin_left(self, value):
self._margin_left = validators.numeric(value, allow_empty = True)
if value is None or isinstance(value, constants.EnforcedNullType):
self._margin_left = None
else:
self._margin_left = validators.numeric(value)

@property
def margin_right(self) -> Optional[int | float | Decimal]:
Expand All @@ -660,7 +678,10 @@ def margin_right(self) -> Optional[int | float | Decimal]:

@margin_right.setter
def margin_right(self, value):
self._margin_right = validators.numeric(value, allow_empty = True)
if value is None or isinstance(value, constants.EnforcedNullType):
self._margin_right = None
else:
self._margin_right = validators.numeric(value)

@property
def margin_top(self) -> Optional[int | float | Decimal]:
Expand All @@ -680,7 +701,10 @@ def margin_top(self) -> Optional[int | float | Decimal]:

@margin_top.setter
def margin_top(self, value):
self._margin_top = validators.numeric(value, allow_empty = True)
if value is None or isinstance(value, constants.EnforcedNullType):
self._margin_top = None
else:
self._margin_top = validators.numeric(value)

@property
def number_formatter(self) -> Optional[CallbackFunction]:
Expand Down Expand Up @@ -1119,13 +1143,23 @@ def spacing(self, value):
f' or an iterable of four values. '
f'Received an iterable of {len(value)} '
f'values ({value})')
value = [validators.numeric(x) for x in value]
self.spacing_top = value[0]
self.spacing_right = value[1]
self.spacing_bottom = value[2]
self.spacing_left = value[3]
if value[0] == 'null':
self.spacing_top = None
else:
self.spacing_top = value[0]
if value[1] == 'null':
self.spacing_right = None
else:
self.spacing_right = value[1]
if value[2] == 'null':
self.spacing_bottom = None
else:
self.spacing_bottom = value[2]
if value[3] == 'null':
self.spacing_left = None
else:
self.spacing_left = value[3]
else:
value = validators.numeric(value, allow_empty = False)
self.spacing_top = value
self.spacing_right = value
self.spacing_bottom = value
Expand Down
163 changes: 163 additions & 0 deletions tests/options/chart/test_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,166 @@ 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('as_dict, as_js_literal, error', [
({
'marginRight': 124
}, False, None),
({
'type': 'bar',
'marginRight': 124,
'marginTop': 421,
'marginBottom': 321,
'marginLeft': 789,
'scrollablePlotArea': {
'minHeight': 1000,
'opacity': 1
}
}, False, None),
({
'marginRight': 124
}, True, None),
({
'type': 'bar',
'marginRight': 124,
'marginTop': 421,
'marginBottom': 321,
'marginLeft': 789,
'scrollablePlotArea': {
'minHeight': 1000,
'opacity': 1
}
}, True, None),
])
def test_bug124_margin_right(as_dict, as_js_literal, error):
if not error:
if not as_js_literal:
result = cls.from_dict(as_dict)
else:
as_str = str(as_dict)
result = cls.from_js_literal(as_str)
assert isinstance(result, cls) is True
if 'marginRight' in as_dict or 'margin_right' in as_dict:
assert result.margin_right == as_dict.get('marginRight', None)
if 'marginTop' in as_dict or 'margin_top' in as_dict:
assert result.margin_top == as_dict.get('marginTop', None)
if 'marginBottom' in as_dict or 'margin_bottom' in as_dict:
assert result.margin_bottom == as_dict.get('marginBottom', None)
if 'marginLeft' in as_dict or 'margin_left' in as_dict:
assert result.margin_left == as_dict.get('marginLeft', None)
else:
with pytest.raises(error):
if not as_js_literal:
result = cls.from_dict(as_dict)
else:
as_str = str(as_dict)
result = cls.from_js_literal(as_str)


@pytest.mark.parametrize('as_str, error', [
("""{
marginRight: 124
}""", None),
("""{type: 'bar',
marginRight: 124,
marginTop: 421,
marginBottom: 321,
marginLeft: 789,
scrollablePlotArea: {
minHeight: 1000,
opacity: 1
}
}""", None),
("""{
marginRight: null
}""", None),
])
def test_bug124_margin_right_from_js_literal(as_str, error):
if not error:
result = cls.from_js_literal(as_str)
assert isinstance(result, cls) is True
if 'marginRight' in as_str or 'margin_right' in as_str:
if 'marginRight: null' not in as_str:
assert result.margin_right is not None
else:
assert result.margin_right is None
if 'marginTop' in as_str or 'margin_top' in as_str:
assert result.margin_top is not None
if 'marginBottom' in as_str or 'margin_bottom' in as_str:
assert result.margin_bottom is not None
if 'marginLeft' in as_str or 'margin_left' in as_str:
assert result.margin_left is not None
else:
with pytest.raises(error):
result = cls.from_js_literal(as_str)


@pytest.mark.parametrize('as_dict, error', [
({
'marginRight': 124
}, None),
({
'type': 'bar',
'marginRight': 124,
'marginTop': 421,
'marginBottom': 321,
'marginLeft': 789,
'scrollablePlotArea': {
'minHeight': 1000,
'opacity': 1
}
}, None),
])
def test_bug124_margin_right_to_dict_from_dict(as_dict, error):
if not error:
initial_result = cls.from_dict(as_dict)
as_new_dict = initial_result.to_dict()
result = cls.from_dict(as_new_dict)
assert isinstance(result, cls) is True
assert result.margin_right == initial_result.margin_right
assert result.margin_top == initial_result.margin_top
assert result.margin_bottom == initial_result.margin_bottom
assert result.margin_left == initial_result.margin_left
else:
with pytest.raises(error):
initial_result = cls.from_dict(as_dict)
as_new_dict = initial_result.to_dict()
result = cls.from_dict(as_new_dict)


@pytest.mark.parametrize('as_dict, error', [
({
'spacingRight': 124
}, None),
({
'type': 'bar',
'spacingRight': 124,
'spacingTop': 421,
'spacingBottom': 321,
'spacingLeft': 789,
'scrollablePlotArea': {
'minHeight': 1000,
'opacity': 1
}
}, None),
])
def test_bug124_spacing_right_to_dict_from_dict(as_dict, error):
if not error:
initial_result = cls.from_dict(as_dict)
as_new_dict = initial_result.to_dict()
result = cls.from_dict(as_new_dict)
assert isinstance(result, cls) is True
assert result.spacing_right == initial_result.spacing_right
assert result.spacing_top == initial_result.spacing_top
assert result.spacing_bottom == initial_result.spacing_bottom
assert result.spacing_left == initial_result.spacing_left
else:
with pytest.raises(error):
initial_result = cls.from_dict(as_dict)
as_new_dict = initial_result.to_dict()
result = cls.from_dict(as_new_dict)

0 comments on commit 8dfe76a

Please sign in to comment.