Gate on H4xx docstrings for pep8

In an effort to help horizon more friendly to OpenStack hacking
guidelines, we now gate on H40* violations.

Change-Id: Id07294543660368d2f7f5ac363710176ab23b874
Signed-off-by: Paul Belanger <paul.belanger@polybeacon.com>
This commit is contained in:
Paul Belanger 2013-11-01 14:02:41 -04:00
parent 94129baebb
commit da8c69afa6
76 changed files with 411 additions and 577 deletions

View File

@ -159,7 +159,7 @@ class Registry(object):
class Panel(HorizonComponent): class Panel(HorizonComponent):
""" A base class for defining Horizon dashboard panels. """A base class for defining Horizon dashboard panels.
All Horizon dashboard panels should extend from this class. It provides All Horizon dashboard panels should extend from this class. It provides
the appropriate hooks for automatically constructing URLconfs, and the appropriate hooks for automatically constructing URLconfs, and
@ -214,7 +214,7 @@ class Panel(HorizonComponent):
return "<Panel: %s>" % self.slug return "<Panel: %s>" % self.slug
def get_absolute_url(self): def get_absolute_url(self):
""" Returns the default URL for this panel. """Returns the default URL for this panel.
The default URL is defined as the URL pattern with ``name="index"`` in The default URL is defined as the URL pattern with ``name="index"`` in
the URLconf for this panel. the URLconf for this panel.
@ -243,7 +243,7 @@ class Panel(HorizonComponent):
class PanelGroup(object): class PanelGroup(object):
""" A container for a set of :class:`~horizon.Panel` classes. """A container for a set of :class:`~horizon.Panel` classes.
When iterated, it will yield each of the ``Panel`` instances it When iterated, it will yield each of the ``Panel`` instances it
contains. contains.
@ -286,7 +286,7 @@ class PanelGroup(object):
class Dashboard(Registry, HorizonComponent): class Dashboard(Registry, HorizonComponent):
""" A base class for defining Horizon dashboards. """A base class for defining Horizon dashboards.
All Horizon dashboards should extend from this base class. It provides the All Horizon dashboards should extend from this base class. It provides the
appropriate hooks for automatic discovery of :class:`~horizon.Panel` appropriate hooks for automatic discovery of :class:`~horizon.Panel`
@ -390,15 +390,13 @@ class Dashboard(Registry, HorizonComponent):
self._panel_groups = None self._panel_groups = None
def get_panel(self, panel): def get_panel(self, panel):
""" """Returns the specified :class:`~horizon.Panel` instance registered
Returns the specified :class:`~horizon.Panel` instance registered
with this dashboard. with this dashboard.
""" """
return self._registered(panel) return self._registered(panel)
def get_panels(self): def get_panels(self):
""" """Returns the :class:`~horizon.Panel` instances registered with this
Returns the :class:`~horizon.Panel` instances registered with this
dashboard in order, without any panel groupings. dashboard in order, without any panel groupings.
""" """
all_panels = [] all_panels = []
@ -432,7 +430,7 @@ class Dashboard(Registry, HorizonComponent):
return SortedDict(panel_groups) return SortedDict(panel_groups)
def get_absolute_url(self): def get_absolute_url(self):
""" Returns the default URL for this dashboard. """Returns the default URL for this dashboard.
The default URL is defined as the URL pattern with ``name="index"`` The default URL is defined as the URL pattern with ``name="index"``
in the URLconf for the :class:`~horizon.Panel` specified by in the URLconf for the :class:`~horizon.Panel` specified by
@ -478,7 +476,7 @@ class Dashboard(Registry, HorizonComponent):
return urlpatterns, self.slug, self.slug return urlpatterns, self.slug, self.slug
def _autodiscover(self): def _autodiscover(self):
""" Discovers panels to register from the current dashboard module. """ """Discovers panels to register from the current dashboard module."""
if getattr(self, "_autodiscover_complete", False): if getattr(self, "_autodiscover_complete", False):
return return
@ -520,7 +518,7 @@ class Dashboard(Registry, HorizonComponent):
@classmethod @classmethod
def register(cls, panel): def register(cls, panel):
""" Registers a :class:`~horizon.Panel` with this dashboard. """ """Registers a :class:`~horizon.Panel` with this dashboard."""
panel_class = Horizon.register_panel(cls, panel) panel_class = Horizon.register_panel(cls, panel)
# Support template loading from panel template directories. # Support template loading from panel template directories.
panel_mod = import_module(panel.__module__) panel_mod = import_module(panel.__module__)
@ -533,7 +531,7 @@ class Dashboard(Registry, HorizonComponent):
@classmethod @classmethod
def unregister(cls, panel): def unregister(cls, panel):
""" Unregisters a :class:`~horizon.Panel` from this dashboard. """ """Unregisters a :class:`~horizon.Panel` from this dashboard."""
success = Horizon.unregister_panel(cls, panel) success = Horizon.unregister_panel(cls, panel)
if success: if success:
# Remove the panel's template directory. # Remove the panel's template directory.
@ -578,7 +576,7 @@ class LazyURLPattern(SimpleLazyObject):
class Site(Registry, HorizonComponent): class Site(Registry, HorizonComponent):
""" The overarching class which encompasses all dashboards and panels. """ """The overarching class which encompasses all dashboards and panels."""
# Required for registry # Required for registry
_registerable_class = Dashboard _registerable_class = Dashboard
@ -604,11 +602,11 @@ class Site(Registry, HorizonComponent):
return self._conf['default_dashboard'] return self._conf['default_dashboard']
def register(self, dashboard): def register(self, dashboard):
""" Registers a :class:`~horizon.Dashboard` with Horizon.""" """Registers a :class:`~horizon.Dashboard` with Horizon."""
return self._register(dashboard) return self._register(dashboard)
def unregister(self, dashboard): def unregister(self, dashboard):
""" Unregisters a :class:`~horizon.Dashboard` from Horizon. """ """Unregisters a :class:`~horizon.Dashboard` from Horizon."""
return self._unregister(dashboard) return self._unregister(dashboard)
def registered(self, dashboard): def registered(self, dashboard):
@ -626,11 +624,11 @@ class Site(Registry, HorizonComponent):
return dash_instance._unregister(panel) return dash_instance._unregister(panel)
def get_dashboard(self, dashboard): def get_dashboard(self, dashboard):
""" Returns the specified :class:`~horizon.Dashboard` instance. """ """Returns the specified :class:`~horizon.Dashboard` instance."""
return self._registered(dashboard) return self._registered(dashboard)
def get_dashboards(self): def get_dashboards(self):
""" Returns an ordered tuple of :class:`~horizon.Dashboard` modules. """Returns an ordered tuple of :class:`~horizon.Dashboard` modules.
Orders dashboards according to the ``"dashboards"`` key in Orders dashboards according to the ``"dashboards"`` key in
``HORIZON_CONFIG`` or else returns all registered dashboards ``HORIZON_CONFIG`` or else returns all registered dashboards
@ -658,7 +656,7 @@ class Site(Registry, HorizonComponent):
return dashboards return dashboards
def get_default_dashboard(self): def get_default_dashboard(self):
""" Returns the default :class:`~horizon.Dashboard` instance. """Returns the default :class:`~horizon.Dashboard` instance.
If ``"default_dashboard"`` is specified in ``HORIZON_CONFIG`` If ``"default_dashboard"`` is specified in ``HORIZON_CONFIG``
then that dashboard will be returned. If not, the first dashboard then that dashboard will be returned. If not, the first dashboard
@ -672,7 +670,7 @@ class Site(Registry, HorizonComponent):
raise NotRegistered("No dashboard modules have been registered.") raise NotRegistered("No dashboard modules have been registered.")
def get_user_home(self, user): def get_user_home(self, user):
""" Returns the default URL for a particular user. """Returns the default URL for a particular user.
This method can be used to customize where a user is sent when This method can be used to customize where a user is sent when
they log in, etc. By default it returns the value of they log in, etc. By default it returns the value of
@ -710,7 +708,7 @@ class Site(Registry, HorizonComponent):
return self.get_absolute_url() return self.get_absolute_url()
def get_absolute_url(self): def get_absolute_url(self):
""" Returns the default URL for Horizon's URLconf. """Returns the default URL for Horizon's URLconf.
The default URL is determined by calling The default URL is determined by calling
:meth:`~horizon.Dashboard.get_absolute_url` :meth:`~horizon.Dashboard.get_absolute_url`
@ -721,7 +719,7 @@ class Site(Registry, HorizonComponent):
@property @property
def _lazy_urls(self): def _lazy_urls(self):
""" Lazy loading for URL patterns. """Lazy loading for URL patterns.
This method avoids problems associated with attempting to evaluate This method avoids problems associated with attempting to evaluate
the the URLconf before the settings module has been loaded. the the URLconf before the settings module has been loaded.
@ -732,7 +730,7 @@ class Site(Registry, HorizonComponent):
return LazyURLPattern(url_patterns), self.namespace, self.slug return LazyURLPattern(url_patterns), self.namespace, self.slug
def _urls(self): def _urls(self):
""" Constructs the URLconf for Horizon from registered Dashboards. """ """Constructs the URLconf for Horizon from registered Dashboards."""
urlpatterns = self._get_default_urlpatterns() urlpatterns = self._get_default_urlpatterns()
self._autodiscover() self._autodiscover()
@ -764,7 +762,7 @@ class Site(Registry, HorizonComponent):
return urlpatterns, self.namespace, self.slug return urlpatterns, self.namespace, self.slug
def _autodiscover(self): def _autodiscover(self):
""" Discovers modules to register from ``settings.INSTALLED_APPS``. """Discovers modules to register from ``settings.INSTALLED_APPS``.
This makes sure that the appropriate modules get imported to register This makes sure that the appropriate modules get imported to register
themselves with Horizon. themselves with Horizon.
@ -787,8 +785,7 @@ class Site(Registry, HorizonComponent):
class HorizonSite(Site): class HorizonSite(Site):
""" """A singleton implementation of Site such that all dealings with horizon
A singleton implementation of Site such that all dealings with horizon
get the same instance no matter what. There can be only one. get the same instance no matter what. There can be only one.
""" """
_instance = None _instance = None

View File

@ -121,9 +121,8 @@ class ResourceBrowser(html.HTMLElement):
% (attr_name, self.__class__.__name__)) % (attr_name, self.__class__.__name__))
def set_tables(self, tables): def set_tables(self, tables):
""" """Sets the table instances on the browser from a dictionary mapping
Sets the table instances on the browser from a dictionary mapping table table names to table instances (as constructed by MultiTableView).
names to table instances (as constructed by MultiTableView).
""" """
self.navigation_table = tables[self.navigation_table_class._meta.name] self.navigation_table = tables[self.navigation_table_class._meta.name]
self.content_table = tables[self.content_table_class._meta.name] self.content_table = tables[self.content_table_class._meta.name]

View File

@ -41,7 +41,7 @@ class Breadcrumb(html.HTMLElement):
return self._subfolders return self._subfolders
def render(self): def render(self):
""" Renders the table using the template from the table options. """ """Renders the table using the template from the table options."""
breadcrumb_template = template.loader.get_template(self.template) breadcrumb_template = template.loader.get_template(self.template)
extra_context = {"breadcrumb": self} extra_context = {"breadcrumb": self}
context = template.RequestContext(self.request, extra_context) context = template.RequestContext(self.request, extra_context)

View File

@ -25,7 +25,7 @@ from horizon import conf
def horizon(request): def horizon(request):
""" The main Horizon context processor. Required for Horizon to function. """The main Horizon context processor. Required for Horizon to function.
It adds the Horizon config to the context as well as setting the names It adds the Horizon config to the context as well as setting the names
``True`` and ``False`` in the context to their boolean equivalents ``True`` and ``False`` in the context to their boolean equivalents

View File

@ -28,7 +28,7 @@ from django.utils.translation import ugettext_lazy as _ # noqa
def _current_component(view_func, dashboard=None, panel=None): def _current_component(view_func, dashboard=None, panel=None):
""" Sets the currently-active dashboard and/or panel on the request. """ """Sets the currently-active dashboard and/or panel on the request."""
@functools.wraps(view_func, assigned=available_attrs(view_func)) @functools.wraps(view_func, assigned=available_attrs(view_func))
def dec(request, *args, **kwargs): def dec(request, *args, **kwargs):
if dashboard: if dashboard:
@ -40,7 +40,7 @@ def _current_component(view_func, dashboard=None, panel=None):
def require_auth(view_func): def require_auth(view_func):
""" Performs user authentication check. """Performs user authentication check.
Similar to Django's `login_required` decorator, except that this throws Similar to Django's `login_required` decorator, except that this throws
:exc:`~horizon.exceptions.NotAuthenticated` exception if the user is not :exc:`~horizon.exceptions.NotAuthenticated` exception if the user is not
@ -57,7 +57,7 @@ def require_auth(view_func):
def require_perms(view_func, required): def require_perms(view_func, required):
""" Enforces permission-based access controls. """Enforces permission-based access controls.
:param list required: A tuple of permission names, all of which the request :param list required: A tuple of permission names, all of which the request
user must possess in order access the decorated view. user must possess in order access the decorated view.

View File

@ -36,15 +36,14 @@ LOG = logging.getLogger(__name__)
class HorizonReporterFilter(SafeExceptionReporterFilter): class HorizonReporterFilter(SafeExceptionReporterFilter):
""" Error report filter that's always active, even in DEBUG mode. """ """Error report filter that's always active, even in DEBUG mode."""
def is_active(self, request): def is_active(self, request):
return True return True
# TODO(gabriel): This bugfix is cribbed from Django's code. When 1.4.1 # TODO(gabriel): This bugfix is cribbed from Django's code. When 1.4.1
# is available we can remove this code. # is available we can remove this code.
def get_traceback_frame_variables(self, request, tb_frame): def get_traceback_frame_variables(self, request, tb_frame):
""" """Replaces the values of variables marked as sensitive with
Replaces the values of variables marked as sensitive with
stars (*********). stars (*********).
""" """
# Loop through the frame's callers to see if the sensitive_variables # Loop through the frame's callers to see if the sensitive_variables
@ -93,13 +92,12 @@ class HorizonReporterFilter(SafeExceptionReporterFilter):
class HorizonException(Exception): class HorizonException(Exception):
""" Base exception class for distinguishing our own exception classes. """ """Base exception class for distinguishing our own exception classes."""
pass pass
class Http302(HorizonException): class Http302(HorizonException):
""" """Error class which can be raised from within a handler to cause an
Error class which can be raised from within a handler to cause an
early bailout and redirect at the middleware level. early bailout and redirect at the middleware level.
""" """
status_code = 302 status_code = 302
@ -110,8 +108,7 @@ class Http302(HorizonException):
class NotAuthorized(HorizonException): class NotAuthorized(HorizonException):
""" """Raised whenever a user attempts to access a resource which they do not
Raised whenever a user attempts to access a resource which they do not
have permission-based access to (such as when failing the have permission-based access to (such as when failing the
:func:`~horizon.decorators.require_perms` decorator). :func:`~horizon.decorators.require_perms` decorator).
@ -123,8 +120,8 @@ class NotAuthorized(HorizonException):
class NotAuthenticated(HorizonException): class NotAuthenticated(HorizonException):
""" """Raised when a user is trying to make requests and they are not logged
Raised when a user is trying to make requests and they are not logged in. in.
The included :class:`~horizon.middleware.HorizonMiddleware` catches The included :class:`~horizon.middleware.HorizonMiddleware` catches
``NotAuthenticated`` and handles it gracefully by displaying an error ``NotAuthenticated`` and handles it gracefully by displaying an error
@ -134,19 +131,18 @@ class NotAuthenticated(HorizonException):
class NotFound(HorizonException): class NotFound(HorizonException):
""" Generic error to replace all "Not Found"-type API errors. """ """Generic error to replace all "Not Found"-type API errors."""
status_code = 404 status_code = 404
class RecoverableError(HorizonException): class RecoverableError(HorizonException):
""" Generic error to replace any "Recoverable"-type API errors. """ """Generic error to replace any "Recoverable"-type API errors."""
status_code = 100 # HTTP status code "Continue" status_code = 100 # HTTP status code "Continue"
class ServiceCatalogException(HorizonException): class ServiceCatalogException(HorizonException):
""" """Raised when a requested service is not available in the
Raised when a requested service is not available in the ``ServiceCatalog`` ``ServiceCatalog`` returned by Keystone.
returned by Keystone.
""" """
def __init__(self, service_name): def __init__(self, service_name):
message = 'Invalid service catalog service: %s' % service_name message = 'Invalid service catalog service: %s' % service_name
@ -154,8 +150,7 @@ class ServiceCatalogException(HorizonException):
class AlreadyExists(HorizonException): class AlreadyExists(HorizonException):
""" """Exception to be raised when trying to create an API resource which
Exception to be raised when trying to create an API resource which
already exists. already exists.
""" """
def __init__(self, name, resource_type): def __init__(self, name, resource_type):
@ -173,21 +168,19 @@ class AlreadyExists(HorizonException):
class WorkflowError(HorizonException): class WorkflowError(HorizonException):
""" Exception to be raised when something goes wrong in a workflow. """ """Exception to be raised when something goes wrong in a workflow."""
pass pass
class WorkflowValidationError(HorizonException): class WorkflowValidationError(HorizonException):
""" """Exception raised during workflow validation if required data is missing,
Exception raised during workflow validation if required data is missing,
or existing data is not valid. or existing data is not valid.
""" """
pass pass
class HandledException(HorizonException): class HandledException(HorizonException):
""" """Used internally to track exceptions that have gone through
Used internally to track exceptions that have gone through
:func:`horizon.exceptions.handle` more than once. :func:`horizon.exceptions.handle` more than once.
""" """
def __init__(self, wrapped): def __init__(self, wrapped):
@ -205,8 +198,7 @@ def error_color(msg):
def check_message(keywords, message): def check_message(keywords, message):
""" """Checks an exception for given keywords and raises a new ``ActionError``
Checks an exception for given keywords and raises a new ``ActionError``
with the desired message if the keywords are found. This allows selective with the desired message if the keywords are found. This allows selective
control over API error messages. control over API error messages.
""" """
@ -218,7 +210,7 @@ def check_message(keywords, message):
def handle(request, message=None, redirect=None, ignore=False, def handle(request, message=None, redirect=None, ignore=False,
escalate=False, log_level=None, force_log=None): escalate=False, log_level=None, force_log=None):
""" Centralized error handling for Horizon. """Centralized error handling for Horizon.
Because Horizon consumes so many different APIs with completely Because Horizon consumes so many different APIs with completely
different ``Exception`` types, it's necessary to have a centralized different ``Exception`` types, it's necessary to have a centralized

View File

