From 16642fd3a559ff6ce3aa3cdf2cc567990f09bc15 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Tue, 26 Apr 2016 15:39:51 +0200 Subject: [PATCH] Fix state and add some docs --- docs/changelog.rst | 4 +-- .../documentation/configuration/rendering.rst | 31 +++++++++++++++++++ docs/documentation/types/line.rst | 4 +-- docs/ext/pygal_sphinx_directives.py | 1 + pygal/config.py | 10 +++--- pygal/state.py | 10 +++--- pygal/test/test_config.py | 7 ++++- pygal/util.py | 15 ++++++++- 8 files changed, 66 insertions(+), 16 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index e9dbc04..b01e95f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -31,8 +31,8 @@ Changelog 2.1.0 ===== -* Bar print value positioning with `print_values_position`. Can be `top`, `center` or `bottom` (thanks @chartique #291) `doc `_ -* Confidence intervals (thanks @chartique #292) `doc `_ +* Bar print value positioning with `print_values_position`. Can be `top`, `center` or `bottom` (thanks @chartique #291) `ci doc `_ +* Confidence intervals (thanks @chartique #292) `data doc `_ 2.0.12 diff --git a/docs/documentation/configuration/rendering.rst b/docs/documentation/configuration/rendering.rst index 4e42e8f..0d7143a 100644 --- a/docs/documentation/configuration/rendering.rst +++ b/docs/documentation/configuration/rendering.rst @@ -114,6 +114,27 @@ see `styles <../styles.html>`_ You can add or replace css/js files in pygal using the `css` and `js` array options. These lists contain absolute filenames and/or external URI. (Relative filenames are relative to pygal internal files) +All config lists now support the use of ellipsis as an extender. For instance: + +.. code-block:: python + + config = Config() + config.css.append('style.css') + chart = pygal.Line(config) + +can now be replaced with: + +.. code-block:: python + + chart = pygal.Line(css=(..., 'style.css')) + +or if you are still using python from the last decade: + +.. code-block:: python + + from pygal._compat import _ellipsis + chart = pygal.Line(css=(_ellipsis, 'style.css')) + css --- @@ -132,6 +153,16 @@ Css can also specified inline by prepending `inline:` to the css: css = ['inline:.rect { fill: blue; }'] +classes +------- + +You can alter pygal svg node classes with the classes option: + +.. code-block:: python + + chart = pygal.Line(classes=(..., 'flex')) + + defs ---- diff --git a/docs/documentation/types/line.rst b/docs/documentation/types/line.rst index 1d11417..4ed2f33 100644 --- a/docs/documentation/types/line.rst +++ b/docs/documentation/types/line.rst @@ -15,7 +15,7 @@ Basic simple line graph: line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) - + Horizontal Line ~~~~~~~~~~~~~~~ @@ -31,7 +31,7 @@ Same graph but horizontal and with a range of 0-100. line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3]) line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1]) line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5]) - line.range = [0, 100] + line_chart.range = [0, 100] Stacked diff --git a/docs/ext/pygal_sphinx_directives.py b/docs/ext/pygal_sphinx_directives.py index 5ebba28..9b50b04 100644 --- a/docs/ext/pygal_sphinx_directives.py +++ b/docs/ext/pygal_sphinx_directives.py @@ -64,6 +64,7 @@ class PygalDirective(Directive): try: exec(code, scope) except Exception: + print(code) print_exc() return [docutils.nodes.system_message( 'An exception as occured during code parsing:' diff --git a/pygal/config.py b/pygal/config.py index a6e77d7..7465287 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -22,7 +22,6 @@ from copy import deepcopy from pygal.interpolate import INTERPOLATIONS from pygal.style import DefaultStyle, Style -from pygal.util import mergextend from pygal import formatters @@ -169,12 +168,11 @@ class BaseConfig(MetaConfig('ConfigBase', (object,), {})): def _update(self, kwargs): """Update the config with the given dictionary""" + from pygal.util import merge dir_self_set = set(dir(self)) - self.__dict__.update( - dict([ - (k, mergextend(v, self.__dict__.get(k, ()))) - if getattr(Config, k, Key(*[''] * 4)).type == list - else (k, v) for (k, v) in kwargs.items() + merge( + self.__dict__, dict([ + (k, v) for (k, v) in kwargs.items() if not k.startswith('_') and k in dir_self_set])) def to_dict(self): diff --git a/pygal/state.py b/pygal/state.py index a27336e..7570a84 100644 --- a/pygal/state.py +++ b/pygal/state.py @@ -19,6 +19,8 @@ """Class holding state during render""" +from pygal.util import merge + class State(object): @@ -30,7 +32,7 @@ class State(object): def __init__(self, graph, **kwargs): """Create the transient state""" - self.__dict__.update(**graph.config.__class__.__dict__) - self.__dict__.update(**graph.config.__dict__) - self.__dict__.update(**graph.__dict__) - self.__dict__.update(**kwargs) + merge(self.__dict__, graph.config.__class__.__dict__) + merge(self.__dict__, graph.config.__dict__) + merge(self.__dict__, graph.__dict__) + merge(self.__dict__, kwargs) diff --git a/pygal/test/test_config.py b/pygal/test/test_config.py index 7a12b7b..e699899 100644 --- a/pygal/test/test_config.py +++ b/pygal/test/test_config.py @@ -31,7 +31,7 @@ from pygal.graph.map import BaseMap from pygal.graph.horizontal import HorizontalGraph from pygal.graph.dual import Dual from pygal import formatters -from pygal._compat import u +from pygal._compat import u, _ellipsis from pygal.test.utils import texts from tempfile import NamedTemporaryFile @@ -337,6 +337,11 @@ def test_css(Chart): svg = chart.render().decode('utf-8') assert '#bedead' in svg + chart = Chart(css=(_ellipsis, 'file://' + f.name)) + chart.add('/', [10, 1, 5]) + svg = chart.render().decode('utf-8') + assert '#bedead' in svg + def test_inline_css(Chart): """Test inline css option""" diff --git a/pygal/util.py b/pygal/util.py index 94bb388..4bfcb2a 100644 --- a/pygal/util.py +++ b/pygal/util.py @@ -367,7 +367,20 @@ def coord_abs_project(center, rho, theta): def mergextend(list1, list2): - if _ellipsis not in list1: + if list1 is None or _ellipsis not in list1: return list1 index = list1.index(_ellipsis) return list(list1[:index]) + list(list2) + list(list1[index + 1:]) + + +def merge(dict1, dict2): + from pygal.config import CONFIG_ITEMS, Key + _list_items = [item.name for item in CONFIG_ITEMS if item.type == list] + for key, val in dict2.items(): + if isinstance(val, Key): + val = val.value + + if key in _list_items: + dict1[key] = mergextend(val, dict1.get(key, ())) + else: + dict1[key] = val