from typing import Optional, List
from collections import UserDict
try:
import orjson as json
except ImportError:
try:
import rapidjson as json
except ImportError:
try:
import simplejson as json
except ImportError:
import json
from validator_collection import validators, errors as validator_errors
from highcharts_core.decorators import validate_types, class_sensitive
from highcharts_core.metaclasses import HighchartsMeta, JavaScriptDict
[docs]class AttributeObject(JavaScriptDict):
"""Special :class:`dict <python:dict>` class used to construct an arbitrary set of
SVG attributes. Each key represents the key to the attribute (expressed as a string),
while the value represents the value of the attribute.
Keys are validated to be valid variable names.
"""
def __setitem__(self, key, item):
validate_key = False
try:
validate_key = key not in self
except AttributeError:
validate_key = True
if validate_key:
try:
key = validators.variable_name(key, allow_empty = False)
except validator_errors.InvalidVariableNameError as error:
if '-' in key:
try:
test_key = key.replace('-', '_')
validators.variable_name(test_key, allow_empty = False)
except validator_errors.InvalidVariableNameError:
raise error
else:
raise error
super().__setitem__(key, item)
[docs]class ASTNode(HighchartsMeta):
"""Generic representation of an AST node."""
def __init__(self, **kwargs):
self._attributes = None
self._children = []
self._tag_name = None
self._text_content = None
self.attributes = kwargs.get('attributes', None)
self.children = kwargs.get('children', [])
self.tag_name = kwargs.get('tag_name', None)
self.text_content = kwargs.get('text_content', None)
@property
def attributes(self) -> Optional[AttributeObject]:
"""Map of attributes that are used to describe the node.
Basically corresponds to a :class:`dict <python:dict>`, where keys have to
generally conform to standard variable-naming conventions and values are basic
literals (string, array, numer, boolean, :class:`dict <python:dict>`, etc.)
:rtype: :class:`SVGAttributeMap` or :obj:`None <python:None>`
"""
return self._attributes
@attributes.setter
@class_sensitive(AttributeObject)
def attributes(self, value):
self._attributes = value
@property
def children(self) -> List:
"""Collection of :class:`ASTNode` instances that should be considered children
of this node.
:rtype: :class:`list <python:list>` of :class:`ASTNode` objects
"""
return self._children
@children.setter
def children(self, value):
if not value:
self._children = []
else:
value = validate_types(value,
types = self.__class__,
allow_none = False,
force_iterable = True)
self._children = value
@property
def tag_name(self) -> Optional[str]:
"""The name given to the SVG tag.
:rtype: :class:`str <python:str>` or :obj:`None <python:None>`
"""
return self._tag_name
@tag_name.setter
def tag_name(self, value):
self._tag_name = validators.string(value, allow_empty = True)
@property
def text_content(self) -> Optional[str]:
"""Text content that populates the tag, if applicable.
:rtype: :class:`str <python:str>` or :obj:`None <python:None>`
"""
return self._text_content
@text_content.setter
def text_content(self, value):
self._text_content = validators.string(value, allow_empty = True)
@classmethod
def _get_kwargs_from_dict(cls, as_dict):
kwargs = {
'attributes': as_dict.get('attributes', None),
'children': as_dict.get('children', []),
'tag_name': as_dict.get('tagName', None),
'text_content': as_dict.get('textContent', None)
}
return kwargs
def _to_untrimmed_dict(self, in_cls = None) -> dict:
untrimmed = {
'attributes': self.attributes,
'children': self.children,
'tagName': self.tag_name,
'textContent': self.text_content
}
return untrimmed
[docs]class ASTMap(JavaScriptDict):
"""Special :class:`dict <python:dict>` class used to construct a JavaScript object
literal map. Each key represents a key or node within that map, while
the value for that key is an :class:`ASTNode`.
Keys are validated to be valid variable names, while each value is validated to be an
:class:`ASTNode`.
"""
_valid_value_types = ASTNode
_allow_empty_value = True
[docs]class TextPath(HighchartsMeta):
"""Options for a label text which should follow marker's shape.
.. note::
Border and background are disabled for a label that follows a path.
.. warning::
Only SVG-based renderer supports this option. Setting :meth:`DataLabel.use_html` to
``True`` will disable this option.
"""
def __init__(self, **kwargs):
self._attributes = None
self._enabled = None
self.attributes = kwargs.get('attributes', None)
self.enabled = kwargs.get('enabled', None)
@property
def attributes(self) -> Optional[AttributeObject]:
"""Presentation attributes for the text path.
:rtype: :class:`AttributeObject` or :obj:`None <python:None>`
"""
return self._attributes
@attributes.setter
@class_sensitive(AttributeObject)
def attributes(self, value):
self._attributes = value
@property
def enabled(self) -> Optional[bool]:
"""If ``True``, enables the use of a text path for links or marker data labels.
Defaults to ``False``.
:rtype: :class:`bool <python:bool>` or :obj:`None <python:None>`
"""
return self._enabled
@enabled.setter
def enabled(self, value):
if value is None:
self._enabled = None
else:
self._enabled = bool(value)
@classmethod
def _get_kwargs_from_dict(cls, as_dict):
kwargs = {
'attributes': as_dict.get('attributes', None),
'enabled': as_dict.get('enabled', None)
}
return kwargs
def _to_untrimmed_dict(self, in_cls = None) -> dict:
untrimmed = {
'attributes': self.attributes,
'enabled': self.enabled
}
return untrimmed