@ -32,15 +32,13 @@ class SelfHandlingMixin(object):
class SelfHandlingForm(SelfHandlingMixin, forms.Form): class SelfHandlingForm(SelfHandlingMixin, forms.Form):
""" """A base :class:`Form <django:django.forms.Form>` class which includes
A base :class:`Form <django:django.forms.Form>` class which includes
processing logic in its subclasses. processing logic in its subclasses.
""" """
required_css_class = 'required' required_css_class = 'required'
def api_error(self, message): def api_error(self, message):
""" """Adds an error to the form's error dictionary after validation
Adds an error to the form's error dictionary after validation
based on problems reported via the API. This is useful when you based on problems reported via the API. This is useful when you
wish for API errors to appear as errors on the form rather than wish for API errors to appear as errors on the form rather than
using the messages framework. using the messages framework.
@ -49,7 +47,7 @@ class SelfHandlingForm(SelfHandlingMixin, forms.Form):
class DateForm(forms.Form): class DateForm(forms.Form):
""" A simple form for selecting a range of time. """ """A simple form for selecting a range of time."""
start = forms.DateField(input_formats=("%Y-%m-%d",)) start = forms.DateField(input_formats=("%Y-%m-%d",))
end = forms.DateField(input_formats=("%Y-%m-%d",)) end = forms.DateField(input_formats=("%Y-%m-%d",))

View File

@ -20,9 +20,8 @@ from django.forms import widgets
class DynamicSelectWidget(widgets.Select): class DynamicSelectWidget(widgets.Select):
""" """A subclass of the ``Select`` widget which renders extra attributes for
A subclass of the ``Select`` widget which renders extra attributes for use use in callbacks to handle dynamic changes to the available choices.
in callbacks to handle dynamic changes to the available choices.
""" """
_data_add_url_attr = "data-add-item-url" _data_add_url_attr = "data-add-item-url"
@ -46,8 +45,7 @@ class DynamicSelectWidget(widgets.Select):
class DynamicChoiceField(fields.ChoiceField): class DynamicChoiceField(fields.ChoiceField):
""" """A subclass of ``ChoiceField`` with additional properties that make
A subclass of ``ChoiceField`` with additional properties that make
dynamically updating its elements easier. dynamically updating its elements easier.
Notably, the field declaration takes an extra argument, ``add_item_link`` Notably, the field declaration takes an extra argument, ``add_item_link``
@ -67,5 +65,5 @@ class DynamicChoiceField(fields.ChoiceField):
class DynamicTypedChoiceField(DynamicChoiceField, fields.TypedChoiceField): class DynamicTypedChoiceField(DynamicChoiceField, fields.TypedChoiceField):
""" Simple mix of ``DynamicChoiceField`` and ``TypedChoiceField``. """ """Simple mix of ``DynamicChoiceField`` and ``TypedChoiceField``."""
pass pass

View File

@ -49,8 +49,7 @@ class ModalFormMixin(object):
class ModalFormView(ModalFormMixin, generic.FormView): class ModalFormView(ModalFormMixin, generic.FormView):
""" """The main view class from which all views which handle forms in Horizon
The main view class from which all views which handle forms in Horizon
should inherit. It takes care of all details with processing should inherit. It takes care of all details with processing
:class:`~horizon.forms.base.SelfHandlingForm` classes, and modal concerns :class:`~horizon.forms.base.SelfHandlingForm` classes, and modal concerns
when the associated template inherits from when the associated template inherits from
@ -65,25 +64,21 @@ class ModalFormView(ModalFormMixin, generic.FormView):
""" """
def get_object_id(self, obj): def get_object_id(self, obj):
""" """For dynamic insertion of resources created in modals, this method
For dynamic insertion of resources created in modals, this method
returns the id of the created object. Defaults to returning the ``id`` returns the id of the created object. Defaults to returning the ``id``
attribute. attribute.
""" """
return obj.id return obj.id
def get_object_display(self, obj): def get_object_display(self, obj):
""" """For dynamic insertion of resources created in modals, this method
For dynamic insertion of resources created in modals, this method
returns the display name of the created object. Defaults to returning returns the display name of the created object. Defaults to returning
the ``name`` attribute. the ``name`` attribute.
""" """
return obj.name return obj.name
def get_form(self, form_class): def get_form(self, form_class):
""" """Returns an instance of the form to be used in this view."""
Returns an instance of the form to be used in this view.
"""
return form_class(self.request, **self.get_form_kwargs()) return form_class(self.request, **self.get_form_kwargs())
def form_valid(self, form): def form_valid(self, form):

View File

@ -26,9 +26,7 @@ from django.utils.safestring import SafeData # noqa
def add_message(request, level, message, extra_tags='', fail_silently=False): def add_message(request, level, message, extra_tags='', fail_silently=False):
""" """Attempts to add a message to the request using the 'messages' app."""
Attempts to add a message to the request using the 'messages' app.
"""
if request.is_ajax(): if request.is_ajax():
tag = constants.DEFAULT_TAGS[level] tag = constants.DEFAULT_TAGS[level]
# if message is marked as safe, pass "safe" tag as extra_tags so that # if message is marked as safe, pass "safe" tag as extra_tags so that
@ -44,40 +42,30 @@ def add_message(request, level, message, extra_tags='', fail_silently=False):
def debug(request, message, extra_tags='', fail_silently=False): def debug(request, message, extra_tags='', fail_silently=False):
""" """Adds a message with the ``DEBUG`` level."""
Adds a message with the ``DEBUG`` level.
"""
add_message(request, constants.DEBUG, message, extra_tags=extra_tags, add_message(request, constants.DEBUG, message, extra_tags=extra_tags,
fail_silently=fail_silently) fail_silently=fail_silently)
def info(request, message, extra_tags='', fail_silently=False): def info(request, message, extra_tags='', fail_silently=False):
""" """Adds a message with the ``INFO`` level."""
Adds a message with the ``INFO`` level.
"""
add_message(request, constants.INFO, message, extra_tags=extra_tags, add_message(request, constants.INFO, message, extra_tags=extra_tags,
fail_silently=fail_silently) fail_silently=fail_silently)
def success(request, message, extra_tags='', fail_silently=False): def success(request, message, extra_tags='', fail_silently=False):
""" """Adds a message with the ``SUCCESS`` level."""
Adds a message with the ``SUCCESS`` level.
"""
add_message(request, constants.SUCCESS, message, extra_tags=extra_tags, add_message(request, constants.SUCCESS, message, extra_tags=extra_tags,
fail_silently=fail_silently) fail_silently=fail_silently)
def warning(request, message, extra_tags='', fail_silently=False): def warning(request, message, extra_tags='', fail_silently=False):
""" """Adds a message with the ``WARNING`` level."""
Adds a message with the ``WARNING`` level.
"""
add_message(request, constants.WARNING, message, extra_tags=extra_tags, add_message(request, constants.WARNING, message, extra_tags=extra_tags,
fail_silently=fail_silently) fail_silently=fail_silently)
def error(request, message, extra_tags='', fail_silently=False): def error(request, message, extra_tags='', fail_silently=False):
""" """Adds a message with the ``ERROR`` level."""
Adds a message with the ``ERROR`` level.
"""
add_message(request, constants.ERROR, message, extra_tags=extra_tags, add_message(request, constants.ERROR, message, extra_tags=extra_tags,
fail_silently=fail_silently) fail_silently=fail_silently)

View File

