diff --git a/.gitignore b/.gitignore index d58e921..df1f2e0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ docs/_build build .env* .eggs +.pytest_cache diff --git a/.travis.yml b/.travis.yml index 1598964..0ec74c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python python: - 2.7 - - 3.3 - 3.4 - 3.5 - 3.6 diff --git a/Makefile b/Makefile index 6c0a02d..dd1b8d3 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ all: install lint check check-outdated install: test -d $(VENV) || virtualenv $(VENV) -p $(PYTHON_VERSION) - $(PIP) install --upgrade --no-cache --no-use-wheel pip setuptools -e .[test,docs] devcore + $(PIP) install --upgrade --no-cache --no-binary :all: pip setuptools -e .[test,docs] devcore clean: rm -fr $(VENV) diff --git a/pygal/config.py b/pygal/config.py index 9a6d2a3..69f12b8 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -29,7 +29,6 @@ callable = type(lambda: 1) class Key(object): - """ Represents a config parameter. @@ -44,8 +43,8 @@ class Key(object): _categories = [] def __init__( - self, default_value, type_, category, doc, - subdoc="", subtype=None): + self, default_value, type_, category, doc, subdoc="", subtype=None + ): """Create a configuration key""" self.value = default_value self.type = type_ @@ -69,10 +68,8 @@ class Key(object): Default: %r      %s%s """ % ( - self.type.__name__, - (' of %s' % self.subtype.__name__) if self.subtype else '', - self.value, - self.doc, + self.type.__name__, (' of %s' % self.subtype.__name__) + if self.subtype else '', self.value, self.doc, (' %s' % self.subdoc) if self.subdoc else '' ) @@ -107,9 +104,8 @@ class Key(object): return value elif self.type == list: return self.type( - map( - self.subtype, map( - lambda x: x.strip(), value.split(',')))) + map(self.subtype, map(lambda x: x.strip(), value.split(','))) + ) elif self.type == dict: rv = {} for pair in value.split(','): @@ -118,14 +114,13 @@ class Key(object): val = val.strip() try: rv[key] = self.subtype(val) - except: + except Exception: rv[key] = val return rv return self.type(value) class MetaConfig(type): - """Config metaclass. Used to get the key name and set it on the value.""" def __new__(mcs, classname, bases, classdict): @@ -137,8 +132,7 @@ class MetaConfig(type): 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. @@ -150,9 +144,8 @@ class BaseConfig(MetaConfig('ConfigBase', (object,), {})): """Can be instanciated with config kwargs""" for k in dir(self): v = getattr(self, k) - if (k not in self.__dict__ and not - k.startswith('_') and not - hasattr(v, '__call__')): + if (k not in self.__dict__ and not k.startswith('_') + and not hasattr(v, '__call__')): if isinstance(v, Key): if v.is_list and v.value is not None: v = list(v.value) @@ -170,9 +163,10 @@ class BaseConfig(MetaConfig('ConfigBase', (object,), {})): from pygal.util import merge dir_self_set = set(dir(self)) merge( - self.__dict__, dict([ - (k, v) for (k, v) in kwargs.items() - if not k.startswith('_') and k in dir_self_set])) + 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): """Export a JSON serializable dictionary of the config""" @@ -192,354 +186,355 @@ class BaseConfig(MetaConfig('ConfigBase', (object,), {})): class CommonConfig(BaseConfig): - """Class holding options used in both chart and serie configuration""" stroke = Key( - True, bool, "Look", - "Line dots (set it to false to get a scatter plot)") + True, bool, "Look", "Line dots (set it to false to get a scatter plot)" + ) show_dots = Key(True, bool, "Look", "Set to false to remove dots") show_only_major_dots = Key( False, bool, "Look", - "Set to true to show only major dots according to their majored label") + "Set to true to show only major dots according to their majored label" + ) dots_size = Key(2.5, float, "Look", "Radius of the dots") - fill = Key( - False, bool, "Look", "Fill areas under lines") + fill = Key(False, bool, "Look", "Fill areas under lines") - stroke_style = Key(None, dict, "Look", "Stroke style of serie element.", - "This is a dict which can contain a " - "'width', 'linejoin', 'linecap', 'dasharray' " - "and 'dashoffset'") + stroke_style = Key( + None, dict, "Look", "Stroke style of serie element.", + "This is a dict which can contain a " + "'width', 'linejoin', 'linecap', 'dasharray' " + "and 'dashoffset'" + ) rounded_bars = Key( None, int, "Look", - "Set this to the desired radius in px (for Bar-like charts)") + "Set this to the desired radius in px (for Bar-like charts)" + ) inner_radius = Key( - 0, float, "Look", "Piechart inner radius (donut), must be <.9") + 0, float, "Look", "Piechart inner radius (donut), must be <.9" + ) allow_interruptions = Key( - False, bool, "Look", "Break lines on None values") + False, bool, "Look", "Break lines on None values" + ) formatter = Key( None, callable, "Value", "A function to convert raw value to strings for this chart or serie", "Default to value_formatter in most charts, it depends on dual charts." - "(Can be overriden by value with the formatter metadata.)") + "(Can be overriden by value with the formatter metadata.)" + ) class Config(CommonConfig): - """Class holding config values""" style = Key( - DefaultStyle, Style, "Style", "Style holding values injected in css") + DefaultStyle, Style, "Style", "Style holding values injected in css" + ) css = Key( ('file://style.css', 'file://graph.css'), list, "Style", "List of css file", "It can be any uri from file:///tmp/style.css to //domain/style.css", - str) + str + ) - classes = Key( - ('pygal-chart',), - list, "Style", "Classes of the root svg node", - 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", - "Useful for adding gradients / patterns…", - str) + defs = Key([], list, "Misc", "Extraneous defs to be inserted in svg", + "Useful for adding gradients / patterns…", str) # Look # title = Key( - None, str, "Look", - "Graph title.", "Leave it to None to disable title.") + None, str, "Look", "Graph title.", "Leave it to None to disable title." + ) x_title = Key( - None, str, "Look", - "Graph X-Axis title.", "Leave it to None to disable X-Axis title.") + None, str, "Look", "Graph X-Axis title.", + "Leave it to None to disable X-Axis title." + ) y_title = Key( - None, str, "Look", - "Graph Y-Axis title.", "Leave it to None to disable Y-Axis title.") + None, str, "Look", "Graph Y-Axis title.", + "Leave it to None to disable Y-Axis title." + ) - width = Key( - 800, int, "Look", "Graph width") + width = Key(800, int, "Look", "Graph width") - height = Key( - 600, int, "Look", "Graph height") + height = Key(600, int, "Look", "Graph height") - show_x_guides = Key(False, bool, "Look", - "Set to true to always show x guide lines") + show_x_guides = Key( + False, bool, "Look", "Set to true to always show x guide lines" + ) - show_y_guides = Key(True, bool, "Look", - "Set to false to hide y guide lines") + show_y_guides = Key( + True, bool, "Look", "Set to false to hide y guide lines" + ) - show_legend = Key( - True, bool, "Look", "Set to false to remove legend") + show_legend = Key(True, bool, "Look", "Set to false to remove legend") legend_at_bottom = Key( - False, bool, "Look", "Set to true to position legend at bottom") + False, bool, "Look", "Set to true to position legend at bottom" + ) legend_at_bottom_columns = Key( - None, int, "Look", "Set to true to position legend at bottom") + None, int, "Look", "Set to true to position legend at bottom" + ) - legend_box_size = Key( - 12, int, "Look", "Size of legend boxes") + legend_box_size = Key(12, int, "Look", "Size of legend boxes") rounded_bars = Key( - None, int, "Look", "Set this to the desired radius in px") + None, int, "Look", "Set this to the desired radius in px" + ) stack_from_top = Key( False, bool, "Look", "Stack from top to zero, this makes the stacked " - "data match the legend order") + "data match the legend order" + ) - spacing = Key( - 10, int, "Look", - "Space between titles/legend/axes") + spacing = Key(10, int, "Look", "Space between titles/legend/axes") - margin = Key( - 20, int, "Look", - "Margin around chart") + margin = Key(20, int, "Look", "Margin around chart") - margin_top = Key( - None, int, "Look", - "Margin around top of chart") + margin_top = Key(None, int, "Look", "Margin around top of chart") - margin_right = Key( - None, int, "Look", - "Margin around right of chart") + margin_right = Key(None, int, "Look", "Margin around right of chart") - margin_bottom = Key( - None, int, "Look", - "Margin around bottom of chart") + margin_bottom = Key(None, int, "Look", "Margin around bottom of chart") - margin_left = Key( - None, int, "Look", - "Margin around left of chart") + margin_left = Key(None, int, "Look", "Margin around left of chart") tooltip_border_radius = Key(0, int, "Look", "Tooltip border radius") tooltip_fancy_mode = Key( True, bool, "Look", "Fancy tooltips", - "Print legend, x label in tooltip and use serie color for value.") + "Print legend, x label in tooltip and use serie color for value." + ) inner_radius = Key( - 0, float, "Look", "Piechart inner radius (donut), must be <.9") + 0, float, "Look", "Piechart inner radius (donut), must be <.9" + ) - half_pie = Key( - False, bool, "Look", "Create a half-pie chart") + half_pie = Key(False, bool, "Look", "Create a half-pie chart") x_labels = Key( - None, list, "Label", - "X labels, must have same len than data.", - "Leave it to None to disable x labels display.", - str) + None, list, "Label", "X labels, must have same len than data.", + "Leave it to None to disable x labels display.", str + ) x_labels_major = Key( - None, list, "Label", + None, + list, + "Label", "X labels that will be marked major.", - subtype=str) + subtype=str + ) x_labels_major_every = Key( - None, int, "Label", - "Mark every n-th x label as major.") + None, int, "Label", "Mark every n-th x label as major." + ) x_labels_major_count = Key( - None, int, "Label", - "Mark n evenly distributed labels as major.") + None, int, "Label", "Mark n evenly distributed labels as major." + ) - show_x_labels = Key( - True, bool, "Label", "Set to false to hide x-labels") + show_x_labels = Key(True, bool, "Label", "Set to false to hide x-labels") show_minor_x_labels = Key( - True, bool, "Label", "Set to false to hide x-labels not marked major") + True, bool, "Label", "Set to false to hide x-labels not marked major" + ) y_labels = Key( - None, list, "Label", - "You can specify explicit y labels", - "Must be a list of numbers", float) + None, list, "Label", "You can specify explicit y labels", + "Must be a list of numbers", float + ) y_labels_major = Key( - None, list, "Label", + None, + list, + "Label", "Y labels that will be marked major. Default: auto", - subtype=str) + subtype=str + ) y_labels_major_every = Key( - None, int, "Label", - "Mark every n-th y label as major.") + None, int, "Label", "Mark every n-th y label as major." + ) y_labels_major_count = Key( - None, int, "Label", - "Mark n evenly distributed y labels as major.") + None, int, "Label", "Mark n evenly distributed y labels as major." + ) show_minor_y_labels = Key( - True, bool, "Label", "Set to false to hide y-labels not marked major") + True, bool, "Label", "Set to false to hide y-labels not marked major" + ) - show_y_labels = Key( - True, bool, "Label", "Set to false to hide y-labels") + show_y_labels = Key(True, bool, "Label", "Set to false to hide y-labels") x_label_rotation = Key( - 0, int, "Label", "Specify x labels rotation angles", "in degrees") + 0, int, "Label", "Specify x labels rotation angles", "in degrees" + ) y_label_rotation = Key( - 0, int, "Label", "Specify y labels rotation angles", "in degrees") + 0, int, "Label", "Specify y labels rotation angles", "in degrees" + ) missing_value_fill_truncation = Key( "x", str, "Look", "Filled series with missing x and/or y values at the end of a series " "are closed at the first value with a missing " - "'x' (default), 'y' or 'either'") + "'x' (default), 'y' or 'either'" + ) # Value # x_value_formatter = Key( formatters.default, callable, "Value", "A function to convert abscissa numeric value to strings " - "(used in XY and Date charts)") + "(used in XY and Date charts)" + ) value_formatter = Key( formatters.default, callable, "Value", - "A function to convert ordinate numeric value to strings") + "A function to convert ordinate numeric value to strings" + ) logarithmic = Key( - False, bool, "Value", "Display values in logarithmic scale") + False, bool, "Value", "Display values in logarithmic scale" + ) interpolate = Key( None, str, "Value", "Interpolation", - "May be %s" % ' or '.join(INTERPOLATIONS)) + "May be %s" % ' or '.join(INTERPOLATIONS) + ) interpolation_precision = Key( - 250, int, "Value", "Number of interpolated points between two values") + 250, int, "Value", "Number of interpolated points between two values" + ) interpolation_parameters = Key( {}, dict, "Value", "Various parameters for parametric interpolations", "ie: For hermite interpolation, you can set the cardinal tension with" - "{'type': 'cardinal', 'c': .5}", int) + "{'type': 'cardinal', 'c': .5}", int + ) box_mode = Key( 'extremes', str, "Value", "Sets the mode to be used. " - "(Currently only supported on box plot)", - "May be %s" % ' or '.join([ - "1.5IQR", "extremes", "tukey", "stdev", "pstdev"])) + "(Currently only supported on box plot)", "May be %s" % + ' or '.join(["1.5IQR", "extremes", "tukey", "stdev", "pstdev"]) + ) order_min = Key( - None, int, "Value", - "Minimum order of scale, defaults to None") + None, int, "Value", "Minimum order of scale, defaults to None" + ) min_scale = Key( - 4, int, "Value", - "Minimum number of scale graduation for auto scaling") + 4, int, "Value", "Minimum number of scale graduation for auto scaling" + ) max_scale = Key( - 16, int, "Value", - "Maximum number of scale graduation for auto scaling") + 16, int, "Value", "Maximum number of scale graduation for auto scaling" + ) range = Key( None, list, "Value", "Explicitly specify min and max of values", - "(ie: (0, 100))", int) + "(ie: (0, 100))", int + ) secondary_range = Key( None, list, "Value", - "Explicitly specify min and max of secondary values", - "(ie: (0, 100))", int) + "Explicitly specify min and max of secondary values", "(ie: (0, 100))", + int + ) xrange = Key( None, list, "Value", "Explicitly specify min and max of x values " - "(used in XY and Date charts)", - "(ie: (0, 100))", int) + "(used in XY and Date charts)", "(ie: (0, 100))", int + ) - include_x_axis = Key( - False, bool, "Value", "Always include x axis") + include_x_axis = Key(False, bool, "Value", "Always include x axis") zero = Key( - 0, int, "Value", - "Set the ordinate zero value", - "Useful for filling to another base than abscissa") + 0, int, "Value", "Set the ordinate zero value", + "Useful for filling to another base than abscissa" + ) # Text # no_data_text = Key( - "No data", str, "Text", "Text to display when no data is given") + "No data", str, "Text", "Text to display when no data is given" + ) - print_values = Key( - False, bool, - "Text", "Display values as text over plot") + print_values = Key(False, bool, "Text", "Display values as text over plot") dynamic_print_values = Key( - False, bool, - "Text", "Show values only on hover") + False, bool, "Text", "Show values only on hover" + ) print_values_position = Key( - 'center', str, - "Text", "Customize position of `print_values`. " - "(For bars: `top`, `center` or `bottom`)") + 'center', str, "Text", "Customize position of `print_values`. " + "(For bars: `top`, `center` or `bottom`)" + ) - print_zeroes = Key( - True, bool, - "Text", "Display zero values as well") + print_zeroes = Key(True, bool, "Text", "Display zero values as well") - print_labels = Key( - False, bool, - "Text", "Display value labels") + print_labels = Key(False, bool, "Text", "Display value labels") truncate_legend = Key( - None, int, "Text", - "Legend string length truncation threshold", - "None = auto, Negative for none") + None, int, "Text", "Legend string length truncation threshold", + "None = auto, Negative for none" + ) truncate_label = Key( - None, int, "Text", - "Label string length truncation threshold", - "None = auto, Negative for none") + None, int, "Text", "Label string length truncation threshold", + "None = auto, Negative for none" + ) # Misc # - js = Key( - ('//kozea.github.io/pygal.js/2.0.x/pygal-tooltips.min.js',), - list, "Misc", "List of js file", - "It can be any uri from file:///tmp/ext.js to //domain/ext.js", - str) + js = Key(('//kozea.github.io/pygal.js/2.0.x/pygal-tooltips.min.js', ), + list, "Misc", "List of js file", + "It can be any uri from file:///tmp/ext.js to //domain/ext.js", + str) disable_xml_declaration = Key( False, bool, "Misc", "Don't write xml declaration and return str instead of string", - "useful for writing output directly in html") + "useful for writing output directly in html" + ) force_uri_protocol = Key( - 'https', str, "Misc", - "Default uri protocol", + 'https', str, "Misc", "Default uri protocol", "Default protocol for external files. " - "Can be set to None to use a // uri") + "Can be set to None to use a // uri" + ) explicit_size = Key( - False, bool, "Misc", "Write width and height attributes") + False, bool, "Misc", "Write width and height attributes" + ) - pretty_print = Key( - False, bool, "Misc", "Pretty print the svg") + pretty_print = Key(False, bool, "Misc", "Pretty print the svg") strict = Key( - False, bool, "Misc", - "If True don't try to adapt / filter wrong values") + False, bool, "Misc", "If True don't try to adapt / filter wrong values" + ) - no_prefix = Key( - False, bool, "Misc", - "Don't prefix css") + no_prefix = Key(False, bool, "Misc", "Don't prefix css") inverse_y_axis = Key(False, bool, "Misc", "Inverse Y axis direction") class SerieConfig(CommonConfig): - """Class holding serie config values""" title = Key( - None, str, "Look", - "Serie title.", "Leave it to None to disable title.") + None, str, "Look", "Serie title.", "Leave it to None to disable title." + ) secondary = Key( - False, bool, "Misc", - "Set it to put the serie in a second axis") + False, bool, "Misc", "Set it to put the serie in a second axis" + ) diff --git a/pygal/svg.py b/pygal/svg.py index d72c1e6..1a1b69b 100644 --- a/pygal/svg.py +++ b/pygal/svg.py @@ -494,5 +494,6 @@ class Svg(object): for secondary_serie in self.graph.secondary_series: if secondary_serie.stroke_style is not None: - css.append(stroke_dict_to_css(secondary_serie.stroke_style, secondary_serie.index)) + css.append(stroke_dict_to_css( + secondary_serie.stroke_style, secondary_serie.index)) return '\n'.join(css) diff --git a/setup.cfg b/setup.cfg index 40a8157..52c54d1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,7 +3,7 @@ universal = 1 [pytest] flake8-ignore = - *.py E731 E402 + *.py E731 E402 E741 pygal/__init__.py F401 pygal/_compat.py F821 F401 docs/conf.py ALL