Browse Source

Add some docstring and repr the config key with their doc

pull/242/head
Florian Mounier 9 years ago
parent
commit
37697fe0e5
  1. 15
      pygal/__init__.py
  2. 20
      pygal/colors.py
  3. 46
      pygal/config.py

15
pygal/__init__.py

@ -17,7 +17,10 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # along with pygal. If not, see <http://www.gnu.org/licenses/>.
""" """
Pygal - A python svg graph plotting library Main pygal package
This package holds all available charts in pygal, the Config class
and the maps extensions namespace module.
""" """
@ -73,16 +76,26 @@ CHARTS = list(CHARTS_BY_NAME.values())
class PluginImportFixer(object): class PluginImportFixer(object):
"""Allow external map plugins to be imported from pygal.maps package.
It is a ``sys.meta_path`` loader.
"""
def __init__(self): def __init__(self):
pass pass
def find_module(self, fullname, path=None): def find_module(self, fullname, path=None):
"""This method says if the module to load can be loaded by
the load_module function, that is here if it is a ``pygal.maps.*``
module.
"""
if fullname.startswith('pygal.maps.') and hasattr( if fullname.startswith('pygal.maps.') and hasattr(
maps, fullname.split('.')[2]): maps, fullname.split('.')[2]):
return self return self
return None return None
def load_module(self, name): def load_module(self, name):
"""Loads the ``pygal.maps.name`` module from
the previously loaded plugin"""
if name not in sys.modules: if name not in sys.modules:
sys.modules[name] = getattr(maps, name.split('.')[2]) sys.modules[name] = getattr(maps, name.split('.')[2])
return sys.modules[name] return sys.modules[name]

20
pygal/colors.py

@ -17,19 +17,23 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # along with pygal. If not, see <http://www.gnu.org/licenses/>.
""" """
Color utils This package is an utility package oriented on color alteration.
This is used by the :py:mod:`pygal.style` package to generate
parametric styles.
""" """
from __future__ import division from __future__ import division
def normalize_float(f): def normalize_float(f):
"""Round float errors"""
if abs(f - round(f)) < .0000000000001: if abs(f - round(f)) < .0000000000001:
return round(f) return round(f)
return f return f
def rgb_to_hsl(r, g, b): def rgb_to_hsl(r, g, b):
"""Convert a color in r, g, b to a color in h, s, l"""
r /= 255 r /= 255
g /= 255 g /= 255
b /= 255 b /= 255
@ -57,6 +61,7 @@ def rgb_to_hsl(r, g, b):
def hsl_to_rgb(h, s, l): def hsl_to_rgb(h, s, l):
"""Convert a color in h, s, l to a color in r, g, b"""
h /= 360 h /= 360
s /= 100 s /= 100
l /= 100 l /= 100
@ -80,6 +85,10 @@ def hsl_to_rgb(h, s, l):
def parse_color(color): def parse_color(color):
"""Take any css color definition and give back a tuple containing the
r, g, b, a values along with a type which can be: #rgb, #rgba, #rrggbb,
#rrggbbaa, rgb, rgba
"""
r = g = b = a = type = None r = g = b = a = type = None
if color.startswith('#'): if color.startswith('#'):
color = color[1:] color = color[1:]
@ -110,6 +119,9 @@ def parse_color(color):
def unparse_color(r, g, b, a, type): def unparse_color(r, g, b, a, type):
"""Take the r, g, b, a color values and give back
a type css color string. This is the inverse function of parse_color"""
if type == '#rgb': if type == '#rgb':
# Don't lose precision on rgb shortcut # Don't lose precision on rgb shortcut
if r % 17 == 0 and g % 17 == 0 and b % 17 == 0: if r % 17 == 0 and g % 17 == 0 and b % 17 == 0:
@ -148,26 +160,32 @@ def _adjust(hsl, attribute, percent):
def adjust(color, attribute, percent): def adjust(color, attribute, percent):
"""Adjust an attribute of color by a percent"""
r, g, b, a, type = parse_color(color) r, g, b, a, type = parse_color(color)
r, g, b = hsl_to_rgb(*_adjust(rgb_to_hsl(r, g, b), attribute, percent)) r, g, b = hsl_to_rgb(*_adjust(rgb_to_hsl(r, g, b), attribute, percent))
return unparse_color(r, g, b, a, type) return unparse_color(r, g, b, a, type)
def rotate(color, percent): def rotate(color, percent):
"""Rotates a color by changing its hue value by percent"""
return adjust(color, 0, percent) return adjust(color, 0, percent)
def saturate(color, percent): def saturate(color, percent):
"""Saturate a color by increasing its saturation by percent"""
return adjust(color, 1, percent) return adjust(color, 1, percent)
def desaturate(color, percent): def desaturate(color, percent):
"""Desaturate a color by decreasing its saturation by percent"""
return adjust(color, 1, -percent) return adjust(color, 1, -percent)
def lighten(color, percent): def lighten(color, percent):
"""Lighten a color by increasing its lightness by percent"""
return adjust(color, 2, percent) return adjust(color, 2, percent)
def darken(color, percent): def darken(color, percent):
"""Darken a color by decreasing its lightness by percent"""
return adjust(color, 2, -percent) return adjust(color, 2, -percent)