@ -43,12 +43,12 @@ LOG = logging.getLogger(__name__)
class HorizonMiddleware(object): class HorizonMiddleware(object):
""" The main Horizon middleware class. Required for use of Horizon. """ """The main Horizon middleware class. Required for use of Horizon."""
logout_reason = None logout_reason = None
def process_request(self, request): def process_request(self, request):
""" Adds data necessary for Horizon to function to the request. """ """Adds data necessary for Horizon to function to the request."""
# Activate timezone handling # Activate timezone handling
tz = request.session.get('django_timezone') tz = request.session.get('django_timezone')
if tz: if tz:
@ -75,8 +75,7 @@ class HorizonMiddleware(object):
request.session['last_activity'] = timestamp request.session['last_activity'] = timestamp
def process_exception(self, request, exception): def process_exception(self, request, exception):
""" """Catches internal Horizon exception classes such as NotAuthorized,
Catches internal Horizon exception classes such as NotAuthorized,
NotFound and Http302 and handles them gracefully. NotFound and Http302 and handles them gracefully.
""" """
if isinstance(exception, (exceptions.NotAuthorized, if isinstance(exception, (exceptions.NotAuthorized,
@ -108,8 +107,7 @@ class HorizonMiddleware(object):
return shortcuts.redirect(exception.location) return shortcuts.redirect(exception.location)
def process_response(self, request, response): def process_response(self, request, response):
""" """Convert HttpResponseRedirect to HttpResponse if request is via ajax
Convert HttpResponseRedirect to HttpResponse if request is via ajax
to allow ajax request to redirect url to allow ajax request to redirect url
""" """
if request.is_ajax() and hasattr(request, 'horizon'): if request.is_ajax() and hasattr(request, 'horizon'):

View File

@ -39,7 +39,7 @@ STRING_SEPARATOR = "__"
class BaseAction(html.HTMLElement): class BaseAction(html.HTMLElement):
""" Common base class for all ``Action`` classes. """ """Common base class for all ``Action`` classes."""
table = None table = None
handles_multiple = False handles_multiple = False
requires_input = False requires_input = False
@ -51,8 +51,8 @@ class BaseAction(html.HTMLElement):
self.datum = datum self.datum = datum
def data_type_matched(self, datum): def data_type_matched(self, datum):
""" Method to see if the action is allowed for a certain type of data. """Method to see if the action is allowed for a certain type of data.
Only affects mixed data type tables. Only affects mixed data type tables.
""" """
if datum: if datum:
action_data_types = getattr(self, "allowed_data_types", []) action_data_types = getattr(self, "allowed_data_types", [])
@ -66,7 +66,7 @@ class BaseAction(html.HTMLElement):
return True return True
def get_policy_target(self, request, datum): def get_policy_target(self, request, datum):
""" Provide the target for a policy request. """Provide the target for a policy request.
This method is meant to be overridden to return target details when This method is meant to be overridden to return target details when
one of the policy checks requires them. E.g., {"user_id": datum.id} one of the policy checks requires them. E.g., {"user_id": datum.id}
@ -74,7 +74,7 @@ class BaseAction(html.HTMLElement):
return {} return {}
def allowed(self, request, datum): def allowed(self, request, datum):
""" Determine whether this action is allowed for the current request. """Determine whether this action is allowed for the current request.
This method is meant to be overridden with more specific checks. This method is meant to be overridden with more specific checks.
""" """
@ -90,7 +90,7 @@ class BaseAction(html.HTMLElement):
return self.allowed(request, datum) return self.allowed(request, datum)
def update(self, request, datum): def update(self, request, datum):
""" Allows per-action customization based on current conditions. """Allows per-action customization based on current conditions.
This is particularly useful when you wish to create a "toggle" This is particularly useful when you wish to create a "toggle"
action that will be rendered differently based on the value of an action that will be rendered differently based on the value of an
@ -101,16 +101,14 @@ class BaseAction(html.HTMLElement):
pass pass
def get_default_classes(self): def get_default_classes(self):
""" """Returns a list of the default classes for the action. Defaults to
Returns a list of the default classes for the action. Defaults to
``["btn", "btn-small"]``. ``["btn", "btn-small"]``.
""" """
return getattr(settings, "ACTION_CSS_CLASSES", ACTION_CSS_CLASSES) return getattr(settings, "ACTION_CSS_CLASSES", ACTION_CSS_CLASSES)
def get_default_attrs(self): def get_default_attrs(self):
""" """Returns a list of the default HTML attributes for the action.
Returns a list of the default HTML attributes for the action. Defaults Defaults to returning an ``id`` attribute with the value
to returning an ``id`` attribute with the value
``{{ table.name }}__action_{{ action.name }}__{{ creation counter }}``. ``{{ table.name }}__action_{{ action.name }}__{{ creation counter }}``.
""" """
if self.datum is not None: if self.datum is not None:
@ -126,7 +124,7 @@ class BaseAction(html.HTMLElement):
class Action(BaseAction): class Action(BaseAction):
""" Represents an action which can be taken on this table's data. """Represents an action which can be taken on this table's data.
.. attribute:: name .. attribute:: name
@ -265,7 +263,7 @@ class Action(BaseAction):
self.multiple = new.instancemethod(multiple, self) self.multiple = new.instancemethod(multiple, self)
def get_param_name(self): def get_param_name(self):
""" Returns the full POST parameter name for this action. """Returns the full POST parameter name for this action.
Defaults to Defaults to
``{{ table.name }}__{{ action.name }}``. ``{{ table.name }}__{{ action.name }}``.
@ -274,7 +272,7 @@ class Action(BaseAction):
class LinkAction(BaseAction): class LinkAction(BaseAction):
""" A table action which is simply a link rather than a form POST. """A table action which is simply a link rather than a form POST.
.. attribute:: name .. attribute:: name
@ -319,7 +317,7 @@ class LinkAction(BaseAction):
self.attrs.update(attrs) self.attrs.update(attrs)
def get_link_url(self, datum=None): def get_link_url(self, datum=None):
""" Returns the final URL based on the value of ``url``. """Returns the final URL based on the value of ``url``.
If ``url`` is callable it will call the function. If ``url`` is callable it will call the function.
If not, it will then try to call ``reverse`` on ``url``. If not, it will then try to call ``reverse`` on ``url``.
@ -346,7 +344,7 @@ class LinkAction(BaseAction):
class FilterAction(BaseAction): class FilterAction(BaseAction):
""" A base class representing a filter action for a table. """A base class representing a filter action for a table.
.. attribute:: name .. attribute:: name
@ -389,7 +387,7 @@ class FilterAction(BaseAction):
self.param_name = param_name or 'q' self.param_name = param_name or 'q'
def get_param_name(self): def get_param_name(self):
""" Returns the full query parameter name for this action. """Returns the full query parameter name for this action.
Defaults to Defaults to
``{{ table.name }}__{{ action.name }}__{{ action.param_name }}``. ``{{ table.name }}__{{ action.name }}__{{ action.param_name }}``.
@ -424,7 +422,7 @@ class FilterAction(BaseAction):
return filtered_data return filtered_data
def filter(self, table, data, filter_string): def filter(self, table, data, filter_string):
""" Provides the actual filtering logic. """Provides the actual filtering logic.
This method must be overridden by subclasses and return This method must be overridden by subclasses and return
the filtered data. the filtered data.
@ -434,8 +432,7 @@ class FilterAction(BaseAction):
class FixedFilterAction(FilterAction): class FixedFilterAction(FilterAction):
""" A filter action with fixed buttons. """A filter action with fixed buttons."""
"""
filter_type = 'fixed' filter_type = 'fixed'
needs_preloading = True needs_preloading = True
@ -480,9 +477,9 @@ class FixedFilterAction(FilterAction):
class BatchAction(Action): class BatchAction(Action):
""" A table action which takes batch action on one or more """A table action which takes batch action on one or more
objects. This action should not require user input on a objects. This action should not require user input on a
per-object basis. per-object basis.
.. attribute:: name .. attribute:: name
@ -543,8 +540,7 @@ class BatchAction(Action):
return super(BatchAction, self)._allowed(request, datum) return super(BatchAction, self)._allowed(request, datum)
def _conjugate(self, items=None, past=False): def _conjugate(self, items=None, past=False):
""" """Builds combinations like 'Delete Object' and 'Deleted
Builds combinations like 'Delete Object' and 'Deleted
Objects' based on the number of items and `past` flag. Objects' based on the number of items and `past` flag.
""" """
action_type = "past" if past else "present" action_type = "past" if past else "present"
@ -565,8 +561,8 @@ class BatchAction(Action):
return msgstr % {'action': action, 'data_type': data_type} return msgstr % {'action': action, 'data_type': data_type}
def action(self, request, datum_id): def action(self, request, datum_id):
""" """Required. Accepts a single object id and performs the specific
Required. Accepts a single object id and performs the specific action. action.
Return values are discarded, errors raised are caught and logged. Return values are discarded, errors raised are caught and logged.
""" """
@ -574,17 +570,13 @@ class BatchAction(Action):
'BatchAction: %s' % self.data_type_singular) 'BatchAction: %s' % self.data_type_singular)
def update(self, request, datum): def update(self, request, datum):
""" """Switches the action verbose name, if needed."""
Switches the action verbose name, if needed
"""
if getattr(self, 'action_present', False): if getattr(self, 'action_present', False):
self.verbose_name = self._conjugate() self.verbose_name = self._conjugate()
self.verbose_name_plural = self._conjugate('plural') self.verbose_name_plural = self._conjugate('plural')
def get_success_url(self, request=None): def get_success_url(self, request=None):
""" """Returns the URL to redirect to after a successful action."""
Returns the URL to redirect to after a successful action.
"""
if self.success_url: if self.success_url:
return self.success_url return self.success_url
return request.get_full_path() return request.get_full_path()

View File

@ -49,7 +49,7 @@ STRING_SEPARATOR = "__"
class Column(html.HTMLElement): class Column(html.HTMLElement):
""" A class which represents a single column in a :class:`.DataTable`. """A class which represents a single column in a :class:`.DataTable`.
.. attribute:: transform .. attribute:: transform
@ -270,10 +270,9 @@ class Column(html.HTMLElement):
return '<%s: %s>' % (self.__class__.__name__, self.name) return '<%s: %s>' % (self.__class__.__name__, self.name)
def get_raw_data(self, datum): def get_raw_data(self, datum):
""" """Returns the raw data for this column, before any filters or
Returns the raw data for this column, before any filters or formatting formatting are applied to it. This is useful when doing calculations
are applied to it. This is useful when doing calculations on data in on data in the table.
the table.
""" """
# Callable transformations # Callable transformations
if callable(self.transform): if callable(self.transform):
@ -295,8 +294,8 @@ class Column(html.HTMLElement):
return data return data
def get_data(self, datum): def get_data(self, datum):
""" """Returns the final display data for this column from the given
Returns the final display data for this column from the given inputs. inputs.
The return value will be either the attribute specified for this column The return value will be either the attribute specified for this column
or the return value of the attr:`~horizon.tables.Column.transform` or the return value of the attr:`~horizon.tables.Column.transform`
@ -329,7 +328,7 @@ class Column(html.HTMLElement):
return self.table._data_cache[self][datum_id] return self.table._data_cache[self][datum_id]
def get_link_url(self, datum): def get_link_url(self, datum):
""" Returns the final value for the column's ``link`` property. """Returns the final value for the column's ``link`` property.
If ``allowed_data_types`` of this column is not empty and the datum If ``allowed_data_types`` of this column is not empty and the datum
has an assigned type, check if the datum's type is in the has an assigned type, check if the datum's type is in the
@ -355,8 +354,7 @@ class Column(html.HTMLElement):
return self.link return self.link
def get_summation(self): def get_summation(self):
""" """Returns the summary value for the data in this column if a
Returns the summary value for the data in this column if a
valid summation method is specified for it. Otherwise returns ``None``. valid summation method is specified for it. Otherwise returns ``None``.
""" """
if self.summation not in self.summation_methods: if self.summation not in self.summation_methods:
@ -376,7 +374,7 @@ class Column(html.HTMLElement):
class Row(html.HTMLElement): class Row(html.HTMLElement):
""" Represents a row in the table. """Represents a row in the table.
When iterated, the ``Row`` instance will yield each of its cells. When iterated, the ``Row`` instance will yield each of its cells.
@ -444,8 +442,7 @@ class Row(html.HTMLElement):
self.cells = [] self.cells = []
def load_cells(self, datum=None): def load_cells(self, datum=None):
""" """Load the row's data (either provided at initialization or as an
Load the row's data (either provided at initialization or as an
argument to this function), initiailize all the cells contained argument to this function), initiailize all the cells contained
by this row, and set the appropriate row properties which require by this row, and set the appropriate row properties which require
the row's data to be determined. the row's data to be determined.
@ -526,7 +523,7 @@ class Row(html.HTMLElement):
{"row": self}) {"row": self})
def get_cells(self): def get_cells(self):
""" Returns the bound cells for this row in order. """ """Returns the bound cells for this row in order."""
return self.cells.values() return self.cells.values()
def get_ajax_update_url(self): def get_ajax_update_url(self):
@ -537,8 +534,7 @@ class Row(html.HTMLElement):
return "%s?%s" % (table_url, params) return "%s?%s" % (table_url, params)
def get_data(self, request, obj_id): def get_data(self, request, obj_id):
""" """Fetches the updated data for the row based on the object id
Fetches the updated data for the row based on the object id
passed in. Must be implemented by a subclass to allow AJAX updating. passed in. Must be implemented by a subclass to allow AJAX updating.
""" """
raise NotImplementedError("You must define a get_data method on %s" raise NotImplementedError("You must define a get_data method on %s"
@ -546,7 +542,7 @@ class Row(html.HTMLElement):
class Cell(html.HTMLElement): class Cell(html.HTMLElement):
""" Represents a single cell in the table. """ """Represents a single cell in the table."""
def __init__(self, datum, data, column, row, attrs=None, classes=None): def __init__(self, datum, data, column, row, attrs=None, classes=None):
self.classes = classes or getattr(self, "classes", []) self.classes = classes or getattr(self, "classes", [])
super(Cell, self).__init__() super(Cell, self).__init__()
@ -565,8 +561,7 @@ class Cell(html.HTMLElement):
@property @property
def value(self): def value(self):
""" """Returns a formatted version of the data for final output.
Returns a formatted version of the data for final output.
This takes into consideration the This takes into consideration the
:attr:`~horizon.tables.Column.link`` and :attr:`~horizon.tables.Column.link`` and
@ -602,7 +597,7 @@ class Cell(html.HTMLElement):
@property @property
def status(self): def status(self):
""" Gets the status for the column based on the cell's data. """ """Gets the status for the column based on the cell's data."""
# Deal with status column mechanics based in this cell's data # Deal with status column mechanics based in this cell's data
if hasattr(self, '_status'): if hasattr(self, '_status'):
return self._status return self._status
@ -619,7 +614,7 @@ class Cell(html.HTMLElement):
return self._status return self._status
def get_status_class(self, status): def get_status_class(self, status):
""" Returns a css class name determined by the status value. """ """Returns a css class name determined by the status value."""
if status is True: if status is True:
return "status_up" return "status_up"
elif status is False: elif status is False:
@ -628,7 +623,7 @@ class Cell(html.HTMLElement):
return "status_unknown" return "status_unknown"
def get_default_classes(self): def get_default_classes(self):
""" Returns a flattened string of the cell's CSS classes. """ """Returns a flattened string of the cell's CSS classes."""
if not self.url: if not self.url:
self.column.classes = [cls for cls in self.column.classes self.column.classes = [cls for cls in self.column.classes
if cls != "anchor"] if cls != "anchor"]
@ -640,7 +635,7 @@ class Cell(html.HTMLElement):
class DataTableOptions(object): class DataTableOptions(object):
""" Contains options for :class:`.DataTable` objects. """Contains options for :class:`.DataTable` objects.
.. attribute:: name .. attribute:: name
@ -823,7 +818,7 @@ class DataTableOptions(object):
class DataTableMetaclass(type): class DataTableMetaclass(type):
""" Metaclass to add options to DataTable class and collect columns. """ """Metaclass to add options to DataTable class and collect columns."""
def __new__(mcs, name, bases, attrs): def __new__(mcs, name, bases, attrs):
# Process options from Meta # Process options from Meta
class_name = name class_name = name
@ -896,7 +891,7 @@ class DataTableMetaclass(type):
class DataTable(object): class DataTable(object):
""" A class which defines a table with all data and associated actions. """A class which defines a table with all data and associated actions.
.. attribute:: name .. attribute:: name
@ -1017,14 +1012,14 @@ class DataTable(object):
return False return False
def render(self): def render(self):
""" Renders the table using the template from the table options. """ """Renders the table using the template from the table options."""
table_template = template.loader.get_template(self._meta.template) table_template = template.loader.get_template(self._meta.template)
extra_context = {self._meta.context_var_name: self} extra_context = {self._meta.context_var_name: self}
context = template.RequestContext(self.request, extra_context) context = template.RequestContext(self.request, extra_context)
return table_template.render(context) return table_template.render(context)
def get_absolute_url(self): def get_absolute_url(self):
""" Returns the canonical URL for this table. """Returns the canonical URL for this table.
This is used for the POST action attribute on the form element This is used for the POST action attribute on the form element
wrapping the table. In many cases it is also useful for redirecting wrapping the table. In many cases it is also useful for redirecting
@ -1037,12 +1032,11 @@ class DataTable(object):
return self.request.get_full_path().partition('?')[0] return self.request.get_full_path().partition('?')[0]
def get_empty_message(self): def get_empty_message(self):
""" Returns the message to be displayed when there is no data. """ """Returns the message to be displayed when there is no data."""
return self._no_data_message return self._no_data_message
def get_object_by_id(self, lookup): def get_object_by_id(self, lookup):
""" """Returns the data object from the table's dataset which matches
Returns the data object from the table's dataset which matches
the ``lookup`` parameter specified. An error will be raised if the ``lookup`` parameter specified. An error will be raised if
the match is not a single data object. the match is not a single data object.
@ -1071,8 +1065,7 @@ class DataTable(object):
@property @property
def has_actions(self): def has_actions(self):
""" """Boolean. Indicates whether there are any available actions on this
Boolean. Indicates whether there are any available actions on this
table. table.
""" """
if not self.base_actions: if not self.base_actions:
@ -1081,8 +1074,7 @@ class DataTable(object):
@property @property
def needs_form_wrapper(self): def needs_form_wrapper(self):
""" """Boolean. Indicates whather this table should be rendered wrapped in
Boolean. Indicates whather this table should be rendered wrapped in
a ``<form>`` tag or not. a ``<form>`` tag or not.
""" """
# If needs_form_wrapper is explicitly set, defer to that. # If needs_form_wrapper is explicitly set, defer to that.
@ -1092,14 +1084,14 @@ class DataTable(object):
return self.has_actions return self.has_actions
def get_table_actions(self): def get_table_actions(self):
""" Returns a list of the action instances for this table. """ """Returns a list of the action instances for this table."""
bound_actions = [self.base_actions[action.name] for bound_actions = [self.base_actions[action.name] for
action in self._meta.table_actions] action in self._meta.table_actions]
return [action for action in bound_actions if return [action for action in bound_actions if
self._filter_action(action, self.request)] self._filter_action(action, self.request)]
def get_row_actions(self, datum): def get_row_actions(self, datum):
""" Returns a list of the action instances for a specific row. """ """Returns a list of the action instances for a specific row."""
bound_actions = [] bound_actions = []
for action in self._meta.row_actions: for action in self._meta.row_actions:
# Copy to allow modifying properties per row # Copy to allow modifying properties per row
@ -1120,7 +1112,7 @@ class DataTable(object):
return bound_actions return bound_actions
def render_table_actions(self): def render_table_actions(self):
""" Renders the actions specified in ``Meta.table_actions``. """ """Renders the actions specified in ``Meta.table_actions``."""
template_path = self._meta.table_actions_template template_path = self._meta.table_actions_template
table_actions_template = template.loader.get_template(template_path) table_actions_template = template.loader.get_template(template_path)
bound_actions = self.get_table_actions() bound_actions = self.get_table_actions()
@ -1132,9 +1124,9 @@ class DataTable(object):
return table_actions_template.render(context) return table_actions_template.render(context)
def render_row_actions(self, datum): def render_row_actions(self, datum):
"""Renders the actions specified in ``Meta.row_actions`` using the
current row data.
""" """
Renders the actions specified in ``Meta.row_actions`` using the
current row data. """
template_path = self._meta.row_actions_template template_path = self._meta.row_actions_template
row_actions_template = template.loader.get_template(template_path) row_actions_template = template.loader.get_template(template_path)
bound_actions = self.get_row_actions(datum) bound_actions = self.get_row_actions(datum)
@ -1145,8 +1137,7 @@ class DataTable(object):
@staticmethod @staticmethod
def parse_action(action_string): def parse_action(action_string):
""" """Parses the ``action`` parameter (a string) sent back with the
Parses the ``action`` parameter (a string) sent back with the
POST data. By default this parses a string formatted as POST data. By default this parses a string formatted as
``{{ table_name }}__{{ action_name }}__{{ row_id }}`` and returns ``{{ table_name }}__{{ action_name }}__{{ row_id }}`` and returns
each of the pieces. The ``row_id`` is optional. each of the pieces. The ``row_id`` is optional.
@ -1163,8 +1154,7 @@ class DataTable(object):
return table, action, object_id return table, action, object_id
def take_action(self, action_name, obj_id=None, obj_ids=None): def take_action(self, action_name, obj_id=None, obj_ids=None):
""" """Locates the appropriate action and routes the object
Locates the appropriate action and routes the object
data to it. The action should return an HTTP redirect data to it. The action should return an HTTP redirect
if successful, or a value which evaluates to ``False`` if successful, or a value which evaluates to ``False``
if unsuccessful. if unsuccessful.
@ -1200,7 +1190,7 @@ class DataTable(object):
@classmethod @classmethod
def check_handler(cls, request): def check_handler(cls, request):
""" Determine whether the request should be handled by this table. """ """Determine whether the request should be handled by this table."""
if request.method == "POST" and "action" in request.POST: if request.method == "POST" and "action" in request.POST:
table, action, obj_id = cls.parse_action(request.POST["action"]) table, action, obj_id = cls.parse_action(request.POST["action"])
elif "table" in request.GET and "action" in request.GET: elif "table" in request.GET and "action" in request.GET:
@ -1212,9 +1202,8 @@ class DataTable(object):
return table, action, obj_id return table, action, obj_id
def maybe_preempt(self): def maybe_preempt(self):
""" """Determine whether the request should be handled by a preemptive
Determine whether the request should be handled by a preemptive action action on this table or by an AJAX row update before loading any data.
on this table or by an AJAX row update before loading any data.
""" """
request = self.request request = self.request
table_name, action_name, obj_id = self.check_handler(request) table_name, action_name, obj_id = self.check_handler(request)
@ -1247,9 +1236,8 @@ class DataTable(object):
return None return None
def maybe_handle(self): def maybe_handle(self):
""" """Determine whether the request should be handled by any action on
Determine whether the request should be handled by any action on this this table after data has been loaded.
table after data has been loaded.
""" """
request = self.request request = self.request
table_name, action_name, obj_id = self.check_handler(request) table_name, action_name, obj_id = self.check_handler(request)
@ -1262,13 +1250,13 @@ class DataTable(object):
return None return None
def sanitize_id(self, obj_id): def sanitize_id(self, obj_id):
""" Override to modify an incoming obj_id to match existing """Override to modify an incoming obj_id to match existing
API data types or modify the format. API data types or modify the format.
""" """
return obj_id return obj_id
def get_object_id(self, datum): def get_object_id(self, datum):
""" Returns the identifier for the object this row will represent. """Returns the identifier for the object this row will represent.
By default this returns an ``id`` attribute on the given object, By default this returns an ``id`` attribute on the given object,
but this can be overridden to return other values. but this can be overridden to return other values.
@ -1281,7 +1269,7 @@ class DataTable(object):
return datum.id return datum.id
def get_object_display(self, datum): def get_object_display(self, datum):
""" Returns a display name that identifies this object. """Returns a display name that identifies this object.
By default, this returns a ``name`` attribute from the given object, By default, this returns a ``name`` attribute from the given object,
but this can be overriden to return other values. but this can be overriden to return other values.
@ -1291,8 +1279,7 @@ class DataTable(object):
return None return None
def has_more_data(self): def has_more_data(self):
""" """Returns a boolean value indicating whether there is more data
Returns a boolean value indicating whether there is more data
available to this table from the source (generally an API). available to this table from the source (generally an API).
The method is largely meant for internal use, but if you want to The method is largely meant for internal use, but if you want to
@ -1301,19 +1288,17 @@ class DataTable(object):
return self._meta.has_more_data return self._meta.has_more_data
def get_marker(self): def get_marker(self):
""" """Returns the identifier for the last object in the current data set
Returns the identifier for the last object in the current data set
for APIs that use marker/limit-based paging. for APIs that use marker/limit-based paging.
""" """
return http.urlquote_plus(self.get_object_id(self.data[-1])) return http.urlquote_plus(self.get_object_id(self.data[-1]))
def get_pagination_string(self): def get_pagination_string(self):
""" Returns the query parameter string to paginate this table. """ """Returns the query parameter string to paginate this table."""
return "=".join([self._meta.pagination_param, self.get_marker()]) return "=".join([self._meta.pagination_param, self.get_marker()])
def calculate_row_status(self, statuses): def calculate_row_status(self, statuses):
""" """Returns a boolean value determining the overall row status
Returns a boolean value determining the overall row status
based on the dictionary of column name to status mappings passed in. based on the dictionary of column name to status mappings passed in.
By default, it uses the following logic: By default, it uses the following logic:
@ -1339,8 +1324,7 @@ class DataTable(object):
return True return True
def get_row_status_class(self, status): def get_row_status_class(self, status):
""" """Returns a css class name determined by the status value. This class
Returns a css class name determined by the status value. This class
name is used to indicate the status of the rows in the table if name is used to indicate the status of the rows in the table if
any ``status_columns`` have been specified. any ``status_columns`` have been specified.
""" """
@ -1352,11 +1336,11 @@ class DataTable(object):
return "status_unknown" return "status_unknown"
def get_columns(self): def get_columns(self):
""" Returns this table's columns including auto-generated ones.""" """Returns this table's columns including auto-generated ones."""
return self.columns.values() return self.columns.values()
def get_rows(self): def get_rows(self):
""" Return the row data for this table broken out by columns. """ """Return the row data for this table broken out by columns."""
rows = [] rows = []
try: try:
for datum in self.filtered_data: for datum in self.filtered_data:

View File

@ -22,7 +22,7 @@ from horizon.templatetags.horizon import has_permissions # noqa
class MultiTableMixin(object): class MultiTableMixin(object):
""" A generic mixin which provides methods for handling DataTables. """ """A generic mixin which provides methods for handling DataTables."""
data_method_pattern = "get_%s_data" data_method_pattern = "get_%s_data"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -123,8 +123,7 @@ class MultiTableMixin(object):
class MultiTableView(MultiTableMixin, generic.TemplateView): class MultiTableView(MultiTableMixin, generic.TemplateView):
""" """A class-based generic view to handle the display and processing of
A class-based generic view to handle the display and processing of
multiple :class:`~horizon.tables.DataTable` classes in a single view. multiple :class:`~horizon.tables.DataTable` classes in a single view.
Three steps are required to use this view: set the ``table_classes`` Three steps are required to use this view: set the ``table_classes``
@ -164,7 +163,7 @@ class MultiTableView(MultiTableMixin, generic.TemplateView):
class DataTableView(MultiTableView): class DataTableView(MultiTableView):
""" A class-based generic view to handle basic DataTable processing. """A class-based generic view to handle basic DataTable processing.
Three steps are required to use this view: set the ``table_class`` Three steps are required to use this view: set the ``table_class``
attribute with the desired :class:`~horizon.tables.DataTable` class; attribute with the desired :class:`~horizon.tables.DataTable` class;
@ -211,7 +210,7 @@ class DataTableView(MultiTableView):
class MixedDataTableView(DataTableView): class MixedDataTableView(DataTableView):
""" A class-based generic view to handle DataTable with mixed data """A class-based generic view to handle DataTable with mixed data
types. types.
Basic usage is the same as DataTableView. Basic usage is the same as DataTableView.

View File

@ -30,8 +30,7 @@ CSS_DISABLED_TAB_CLASSES = ["disabled"]
class TabGroup(html.HTMLElement): class TabGroup(html.HTMLElement):
""" """A container class which knows how to manage and render
A container class which knows how to manage and render
:class:`~horizon.tabs.Tab` objects. :class:`~horizon.tabs.Tab` objects.
.. attribute:: slug .. attribute:: slug
@ -110,9 +109,7 @@ class TabGroup(html.HTMLElement):
return "<%s: %s>" % (self.__class__.__name__, self.slug) return "<%s: %s>" % (self.__class__.__name__, self.slug)
def load_tab_data(self): def load_tab_data(self):
""" """Preload all data that for the tabs that will be displayed."""
Preload all data that for the tabs that will be displayed.
"""
for tab in self._tabs.values(): for tab in self._tabs.values():
if tab.load and not tab.data_loaded: if tab.load and not tab.data_loaded:
try: try:
@ -122,15 +119,13 @@ class TabGroup(html.HTMLElement):
exceptions.handle(self.request) exceptions.handle(self.request)
def get_id(self): def get_id(self):
""" """Returns the id for this tab group. Defaults to the value of the tab
Returns the id for this tab group. Defaults to the value of the tab
group's :attr:`horizon.tabs.Tab.slug`. group's :attr:`horizon.tabs.Tab.slug`.
""" """
return self.slug return self.slug
def get_default_classes(self): def get_default_classes(self):
""" """Returns a list of the default classes for the tab group. Defaults to
Returns a list of the default classes for the tab group. Defaults to
``["nav", "nav-tabs", "ajax-tabs"]``. ``["nav", "nav-tabs", "ajax-tabs"]``.
""" """
default_classes = super(TabGroup, self).get_default_classes() default_classes = super(TabGroup, self).get_default_classes()
@ -138,8 +133,7 @@ class TabGroup(html.HTMLElement):
return default_classes return default_classes
def tabs_not_available(self): def tabs_not_available(self):
""" """In the event that no tabs are either allowed or enabled, this method
In the event that no tabs are either allowed or enabled, this method
is the fallback handler. By default it's a no-op, but it exists is the fallback handler. By default it's a no-op, but it exists
to make redirecting or raising exceptions possible for subclasses. to make redirecting or raising exceptions possible for subclasses.
""" """
@ -169,15 +163,15 @@ class TabGroup(html.HTMLElement):
return marked_active return marked_active
def render(self): def render(self):
""" Renders the HTML output for this tab group. """ """Renders the HTML output for this tab group."""
return render_to_string(self.template_name, {"tab_group": self}) return render_to_string(self.template_name, {"tab_group": self})
def get_tabs(self): def get_tabs(self):
""" Returns a list of the allowed tabs for this tab group. """ """Returns a list of the allowed tabs for this tab group."""
return filter(lambda tab: tab._allowed, self._tabs.values()) return filter(lambda tab: tab._allowed, self._tabs.values())
def get_tab(self, tab_name, allow_disabled=False): def get_tab(self, tab_name, allow_disabled=False):
""" Returns a specific tab from this tab group. """Returns a specific tab from this tab group.
If the tab is not allowed or not enabled this method returns ``None``. If the tab is not allowed or not enabled this method returns ``None``.
@ -193,7 +187,7 @@ class TabGroup(html.HTMLElement):
return filter(lambda t: self.get_tab(t.slug), self._tabs.values()) return filter(lambda t: self.get_tab(t.slug), self._tabs.values())
def get_selected_tab(self): def get_selected_tab(self):
""" Returns the tab specific by the GET request parameter. """Returns the tab specific by the GET request parameter.
In the event that there is no GET request parameter, the value In the event that there is no GET request parameter, the value
of the query parameter is invalid, or the tab is not allowed/enabled, of the query parameter is invalid, or the tab is not allowed/enabled,
@ -208,8 +202,7 @@ class TabGroup(html.HTMLElement):
class Tab(html.HTMLElement): class Tab(html.HTMLElement):
""" """A reusable interface for constructing a tab within a
A reusable interface for constructing a tab within a
:class:`~horizon.tabs.TabGroup`. :class:`~horizon.tabs.TabGroup`.
.. attribute:: name .. attribute:: name
@ -265,7 +258,7 @@ class Tab(html.HTMLElement):
return "<%s: %s>" % (self.__class__.__name__, self.slug) return "<%s: %s>" % (self.__class__.__name__, self.slug)
def is_active(self): def is_active(self):
""" Method to access whether or not this tab is the active tab. """ """Method to access whether or not this tab is the active tab."""
if self._active is None: if self._active is None:
self.tab_group._set_active_tab() self.tab_group._set_active_tab()
return self._active return self._active
@ -286,8 +279,7 @@ class Tab(html.HTMLElement):
return getattr(self, "_data", None) is not None return getattr(self, "_data", None) is not None
def render(self): def render(self):
""" """Renders the tab to HTML using the
Renders the tab to HTML using the
:meth:`~horizon.tabs.Tab.get_context_data` method and :meth:`~horizon.tabs.Tab.get_context_data` method and
the :meth:`~horizon.tabs.Tab.get_template_name` method. the :meth:`~horizon.tabs.Tab.get_template_name` method.
@ -309,8 +301,7 @@ class Tab(html.HTMLElement):
return render_to_string(self.get_template_name(self.request), context) return render_to_string(self.get_template_name(self.request), context)
def get_id(self): def get_id(self):
""" """Returns the id for this tab. Defaults to
Returns the id for this tab. Defaults to
``"{{ tab_group.slug }}__{{ tab.slug }}"``. ``"{{ tab_group.slug }}__{{ tab.slug }}"``.
""" """
return SEPARATOR.join([self.tab_group.slug, self.slug]) return SEPARATOR.join([self.tab_group.slug, self.slug])
@ -319,8 +310,7 @@ class Tab(html.HTMLElement):
return "=".join((self.tab_group.param_name, self.get_id())) return "=".join((self.tab_group.param_name, self.get_id()))
def get_default_classes(self): def get_default_classes(self):
""" """Returns a list of the default classes for the tab. Defaults to
Returns a list of the default classes for the tab. Defaults to
and empty list (``[]``), however additional classes may be added and empty list (``[]``), however additional classes may be added
depending on the state of the tab as follows: depending on the state of the tab as follows:
@ -338,8 +328,7 @@ class Tab(html.HTMLElement):
return default_classes return default_classes
def get_template_name(self, request): def get_template_name(self, request):
""" """Returns the name of the template to be used for rendering this tab.
Returns the name of the template to be used for rendering this tab.
By default it returns the value of the ``template_name`` attribute By default it returns the value of the ``template_name`` attribute
on the ``Tab`` class. on the ``Tab`` class.
@ -351,16 +340,14 @@ class Tab(html.HTMLElement):
return self.template_name return self.template_name
def get_context_data(self, request): def get_context_data(self, request):
""" """This method should return a dictionary of context data used to
This method should return a dictionary of context data used to render render the tab. Required.
the tab. Required.
""" """
raise NotImplementedError("%s needs to define a get_context_data " raise NotImplementedError("%s needs to define a get_context_data "
"method." % self.__class__.__name__) "method." % self.__class__.__name__)
def enabled(self, request): def enabled(self, request):
""" """Determines whether or not the tab should be accessible
Determines whether or not the tab should be accessible
(e.g. be rendered into the HTML on load and respond to a click event). (e.g. be rendered into the HTML on load and respond to a click event).
If a tab returns ``False`` from ``enabled`` it will ignore the value If a tab returns ``False`` from ``enabled`` it will ignore the value
@ -371,8 +358,7 @@ class Tab(html.HTMLElement):
return True return True
def allowed(self, request): def allowed(self, request):
""" """Determines whether or not the tab is displayed.
Determines whether or not the tab is displayed.
Tab instances can override this method to specify conditions under Tab instances can override this method to specify conditions under
which this tab should not be shown at all by returning ``False``. which this tab should not be shown at all by returning ``False``.
@ -382,8 +368,7 @@ class Tab(html.HTMLElement):
return True return True
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
""" """Handles POST data sent to a tab.
Handles POST data sent to a tab.
Tab instances can override this method to have tab-specific POST logic Tab instances can override this method to have tab-specific POST logic
without polluting the TabView code. without polluting the TabView code.
@ -394,8 +379,7 @@ class Tab(html.HTMLElement):
class TableTab(Tab): class TableTab(Tab):
""" """A :class:`~horizon.tabs.Tab` class which knows how to deal with
A :class:`~horizon.tabs.Tab` class which knows how to deal with
:class:`~horizon.tables.DataTable` classes rendered inside of it. :class:`~horizon.tables.DataTable` classes rendered inside of it.
This distinct class is required due to the complexity involved in handling This distinct class is required due to the complexity involved in handling
@ -427,8 +411,7 @@ class TableTab(Tab):
self._table_data_loaded = False self._table_data_loaded = False
def load_table_data(self): def load_table_data(self):
""" """Calls the ``get_{{ table_name }}_data`` methods for each table class
Calls the ``get_{{ table_name }}_data`` methods for each table class
and sets the data on the tables. and sets the data on the tables.
""" """
# We only want the data to be loaded once, so we track if we have... # We only want the data to be loaded once, so we track if we have...
@ -448,8 +431,7 @@ class TableTab(Tab):
self._table_data_loaded = True self._table_data_loaded = True
def get_context_data(self, request): def get_context_data(self, request):
""" """Adds a ``{{ table_name }}_table`` item to the context for each table
Adds a ``{{ table_name }}_table`` item to the context for each table
in the :attr:`~horizon.tabs.TableTab.table_classes` attribute. in the :attr:`~horizon.tabs.TableTab.table_classes` attribute.
If only one table class is provided, a shortcut ``table`` context If only one table class is provided, a shortcut ``table`` context

View File

@ -19,8 +19,8 @@ from horizon.tabs.base import TableTab # noqa
class TabView(generic.TemplateView): class TabView(generic.TemplateView):
""" """A generic class-based view for displaying a
A generic class-based view for displaying a :class:`horizon.tabs.TabGroup`. :class:`horizon.tabs.TabGroup`.
This view handles selecting specific tabs and deals with AJAX requests This view handles selecting specific tabs and deals with AJAX requests
gracefully. gracefully.
@ -39,13 +39,13 @@ class TabView(generic.TemplateView):
"on %s." % self.__class__.__name__) "on %s." % self.__class__.__name__)
def get_tabs(self, request, **kwargs): def get_tabs(self, request, **kwargs):
""" Returns the initialized tab group for this view. """ """Returns the initialized tab group for this view."""
if self._tab_group is None: if self._tab_group is None:
self._tab_group = self.tab_group_class(request, **kwargs) self._tab_group = self.tab_group_class(request, **kwargs)
return self._tab_group return self._tab_group
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
""" Adds the ``tab_group`` variable to the context data. """ """Adds the ``tab_group`` variable to the context data."""
context = super(TabView, self).get_context_data(**kwargs) context = super(TabView, self).get_context_data(**kwargs)
try: try:
tab_group = self.get_tabs(self.request, **kwargs) tab_group = self.get_tabs(self.request, **kwargs)
@ -57,8 +57,7 @@ class TabView(generic.TemplateView):
return context return context
def handle_tabbed_response(self, tab_group, context): def handle_tabbed_response(self, tab_group, context):
""" """Sends back an AJAX-appropriate response for the tab group if
Sends back an AJAX-appropriate response for the tab group if
required, otherwise renders the response as normal. required, otherwise renders the response as normal.
""" """
if self.request.is_ajax(): if self.request.is_ajax():
@ -90,8 +89,7 @@ class TabbedTableView(tables.MultiTableMixin, TabView):
self._table_dict = {} self._table_dict = {}
def load_tabs(self): def load_tabs(self):
""" """Loads the tab group, and compiles the table instances for each
Loads the tab group, and compiles the table instances for each
table attached to any :class:`horizon.tabs.TableTab` instances on table attached to any :class:`horizon.tabs.TableTab` instances on
the tab group. This step is necessary before processing any the tab group. This step is necessary before processing any
tab or table actions. tab or table actions.
@ -105,14 +103,13 @@ class TabbedTableView(tables.MultiTableMixin, TabView):
'tab': tab} 'tab': tab}
def get_tables(self): def get_tables(self):
""" A no-op on this class. Tables are handled at the tab level. """ """A no-op on this class. Tables are handled at the tab level."""
# Override the base class implementation so that the MultiTableMixin # Override the base class implementation so that the MultiTableMixin
# doesn't freak out. We do the processing at the TableTab level. # doesn't freak out. We do the processing at the TableTab level.
return {} return {}
def handle_table(self, table_dict): def handle_table(self, table_dict):
""" """For the given dict containing a ``DataTable`` and a ``TableTab``
For the given dict containing a ``DataTable`` and a ``TableTab``
instance, it loads the table data for that tab and calls the instance, it loads the table data for that tab and calls the
table's :meth:`~horizon.tables.DataTable.maybe_handle` method. The table's :meth:`~horizon.tables.DataTable.maybe_handle` method. The
return value will be the result of ``maybe_handle``. return value will be the result of ``maybe_handle``.

