diff --git a/dash/_utils.py b/dash/_utils.py index 340abd6c79..edc5c20f52 100644 --- a/dash/_utils.py +++ b/dash/_utils.py @@ -27,6 +27,7 @@ def __getattr__(self, key): # to conform with __getattr__ spec raise AttributeError(key) + # pylint: disable=inconsistent-return-statements def first(self, *names): for name in names: value = self.get(name) diff --git a/dash/dash.py b/dash/dash.py index 07477f2825..71f7d5ec54 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -4,8 +4,8 @@ import pkgutil import warnings from flask import Flask, Response -from flask_compress import Compress import flask +from flask_compress import Compress import plotly import dash_renderer @@ -17,16 +17,17 @@ from ._utils import AttributeDict as _AttributeDict +# pylint: disable=too-many-instance-attributes class Dash(object): def __init__( - self, - name=None, - server=None, - static_folder=None, - url_base_pathname='/', - **kwargs - ): - + self, + name=None, + server=None, + static_folder=None, + url_base_pathname='/', + **kwargs): + + # pylint-disable: too-many-instance-attributes if 'csrf_protect' in kwargs: warnings.warn(''' `csrf_protect` is no longer used, @@ -58,12 +59,13 @@ def __init__( self.registered_paths = {} # urls - def add_url(name, view_func, methods=['GET']): + + def add_url(name, view_func, methods=('GET',)): self.server.add_url_rule( name, view_func=view_func, endpoint=name, - methods=methods + methods=list(methods) ) add_url( @@ -77,8 +79,7 @@ def add_url(name, view_func, methods=['GET']): add_url( '{}_dash-update-component'.format( - self.config['routes_pathname_prefix'] - ), + self.config['routes_pathname_prefix']), self.dispatch, ['POST']) @@ -86,9 +87,8 @@ def add_url(name, view_func, methods=['GET']): '{}_dash-component-suites' '/' '/').format( - self.config['routes_pathname_prefix'] - ), - self.serve_component_suites) + self.config['routes_pathname_prefix']), + self.serve_component_suites) add_url( '{}_dash-routes'.format(self.config['routes_pathname_prefix']), @@ -133,6 +133,7 @@ def layout(self, value): self._layout = value layout_value = self._layout_value() + # pylint: disable=protected-access self.css._update_layout(layout_value) self.scripts._update_layout(layout_value) self._collect_and_register_resources( @@ -223,6 +224,7 @@ def _generate_scripts_html(self): # scripts have rendered. # The rest of the scripts can just be loaded after React but before # dash renderer. + # pylint: disable=protected-access srcs = self._collect_and_register_resources( self.scripts._resources._filter_resources( dash_renderer._js_dist_dependencies @@ -275,7 +277,7 @@ def serve_component_suites(self, package_name, path_in_package_dist): mimetype=mimetype ) - def index(self, *args, **kwargs): + def index(self): scripts = self._generate_scripts_html() css = self._generate_css_dist_html() config = self._generate_config_html() @@ -315,6 +317,7 @@ def dependencies(self): } for k, v in list(self.callback_map.items()) ]) + # pylint: disable=unused-argument, no-self-use def react(self, *args, **kwargs): raise exceptions.DashException( 'Yo! `react` is no longer used. \n' @@ -322,6 +325,7 @@ def react(self, *args, **kwargs): 'so make sure to call `help(app.callback)` to learn more.') def _validate_callback(self, output, inputs, state, events): + # pylint: disable=too-many-branches layout = self._cached_layout or self._layout_value() if (layout is None and @@ -337,10 +341,10 @@ def _validate_callback(self, output, inputs, state, events): `app.config['suppress_callback_exceptions']=True` '''.replace(' ', '')) - for args, object, name in [([output], Output, 'Output'), - (inputs, Input, 'Input'), - (state, State, 'State'), - (events, Event, 'Event')]: + for args, obj, name in [([output], Output, 'Output'), + (inputs, Input, 'Input'), + (state, State, 'State'), + (events, Event, 'Event')]: if not isinstance(args, list): raise exceptions.IncorrectTypeException( @@ -350,7 +354,7 @@ def _validate_callback(self, output, inputs, state, events): )) for arg in args: - if not isinstance(arg, object): + if not isinstance(arg, obj): raise exceptions.IncorrectTypeException( 'The {} argument `{}` is ' 'not of type `dash.{}`.'.format( @@ -402,8 +406,8 @@ def _validate_callback(self, output, inputs, state, events): arg.component_id, arg.component_property, arg.component_id, - component.available_properties - ).replace(' ', '')) + component.available_properties)\ + .replace(' ', '')) if (hasattr(arg, 'component_event') and arg.component_event not in @@ -418,10 +422,10 @@ def _validate_callback(self, output, inputs, state, events): arg.component_id, arg.component_event, arg.component_id, - component.available_events - ).replace(' ', '')) + component.available_events)\ + .replace(' ', '')) - if len(state) > 0 and len(events) == 0 and len(inputs) == 0: + if state and not events and not inputs: raise exceptions.MissingEventsException(''' This callback has {} `State` {} but no `Input` elements or `Event` elements.\n @@ -466,6 +470,7 @@ def _validate_callback(self, output, inputs, state, events): # the dropdown. # TODO - Check this map for recursive or other ill-defined non-tree # relationships + # pylint: disable=dangerous-default-value def callback(self, output, inputs=[], state=[], events=[]): self._validate_callback(output, inputs, state, events) diff --git a/dash/dependencies.py b/dash/dependencies.py index decaad3ae0..825dbf964c 100644 --- a/dash/dependencies.py +++ b/dash/dependencies.py @@ -1,21 +1,22 @@ +# pylint: disable=old-style-class, too-few-public-methods class Output: def __init__(self, component_id, component_property): self.component_id = component_id self.component_property = component_property - +# pylint: disable=old-style-class, too-few-public-methods class Input: def __init__(self, component_id, component_property): self.component_id = component_id self.component_property = component_property - +# pylint: disable=old-style-class, too-few-public-methods class State: def __init__(self, component_id, component_property): self.component_id = component_id self.component_property = component_property - +# pylint: disable=old-style-class, too-few-public-methods class Event: def __init__(self, component_id, component_event): self.component_id = component_id diff --git a/dash/development/base_component.py b/dash/development/base_component.py index 6f4aff9a34..5d875bafc1 100644 --- a/dash/development/base_component.py +++ b/dash/development/base_component.py @@ -10,15 +10,24 @@ def is_number(s): return False +def _check_if_has_indexable_children(item): + if (not hasattr(item, 'children') or + (not isinstance(item.children, Component) and + not isinstance(item.children, collections.MutableSequence))): + + raise KeyError + + class Component(collections.MutableMapping): def __init__(self, **kwargs): + # pylint: disable=super-init-not-called for k, v in list(kwargs.items()): - if k not in self._prop_names: + if k not in self._prop_names: # pylint: disable=no-member # TODO - What's the right exception here? raise Exception( 'Unexpected keyword argument `{}`'.format(k) + '\nAllowed arguments: {}'.format( - ', '.join(sorted(self._prop_names)) + ', '.join(sorted(self._prop_names)) # pylint: disable=no-member ) ) setattr(self, k, v) @@ -26,24 +35,20 @@ def __init__(self, **kwargs): def to_plotly_json(self): as_json = { 'props': {p: getattr(self, p) - for p in self._prop_names + for p in self._prop_names # pylint: disable=no-member if hasattr(self, p)}, - 'type': self._type, - 'namespace': self._namespace + 'type': self._type, # pylint: disable=no-member + 'namespace': self._namespace # pylint: disable=no-member } return as_json - def _check_if_has_indexable_children(self, item): - if (not hasattr(item, 'children') or - (not isinstance(item.children, Component) and - not isinstance(item.children, collections.MutableSequence))): - - raise KeyError + # pylint: disable=too-many-branches, too-many-return-statements, redefined-builtin, inconsistent-return-statements def _get_set_or_delete(self, id, operation, new_item=None): - self._check_if_has_indexable_children(self) + _check_if_has_indexable_children(self) + # pylint: disable=access-member-before-definition, attribute-defined-outside-init if isinstance(self.children, Component): if getattr(self.children, 'id', None) is not None: # Woohoo! It's the item that we're looking for @@ -110,7 +115,7 @@ def _get_set_or_delete(self, id, operation, new_item=None): # - __iter__ # - __len__ - def __getitem__(self, id): + def __getitem__(self, id): # pylint: disable=redefined-builtin """Recursively find the element with the given ID through the tree of children. """ @@ -119,11 +124,11 @@ def __getitem__(self, id): # or a list of components. return self._get_set_or_delete(id, 'get') - def __setitem__(self, id, item): + def __setitem__(self, id, item): # pylint: disable=redefined-builtin """Set an element by its ID.""" return self._get_set_or_delete(id, 'set', item) - def __delitem__(self, id): + def __delitem__(self, id): # pylint: disable=redefined-builtin """Delete items by ID in the tree of children.""" return self._get_set_or_delete(id, 'delete') @@ -139,7 +144,7 @@ def traverse(self): # children is a list of components elif isinstance(children, collections.MutableSequence): - for i in children: + for i in children: # pylint: disable=not-an-iterable yield i if isinstance(i, Component): @@ -177,7 +182,7 @@ def __len__(self): return length -def generate_class(typename, props, description, namespace): +def generate_class(typename, props, description, namespace): # pylint: disable=unused-argument # Dynamically generate classes to have nicely formatted docstrings, # keyword arguments, and repr # Insired by http://jameso.be/2013/08/06/namedtuple.html @@ -229,28 +234,28 @@ def __repr__(self): repr(getattr(self, self._prop_names[0], None)) + ')') ''' - filtered_props = reorder_props(filter_props(props)) - list_of_valid_keys = repr(list(filtered_props.keys())) - docstring = create_docstring( + filtered_props = reorder_props(filter_props(props)) # pylint: disable=unused-variable + list_of_valid_keys = repr(list(filtered_props.keys())) # pylint: disable=unused-variable + docstring = create_docstring( # pylint: disable=unused-variable typename, filtered_props, parse_events(props), description ) - events = '[' + ', '.join(parse_events(props)) + ']' + events = '[' + ', '.join(parse_events(props)) + ']' # pylint: disable=unused-variable if 'children' in props: - default_argtext = 'children=None, **kwargs' - argtext = 'children=children, **kwargs' + default_argtext = 'children=None, **kwargs' # pylint: disable=unused-variable + argtext = 'children=children, **kwargs' # pylint: disable=unused-variable else: - default_argtext = '**kwargs' - argtext = '**kwargs' + default_argtext = '**kwargs' # pylint: disable=unused-variable + argtext = '**kwargs' # pylint: disable=unused-variable - required_args = required_props(props) + required_args = required_props(props) # pylint: disable=unused-variable d = c.format(**locals()) scope = {'Component': Component} - exec(d, scope) + exec(d, scope) # pylint: disable=exec-used result = scope[typename] return result @@ -350,7 +355,7 @@ def js_to_py_type(type_object): ])), # React's PropTypes.arrayOf - 'arrayOf': lambda: 'list'.format( + 'arrayOf': lambda: 'list'.format( # pylint: disable=too-many-format-args 'of {}s'.format(js_to_py_type(type_object['value'])) if js_to_py_type(type_object['value']) != '' else '' @@ -387,8 +392,7 @@ def js_to_py_type(type_object): return '' if js_type_name in js_to_py_types: return js_to_py_types[js_type_name]() - else: - return '' + return '' def argument_doc(arg_name, type_object, required, description): @@ -404,12 +408,11 @@ def argument_doc(arg_name, type_object, required, description): is_required='required' if required else 'optional' ) - else: - return '{name} ({type}{is_required}){description}'.format( - name=arg_name, - type='{}; '.format(py_type_name) if py_type_name else '', - description=( - ': {}'.format(description) if description != '' else '' - ), - is_required='required' if required else 'optional' - ) + return '{name} ({type}{is_required}){description}'.format( + name=arg_name, + type='{}; '.format(py_type_name) if py_type_name else '', + description=( + ': {}'.format(description) if description != '' else '' + ), + is_required='required' if required else 'optional' + ) diff --git a/dash/resources.py b/dash/resources.py index 108cfce64f..c08c0bad3f 100644 --- a/dash/resources.py +++ b/dash/resources.py @@ -5,6 +5,7 @@ from .development.base_component import Component +# pylint: disable=old-style-class class Resources: def __init__(self, resource_name, layout): self._resources = [] @@ -66,6 +67,7 @@ def get_inferred_resources(self): layout = self.layout def extract_resource_from_component(component): + # pylint: disable=protected-access if (isinstance(component, Component) and component._namespace not in namespaces): @@ -87,6 +89,7 @@ def extract_resource_from_component(component): class Css: + # pylint: disable=old-style-class def __init__(self, layout=None): self._resources = Resources('_css_dist', layout) self._resources.config = self.config @@ -103,12 +106,14 @@ def get_all_css(self): def get_inferred_css_dist(self): return self._resources.get_inferred_resources() + # pylint: disable=old-style-class, no-init, too-few-public-methods class config: infer_from_layout = True serve_locally = False class Scripts: + # pylint: disable=old-style-class def __init__(self, layout=None): self._resources = Resources('_js_dist', layout) self._resources.config = self.config @@ -125,6 +130,7 @@ def get_all_scripts(self): def get_inferred_scripts(self): return self._resources.get_inferred_resources() + # pylint: disable=old-style-class, no-init, too-few-public-methods class config: infer_from_layout = True serve_locally = False diff --git a/setup.py b/setup.py index cdb2214b43..ce48101363 100644 --- a/setup.py +++ b/setup.py @@ -2,11 +2,11 @@ from setuptools import setup, find_packages -exec(open('dash/version.py').read()) +exec(open('dash/version.py').read()) # pylint: disable=exec-used setup( name='dash', - version=__version__, # noqa: F821 + version=__version__, # noqa: F821 pylint: disable=undefined-variable author='chris p', author_email='chris@plot.ly', packages=find_packages(exclude=['tests*']),