46
pygal/config.py

@ -18,7 +18,7 @@
# along with pygal. If not, see <http://www.gnu.org/licenses/>. # along with pygal. If not, see <http://www.gnu.org/licenses/>.
""" """
Config module with all options Config module holding all options and their default values.
""" """
from copy import deepcopy from copy import deepcopy
from pygal.style import Style, DefaultStyle from pygal.style import Style, DefaultStyle
@ -29,6 +29,16 @@ CONFIG_ITEMS = []
class Key(object): class Key(object):
"""
Represents a config parameter.
A config parameter has a name, a default value, a type,
a category, a documentation, an optional longer documentatation
and an optional subtype for list style option.
Most of these informations are used in cabaret to auto generate
forms representing these options.
"""
_categories = [] _categories = []
@ -48,27 +58,46 @@ class Key(object):
CONFIG_ITEMS.append(self) CONFIG_ITEMS.append(self)
def __repr__(self):
return """
Type: %s%s     
Default: %r     
%s%s
""" % (
self.type.__name__,
(' of %s' % self.subtype.__name__) if self.subtype else '',
self.value,
self.doc,
(' %s' % self.subdoc) if self.subdoc else ''
)
@property @property
def is_boolean(self): def is_boolean(self):
"""Return `True` if this parameter is a boolean"""
return self.type == bool return self.type == bool
@property @property
def is_numeric(self): def is_numeric(self):
"""Return `True` if this parameter is numeric (int or float)"""
return self.type in (int, float) return self.type in (int, float)
@property @property
def is_string(self): def is_string(self):
"""Return `True` if this parameter is a string"""
return self.type == str return self.type == str
@property @property
def is_dict(self): def is_dict(self):
"""Return `True` if this parameter is a mapping"""
return self.type == dict return self.type == dict
@property @property
def is_list(self): def is_list(self):
"""Return `True` if this parameter is a list"""
return self.type == list return self.type == list
def coerce(self, value): def coerce(self, value):
"""Cast a string into this key type"""
if self.type == Style: if self.type == Style:
return value return value
elif self.type == list: elif self.type == list:
@ -91,14 +120,24 @@ class Key(object):
class MetaConfig(type): class MetaConfig(type):
"""
Metaclass for configs. Used to get the key name and set it on the value.
"""
def __new__(mcs, classname, bases, classdict): def __new__(mcs, classname, bases, classdict):
for k, v in classdict.items(): for k, v in classdict.items():
if isinstance(v, Key): if isinstance(v, Key):
v.name = k v.name = k
return type.__new__(mcs, classname, bases, classdict) return type.__new__(mcs, classname, bases, classdict)
class BaseConfig(MetaConfig('ConfigBase', (object,), {})): class BaseConfig(MetaConfig('ConfigBase', (object,), {})):
"""
This class holds the common method for configs.
A config object can be instanciated with keyword arguments and
updated on call with keyword arguments.
"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
"""Can be instanciated with config kwargs""" """Can be instanciated with config kwargs"""
@ -120,11 +159,13 @@ class BaseConfig(MetaConfig('ConfigBase', (object,), {})):
self._update(kwargs) self._update(kwargs)
def _update(self, kwargs): def _update(self, kwargs):
"""Updates the config with the given dictionary"""
self.__dict__.update( self.__dict__.update(
dict([(k, v) for (k, v) in kwargs.items() dict([(k, v) for (k, v) in kwargs.items()
if not k.startswith('_') and k in dir(self)])) if not k.startswith('_') and k in dir(self)]))
def to_dict(self): def to_dict(self):
"""Export a JSON serializable dictionary of the config"""
config = {} config = {}
for attr in dir(self): for attr in dir(self):
if not attr.startswith('__'): if not attr.startswith('__'):
@ -136,10 +177,13 @@ class BaseConfig(MetaConfig('ConfigBase', (object,), {})):
return config return config
def copy(self): def copy(self):
"""Copy this config object into another"""
return deepcopy(self) return deepcopy(self)
class CommonConfig(BaseConfig): class CommonConfig(BaseConfig):
"""Class holding options used in both chart and serie configuration"""
stroke = Key( stroke = Key(
True, bool, "Look", True, bool, "Look",
"Line dots (set it to false to get a scatter plot)") "Line dots (set it to false to get a scatter plot)")

Loading…
Cancel
Save