View File

@ -30,8 +30,7 @@ register = template.Library()
@register.filter @register.filter
def has_permissions(user, component): def has_permissions(user, component):
""" """Checks if the given user meets the permissions requirements for
Checks if the given user meets the permissions requirements for
the component. the component.
""" """
return user.has_perms(getattr(component, 'permissions', set())) return user.has_perms(getattr(component, 'permissions', set()))
@ -45,7 +44,7 @@ def has_permissions_on_list(components, user):
@register.inclusion_tag('horizon/_nav_list.html', takes_context=True) @register.inclusion_tag('horizon/_nav_list.html', takes_context=True)
def horizon_main_nav(context): def horizon_main_nav(context):
""" Generates top-level dashboard navigation entries. """ """Generates top-level dashboard navigation entries."""
if 'request' not in context: if 'request' not in context:
return {} return {}
current_dashboard = context['request'].horizon.get('dashboard', None) current_dashboard = context['request'].horizon.get('dashboard', None)
@ -63,7 +62,7 @@ def horizon_main_nav(context):
@register.inclusion_tag('horizon/_subnav_list.html', takes_context=True) @register.inclusion_tag('horizon/_subnav_list.html', takes_context=True)
def horizon_dashboard_nav(context): def horizon_dashboard_nav(context):
""" Generates sub-navigation entries for the current dashboard. """ """Generates sub-navigation entries for the current dashboard."""
if 'request' not in context: if 'request' not in context:
return {} return {}
dashboard = context['request'].horizon['dashboard'] dashboard = context['request'].horizon['dashboard']
@ -97,7 +96,7 @@ def quota(val, units=None):
class JSTemplateNode(template.Node): class JSTemplateNode(template.Node):
""" Helper node for the ``jstemplate`` template tag. """ """Helper node for the ``jstemplate`` template tag."""
def __init__(self, nodelist): def __init__(self, nodelist):
self.nodelist = nodelist self.nodelist = nodelist
@ -111,8 +110,7 @@ class JSTemplateNode(template.Node):
@register.tag @register.tag
def jstemplate(parser, token): def jstemplate(parser, token):
""" """Replaces ``[[[`` and ``]]]`` with ``{{{`` and ``}}}``,
Replaces ``[[[`` and ``]]]`` with ``{{{`` and ``}}}``,
``[[`` and ``]]`` with ``{{`` and ``}}`` and ``[[`` and ``]]`` with ``{{`` and ``}}`` and
``[%`` and ``%]`` with ``{%`` and ``%}`` to avoid conflicts ``[%`` and ``%]`` with ``{%`` and ``%}`` to avoid conflicts
with Django's template engine when using any of the Mustache-based with Django's template engine when using any of the Mustache-based

View File

@ -32,8 +32,8 @@ register = template.Library()
class ParseDateNode(template.Node): class ParseDateNode(template.Node):
def render(self, datestring): def render(self, datestring):
""" """Parses a date-like input string into a timezone aware Python
Parses a date-like input string into a timezone aware Python datetime. datetime.
""" """
formats = ["%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%d %H:%M:%S.%f", formats = ["%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%d %H:%M:%S.%f",
"%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"] "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"]

View File

@ -73,8 +73,9 @@ def mbformat(mb):
@register.filter(name='mb_float_format') @register.filter(name='mb_float_format')
def mb_float_format(mb): def mb_float_format(mb):
""" Takes a size value in mb, and prints returns the data in a """Takes a size value in mb, and prints returns the data in a
saner unit. """ saner unit.
"""
if not mb: if not mb:
return 0 return 0
return filesizeformat(mb * 1024 * 1024, float_format) return filesizeformat(mb * 1024 * 1024, float_format)

View File

@ -75,8 +75,7 @@ class RequestFactoryWithMessages(RequestFactory):
@unittest.skipIf(os.environ.get('SKIP_UNITTESTS', False), @unittest.skipIf(os.environ.get('SKIP_UNITTESTS', False),
"The SKIP_UNITTESTS env variable is set.") "The SKIP_UNITTESTS env variable is set.")
class TestCase(django_test.TestCase): class TestCase(django_test.TestCase):
""" """Specialized base test case class for Horizon which gives access to
Specialized base test case class for Horizon which gives access to
numerous additional features: numerous additional features:
* The ``mox`` mocking framework via ``self.mox``. * The ``mox`` mocking framework via ``self.mox``.
@ -115,15 +114,13 @@ class TestCase(django_test.TestCase):
del self.user._perm_cache del self.user._perm_cache
def assertNoMessages(self, response=None): def assertNoMessages(self, response=None):
""" """Asserts that no messages have been attached by the
Asserts that no messages have been attached by the ``contrib.messages`` ``contrib.messages`` framework.
framework.
""" """
self.assertMessageCount(response, success=0, warn=0, info=0, error=0) self.assertMessageCount(response, success=0, warn=0, info=0, error=0)
def assertMessageCount(self, response=None, **kwargs): def assertMessageCount(self, response=None, **kwargs):
""" """Asserts that the specified number of messages have been attached
Asserts that the specified number of messages have been attached
for various message types. Usage would look like for various message types. Usage would look like
``self.assertMessageCount(success=1)``. ``self.assertMessageCount(success=1)``.
""" """

View File

