Browse Source

Add classes option. Handle ellipsis in list type configs to auto-extend parent.

pull/317/head
Florian Mounier 9 years ago
parent
commit
9ae5f3e6a5
  1. 7
      docs/changelog.rst
  2. 2
      pygal/__init__.py
  3. 7
      pygal/_compat.py
  4. 13
      pygal/config.py
  5. 5
      pygal/svg.py
  6. 24
      pygal/test/test_config.py
  7. 23
      pygal/test/test_util.py
  8. 9
      pygal/util.py

7
docs/changelog.rst

@ -2,6 +2,13 @@
Changelog
=========
2.2.2
=====
* Add classes option.
* Handle ellipsis in list type configs to auto-extend parent. (Viva python3)
2.2.0
=====

2
pygal/__init__.py

@ -24,7 +24,7 @@ and the maps extensions namespace module.
"""
__version__ = '2.2.1'
__version__ = '2.2.2'
import pkg_resources
import sys

7
pygal/_compat.py

@ -27,10 +27,17 @@ from datetime import datetime, timedelta, tzinfo
if sys.version_info[0] == 3:
base = (str, bytes)
coerce = str
_ellipsis = eval('...')
else:
base = basestring
coerce = unicode
class EllipsisGetter(object):
def __getitem__(self, key):
return key
_ellipsis = EllipsisGetter()[...]
def is_list_like(value):
"""Return whether value is an iterable but not a mapping / string"""

13
pygal/config.py

@ -22,6 +22,7 @@ from copy import deepcopy
from pygal.interpolate import INTERPOLATIONS
from pygal.style import DefaultStyle, Style
from pygal.util import mergextend
from pygal import formatters
@ -170,8 +171,11 @@ class BaseConfig(MetaConfig('ConfigBase', (object,), {})):
"""Update the config with the given dictionary"""
dir_self_set = set(dir(self))
self.__dict__.update(
dict([(k, v) for (k, v) in kwargs.items()
if not k.startswith('_') and k in dir_self_set]))
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()
if not k.startswith('_') and k in dir_self_set]))
def to_dict(self):
"""Export a JSON serializable dictionary of the config"""
@ -244,6 +248,11 @@ class Config(CommonConfig):
"It can be any uri from file:///tmp/style.css to //domain/style.css",
str)
classes = Key(
('pygal-chart',),
list, "Style", "Classes of the root svg node",
str)
defs = Key(
[],
list, "Misc", "Extraneous defs to be inserted in svg",

5
pygal/svg.py

@ -68,10 +68,11 @@ class Svg(object):
self.root = etree.Element('svg', **attrs)
self.root.attrib['id'] = self.id.lstrip('#').rstrip()
self.root.attrib['class'] = 'pygal-chart'
if graph.classes:
self.root.attrib['class'] = ' '.join(graph.classes)
self.root.append(
etree.Comment(u(
'Generated with pygal %s (%s) ©Kozea 2011-2015 on %s' % (
'Generated with pygal %s (%s) ©Kozea 2011-2016 on %s' % (
__version__,
'lxml' if etree.lxml else 'etree',
date.today().isoformat()))))

24
pygal/test/test_config.py

@ -542,3 +542,27 @@ def test_formatters(Chart):
assert set([v.text for v in q(".value")]) == set((
u('4€'), u('5€'), u('6€'), '1_a$', '2_a$', u('3¥')) + (
('6_a$', u('15€')) if Chart in (Pie, SolidGauge) else ()))
def test_classes(Chart):
"""Test classes option"""
chart = Chart()
assert chart.render_pyquery().attr('class') == 'pygal-chart'
chart = Chart(classes=())
assert not chart.render_pyquery().attr('class')
chart = Chart(classes=(...,))
assert chart.render_pyquery().attr('class') == 'pygal-chart'
chart = Chart(classes=('graph',))
assert chart.render_pyquery().attr('class') == 'graph'
chart = Chart(classes=('pygal-chart', 'graph'))
assert chart.render_pyquery().attr('class') == 'pygal-chart graph'
chart = Chart(classes=(..., 'graph'))
assert chart.render_pyquery().attr('class') == 'pygal-chart graph'
chart = Chart(classes=('graph', ...))
assert chart.render_pyquery().attr('class') == 'graph pygal-chart'

23
pygal/test/test_util.py

@ -19,11 +19,12 @@
"""Utility functions tests"""
from pygal._compat import u
from pygal._compat import u, _ellipsis
from pygal.util import (
round_to_int, round_to_float, _swap_curly, template,
truncate, minify_css, majorize)
truncate, minify_css, majorize, mergextend)
from pytest import raises
import sys
def test_round_to_int():
@ -153,3 +154,21 @@ def test_majorize():
assert majorize(range(21, 83, 3)) == [30, 45, 60, 75]
# TODO: handle crazy cases
# assert majorize(range(20, 83, 3)) == [20, 35, 50, 65, 80]
def test_mergextend():
"""Test mergextend function"""
assert mergextend(['a', 'b'], ['c', 'd']) == ['a', 'b']
assert mergextend([], ['c', 'd']) == []
assert mergextend(['a', 'b'], []) == ['a', 'b']
assert mergextend([_ellipsis], ['c', 'd']) == ['c', 'd']
assert mergextend([_ellipsis, 'b'], ['c', 'd']) == ['c', 'd', 'b']
assert mergextend(['a', _ellipsis], ['c', 'd']) == ['a', 'c', 'd']
assert mergextend(['a', _ellipsis, 'b'], ['c', 'd']) == [
'a', 'c', 'd', 'b']
if sys.version_info[0] >= 3:
# For @#! sake it's 2016 now
assert eval("mergextend(['a', ..., 'b'], ['c', 'd'])") == [
'a', 'c', 'd', 'b']

9
pygal/util.py

@ -26,7 +26,7 @@ from decimal import Decimal
from math import ceil, floor, log10, pi, cos, sin
from pygal._compat import to_unicode, u
from pygal._compat import to_unicode, u, _ellipsis
def float_format(number):
@ -364,3 +364,10 @@ def coord_dual(r):
def coord_abs_project(center, rho, theta):
return coord_format(coord_diff(center, coord_project(rho, theta)))
def mergextend(list1, list2):
if _ellipsis not in list1:
return list1
index = list1.index(_ellipsis)
return list(list1[:index]) + list(list2) + list(list1[index + 1:])

Loading…
Cancel
Save