@ -102,12 +102,11 @@ class BaseHorizonTests(test.TestCase):
dash.register(panel) dash.register(panel)
def _reload_urls(self): def _reload_urls(self):
''' """Clears out the URL caches, reloads the root urls module, and
Clears out the URL caches, reloads the root urls module, and
re-triggers the autodiscovery mechanism for Horizon. Allows URLs re-triggers the autodiscovery mechanism for Horizon. Allows URLs
to be re-calculated after registering new dashboards. Useful to be re-calculated after registering new dashboards. Useful
only for testing and should never be used on a live site. only for testing and should never be used on a live site.
''' """
urlresolvers.clear_url_caches() urlresolvers.clear_url_caches()
reload(import_module(settings.ROOT_URLCONF)) reload(import_module(settings.ROOT_URLCONF))
base.Horizon._urls() base.Horizon._urls()
@ -116,7 +115,7 @@ class BaseHorizonTests(test.TestCase):
class HorizonTests(BaseHorizonTests): class HorizonTests(BaseHorizonTests):
def test_registry(self): def test_registry(self):
""" Verify registration and autodiscovery work correctly. """Verify registration and autodiscovery work correctly.
Please note that this implicitly tests that autodiscovery works Please note that this implicitly tests that autodiscovery works
by virtue of the fact that the dashboards listed in by virtue of the fact that the dashboards listed in
@ -210,12 +209,12 @@ class HorizonTests(BaseHorizonTests):
reversed(urlpatterns) reversed(urlpatterns)
def test_horizon_test_isolation_1(self): def test_horizon_test_isolation_1(self):
""" Isolation Test Part 1: sets a value. """ """Isolation Test Part 1: sets a value."""
cats = horizon.get_dashboard("cats") cats = horizon.get_dashboard("cats")
cats.evil = True cats.evil = True
def test_horizon_test_isolation_2(self): def test_horizon_test_isolation_2(self):
""" Isolation Test Part 2: The value set in part 1 should be gone. """ """Isolation Test Part 2: The value set in part 1 should be gone."""
cats = horizon.get_dashboard("cats") cats = horizon.get_dashboard("cats")
self.assertFalse(hasattr(cats, "evil")) self.assertFalse(hasattr(cats, "evil"))
@ -299,7 +298,7 @@ class HorizonTests(BaseHorizonTests):
class CustomPanelTests(BaseHorizonTests): class CustomPanelTests(BaseHorizonTests):
""" Test customization of dashboards and panels """Test customization of dashboards and panels
using 'customization_module' to HORIZON_CONFIG. using 'customization_module' to HORIZON_CONFIG.
""" """
@ -334,7 +333,7 @@ class CustomPanelTests(BaseHorizonTests):
class CustomPermissionsTests(BaseHorizonTests): class CustomPermissionsTests(BaseHorizonTests):
""" Test customization of permissions on panels """Test customization of permissions on panels
using 'customization_module' to HORIZON_CONFIG. using 'customization_module' to HORIZON_CONFIG.
""" """

View File

@ -190,7 +190,7 @@ class NoActionsTable(tables.DataTable):
class DataTableTests(test.TestCase): class DataTableTests(test.TestCase):
def test_table_instantiation(self): def test_table_instantiation(self):
""" Tests everything that happens when the table is instantiated. """ """Tests everything that happens when the table is instantiated."""
self.table = MyTable(self.request, TEST_DATA) self.table = MyTable(self.request, TEST_DATA)
# Properties defined on the table # Properties defined on the table
self.assertEqual(self.table.data, TEST_DATA) self.assertEqual(self.table.data, TEST_DATA)

View File

@ -29,22 +29,22 @@ from horizon.test import helpers as test
def single_line(text): def single_line(text):
''' Quick utility to make comparing template output easier. ''' """Quick utility to make comparing template output easier."""
return re.sub(' +', return re.sub(' +',
' ', ' ',
normalize_newlines(text).replace('\n', '')).strip() normalize_newlines(text).replace('\n', '')).strip()
class TemplateTagTests(test.TestCase): class TemplateTagTests(test.TestCase):
'''Test Custom Template Tag''' """Test Custom Template Tag."""
def render_template_tag(self, tag_name, tag_require=''): def render_template_tag(self, tag_name, tag_require=''):
'''Render a Custom Template Tag to string''' """Render a Custom Template Tag to string."""
template = Template("{%% load %s %%}{%% %s %%}" template = Template("{%% load %s %%}{%% %s %%}"
% (tag_require, tag_name)) % (tag_require, tag_name))
return template.render(Context()) return template.render(Context())
def test_site_branding_tag(self): def test_site_branding_tag(self):
'''Test if site_branding tag renders the correct setting''' """Test if site_branding tag renders the correct setting."""
rendered_str = self.render_template_tag("site_branding", "branding") rendered_str = self.render_template_tag("site_branding", "branding")
self.assertEqual(settings.SITE_BRANDING, rendered_str.strip(), self.assertEqual(settings.SITE_BRANDING, rendered_str.strip(),
"tag site_branding renders %s" % rendered_str.strip()) "tag site_branding renders %s" % rendered_str.strip())

View File

@ -27,8 +27,7 @@ IPv6 = 2
class IPField(forms.Field): class IPField(forms.Field):
""" """Form field for entering IP/range values, with validation.
Form field for entering IP/range values, with validation.
Supports IPv4/IPv6 in the format: Supports IPv4/IPv6 in the format:
.. xxx.xxx.xxx.xxx .. xxx.xxx.xxx.xxx
.. xxx.xxx.xxx.xxx/zz .. xxx.xxx.xxx.xxx/zz
@ -102,9 +101,7 @@ class IPField(forms.Field):
class MultiIPField(IPField): class MultiIPField(IPField):
""" """Extends IPField to allow comma-separated lists of addresses."""
Extends IPField to allow comma-separated lists of addresses
"""
def validate(self, value): def validate(self, value):
self.addresses = [] self.addresses = []
if value: if value:
@ -121,8 +118,7 @@ class MultiIPField(IPField):
class SelectWidget(widgets.Select): class SelectWidget(widgets.Select):
""" """Customizable select widget, that allows to render
Customizable select widget, that allows to render
data-xxx attributes from choices. data-xxx attributes from choices.
.. attribute:: data_attrs .. attribute:: data_attrs

View File

@ -29,8 +29,7 @@ def replace_underscores(string):
@register.filter @register.filter
def parse_isotime(timestr): def parse_isotime(timestr):
""" """This duplicates oslo timeutils parse_isotime but with a
This duplicates oslo timeutils parse_isotime but with a
@register.filter annotation. @register.filter annotation.
""" """
try: try:

View File

@ -16,28 +16,25 @@ from django.forms.util import flatatt # noqa
class HTMLElement(object): class HTMLElement(object):
""" A generic base class that gracefully handles html-style attributes. """ """A generic base class that gracefully handles html-style attributes."""
def __init__(self): def __init__(self):
self.attrs = getattr(self, "attrs", {}) self.attrs = getattr(self, "attrs", {})
self.classes = getattr(self, "classes", []) self.classes = getattr(self, "classes", [])
def get_default_classes(self): def get_default_classes(self):
""" """Returns an iterable of default classes which should be combined with
Returns an iterable of default classes which should be combined with
any other declared classes. any other declared classes.
""" """
return [] return []
def get_default_attrs(self): def get_default_attrs(self):
""" """Returns a dict of default attributes which should be combined with
Returns a dict of default attributes which should be combined with
other declared attributes. other declared attributes.
""" """
return {} return {}
def get_final_attrs(self): def get_final_attrs(self):
""" """Returns a dict containing the final attributes of this element
Returns a dict containing the final attributes of this element
which will be rendered. which will be rendered.
""" """
final_attrs = copy.copy(self.get_default_attrs()) final_attrs = copy.copy(self.get_default_attrs())
@ -53,16 +50,13 @@ class HTMLElement(object):
@property @property
def attr_string(self): def attr_string(self):
""" """Returns a flattened string of HTML attributes based on the
Returns a flattened string of HTML attributes based on the
``attrs`` dict provided to the class. ``attrs`` dict provided to the class.
""" """
return flatatt(self.get_final_attrs()) return flatatt(self.get_final_attrs())
@property @property
def class_string(self): def class_string(self):
""" """Returns a list of class name of HTML Element in string."""
Returns a list of class name of HTML Element in string
"""
classes_str = " ".join(self.classes) classes_str = " ".join(self.classes)
return classes_str return classes_str

View File

@ -39,7 +39,7 @@ def password_validator_msg():
def validate_port_or_colon_separated_port_range(port_range): def validate_port_or_colon_separated_port_range(port_range):
"""accepts a port number or a single-colon separated range""" """Accepts a port number or a single-colon separated range."""
if port_range.count(':') > 1: if port_range.count(':') > 1:
raise ValidationError(_("One colon allowed in port range")) raise ValidationError(_("One colon allowed in port range"))
ports = port_range.split(':') ports = port_range.split(':')

View File

@ -22,12 +22,12 @@ from horizon import exceptions
def user_home(request): def user_home(request):
""" Reversible named view to direct a user to the appropriate homepage. """ """Reversible named view to direct a user to the appropriate homepage."""
return shortcuts.redirect(horizon.get_user_home(request.user)) return shortcuts.redirect(horizon.get_user_home(request.user))
class APIView(generic.TemplateView): class APIView(generic.TemplateView):
""" A quick class-based view for putting API data into a template. """A quick class-based view for putting API data into a template.
Subclasses must define one method, ``get_data``, and a template name Subclasses must define one method, ``get_data``, and a template name
via the ``template_name`` attribute on the class. via the ``template_name`` attribute on the class.
@ -37,8 +37,7 @@ class APIView(generic.TemplateView):
caught. caught.
""" """
def get_data(self, request, context, *args, **kwargs): def get_data(self, request, context, *args, **kwargs):
""" """This method should handle any necessary API calls, update the
This method should handle any necessary API calls, update the
context object, and return the context object at the end. context object, and return the context object at the end.
""" """
raise NotImplementedError("You must define a get_data method " raise NotImplementedError("You must define a get_data method "

View File

@ -76,8 +76,7 @@ class ActionMetaclass(forms.forms.DeclarativeFieldsMetaclass):
class Action(forms.Form): class Action(forms.Form):
""" """An ``Action`` represents an atomic logical interaction you can have with
An ``Action`` represents an atomic logical interaction you can have with
the system. This is easier to understand with a conceptual example: in the the system. This is easier to understand with a conceptual example: in the
context of a "launch instance" workflow, actions would include "naming context of a "launch instance" workflow, actions would include "naming
the instance", "selecting an image", and ultimately "launching the the instance", "selecting an image", and ultimately "launching the
@ -154,7 +153,7 @@ class Action(forms.Form):
bound_field.choices = meth(request, context) bound_field.choices = meth(request, context)
def get_help_text(self, extra_context=None): def get_help_text(self, extra_context=None):
""" Returns the help text for this step. """ """Returns the help text for this step."""
text = "" text = ""
extra_context = extra_context or {} extra_context = extra_context or {}
if self.help_text_template: if self.help_text_template:
@ -166,14 +165,11 @@ class Action(forms.Form):
return safe(text) return safe(text)
def add_error(self, message): def add_error(self, message):
""" """Adds an error to the Action's Step based on API issues."""
Adds an error to the Action's Step based on API issues.
"""
self._get_errors()[NON_FIELD_ERRORS] = self.error_class([message]) self._get_errors()[NON_FIELD_ERRORS] = self.error_class([message])
def handle(self, request, context): def handle(self, request, context):
""" """Handles any requisite processing for this action. The method should
Handles any requisite processing for this action. The method should
return either ``None`` or a dictionary of data to be passed to return either ``None`` or a dictionary of data to be passed to
:meth:`~horizon.workflows.Step.contribute`. :meth:`~horizon.workflows.Step.contribute`.
@ -183,8 +179,7 @@ class Action(forms.Form):
class MembershipAction(Action): class MembershipAction(Action):
""" """An action that allows a user to add/remove members from a group.
An action that allows a user to add/remove members from a group.
Extend the Action class with additional helper method for membership Extend the Action class with additional helper method for membership
management. management.
@ -197,8 +192,7 @@ class MembershipAction(Action):
class Step(object): class Step(object):
""" """A step is a wrapper around an action which defines its context in a
A step is a wrapper around an action which defines its context in a
workflow. It knows about details such as: workflow. It knows about details such as:
* The workflow's context data (data passed from step to step). * The workflow's context data (data passed from step to step).
@ -380,9 +374,8 @@ class Step(object):
return self._action return self._action
def prepare_action_context(self, request, context): def prepare_action_context(self, request, context):
""" """Allows for customization of how the workflow context is passed to
Allows for customization of how the workflow context is passed to the the action; this is the reverse of what "contribute" does to make the
action; this is the reverse of what "contribute" does to make the
action outputs sane for the workflow. Changes to the context are not action outputs sane for the workflow. Changes to the context are not
saved globally here. They are localized to the action. saved globally here. They are localized to the action.
@ -391,7 +384,7 @@ class Step(object):
return context return context
def get_id(self): def get_id(self):
""" Returns the ID for this step. Suitable for use in HTML markup. """ """Returns the ID for this step. Suitable for use in HTML markup."""
return "%s__%s" % (self.workflow.slug, self.slug) return "%s__%s" % (self.workflow.slug, self.slug)
def _verify_contributions(self, context): def _verify_contributions(self, context):
@ -412,8 +405,7 @@ class Step(object):
return True return True
def contribute(self, data, context): def contribute(self, data, context):
""" """Adds the data listed in ``contributes`` to the workflow's shared
Adds the data listed in ``contributes`` to the workflow's shared
context. By default, the context is simply updated with all the data context. By default, the context is simply updated with all the data
returned by the action. returned by the action.
@ -427,7 +419,7 @@ class Step(object):
return context return context
def render(self): def render(self):
""" Renders the step. """ """Renders the step."""
step_template = template.loader.get_template(self.template_name) step_template = template.loader.get_template(self.template_name)
extra_context = {"form": self.action, extra_context = {"form": self.action,
"step": self} "step": self}
@ -435,21 +427,17 @@ class Step(object):
return step_template.render(context) return step_template.render(context)
def get_help_text(self): def get_help_text(self):
""" Returns the help text for this step. """ """Returns the help text for this step."""
text = linebreaks(force_unicode(self.help_text)) text = linebreaks(force_unicode(self.help_text))
text += self.action.get_help_text() text += self.action.get_help_text()
return safe(text) return safe(text)
def add_error(self, message): def add_error(self, message):
""" """Adds an error to the Step based on API issues."""
Adds an error to the Step based on API issues.
"""
self.action.add_error(message) self.action.add_error(message)
def has_required_fields(self): def has_required_fields(self):
""" """Returns True if action contains any required fields."""
Returns True if action contains any required fields
"""
for key in self.contributes: for key in self.contributes:
field = self.action.fields.get(key, None) field = self.action.fields.get(key, None)
if (field and field.required): if (field and field.required):
@ -503,8 +491,7 @@ class UpdateMembersStep(Step):
class Workflow(html.HTMLElement): class Workflow(html.HTMLElement):
""" """A Workflow is a collection of Steps. Its interface is very
A Workflow is a collection of Steps. Its interface is very
straightforward, but it is responsible for handling some very straightforward, but it is responsible for handling some very
important tasks such as: important tasks such as:
@ -665,7 +652,7 @@ class Workflow(html.HTMLElement):
return self._ordered_steps return self._ordered_steps
def get_step(self, slug): def get_step(self, slug):
""" Returns the instantiated step matching the given slug. """ """Returns the instantiated step matching the given slug."""
for step in self.steps: for step in self.steps:
if step.slug == slug: if step.slug == slug:
return step return step
@ -705,8 +692,7 @@ class Workflow(html.HTMLElement):
return steps return steps
def get_entry_point(self): def get_entry_point(self):
""" """Returns the slug of the step which the workflow should begin on.
Returns the slug of the step which the workflow should begin on.
This method takes into account both already-available data and errors This method takes into account both already-available data and errors
within the steps. within the steps.
@ -736,7 +722,7 @@ class Workflow(html.HTMLElement):
@classmethod @classmethod
def register(cls, step_class): def register(cls, step_class):
""" Registers a :class:`~horizon.workflows.Step` with the workflow. """ """Registers a :class:`~horizon.workflows.Step` with the workflow."""
if not inspect.isclass(step_class): if not inspect.isclass(step_class):
raise ValueError('Only classes may be registered.') raise ValueError('Only classes may be registered.')
elif not issubclass(step_class, cls._registerable_class): elif not issubclass(step_class, cls._registerable_class):
@ -750,8 +736,7 @@ class Workflow(html.HTMLElement):
@classmethod @classmethod
def unregister(cls, step_class): def unregister(cls, step_class):
""" """Unregisters a :class:`~horizon.workflows.Step` from the workflow.
Unregisters a :class:`~horizon.workflows.Step` from the workflow.
""" """
try: try:
cls._cls_registry.remove(step_class) cls._cls_registry.remove(step_class)
@ -760,15 +745,13 @@ class Workflow(html.HTMLElement):
return cls._unregister(step_class) return cls._unregister(step_class)
def validate(self, context): def validate(self, context):
""" """Hook for custom context data validation. Should return a boolean
Hook for custom context data validation. Should return a boolean
value or raise :class:`~horizon.exceptions.WorkflowValidationError`. value or raise :class:`~horizon.exceptions.WorkflowValidationError`.
""" """
return True return True
def is_valid(self): def is_valid(self):
""" """Verified that all required data is present in the context and
Verified that all required data is present in the context and
calls the ``validate`` method to allow for finer-grained checks calls the ``validate`` method to allow for finer-grained checks
on the context data. on the context data.
""" """
@ -790,8 +773,7 @@ class Workflow(html.HTMLElement):
return self.validate(self.context) return self.validate(self.context)
def finalize(self): def finalize(self):
""" """Finalizes a workflow by running through all the actions in order
Finalizes a workflow by running through all the actions in order
and calling their ``handle`` methods. Returns ``True`` on full success, and calling their ``handle`` methods. Returns ``True`` on full success,
or ``False`` for a partial success, e.g. there were non-critical or ``False`` for a partial success, e.g. there were non-critical
errors. (If it failed completely the function wouldn't return.) errors. (If it failed completely the function wouldn't return.)
@ -814,15 +796,13 @@ class Workflow(html.HTMLElement):
return not partial return not partial
def handle(self, request, context): def handle(self, request, context):
""" """Handles any final processing for this workflow. Should return a
Handles any final processing for this workflow. Should return a boolean boolean value indicating success.
value indicating success.
""" """
return True return True
def get_success_url(self): def get_success_url(self):
""" """Returns a URL to redirect the user to upon completion. By default it
Returns a URL to redirect the user to upon completion. By default it
will attempt to parse a ``success_url`` attribute on the workflow, will attempt to parse a ``success_url`` attribute on the workflow,
which can take the form of a reversible URL pattern name, or a which can take the form of a reversible URL pattern name, or a
standard HTTP URL. standard HTTP URL.
@ -833,8 +813,7 @@ class Workflow(html.HTMLElement):
return self.success_url return self.success_url
def format_status_message(self, message): def format_status_message(self, message):
""" """Hook to allow customization of the message returned to the user
Hook to allow customization of the message returned to the user
upon successful or unsuccessful completion of the workflow. upon successful or unsuccessful completion of the workflow.
By default it simply inserts the workflow's name into the message By default it simply inserts the workflow's name into the message
@ -846,7 +825,7 @@ class Workflow(html.HTMLElement):
return message return message
def render(self): def render(self):
""" Renders the workflow. """ """Renders the workflow."""
workflow_template = template.loader.get_template(self.template_name) workflow_template = template.loader.get_template(self.template_name)
extra_context = {"workflow": self} extra_context = {"workflow": self}
if self.request.is_ajax(): if self.request.is_ajax():
@ -855,7 +834,7 @@ class Workflow(html.HTMLElement):
return workflow_template.render(context) return workflow_template.render(context)
def get_absolute_url(self): def get_absolute_url(self):
""" Returns the canonical URL for this workflow. """Returns the canonical URL for this workflow.
This is used for the POST action attribute on the form element This is used for the POST action attribute on the form element
wrapping the workflow. wrapping the workflow.
@ -867,8 +846,7 @@ class Workflow(html.HTMLElement):
return self.request.get_full_path().partition('?')[0] return self.request.get_full_path().partition('?')[0]
def add_error_to_step(self, message, slug): def add_error_to_step(self, message, slug):
""" """Adds an error to the workflow's Step with the
Adds an error to the workflow's Step with the
specifed slug based on API issues. This is useful specifed slug based on API issues. This is useful
when you wish for API errors to appear as errors on when you wish for API errors to appear as errors on
the form rather than using the messages framework. the form rather than using the messages framework.

View File

@ -27,8 +27,7 @@ from horizon import messages
class WorkflowView(generic.TemplateView): class WorkflowView(generic.TemplateView):
""" """A generic class-based view which handles the intricacies of workflow
A generic class-based view which handles the intricacies of workflow
processing with minimal user configuration. processing with minimal user configuration.
.. attribute:: workflow_class .. attribute:: workflow_class
@ -65,14 +64,13 @@ class WorkflowView(generic.TemplateView):
"on %s." % self.__class__.__name__) "on %s." % self.__class__.__name__)
def get_initial(self): def get_initial(self):
""" """Returns initial data for the workflow. Defaults to using the GET
Returns initial data for the workflow. Defaults to using the GET
parameters to allow pre-seeding of the workflow context values. parameters to allow pre-seeding of the workflow context values.
""" """
return copy.copy(self.request.GET) return copy.copy(self.request.GET)
def get_workflow(self): def get_workflow(self):
""" Returns the instanciated workflow class. """ """Returns the instanciated workflow class."""
extra_context = self.get_initial() extra_context = self.get_initial()
entry_point = self.request.GET.get("step", None) entry_point = self.request.GET.get("step", None)
workflow = self.workflow_class(self.request, workflow = self.workflow_class(self.request,
@ -81,8 +79,7 @@ class WorkflowView(generic.TemplateView):
return workflow return workflow
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
""" """Returns the template context, including the workflow class.
Returns the template context, including the workflow class.
This method should be overridden in subclasses to provide additional This method should be overridden in subclasses to provide additional
context data to the template. context data to the template.
@ -99,7 +96,7 @@ class WorkflowView(generic.TemplateView):
return context return context
def get_template_names(self): def get_template_names(self):
""" Returns the template name to use for this request. """ """Returns the template name to use for this request."""
if self.request.is_ajax(): if self.request.is_ajax():
template = self.ajax_template_name template = self.ajax_template_name
else: else:
@ -122,13 +119,13 @@ class WorkflowView(generic.TemplateView):
workflow.add_error_to_step(error_msg, step) workflow.add_error_to_step(error_msg, step)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
""" Handler for HTTP GET requests. """ """Handler for HTTP GET requests."""
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
self.set_workflow_step_errors(context) self.set_workflow_step_errors(context)
return self.render_to_response(context) return self.render_to_response(context)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
""" Handler for HTTP POST requests. """ """Handler for HTTP POST requests."""
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
workflow = context[self.context_object_name] workflow = context[self.context_object_name]
if workflow.is_valid(): if workflow.is_valid():

View File

@ -34,7 +34,7 @@ LOG = logging.getLogger(__name__)
class APIVersionManager(object): class APIVersionManager(object):
""" Object to store and manage API versioning data and utility methods. """ """Object to store and manage API versioning data and utility methods."""
SETTINGS_KEY = "OPENSTACK_API_VERSIONS" SETTINGS_KEY = "OPENSTACK_API_VERSIONS"
@ -67,10 +67,10 @@ class APIVersionManager(object):
class APIResourceWrapper(object): class APIResourceWrapper(object):
""" Simple wrapper for api objects """Simple wrapper for api objects.
Define _attrs on the child class and pass in the Define _attrs on the child class and pass in the
api object as the only argument to the constructor api object as the only argument to the constructor
""" """
_attrs = [] _attrs = []
@ -97,14 +97,14 @@ class APIResourceWrapper(object):
class APIDictWrapper(object): class APIDictWrapper(object):
""" Simple wrapper for api dictionaries """Simple wrapper for api dictionaries
Some api calls return dictionaries. This class provides identical Some api calls return dictionaries. This class provides identical
behavior as APIResourceWrapper, except that it will also behave as a behavior as APIResourceWrapper, except that it will also behave as a
dictionary, in addition to attribute accesses. dictionary, in addition to attribute accesses.
Attribute access is the preferred method of access, to be Attribute access is the preferred method of access, to be
consistent with api resource objects from novaclient. consistent with api resource objects from novaclient.
""" """
def __init__(self, apidict): def __init__(self, apidict):
self._apidict = apidict self._apidict = apidict
@ -146,8 +146,7 @@ class Quota(object):
class QuotaSet(Sequence): class QuotaSet(Sequence):
""" """Wrapper for client QuotaSet objects which turns the individual quotas
Wrapper for client QuotaSet objects which turns the individual quotas
into Quota objects for easier handling/iteration. into Quota objects for easier handling/iteration.
`QuotaSet` objects support a mix of `list` and `dict` methods; you can use `QuotaSet` objects support a mix of `list` and `dict` methods; you can use
@ -177,8 +176,9 @@ class QuotaSet(Sequence):
return self.items[index] return self.items[index]
def __add__(self, other): def __add__(self, other):
'''Merge another QuotaSet into this one. Existing quotas are """Merge another QuotaSet into this one. Existing quotas are
not overriden.''' not overriden.
"""
if not isinstance(other, QuotaSet): if not isinstance(other, QuotaSet):
msg = "Can only add QuotaSet to QuotaSet, " \ msg = "Can only add QuotaSet to QuotaSet, " \
"but received %s instead" % type(other) "but received %s instead" % type(other)

View File

@ -25,8 +25,7 @@ LOG = logging.getLogger(__name__)
def is_iterable(var): def is_iterable(var):
""" Return True if the given is list or tuple. """Return True if the given is list or tuple."""
"""
return (isinstance(var, (list, tuple)) or return (isinstance(var, (list, tuple)) or
issubclass(var.__class__, (list, tuple))) issubclass(var.__class__, (list, tuple)))
@ -34,7 +33,7 @@ def is_iterable(var):
def make_query(user_id=None, tenant_id=None, resource_id=None, def make_query(user_id=None, tenant_id=None, resource_id=None,
user_ids=None, tenant_ids=None, resource_ids=None): user_ids=None, tenant_ids=None, resource_ids=None):
""" Returns query built form given parameters. """Returns query built form given parameters.
This query can be then used for querying resources, meters and This query can be then used for querying resources, meters and
statistics. statistics.
@ -71,15 +70,13 @@ def make_query(user_id=None, tenant_id=None, resource_id=None,
class Meter(base.APIResourceWrapper): class Meter(base.APIResourceWrapper):
""" Represents one Ceilometer meter. """Represents one Ceilometer meter."""
"""
_attrs = ['name', 'type', 'unit', 'resource_id', 'user_id', _attrs = ['name', 'type', 'unit', 'resource_id', 'user_id',
'project_id'] 'project_id']
class Resource(base.APIResourceWrapper): class Resource(base.APIResourceWrapper):
""" Represents one Ceilometer resource. """Represents one Ceilometer resource."""
"""
_attrs = ['resource_id', 'source', 'user_id', 'project_id', 'metadata', _attrs = ['resource_id', 'source', 'user_id', 'project_id', 'metadata',
'links'] 'links']
@ -140,7 +137,7 @@ class Resource(base.APIResourceWrapper):
class ResourceAggregate(Resource): class ResourceAggregate(Resource):
""" Represents aggregate of more resources together. """Represents aggregate of more resources together.
Aggregate of resources can be obtain by specifing Aggregate of resources can be obtain by specifing
multiple ids in one parameter or by not specifying multiple ids in one parameter or by not specifying
@ -194,8 +191,7 @@ class ResourceAggregate(Resource):
class Sample(base.APIResourceWrapper): class Sample(base.APIResourceWrapper):
""" Represents one Ceilometer sample. """Represents one Ceilometer sample."""
"""
_attrs = ['counter_name', 'user_id', 'resource_id', 'timestamp', _attrs = ['counter_name', 'user_id', 'resource_id', 'timestamp',
'resource_metadata', 'source', 'counter_unit', 'counter_volume', 'resource_metadata', 'source', 'counter_unit', 'counter_volume',
@ -215,8 +211,7 @@ class Sample(base.APIResourceWrapper):
class Statistic(base.APIResourceWrapper): class Statistic(base.APIResourceWrapper):
""" Represents one Ceilometer statistic. """Represents one Ceilometer statistic."""
"""
_attrs = ['period', 'period_start', 'period_end', _attrs = ['period', 'period_start', 'period_end',
'count', 'min', 'max', 'sum', 'avg', 'count', 'min', 'max', 'sum', 'avg',
@ -224,11 +219,11 @@ class Statistic(base.APIResourceWrapper):
class GlobalDiskUsage(base.APIResourceWrapper): class GlobalDiskUsage(base.APIResourceWrapper):
""" Represents collection of resources with statistic of defined meters. """Represents collection of resources with statistic of defined meters.
Resources are filtered either by given default query or by Resources are filtered either by given default query or by
meters in python. It's preferred to use default_query as it is more meters in python. It's preferred to use default_query as it is more
effective. effective.
""" """
_attrs = ["id", "tenant", "user", "resource", "disk_read_bytes", _attrs = ["id", "tenant", "user", "resource", "disk_read_bytes",
@ -247,11 +242,11 @@ class GlobalDiskUsage(base.APIResourceWrapper):
class GlobalNetworkTrafficUsage(base.APIResourceWrapper): class GlobalNetworkTrafficUsage(base.APIResourceWrapper):
""" Represents collection of resources with statistic of defined meters. """Represents collection of resources with statistic of defined meters.
Resources are filtered either by given default query or by Resources are filtered either by given default query or by
meters in python. It's preferred to use default_query as it is more meters in python. It's preferred to use default_query as it is more
effective. effective.
""" """
_attrs = ["id", "tenant", "user", "resource", "network_incoming_bytes", _attrs = ["id", "tenant", "user", "resource", "network_incoming_bytes",
@ -270,11 +265,11 @@ class GlobalNetworkTrafficUsage(base.APIResourceWrapper):
class GlobalNetworkUsage(base.APIResourceWrapper): class GlobalNetworkUsage(base.APIResourceWrapper):
""" Represents collection of resources with statistic of defined meters. """Represents collection of resources with statistic of defined meters.
Resources are filtered either by given default query or by Resources are filtered either by given default query or by
meters in python. It's preferred to use default_query as it is more meters in python. It's preferred to use default_query as it is more
effective. effective.
""" """
_attrs = ["id", "tenant", "user", "resource", "network", "network_create", _attrs = ["id", "tenant", "user", "resource", "network", "network_create",
@ -294,11 +289,11 @@ class GlobalNetworkUsage(base.APIResourceWrapper):
class GlobalObjectStoreUsage(base.APIResourceWrapper): class GlobalObjectStoreUsage(base.APIResourceWrapper):
""" Represents collection of resources with statistic of defined meters. """Represents collection of resources with statistic of defined meters.
Resources are filtered either by given default query or by Resources are filtered either by given default query or by
meters in python. It's preferred to use default_query as it is more meters in python. It's preferred to use default_query as it is more
effective. effective.
""" """
_attrs = ["id", "tenant", "user", "resource", "storage_objects", _attrs = ["id", "tenant", "user", "resource", "storage_objects",
@ -317,8 +312,7 @@ class GlobalObjectStoreUsage(base.APIResourceWrapper):
def ceilometerclient(request): def ceilometerclient(request):
""" Initialization of Ceilometer client. """Initialization of Ceilometer client."""
"""
endpoint = base.url_for(request, 'metering') endpoint = base.url_for(request, 'metering')
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
@ -359,8 +353,8 @@ def statistic_list(request, meter_name, query=None, period=None):
class ThreadedUpdateResourceWithStatistics(threading.Thread): class ThreadedUpdateResourceWithStatistics(threading.Thread):
""" Multithread wrapper for update_with_statistics method of """Multithread wrapper for update_with_statistics method of
resource_usage. resource_usage.
A join logic is placed in process_list class method. All resources A join logic is placed in process_list class method. All resources
will have its statistics attribute filled in separate threads. will have its statistics attribute filled in separate threads.
@ -426,7 +420,7 @@ class ThreadedUpdateResourceWithStatistics(threading.Thread):
class CeilometerUsage(object): class CeilometerUsage(object):
""" Represents wrapper of any Ceilometer queries. """Represents wrapper of any Ceilometer queries.
One instance of this class should be shared between resources One instance of this class should be shared between resources
as this class provides a place where users and tenants are as this class provides a place where users and tenants are
@ -448,7 +442,7 @@ class CeilometerUsage(object):
self._tenants = {} self._tenants = {}
def get_user(self, user_id): def get_user(self, user_id):
""" Returns user fetched form API """Returns user fetched form API
Caching the result, so it doesn't contact API twice with the Caching the result, so it doesn't contact API twice with the
same query same query
@ -462,7 +456,7 @@ class CeilometerUsage(object):
return user return user
def preload_all_users(self): def preload_all_users(self):
""" Preloads all users into dictionary. """Preloads all users into dictionary.
It's more effective to preload all users, rather the fetching many It's more effective to preload all users, rather the fetching many
users by separate API get calls. users by separate API get calls.
@ -475,7 +469,7 @@ class CeilometerUsage(object):
self._users[u.id] = u self._users[u.id] = u
def get_tenant(self, tenant_id): def get_tenant(self, tenant_id):
""" Returns tenant fetched form API """Returns tenant fetched form API.
Caching the result, so it doesn't contact API twice with the Caching the result, so it doesn't contact API twice with the
same query same query
@ -489,7 +483,7 @@ class CeilometerUsage(object):
return tenant return tenant
def preload_all_tenants(self): def preload_all_tenants(self):
""" Preloads all teannts into dictionary. """Preloads all teannts into dictionary.
It's more effective to preload all tenants, rather the fetching many It's more effective to preload all tenants, rather the fetching many
tenants by separate API get calls. tenants by separate API get calls.
@ -504,7 +498,7 @@ class CeilometerUsage(object):
def global_data_get(self, used_cls=None, query=None, def global_data_get(self, used_cls=None, query=None,
with_statistics=False, additional_query=None, with_statistics=False, additional_query=None,
with_users_and_tenants=True): with_users_and_tenants=True):
""" Obtaining a resources for table view. """Obtaining a resources for table view.
It obtains resources with statistics data according to declaration It obtains resources with statistics data according to declaration
in used_cls class. in used_cls class.
@ -534,10 +528,9 @@ class CeilometerUsage(object):
filter_func = None filter_func = None
def filter_resources(resource): def filter_resources(resource):
""" Method for filtering resources by theirs links.rel attr. """Method for filtering resources by theirs links.rel attr.
The links.rel attributes contains all meters the resource The links.rel attributes contains all meters the resource have.
have.
""" """
for link in resource.links: for link in resource.links:
if link['rel'] in used_cls.meters: if link['rel'] in used_cls.meters:
@ -567,8 +560,7 @@ class CeilometerUsage(object):
def global_disk_usage(self, query=None, with_statistics=False, def global_disk_usage(self, query=None, with_statistics=False,
additional_query=None): additional_query=None):
""" Wrapper for specific call of global_data_get. """Wrapper for specific call of global_data_get."""
"""
return self.global_data_get(used_cls=GlobalDiskUsage, return self.global_data_get(used_cls=GlobalDiskUsage,
query=query, query=query,
@ -577,7 +569,7 @@ class CeilometerUsage(object):
def global_network_traffic_usage(self, query=None, with_statistics=False, def global_network_traffic_usage(self, query=None, with_statistics=False,
additional_query=None): additional_query=None):
""" Wrapper for specific call of global_data_get. """Wrapper for specific call of global_data_get.
""" """
return self.global_data_get(used_cls=GlobalNetworkTrafficUsage, return self.global_data_get(used_cls=GlobalNetworkTrafficUsage,
@ -587,7 +579,7 @@ class CeilometerUsage(object):
def global_network_usage(self, query=None, with_statistics=False, def global_network_usage(self, query=None, with_statistics=False,
additional_query=None): additional_query=None):
""" Wrapper for specific call of global_data_get. """Wrapper for specific call of global_data_get.
""" """
return self.global_data_get(used_cls=GlobalNetworkUsage, return self.global_data_get(used_cls=GlobalNetworkUsage,
@ -597,7 +589,7 @@ class CeilometerUsage(object):
def global_object_store_usage(self, query=None, with_statistics=False, def global_object_store_usage(self, query=None, with_statistics=False,
additional_query=None): additional_query=None):
""" Wrapper for specific call of global_data_get. """Wrapper for specific call of global_data_get.
""" """
# TODO(lsmola) This call uses all tenants now. When ajax pagination # TODO(lsmola) This call uses all tenants now. When ajax pagination
# is added, it needs to obtain only paginated tenants. # is added, it needs to obtain only paginated tenants.
@ -609,7 +601,7 @@ class CeilometerUsage(object):
additional_query=additional_query) additional_query=additional_query)
def query_from_object_id(self, object_id): def query_from_object_id(self, object_id):
""" Obtaining a query from resource id. """Obtaining a query from resource id.
Query can be then used to identify a resource in resources or meters Query can be then used to identify a resource in resources or meters
API calls. ID is being built in the Resource initializer, or returned API calls. ID is being built in the Resource initializer, or returned
@ -625,7 +617,7 @@ class CeilometerUsage(object):
def update_with_statistics(self, resource, meter_names=None, period=None, def update_with_statistics(self, resource, meter_names=None, period=None,
stats_attr=None, additional_query=None): stats_attr=None, additional_query=None):
""" Adding statistical data into one Resource or ResourceAggregate. """Adding statistical data into one Resource or ResourceAggregate.
It adds each statistic of each meter_names into the resource It adds each statistic of each meter_names into the resource
attributes. Attribute name is the meter name with replaced '.' to '_'. attributes. Attribute name is the meter name with replaced '.' to '_'.
@ -684,7 +676,7 @@ class CeilometerUsage(object):
def resources(self, query=None, filter_func=None, def resources(self, query=None, filter_func=None,
with_users_and_tenants=False): with_users_and_tenants=False):
""" Obtaining resources with the query or filter_func. """Obtaining resources with the query or filter_func.
Obtains resources and also fetch tenants and users associated Obtains resources and also fetch tenants and users associated
with those resources if with_users_and_tenants flag is true. with those resources if with_users_and_tenants flag is true.
@ -712,7 +704,7 @@ class CeilometerUsage(object):
period=None, filter_func=None, period=None, filter_func=None,
stats_attr=None, additional_query=None, stats_attr=None, additional_query=None,
with_users_and_tenants=False): with_users_and_tenants=False):
""" Obtaining resources with statistics data inside. """Obtaining resources with statistics data inside.
:Parameters: :Parameters:
- `query`: Query for fetching the Ceilometer Resources. - `query`: Query for fetching the Ceilometer Resources.
@ -745,7 +737,7 @@ class CeilometerUsage(object):
return resources return resources
def resource_aggregates(self, queries=None): def resource_aggregates(self, queries=None):
""" Obtaining resource aggregates with queries. """Obtaining resource aggregates with queries.
Representing a resource aggregate by query is a most general way Representing a resource aggregate by query is a most general way
how to obtain a resource aggregates. how to obtain a resource aggregates.
@ -764,7 +756,7 @@ class CeilometerUsage(object):
def resource_aggregates_with_statistics(self, queries=None, def resource_aggregates_with_statistics(self, queries=None,
meter_names=None, period=None, filter_func=None, stats_attr=None, meter_names=None, period=None, filter_func=None, stats_attr=None,
additional_query=None): additional_query=None):
""" Obtaining resource aggregates with statistics data inside. """Obtaining resource aggregates with statistics data inside.
:Parameters: :Parameters:
- `queries`: Dictionary of named queries that defines a bulk of - `queries`: Dictionary of named queries that defines a bulk of

View File

@ -68,8 +68,7 @@ def cinderclient(request):
def volume_list(request, search_opts=None): def volume_list(request, search_opts=None):
""" """To see all volumes in the cloud as an admin you can pass in a special
To see all volumes in the cloud as an admin you can pass in a special
search option: {'all_tenants': 1} search option: {'all_tenants': 1}
""" """
c_client = cinderclient(request) c_client = cinderclient(request)
@ -181,8 +180,7 @@ def list_extensions(request):
@memoized @memoized
def extension_supported(request, extension_name): def extension_supported(request, extension_name):
""" """This method will determine if Cinder supports a given extension name.
This method will determine if Cinder supports a given extension name.
""" """
extensions = list_extensions(request) extensions = list_extensions(request)
for extension in extensions: for extension in extensions:

View File

@ -24,7 +24,7 @@ neutronclient = neutron.neutronclient
class Rule(neutron.NeutronAPIDictWrapper): class Rule(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron firewall rule""" """Wrapper for neutron firewall rule."""
def get_dict(self): def get_dict(self):
rule_dict = self._apidict rule_dict = self._apidict
@ -33,7 +33,7 @@ class Rule(neutron.NeutronAPIDictWrapper):
class Policy(neutron.NeutronAPIDictWrapper): class Policy(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron firewall policy""" """Wrapper for neutron firewall policy."""
def get_dict(self): def get_dict(self):
policy_dict = self._apidict policy_dict = self._apidict
@ -42,7 +42,7 @@ class Policy(neutron.NeutronAPIDictWrapper):
class Firewall(neutron.NeutronAPIDictWrapper): class Firewall(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron firewall""" """Wrapper for neutron firewall."""
def get_dict(self): def get_dict(self):
firewall_dict = self._apidict firewall_dict = self._apidict

View File

@ -51,8 +51,7 @@ def image_delete(request, image_id):
def image_get(request, image_id): def image_get(request, image_id):
""" """Returns an Image object populated with metadata for image
Returns an Image object populated with metadata for image
with supplied identifier. with supplied identifier.
""" """
return glanceclient(request).images.get(image_id) return glanceclient(request).images.get(image_id)

View File

@ -74,7 +74,7 @@ except ImportError:
class Service(base.APIDictWrapper): class Service(base.APIDictWrapper):
""" Wrapper for a dict based on the service data from keystone. """ """Wrapper for a dict based on the service data from keystone."""
_attrs = ['id', 'type', 'name'] _attrs = ['id', 'type', 'name']
def __init__(self, service, region, *args, **kwargs): def __init__(self, service, region, *args, **kwargs):
@ -216,8 +216,7 @@ def tenant_create(request, name, description=None, enabled=None, domain=None):
def get_default_domain(request): def get_default_domain(request):
""" """Gets the default domain object to use when creating Identity object.
Gets the default domain object to use when creating Identity object.
Returns the domain context if is set, otherwise return the domain Returns the domain context if is set, otherwise return the domain
of the logon user. of the logon user.
""" """
@ -482,7 +481,7 @@ def role_delete(request, role_id):
def role_list(request): def role_list(request):
""" Returns a global list of available roles. """ """Returns a global list of available roles."""
return keystoneclient(request, admin=True).roles.list() return keystoneclient(request, admin=True).roles.list()
@ -496,7 +495,7 @@ def roles_for_user(request, user, project):
def add_tenant_user_role(request, project=None, user=None, role=None, def add_tenant_user_role(request, project=None, user=None, role=None,
group=None, domain=None): group=None, domain=None):
""" Adds a role for a user on a tenant. """ """Adds a role for a user on a tenant."""
manager = keystoneclient(request, admin=True).roles manager = keystoneclient(request, admin=True).roles
if VERSIONS.active < 3: if VERSIONS.active < 3:
return manager.add_user_role(user, role, project) return manager.add_user_role(user, role, project)
@ -507,7 +506,7 @@ def add_tenant_user_role(request, project=None, user=None, role=None,
def remove_tenant_user_role(request, project=None, user=None, role=None, def remove_tenant_user_role(request, project=None, user=None, role=None,
group=None, domain=None): group=None, domain=None):
""" Removes a given single role for a user from a tenant. """ """Removes a given single role for a user from a tenant."""
manager = keystoneclient(request, admin=True).roles manager = keystoneclient(request, admin=True).roles
if VERSIONS.active < 3: if VERSIONS.active < 3:
return manager.remove_user_role(user, role, project) return manager.remove_user_role(user, role, project)
@ -517,7 +516,7 @@ def remove_tenant_user_role(request, project=None, user=None, role=None,
def remove_tenant_user(request, project=None, user=None, domain=None): def remove_tenant_user(request, project=None, user=None, domain=None):
""" Removes all roles from a user on a tenant, removing them from it. """ """Removes all roles from a user on a tenant, removing them from it."""
client = keystoneclient(request, admin=True) client = keystoneclient(request, admin=True)
roles = client.roles.roles_for_user(user, project) roles = client.roles.roles_for_user(user, project)
for role in roles: for role in roles:
@ -531,22 +530,22 @@ def roles_for_group(request, group, domain=None, project=None):
def add_group_role(request, role, group, domain=None, project=None): def add_group_role(request, role, group, domain=None, project=None):
""" Adds a role for a group on a domain or project .""" """Adds a role for a group on a domain or project."""
manager = keystoneclient(request, admin=True).roles manager = keystoneclient(request, admin=True).roles
return manager.grant(role=role, group=group, domain=domain, return manager.grant(role=role, group=group, domain=domain,
project=project) project=project)
def remove_group_role(request, role, group, domain=None, project=None): def remove_group_role(request, role, group, domain=None, project=None):
""" Removes a given single role for a group from a domain or project. """ """Removes a given single role for a group from a domain or project."""
manager = keystoneclient(request, admin=True).roles manager = keystoneclient(request, admin=True).roles
return manager.revoke(role=role, group=group, project=project, return manager.revoke(role=role, group=group, project=project,
domain=domain) domain=domain)
def remove_group_roles(request, group, domain=None, project=None): def remove_group_roles(request, group, domain=None, project=None):
""" Removes all roles from a group on a domain or project, """Removes all roles from a group on a domain or project,
removing them from it. removing them from it.
""" """
client = keystoneclient(request, admin=True) client = keystoneclient(request, admin=True)
roles = client.roles.list(group=group, domain=domain, project=project) roles = client.roles.list(group=group, domain=domain, project=project)
@ -556,8 +555,7 @@ def remove_group_roles(request, group, domain=None, project=None):
def get_default_role(request): def get_default_role(request):
""" """Gets the default role object from Keystone and saves it as a global
Gets the default role object from Keystone and saves it as a global
since this is configured in settings and should not change from request since this is configured in settings and should not change from request
to request. Supports lookup by name or id. to request. Supports lookup by name or id.
""" """

View File

@ -22,14 +22,14 @@ neutronclient = neutron.neutronclient
class Vip(neutron.NeutronAPIDictWrapper): class Vip(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer vip""" """Wrapper for neutron load balancer vip."""
def __init__(self, apiresource): def __init__(self, apiresource):
super(Vip, self).__init__(apiresource) super(Vip, self).__init__(apiresource)
class Pool(neutron.NeutronAPIDictWrapper): class Pool(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer pool""" """Wrapper for neutron load balancer pool."""
def __init__(self, apiresource): def __init__(self, apiresource):
if 'provider' not in apiresource: if 'provider' not in apiresource:
@ -75,7 +75,7 @@ class Pool(neutron.NeutronAPIDictWrapper):
class Member(neutron.NeutronAPIDictWrapper): class Member(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer member""" """Wrapper for neutron load balancer member."""
def __init__(self, apiresource): def __init__(self, apiresource):
super(Member, self).__init__(apiresource) super(Member, self).__init__(apiresource)
@ -104,14 +104,14 @@ class Member(neutron.NeutronAPIDictWrapper):
class PoolStats(neutron.NeutronAPIDictWrapper): class PoolStats(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer pool stats""" """Wrapper for neutron load balancer pool stats."""
def __init__(self, apiresource): def __init__(self, apiresource):
super(PoolStats, self).__init__(apiresource) super(PoolStats, self).__init__(apiresource)
class PoolMonitor(neutron.NeutronAPIDictWrapper): class PoolMonitor(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer pool health monitor""" """Wrapper for neutron load balancer pool health monitor."""
def __init__(self, apiresource): def __init__(self, apiresource):
super(PoolMonitor, self).__init__(apiresource) super(PoolMonitor, self).__init__(apiresource)

View File

@ -62,7 +62,7 @@ class NeutronAPIDictWrapper(base.APIDictWrapper):
class Agent(NeutronAPIDictWrapper): class Agent(NeutronAPIDictWrapper):
"""Wrapper for neutron agents""" """Wrapper for neutron agents."""
def __init__(self, apiresource): def __init__(self, apiresource):
apiresource['admin_state'] = \ apiresource['admin_state'] = \
@ -71,7 +71,7 @@ class Agent(NeutronAPIDictWrapper):
class Network(NeutronAPIDictWrapper): class Network(NeutronAPIDictWrapper):
"""Wrapper for neutron Networks""" """Wrapper for neutron Networks."""
def __init__(self, apiresource): def __init__(self, apiresource):
apiresource['admin_state'] = \ apiresource['admin_state'] = \
@ -84,7 +84,7 @@ class Network(NeutronAPIDictWrapper):
class Subnet(NeutronAPIDictWrapper): class Subnet(NeutronAPIDictWrapper):
"""Wrapper for neutron subnets""" """Wrapper for neutron subnets."""
def __init__(self, apiresource): def __init__(self, apiresource):
apiresource['ipver_str'] = get_ipver_str(apiresource['ip_version']) apiresource['ipver_str'] = get_ipver_str(apiresource['ip_version'])
@ -92,7 +92,7 @@ class Subnet(NeutronAPIDictWrapper):
class Port(NeutronAPIDictWrapper): class Port(NeutronAPIDictWrapper):
"""Wrapper for neutron ports""" """Wrapper for neutron ports."""
def __init__(self, apiresource): def __init__(self, apiresource):
apiresource['admin_state'] = \ apiresource['admin_state'] = \
@ -110,7 +110,7 @@ class Profile(NeutronAPIDictWrapper):
class Router(NeutronAPIDictWrapper): class Router(NeutronAPIDictWrapper):
"""Wrapper for neutron routers""" """Wrapper for neutron routers."""
def __init__(self, apiresource): def __init__(self, apiresource):
#apiresource['admin_state'] = \ #apiresource['admin_state'] = \
@ -412,7 +412,7 @@ class FloatingIpManager(network_base.FloatingIpManager):
def get_ipver_str(ip_version): def get_ipver_str(ip_version):
"""Convert an ip version number to a human-friendly string""" """Convert an ip version number to a human-friendly string."""
return IP_VERSION_DICT.get(ip_version, '') return IP_VERSION_DICT.get(ip_version, '')
@ -476,8 +476,7 @@ def network_get(request, network_id, expand_subnet=True, **params):
def network_create(request, **kwargs): def network_create(request, **kwargs):
""" """Create a subnet on a specified network.
Create a subnet on a specified network.
:param request: request context :param request: request context
:param tenant_id: (optional) tenant id of the network created :param tenant_id: (optional) tenant id of the network created
:param name: (optional) name of the network created :param name: (optional) name of the network created
@ -519,8 +518,7 @@ def subnet_get(request, subnet_id, **params):
def subnet_create(request, network_id, cidr, ip_version, **kwargs): def subnet_create(request, network_id, cidr, ip_version, **kwargs):
""" """Create a subnet on a specified network.
Create a subnet on a specified network.
:param request: request context :param request: request context
:param network_id: network id a subnet is created on :param network_id: network id a subnet is created on
:param cidr: subnet IP address range :param cidr: subnet IP address range
@ -567,8 +565,7 @@ def port_get(request, port_id, **params):
def port_create(request, network_id, **kwargs): def port_create(request, network_id, **kwargs):
""" """Create a port on a specified network.
Create a port on a specified network.
:param request: request context :param request: request context
:param network_id: network id a subnet is created on :param network_id: network id a subnet is created on
:param device_id: (optional) device id attached to the port :param device_id: (optional) device id attached to the port

View File

@ -166,7 +166,7 @@ class SecurityGroup(base.APIResourceWrapper):
class SecurityGroupRule(base.APIResourceWrapper): class SecurityGroupRule(base.APIResourceWrapper):
""" Wrapper for individual rules in a SecurityGroup. """ """Wrapper for individual rules in a SecurityGroup."""
_attrs = ['id', 'ip_protocol', 'from_port', 'to_port', 'ip_range', 'group'] _attrs = ['id', 'ip_protocol', 'from_port', 'to_port', 'ip_range', 'group']
def __unicode__(self): def __unicode__(self):
@ -686,8 +686,7 @@ def list_extensions(request):
@memoized @memoized
def extension_supported(extension_name, request): def extension_supported(extension_name, request):
""" """this method will determine if nova supports a given extension name.
this method will determine if nova supports a given extension name.
example values for the extension_name include AdminActions, ConsoleOutput, example values for the extension_name include AdminActions, ConsoleOutput,
etc. etc.
""" """

View File

@ -75,7 +75,7 @@ class PseudoFolder(base.APIDictWrapper):
def _objectify(items, container_name): def _objectify(items, container_name):
""" Splits a listing of objects into their appropriate wrapper classes. """ """Splits a listing of objects into their appropriate wrapper classes."""
objects = [] objects = []
# Deal with objects and object pseudo-folders first, save subdirs for later # Deal with objects and object pseudo-folders first, save subdirs for later

View File

@ -30,7 +30,7 @@ except ImportError:
class TokenAuth(object): class TokenAuth(object):
"""Simple Token Authentication handler for trove api""" """Simple Token Authentication handler for trove api."""
def __init__(self, client, auth_strategy, auth_url, username, password, def __init__(self, client, auth_strategy, auth_url, username, password,
tenant, region, service_type, service_name, service_url): tenant, region, service_type, service_name, service_url):

View File

@ -25,7 +25,7 @@ from django.conf import settings # noqa
def openstack(request): def openstack(request):
""" Context processor necessary for OpenStack Dashboard functionality. """Context processor necessary for OpenStack Dashboard functionality.
The following variables are added to the request context: The following variables are added to the request context:

View File

@ -98,7 +98,7 @@ class DomainFilterAction(tables.FilterAction):
return multidomain_support return multidomain_support
def filter(self, table, domains, filter_string): def filter(self, table, domains, filter_string):
""" Naive case-insensitive search """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
def comp(domain): def comp(domain):

View File

@ -72,7 +72,7 @@ class ModifyAccess(tables.LinkAction):
class FlavorFilterAction(tables.FilterAction): class FlavorFilterAction(tables.FilterAction):
def filter(self, table, flavors, filter_string): def filter(self, table, flavors, filter_string):
""" Really naive case-insensitive search. """ """Really naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
def comp(flavor): def comp(flavor):

View File

@ -85,7 +85,7 @@ class ManageUsersLink(tables.LinkAction):
class GroupFilterAction(tables.FilterAction): class GroupFilterAction(tables.FilterAction):
def filter(self, table, groups, filter_string): def filter(self, table, groups, filter_string):
""" Naive case-insensitive search """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
def comp(group): def comp(group):
@ -112,7 +112,7 @@ class GroupsTable(tables.DataTable):
class UserFilterAction(tables.FilterAction): class UserFilterAction(tables.FilterAction):
def filter(self, table, users, filter_string): def filter(self, table, users, filter_string):
""" Naive case-insensitive search """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
return [user for user in users return [user for user in users
if q in user.name.lower() if q in user.name.lower()

View File

@ -68,5 +68,5 @@ class UpdateView(views.UpdateView):
class DetailView(views.DetailView): class DetailView(views.DetailView):
""" Admin placeholder for image detail view. """ """Admin placeholder for image detail view."""
pass pass

View File

@ -60,7 +60,7 @@ class AdminUpdateRow(project_tables.UpdateRow):
class AdminInstanceFilterAction(tables.FilterAction): class AdminInstanceFilterAction(tables.FilterAction):
def filter(self, table, instances, filter_string): def filter(self, table, instances, filter_string):
""" Naive case-insensitive search. """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
return [instance for instance in instances return [instance for instance in instances
if q in instance.name.lower()] if q in instance.name.lower()]

View File

@ -84,7 +84,7 @@ class GlobalDiskUsageTab(tabs.TableTab):
preload = False preload = False
def get_global_disk_usage_data(self): def get_global_disk_usage_data(self):
""" Disk usage table data aggregated by project """ """Disk usage table data aggregated by project."""
request = self.tab_group.request request = self.tab_group.request
return list_of_resource_aggregates(request, return list_of_resource_aggregates(request,
ceilometer.GlobalDiskUsage.meters) ceilometer.GlobalDiskUsage.meters)
@ -214,7 +214,7 @@ class GlobalStatsTab(tabs.Tab):
meter_titles[name] = hint meter_titles[name] = hint
class MetersWrap(object): class MetersWrap(object):
""" A quick wrapper for meter and associated titles. """ """A quick wrapper for meter and associated titles."""
def __init__(self, meter, meter_titles): def __init__(self, meter, meter_titles):
self.name = meter self.name = meter
self.title = meter_titles.get(meter, "") self.title = meter_titles.get(meter, "")

View File

@ -174,7 +174,7 @@ class SamplesView(TemplateView):
query = [] query = []
def filter_by_meter_name(resource): def filter_by_meter_name(resource):
""" Function for filtering of the list of resources. """Function for filtering of the list of resources.
Will pick the right resources according to currently selected Will pick the right resources according to currently selected
meter. meter.

View File

@ -109,7 +109,7 @@ class DeleteTenantsAction(tables.DeleteAction):
class TenantFilterAction(tables.FilterAction): class TenantFilterAction(tables.FilterAction):
def filter(self, table, tenants, filter_string): def filter(self, table, tenants, filter_string):
""" Really naive case-insensitive search. """ """Really naive case-insensitive search."""
# FIXME(gabriel): This should be smarter. Written for demo purposes. # FIXME(gabriel): This should be smarter. Written for demo purposes.
q = filter_string.lower() q = filter_string.lower()

View File

@ -57,7 +57,7 @@ class DeleteRolesAction(tables.DeleteAction):
class RoleFilterAction(tables.FilterAction): class RoleFilterAction(tables.FilterAction):
def filter(self, table, roles, filter_string): def filter(self, table, roles, filter_string):
""" Naive case-insensitive search """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
return [role for role in roles return [role for role in roles
if q in role.name.lower()] if q in role.name.lower()]

View File

@ -115,7 +115,7 @@ class DeleteUsersAction(tables.DeleteAction):
class UserFilterAction(tables.FilterAction): class UserFilterAction(tables.FilterAction):
def filter(self, table, users, filter_string): def filter(self, table, users, filter_string):
""" Naive case-insensitive search """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
return [user for user in users return [user for user in users
if q in user.name.lower() if q in user.name.lower()

View File

@ -36,7 +36,7 @@ class DeleteVolumeType(tables.DeleteAction):
class VolumesFilterAction(tables.FilterAction): class VolumesFilterAction(tables.FilterAction):
def filter(self, table, volumes, filter_string): def filter(self, table, volumes, filter_string):
""" Naive case-insensitive search. """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
return [volume for volume in volumes return [volume for volume in volumes
if q in volume.display_name.lower()] if q in volume.display_name.lower()]

View File

@ -47,8 +47,7 @@ class DeleteContainer(tables.DeleteAction):
api.swift.swift_delete_container(request, obj_id) api.swift.swift_delete_container(request, obj_id)
def get_success_url(self, request=None): def get_success_url(self, request=None):
""" """Returns the URL to redirect to after a successful action.
Returns the URL to redirect to after a successful action.
""" """
current_container = self.table.kwargs.get("container_name", None) current_container = self.table.kwargs.get("container_name", None)

View File

@ -61,7 +61,7 @@ class ContainerView(browsers.ResourceBrowserView):
@cached_property @cached_property
def objects(self): def objects(self):
""" Returns a list of objects given the subfolder's path. """Returns a list of objects given the subfolder's path.
The path is from the kwargs of the request. The path is from the kwargs of the request.
""" """
@ -93,13 +93,13 @@ class ContainerView(browsers.ResourceBrowserView):
return getattr(item, "content_type", None) == content_type return getattr(item, "content_type", None) == content_type
def get_objects_data(self): def get_objects_data(self):
""" Returns a list of objects within the current folder. """ """Returns a list of objects within the current folder."""
filtered_objects = [item for item in self.objects filtered_objects = [item for item in self.objects
if not self.is_subdir(item)] if not self.is_subdir(item)]
return filtered_objects return filtered_objects
def get_subfolders_data(self): def get_subfolders_data(self):
""" Returns a list of subfolders within the current folder. """ """Returns a list of subfolders within the current folder."""
filtered_objects = [item for item in self.objects filtered_objects = [item for item in self.objects
if self.is_subdir(item)] if self.is_subdir(item)]
return filtered_objects return filtered_objects

View File

@ -65,8 +65,7 @@ class SetInstanceDetails(workflows.Step):
class AddDatabasesAction(workflows.Action): class AddDatabasesAction(workflows.Action):
""" """Initialize the database with users/databases. This tab will honor
Initialize the database with users/databases. This tab will honor
the settings which should be a list of permissions required: the settings which should be a list of permissions required:
* TROVE_ADD_USER_PERMS = [] * TROVE_ADD_USER_PERMS = []

View File

@ -44,8 +44,7 @@ IMAGES_INDEX_URL = reverse('horizon:project:images_and_snapshots:index')
class CreateImageFormTests(test.TestCase): class CreateImageFormTests(test.TestCase):
def test_no_location_or_file(self): def test_no_location_or_file(self):
""" """The form will not be valid if both copy_from and image_file are not
The form will not be valid if both copy_from and image_file are not
provided. provided.
""" """
post = { post = {
@ -62,8 +61,7 @@ class CreateImageFormTests(test.TestCase):
@override_settings(HORIZON_IMAGES_ALLOW_UPLOAD=False) @override_settings(HORIZON_IMAGES_ALLOW_UPLOAD=False)
def test_image_upload_disabled(self): def test_image_upload_disabled(self):
""" """If HORIZON_IMAGES_ALLOW_UPLOAD is false, the image_file field widget
If HORIZON_IMAGES_ALLOW_UPLOAD is false, the image_file field widget
will be a HiddenInput widget instead of a FileInput widget. will be a HiddenInput widget instead of a FileInput widget.
""" """
form = forms.CreateImageForm({}) form = forms.CreateImageForm({})

View File

@ -18,8 +18,7 @@ from openstack_dashboard.api import glance
def get_available_images(request, project_id=None, images_cache=None): def get_available_images(request, project_id=None, images_cache=None):
""" """Returns a list of images that are public or owned by the given
Returns a list of images that are public or owned by the given
project_id. If project_id is not specified, only public images project_id. If project_id is not specified, only public images
are returned. are returned.

View File

@ -548,7 +548,7 @@ TASK_DISPLAY_CHOICES = (
class InstancesFilterAction(tables.FilterAction): class InstancesFilterAction(tables.FilterAction):
def filter(self, table, instances, filter_string): def filter(self, table, instances, filter_string):
""" Naive case-insensitive search. """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
return [instance for instance in instances return [instance for instance in instances
if q in instance.name.lower()] if q in instance.name.lower()]

View File

@ -217,7 +217,8 @@ class SetInstanceDetailsAction(workflows.Action):
"""By default, returns the available flavors, sorted by RAM """By default, returns the available flavors, sorted by RAM
usage (ascending). usage (ascending).
Override these behaviours with a CREATE_INSTANCE_FLAVOR_SORT dict Override these behaviours with a CREATE_INSTANCE_FLAVOR_SORT dict
in local_settings.py.""" in local_settings.py.
"""
try: try:
flavors = api.nova.flavor_list(request) flavors = api.nova.flavor_list(request)
flavor_sort = getattr(settings, 'CREATE_INSTANCE_FLAVOR_SORT', {}) flavor_sort = getattr(settings, 'CREATE_INSTANCE_FLAVOR_SORT', {})

View File

@ -368,7 +368,7 @@ class CreateNetwork(workflows.Workflow):
return False return False
def _delete_network(self, request, network): def _delete_network(self, request, network):
"""Delete the created network when subnet creation failed""" """Delete the created network when subnet creation failed."""
try: try:
api.neutron.network_delete(request, network.id) api.neutron.network_delete(request, network.id)
msg = _('Delete the created network "%s" ' msg = _('Delete the created network "%s" '

View File

@ -31,8 +31,7 @@ LOG = logging.getLogger(__name__)
class RuleCIDRField(fields.IPField): class RuleCIDRField(fields.IPField):
""" """Extends IPField to allow ('any','external') keywords and requires CIDR
Extends IPField to allow ('any','external') keywords and requires CIDR
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['mask'] = True kwargs['mask'] = True

View File

@ -29,9 +29,7 @@ LOG = logging.getLogger(__name__)
def exception_to_validation_msg(e): def exception_to_validation_msg(e):
''' """Extracts a validation message to display to the user."""
Extracts a validation message to display to the user.
'''
try: try:
error = json.loads(str(e)) error = json.loads(str(e))
# NOTE(jianingy): if no message exists, we just return 'None' # NOTE(jianingy): if no message exists, we just return 'None'

View File

@ -140,9 +140,7 @@ def get_resource_status(status):
def get_resource_image(status, type): def get_resource_image(status, type):
''' """Sets the image url and in_progress action sw based on status."""
Sets the image url and in_progress action sw based on status.
'''
resource_type = get_resource_type(type) resource_type = get_resource_type(type)
resource_status = get_resource_status(status) resource_status = get_resource_status(status)
resource_state = resource_type + "_" + resource_status resource_state = resource_type + "_" + resource_status

View File

@ -132,8 +132,9 @@ def get_attachment_name(request, attachment):
class AttachmentColumn(tables.Column): class AttachmentColumn(tables.Column):
""" """Customized column class.
Customized column class that does complex processing on the attachments
So it that does complex processing on the attachments
for a volume instance. for a volume instance.
""" """
def get_raw_data(self, volume): def get_raw_data(self, volume):
@ -184,7 +185,7 @@ class VolumesTableBase(tables.DataTable):
class VolumesFilterAction(tables.FilterAction): class VolumesFilterAction(tables.FilterAction):
def filter(self, table, volumes, filter_string): def filter(self, table, volumes, filter_string):
""" Naive case-insensitive search. """ """Naive case-insensitive search."""
q = filter_string.lower() q = filter_string.lower()
return [volume for volume in volumes return [volume for volume in volumes
if q in volume.display_name.lower()] if q in volume.display_name.lower()]
@ -230,8 +231,7 @@ class DetachVolume(tables.BatchAction):
class AttachedInstanceColumn(tables.Column): class AttachedInstanceColumn(tables.Column):
""" """Customized column class that does complex processing on the attachments
Customized column class that does complex processing on the attachments
for a volume instance. for a volume instance.
""" """
def get_raw_data(self, attachment): def get_raw_data(self, attachment):

View File

@ -46,7 +46,7 @@ def get_tenant_choices(request):
class CreateNetworkProfile(forms.SelfHandlingForm): class CreateNetworkProfile(forms.SelfHandlingForm):
""" Create Network Profile form.""" """Create Network Profile form."""
name = forms.CharField(max_length=255, name = forms.CharField(max_length=255,
label=_("Name"), label=_("Name"),
@ -115,7 +115,7 @@ class CreateNetworkProfile(forms.SelfHandlingForm):
class UpdateNetworkProfile(forms.SelfHandlingForm): class UpdateNetworkProfile(forms.SelfHandlingForm):
""" Update Network Profile form.""" """Update Network Profile form."""
profile_id = forms.CharField(label=_("ID"), profile_id = forms.CharField(label=_("ID"),
widget=forms.HiddenInput()) widget=forms.HiddenInput())

View File

@ -60,7 +60,8 @@ def reset():
def check(actions, request, target={}): def check(actions, request, target={}):
""" """Check user permission.
Check if the user has permission to the action according Check if the user has permission to the action according
to policy setting. to policy setting.

View File

@ -27,7 +27,7 @@ from openstack_dashboard.test import helpers as test
class APIResource(api_base.APIResourceWrapper): class APIResource(api_base.APIResourceWrapper):
""" Simple APIResource for testing """ """Simple APIResource for testing."""
_attrs = ['foo', 'bar', 'baz'] _attrs = ['foo', 'bar', 'baz']
@staticmethod @staticmethod
@ -44,7 +44,7 @@ class APIResource(api_base.APIResourceWrapper):
class APIDict(api_base.APIDictWrapper): class APIDict(api_base.APIDictWrapper):
""" Simple APIDict for testing """ """Simple APIDict for testing."""
_attrs = ['foo', 'bar', 'baz'] _attrs = ['foo', 'bar', 'baz']
@staticmethod @staticmethod
@ -116,7 +116,7 @@ class APIDictWrapperTests(test.TestCase):
class ApiHelperTests(test.TestCase): class ApiHelperTests(test.TestCase):
""" Tests for functions that don't use one of the api objects """ """Tests for functions that don't use one of the api objects."""
def test_url_for(self): def test_url_for(self):
url = api_base.url_for(self.request, 'image') url = api_base.url_for(self.request, 'image')

View File

@ -50,8 +50,7 @@ class RoleAPITests(test.APITestCase):
self.roles = self.roles.list() self.roles = self.roles.list()
def test_remove_tenant_user(self): def test_remove_tenant_user(self):
""" """Tests api.keystone.remove_tenant_user
Tests api.keystone.remove_tenant_user
Verifies that remove_tenant_user is called with the right arguments Verifies that remove_tenant_user is called with the right arguments
after iterating the user's roles. after iterating the user's roles.

View File

@ -108,8 +108,7 @@ class RequestFactoryWithMessages(RequestFactory):
@unittest.skipIf(os.environ.get('SKIP_UNITTESTS', False), @unittest.skipIf(os.environ.get('SKIP_UNITTESTS', False),
"The SKIP_UNITTESTS env variable is set.") "The SKIP_UNITTESTS env variable is set.")
class TestCase(horizon_helpers.TestCase): class TestCase(horizon_helpers.TestCase):
""" """Specialized base test case class for Horizon which gives access to
Specialized base test case class for Horizon which gives access to
numerous additional features: numerous additional features:
* A full suite of test data through various attached objects and * A full suite of test data through various attached objects and
@ -180,8 +179,7 @@ class TestCase(horizon_helpers.TestCase):
utils.get_user = get_user utils.get_user = get_user
def assertRedirectsNoFollow(self, response, expected_url): def assertRedirectsNoFollow(self, response, expected_url):
""" """Asserts that the given response issued a 302 redirect without
Asserts that the given response issued a 302 redirect without
processing the view which is redirected to. processing the view which is redirected to.
""" """
assert (response.status_code / 100 == 3), \ assert (response.status_code / 100 == 3), \
@ -191,8 +189,7 @@ class TestCase(horizon_helpers.TestCase):
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
def assertNoFormErrors(self, response, context_name="form"): def assertNoFormErrors(self, response, context_name="form"):
""" """Asserts that the response either does not contain a form in its
Asserts that the response either does not contain a form in its
context, or that if it does, that form has no errors. context, or that if it does, that form has no errors.
""" """
context = getattr(response, "context", {}) context = getattr(response, "context", {})
@ -204,8 +201,7 @@ class TestCase(horizon_helpers.TestCase):
def assertFormErrors(self, response, count=0, message=None, def assertFormErrors(self, response, count=0, message=None,
context_name="form"): context_name="form"):
""" """Asserts that the response does contain a form in its
Asserts that the response does contain a form in its
context, and that form has errors, if count were given, context, and that form has errors, if count were given,
it must match the exact numbers of errors it must match the exact numbers of errors
""" """
@ -226,8 +222,7 @@ class TestCase(horizon_helpers.TestCase):
class BaseAdminViewTests(TestCase): class BaseAdminViewTests(TestCase):
""" """A ``TestCase`` subclass which sets an active user with the "admin" role
A ``TestCase`` subclass which sets an active user with the "admin" role
for testing admin-only views and functionality. for testing admin-only views and functionality.
""" """
def setActiveUser(self, *args, **kwargs): def setActiveUser(self, *args, **kwargs):
@ -248,8 +243,7 @@ class BaseAdminViewTests(TestCase):
class APITestCase(TestCase): class APITestCase(TestCase):
""" """The ``APITestCase`` class is for use with tests which deal with the
The ``APITestCase`` class is for use with tests which deal with the
underlying clients rather than stubbing out the underlying clients rather than stubbing out the
openstack_dashboard.api.* methods. openstack_dashboard.api.* methods.
""" """
@ -258,8 +252,7 @@ class APITestCase(TestCase):
utils.patch_middleware_get_user() utils.patch_middleware_get_user()
def fake_keystoneclient(request, admin=False): def fake_keystoneclient(request, admin=False):
""" """Wrapper function which returns the stub keystoneclient. Only
Wrapper function which returns the stub keystoneclient. Only
necessary because the function takes too many arguments to necessary because the function takes too many arguments to
conveniently be a lambda. conveniently be a lambda.
""" """
@ -414,8 +407,7 @@ class SeleniumTestCase(horizon_helpers.SeleniumTestCase):
class SeleniumAdminTestCase(SeleniumTestCase): class SeleniumAdminTestCase(SeleniumTestCase):
""" """A ``TestCase`` subclass which sets an active user with the "admin" role
A ``TestCase`` subclass which sets an active user with the "admin" role
for testing admin-only views and functionality. for testing admin-only views and functionality.
""" """
def setActiveUser(self, *args, **kwargs): def setActiveUser(self, *args, **kwargs):

View File

@ -53,8 +53,7 @@ def load_test_data(load_onto=None):
class TestData(object): class TestData(object):
""" """Holder object for test data. Any functions passed to the init method
Holder object for test data. Any functions passed to the init method
will be called with the ``TestData`` object as their only argument. They will be called with the ``TestData`` object as their only argument. They
can then load data onto the object as desired. can then load data onto the object as desired.
@ -79,7 +78,7 @@ class TestData(object):
class TestDataContainer(object): class TestDataContainer(object):
""" A container for test data objects. """A container for test data objects.
The behavior of this class is meant to mimic a "manager" class, which The behavior of this class is meant to mimic a "manager" class, which
has convenient shortcuts for common actions like "list", "filter", "get", has convenient shortcuts for common actions like "list", "filter", "get",
@ -89,7 +88,7 @@ class TestDataContainer(object):
self._objects = [] self._objects = []
def add(self, *args): def add(self, *args):
""" Add a new object to this container. """Add a new object to this container.
Generally this method should only be used during data loading, since Generally this method should only be used during data loading, since
adding data during a test can affect the results of other tests. adding data during a test can affect the results of other tests.
@ -99,12 +98,11 @@ class TestDataContainer(object):
self._objects.append(obj) self._objects.append(obj)
def list(self): def list(self):
""" Returns a list of all objects in this container. """ """Returns a list of all objects in this container."""
return self._objects return self._objects
def filter(self, filtered=None, **kwargs): def filter(self, filtered=None, **kwargs):
""" """Returns objects in this container whose attributes match the given
Returns objects in this container whose attributes match the given
keyword arguments. keyword arguments.
""" """
if filtered is None: if filtered is None:
@ -121,8 +119,7 @@ class TestDataContainer(object):
return self.filter(filtered=filter(get_match, filtered), **kwargs) return self.filter(filtered=filter(get_match, filtered), **kwargs)
def get(self, **kwargs): def get(self, **kwargs):
""" """Returns the single object in this container whose attributes match
Returns the single object in this container whose attributes match
the given keyword arguments. An error will be raised if the arguments the given keyword arguments. An error will be raised if the arguments
provided don't return exactly one match. provided don't return exactly one match.
""" """
@ -135,7 +132,7 @@ class TestDataContainer(object):
return matches.pop() return matches.pop()
def first(self): def first(self):
""" Returns the first object from this container. """ """Returns the first object from this container."""
return self._objects[0] return self._objects[0]
def count(self): def count(self):

View File

@ -23,7 +23,7 @@ from openstack_dashboard.test import helpers as test
class ErrorPageTests(test.TestCase): class ErrorPageTests(test.TestCase):
""" Tests for error pages """ """Tests for error pages."""
urls = 'openstack_dashboard.test.error_pages_urls' urls = 'openstack_dashboard.test.error_pages_urls'
def test_500_error(self): def test_500_error(self):

View File

@ -25,7 +25,7 @@ class FakeUser(object):
class TemplateRenderTest(test.TestCase): class TemplateRenderTest(test.TestCase):
""" Tests for templates render """ """Tests for templates render."""
def test_openrc_html_escape(self): def test_openrc_html_escape(self):
context = { context = {

View File

@ -275,8 +275,7 @@ class ProjectUsage(BaseUsage):
class CsvDataMixin(object): class CsvDataMixin(object):
""" """CSV data Mixin - provides handling for CSV data.
CSV data Mixin - provides handling for CSV data
.. attribute:: columns .. attribute:: columns
@ -318,10 +317,7 @@ class CsvDataMixin(object):
class BaseCsvResponse(CsvDataMixin, HttpResponse): class BaseCsvResponse(CsvDataMixin, HttpResponse):
""" """Base CSV response class. Provides handling of CSV data."""
Base CSV response class. Provides handling of CSV data.
"""
def __init__(self, request, template, context, content_type, **kwargs): def __init__(self, request, template, context, content_type, **kwargs):
super(BaseCsvResponse, self).__init__() super(BaseCsvResponse, self).__init__()
@ -358,8 +354,7 @@ if VERSION >= (1, 5, 0):
class BaseCsvStreamingResponse(CsvDataMixin, StreamingHttpResponse): class BaseCsvStreamingResponse(CsvDataMixin, StreamingHttpResponse):
""" """Base CSV Streaming class. Provides streaming response for CSV data.
Base CSV Streaming class. Provides streaming response for CSV data.
""" """
def __init__(self, request, template, context, content_type, **kwargs): def __init__(self, request, template, context, content_type, **kwargs):

View File

@ -60,7 +60,7 @@ QUOTA_FIELDS = NOVA_QUOTA_FIELDS + CINDER_QUOTA_FIELDS + NEUTRON_QUOTA_FIELDS
class QuotaUsage(dict): class QuotaUsage(dict):
""" Tracks quota limit, used, and available for a given set of quotas.""" """Tracks quota limit, used, and available for a given set of quotas."""
def __init__(self): def __init__(self):
self.usages = defaultdict(dict) self.usages = defaultdict(dict)
@ -77,7 +77,7 @@ class QuotaUsage(dict):
return repr(dict(self.usages)) return repr(dict(self.usages))
def add_quota(self, quota): def add_quota(self, quota):
""" Adds an internal tracking reference for the given quota. """ """Adds an internal tracking reference for the given quota."""
if quota.limit is None or quota.limit == -1: if quota.limit is None or quota.limit == -1:
# Handle "unlimited" quotas. # Handle "unlimited" quotas.
self.usages[quota.name]['quota'] = float("inf") self.usages[quota.name]['quota'] = float("inf")
@ -86,7 +86,7 @@ class QuotaUsage(dict):
self.usages[quota.name]['quota'] = int(quota.limit) self.usages[quota.name]['quota'] = int(quota.limit)
def tally(self, name, value): def tally(self, name, value):
""" Adds to the "used" metric for the given quota. """ """Adds to the "used" metric for the given quota."""
value = value or 0 # Protection against None. value = value or 0 # Protection against None.
# Start at 0 if this is the first value. # Start at 0 if this is the first value.
if 'used' not in self.usages[name]: if 'used' not in self.usages[name]:
@ -96,7 +96,7 @@ class QuotaUsage(dict):
self.update_available(name) self.update_available(name)
def update_available(self, name): def update_available(self, name):
""" Updates the "available" metric for the given quota. """ """Updates the "available" metric for the given quota."""
available = self.usages[name]['quota'] - self.usages[name]['used'] available = self.usages[name]['quota'] - self.usages[name]['used']
if available < 0: if available < 0:
available = 0 available = 0

View File

@ -34,8 +34,7 @@ builtins = _
exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py
# E127 continuation line over-indented for visual indent # E127 continuation line over-indented for visual indent
# E128 continuation line under-indented for visual indent # E128 continuation line under-indented for visual indent
# H4xx docstrings
# H701 empty localization string # H701 empty localization string
# H702 Formatting operation should be outside of localization method call # H702 Formatting operation should be outside of localization method call
# H803 git commit title should not end with period (disabled on purpose, see bug #1236621) # H803 git commit title should not end with period (disabled on purpose, see bug #1236621)
ignore = E127,E128,H4,H701,H702,H803 ignore = E127,E128,H701,H702,H803