Fix H405 (multi line docstring) warnings (openstack_dashboard)

H405: multi line docstring summary not separated with an empty line

Closes-Bug: #1696996

Change-Id: Id895695663b19522d9cdc22f8b012e49680d708b
This commit is contained in:
Akihiro Motoki 2017-06-09 10:47:12 +00:00
parent 95629a337e
commit b9d0243c33
55 changed files with 438 additions and 460 deletions

View File

@ -199,8 +199,10 @@ class Quota(object):
class QuotaSet(Sequence):
"""Wrapper for client QuotaSet objects which turns the individual quotas
into Quota objects for easier handling/iteration.
"""Wrapper for client QuotaSet objects.
This turns the individual quotas into Quota objects
for easier handling/iteration.
`QuotaSet` objects support a mix of `list` and `dict` methods; you can use
the bracket notation (`qs["my_quota"] = 0`) to add new quota values, and
@ -229,8 +231,9 @@ class QuotaSet(Sequence):
return self.items[index]
def __add__(self, other):
"""Merge another QuotaSet into this one. Existing quotas are
not overridden.
"""Merge another QuotaSet into this one.
Existing quotas are not overridden.
"""
if not isinstance(other, QuotaSet):
msg = "Can only add QuotaSet to QuotaSet, " \

View File

@ -253,7 +253,9 @@ def update_pagination(entities, page_size, marker, sort_dir):
@profiler.trace
def volume_list_paged(request, search_opts=None, marker=None, paginate=False,
sort_dir="desc"):
"""To see all volumes in the cloud as an admin you can pass in a special
"""List volumes with pagination.
To see all volumes in the cloud as an admin you can pass in a special
search option: {'all_tenants': 1}
"""
has_more_data = False
@ -611,8 +613,7 @@ def volume_cg_snapshot_delete(request, cg_snapshot_id):
@memoized
def volume_backup_supported(request):
"""This method will determine if cinder supports backup.
"""
"""This method will determine if cinder supports backup."""
# TODO(lcheng) Cinder does not expose the information if cinder
# backup is configured yet. This is a workaround until that
# capability is available.
@ -970,8 +971,7 @@ def list_extensions(cinder_api):
@memoized_with_request(list_extensions)
def extension_supported(extensions, extension_name):
"""This method will determine if Cinder supports a given extension name.
"""
"""This method will determine if Cinder supports a given extension name."""
for extension in extensions:
if extension.name == extension_name:
return True
@ -980,7 +980,9 @@ def extension_supported(extensions, extension_name):
@profiler.trace
def transfer_list(request, detailed=True, search_opts=None):
"""To see all volumes transfers as an admin pass in a special
"""List volume transfers.
To see all volumes transfers as an admin pass in a special
search option: {'all_tenants': 1}
"""
c_client = cinderclient(request)

View File

@ -239,9 +239,7 @@ def image_delete(request, image_id):
@profiler.trace
def image_get(request, image_id):
"""Returns an Image object populated with metadata for image
with supplied identifier.
"""
"""Returns an Image object populated with metadata for a given image."""
image = glanceclient(request).images.get(image_id)
return Image(image)
@ -525,8 +523,9 @@ class Namespace(BaseGlanceMetadefAPIResourceWrapper):
def filter_properties_target(namespaces_iter,
resource_types,
properties_target):
"""Filter metadata namespaces based on the given resource types and
properties target.
"""Filter metadata namespaces.
Filtering is done based ongiven resource types and a properties target.
:param namespaces_iter: Metadata namespaces iterable.
:param resource_types: List of resource type names.

View File

@ -311,8 +311,9 @@ def get_default_domain(request, get_name=True):
def get_effective_domain_id(request):
"""Gets the id of the default domain to use when creating Identity
objects. If the requests default domain is the same as DEFAULT_DOMAIN,
"""Gets the id of the default domain.
If the requests default domain is the same as DEFAULT_DOMAIN,
return None.
"""
default_domain = get_default_domain(request)

View File

@ -225,8 +225,9 @@ class FlavorExtraSpec(object):
def get_auth_params_from_request(request):
"""Extracts the properties from the request object needed by the novaclient
call below. These will be used to memoize the calls to novaclient
"""Extracts properties needed by novaclient call from the request object.
These will be used to memoize the calls to novaclient.
"""
return (
request.user.username,

View File

@ -11,8 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API over the cinder service.
"""
"""API over the cinder service."""
from django.utils.translation import ugettext_lazy as _
from django.views import generic
@ -28,14 +27,12 @@ CLIENT_KEYWORDS = {'marker', 'sort_dir', 'paginate'}
@urls.register
class Volumes(generic.View):
"""API for cinder volumes.
"""
"""API for cinder volumes."""
url_regex = r'cinder/volumes/$'
@rest_utils.ajax()
def get(self, request):
"""Get a detailed list of volumes associated with the current user's
project.
"""Get a detailed list of volumes associated with the current project.
Example GET:
http://localhost/api/cinder/volumes?paginate=true&sort_dir=asc
@ -99,8 +96,7 @@ class Volumes(generic.View):
@urls.register
class Volume(generic.View):
"""API for cinder volume.
"""
"""API for cinder volume."""
url_regex = r'cinder/volumes/(?P<volume_id>[^/]+)/$'
@rest_utils.ajax()
@ -118,8 +114,7 @@ class Volume(generic.View):
@urls.register
class VolumeTypes(generic.View):
"""API for volume types.
"""
"""API for volume types."""
url_regex = r'cinder/volumetypes/$'
@rest_utils.ajax()
@ -162,8 +157,7 @@ class VolumeMetadata(generic.View):
@urls.register
class VolumeType(generic.View):
"""API for getting a volume type.
"""
"""API for getting a volume type."""
url_regex = r'cinder/volumetypes/(?P<volumetype_id>[^/]+)/$'
@rest_utils.ajax()
@ -189,14 +183,12 @@ class VolumeType(generic.View):
@urls.register
class VolumeSnapshots(generic.View):
"""API for cinder volume snapshots.
"""
"""API for cinder volume snapshots."""
url_regex = r'cinder/volumesnapshots/$'
@rest_utils.ajax()
def get(self, request):
"""Get a detailed list of volume snapshots associated with the current
user's project.
"""Get a list of volume snapshots associated with the current project.
The listing result is an object with property "items".
"""
@ -277,8 +269,7 @@ class VolumeTypeMetadata(generic.View):
@urls.register
class Extensions(generic.View):
"""API for cinder extensions.
"""
# API for cinder extensions.
url_regex = r'cinder/extensions/$'
@rest_utils.ajax()
@ -324,13 +315,13 @@ class TenantAbsoluteLimits(generic.View):
@urls.register
class Services(generic.View):
"""API for cinder services.
"""
"""API for cinder services."""
url_regex = r'cinder/services/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of cinder services.
Will return HTTP 501 status code if the service_list extension is
not supported.
"""
@ -352,8 +343,7 @@ class Services(generic.View):
@urls.register
class DefaultQuotaSets(generic.View):
"""API for getting default quotas for cinder
"""
"""API for getting default quotas for cinder"""
url_regex = r'cinder/quota-sets/defaults/$'
@rest_utils.ajax()
@ -400,8 +390,7 @@ class DefaultQuotaSets(generic.View):
@urls.register
class QuotaSets(generic.View):
"""API for setting quotas for a given project.
"""
"""API for setting quotas for a given project."""
url_regex = r'cinder/quota-sets/(?P<project_id>[0-9a-f]+)$'
@rest_utils.ajax(data_required=True)

View File

@ -11,8 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API for the glance service.
"""
"""API for the glance service."""
from django import forms
from django.views.decorators.csrf import csrf_exempt
@ -29,21 +28,18 @@ CLIENT_KEYWORDS = {'resource_type', 'marker',
@urls.register
class Version(generic.View):
"""API for active glance version.
"""
"""API for active glance version."""
url_regex = r'glance/version/$'
@rest_utils.ajax()
def get(self, request):
"""Get active glance version.
"""
"""Get active glance version."""
return {'version': str(api.glance.get_version())}
@urls.register
class Image(generic.View):
"""API for retrieving a single image
"""
"""API for retrieving a single image"""
url_regex = r'glance/images/(?P<image_id>[^/]+|default)/$'
@rest_utils.ajax()
@ -95,14 +91,12 @@ class Image(generic.View):
@urls.register
class ImageProperties(generic.View):
"""API for retrieving only a custom properties of single image.
"""
"""API for retrieving only a custom properties of single image."""
url_regex = r'glance/images/(?P<image_id>[^/]+)/properties/'
@rest_utils.ajax()
def get(self, request, image_id):
"""Get custom properties of specific image.
"""
"""Get custom properties of specific image."""
return api.glance.image_get(request, image_id).properties
@rest_utils.ajax(data_required=True)
@ -123,8 +117,7 @@ class UploadObjectForm(forms.Form):
@urls.register
class Images(generic.View):
"""API for Glance images.
"""
"""API for Glance images."""
url_regex = r'glance/images/$'
@rest_utils.ajax()

View File

@ -9,8 +9,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API for the heat service.
"""
"""API for the heat service."""
from django.views import generic
@ -21,8 +20,7 @@ from openstack_dashboard.api.rest import utils as rest_utils
@urls.register
class Validate(generic.View):
"""API for validating a template
"""
"""API for validating a template"""
url_regex = r'heat/validate/$'
@rest_utils.ajax(data_required=True)
@ -40,14 +38,12 @@ class Validate(generic.View):
@urls.register
class Services(generic.View):
"""API for heat services.
"""
"""API for heat services."""
url_regex = r'heat/services/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of heat services.
"""
"""Get a list of heat services."""
if api.base.is_service_enabled(request, 'orchestration'):
result = api.heat.service_list(request)
return {'items': [u.to_dict() for u in result]}

View File

@ -25,7 +25,9 @@ class NaNJSONEncoder(json.JSONEncoder):
super(NaNJSONEncoder, self).__init__(**kwargs)
def iterencode(self, o, _one_shot=False):
"""The sole purpose of defining a custom JSONEncoder class is to
"""JSON encoder with NaN and float inf support.
The sole purpose of defining a custom JSONEncoder class is to
override floatstr() inner function, or more specifically the
representation of NaN and +/-float('inf') values in a JSON. Although
Infinity values are not supported by JSON standard, we still can

View File

@ -11,8 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API over the keystone service.
"""
"""API over the keystone service."""
from django.conf import settings
import django.http
@ -25,21 +24,18 @@ from openstack_dashboard.api.rest import utils as rest_utils
@urls.register
class Version(generic.View):
"""API for active keystone version.
"""
"""API for active keystone version."""
url_regex = r'keystone/version/$'
@rest_utils.ajax()
def get(self, request):
"""Get active keystone version.
"""
"""Get active keystone version."""
return {'version': str(api.keystone.get_version())}
@urls.register
class Users(generic.View):
"""API for keystone users.
"""
"""API for keystone users."""
url_regex = r'keystone/users/$'
client_keywords = {'project_id', 'domain_id', 'group_id'}
@ -113,8 +109,7 @@ class Users(generic.View):
@urls.register
class User(generic.View):
"""API for a single keystone user.
"""
"""API for a single keystone user."""
url_regex = r'keystone/users/(?P<id>[0-9a-f]+|current)$'
@rest_utils.ajax()
@ -172,8 +167,7 @@ class User(generic.View):
@urls.register
class Roles(generic.View):
"""API over all roles.
"""
"""API over all roles."""
url_regex = r'keystone/roles/$'
@rest_utils.ajax()
@ -230,8 +224,7 @@ class Roles(generic.View):
@urls.register
class Role(generic.View):
"""API for a single role.
"""
"""API for a single role."""
url_regex = r'keystone/roles/(?P<id>[0-9a-f]+|default)$'
@rest_utils.ajax()
@ -269,8 +262,7 @@ class Role(generic.View):
@urls.register
class Domains(generic.View):
"""API over all domains.
"""
"""API over all domains."""
url_regex = r'keystone/domains/$'
@rest_utils.ajax()
@ -321,8 +313,7 @@ class Domains(generic.View):
@urls.register
class Domain(generic.View):
"""API over a single domains.
"""
"""API over a single domains."""
url_regex = r'keystone/domains/(?P<id>[0-9a-f]+|default)$'
@rest_utils.ajax()
@ -477,8 +468,7 @@ class Project(generic.View):
@rest_utils.ajax()
def get(self, request, id):
"""Get a specific project by id.
"""
"""Get a specific project by id."""
return api.keystone.tenant_get(request, id).to_dict()
@rest_utils.ajax()
@ -532,16 +522,13 @@ class ServiceCatalog(generic.View):
@rest_utils.ajax()
def get(self, request):
"""Return the Keystone service catalog associated with the current
user.
"""
"""Return the service catalog associated with the current user."""
return request.user.service_catalog
@urls.register
class UserSession(generic.View):
"""API for a single keystone user.
"""
"""API for a single keystone user."""
url_regex = r'keystone/user-session/$'
allowed_fields = {
'available_services_regions',
@ -561,8 +548,7 @@ class UserSession(generic.View):
@rest_utils.ajax()
def get(self, request):
"""Get the current user session.
"""
"""Get the current user session."""
res = {k: getattr(request.user, k, None) for k in self.allowed_fields}
if getattr(settings, 'ENABLE_CLIENT_TOKEN', True):
res['token'] = request.user.token.id
@ -571,14 +557,12 @@ class UserSession(generic.View):
@urls.register
class Services(generic.View):
"""API for keystone services.
"""
"""API for keystone services."""
url_regex = r'keystone/services/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of keystone services.
"""
"""Get a list of keystone services."""
region = request.user.services_region
services = []
for i, service in enumerate(request.user.service_catalog):
@ -591,13 +575,13 @@ class Services(generic.View):
@urls.register
class Groups(generic.View):
"""API over all groups.
"""
"""API over all groups."""
url_regex = r'keystone/groups/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of groups.
The listing result is an object with property "items".
"""
domain_context = request.session.get('domain_context')

View File

@ -13,8 +13,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API for the network abstraction APIs.
"""
"""API for the network abstraction APIs."""
from django.views import generic
@ -49,8 +48,7 @@ class SecurityGroups(generic.View):
@urls.register
class FloatingIP(generic.View):
"""API for a single floating IP address.
"""
"""API for a single floating IP address."""
url_regex = r'network/floatingip/$'
@rest_utils.ajax(data_required=True)
@ -84,8 +82,7 @@ class FloatingIP(generic.View):
@urls.register
class FloatingIPs(generic.View):
"""API for floating IP addresses.
"""
"""API for floating IP addresses."""
url_regex = r'network/floatingips/$'
@rest_utils.ajax()
@ -104,8 +101,7 @@ class FloatingIPs(generic.View):
@urls.register
class FloatingIPPools(generic.View):
"""API for floating IP pools.
"""
"""API for floating IP pools."""
url_regex = r'network/floatingippools/$'
@rest_utils.ajax()

View File

@ -12,8 +12,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API over the neutron service.
"""
"""API over the neutron service."""
from django.utils.translation import ugettext_lazy as _
from django.views import generic
@ -72,7 +71,8 @@ class Networks(generic.View):
@urls.register
class Subnets(generic.View):
"""API for Neutron SubNets
"""API for Neutron Subnets
http://developer.openstack.org/api-ref-networking-v2.html#subnets
"""
url_regex = r'neutron/subnets/$'
@ -119,6 +119,7 @@ class Subnets(generic.View):
@urls.register
class Ports(generic.View):
"""API for Neutron Ports
http://developer.openstack.org/api-ref-networking-v2.html#ports
"""
url_regex = r'neutron/ports/$'
@ -138,8 +139,7 @@ class Ports(generic.View):
@urls.register
class Trunks(generic.View):
"""API for neutron Trunks
"""
"""API for neutron Trunks"""
url_regex = r'neutron/trunks/$'
@rest_utils.ajax()
@ -155,14 +155,12 @@ class Trunks(generic.View):
@urls.register
class Services(generic.View):
"""API for Neutron agents
"""
"""API for Neutron agents"""
url_regex = r'neutron/agents/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of agents
"""
"""Get a list of agents"""
if api.base.is_service_enabled(request, 'network') and \
api.neutron.is_extension_supported(request, 'agent'):
result = api.neutron.agent_list(request, **request.GET)
@ -173,8 +171,7 @@ class Services(generic.View):
@urls.register
class Extensions(generic.View):
"""API for neutron extensions.
"""
"""API for neutron extensions."""
url_regex = r'neutron/extensions/$'
@rest_utils.ajax()
@ -192,8 +189,7 @@ class Extensions(generic.View):
class DefaultQuotaSets(generic.View):
"""API for getting default quotas for neutron
"""
"""API for getting default quotas for neutron"""
url_regex = r'neutron/quota-sets/defaults/$'
@rest_utils.ajax()
@ -218,8 +214,7 @@ class DefaultQuotaSets(generic.View):
@urls.register
class QuotasSets(generic.View):
"""API for setting quotas of a given project.
"""
"""API for setting quotas of a given project."""
url_regex = r'neutron/quotas-sets/(?P<project_id>[0-9a-f]+)$'
@rest_utils.ajax(data_required=True)

View File

@ -11,8 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API over the nova service.
"""
"""API over the nova service."""
from collections import OrderedDict
from django.http import HttpResponse
@ -34,8 +33,7 @@ from openstack_dashboard.usage import quotas
@urls.register
class Snapshots(generic.View):
"""API for nova snapshots.
"""
"""API for nova snapshots."""
url_regex = r'nova/snapshots/$'
@rest_utils.ajax(data_required=True)
@ -50,14 +48,12 @@ class Snapshots(generic.View):
@urls.register
class Keypairs(generic.View):
"""API for nova keypairs.
"""
"""API for nova keypairs."""
url_regex = r'nova/keypairs/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of keypairs associated with the current logged-in
account.
"""Get a list of keypairs associated with the current logged-in user.
The listing result is an object with property "items".
"""
@ -130,13 +126,13 @@ class Keypair(generic.View):
@urls.register
class Services(generic.View):
"""API for nova services.
"""
"""API for nova services."""
url_regex = r'nova/services/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of nova services.
Will return HTTP 501 status code if the service_list extension is
not supported.
"""
@ -150,8 +146,7 @@ class Services(generic.View):
@urls.register
class AvailabilityZones(generic.View):
"""API for nova availability zones.
"""
"""API for nova availability zones."""
url_regex = r'nova/availzones/$'
@rest_utils.ajax()
@ -173,8 +168,7 @@ class AvailabilityZones(generic.View):
@urls.register
class Limits(generic.View):
"""API for nova limits.
"""
"""API for nova limits."""
url_regex = r'nova/limits/$'
@rest_utils.ajax(json_encoder=json_encoder.NaNJSONEncoder)
@ -199,8 +193,7 @@ class Limits(generic.View):
@urls.register
class ServerActions(generic.View):
"""API over all server actions.
"""
"""API over all server actions."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/actions/$'
@rest_utils.ajax()
@ -219,8 +212,7 @@ class ServerActions(generic.View):
@urls.register
class SecurityGroups(generic.View):
"""API over all server security groups.
"""
"""API over all server security groups."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/security-groups/$'
@rest_utils.ajax()
@ -239,8 +231,7 @@ class SecurityGroups(generic.View):
@urls.register
class Volumes(generic.View):
"""API over all server volumes.
"""
"""API over all server volumes."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/volumes/$'
@rest_utils.ajax()
@ -259,14 +250,12 @@ class Volumes(generic.View):
@urls.register
class RemoteConsoleInfo(generic.View):
"""API for remote console information.
"""
"""API for remote console information."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-info/$'
@rest_utils.ajax()
def post(self, request, server_id):
"""Gets information about an available remote console for the given
server.
"""Gets information of a remote console for the given server.
Example POST:
http://localhost/api/nova/servers/abcd/console-info/
@ -317,8 +306,7 @@ class RemoteConsoleInfo(generic.View):
@urls.register
class ConsoleOutput(generic.View):
"""API for console output.
"""
"""API for console output."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-output/$'
@rest_utils.ajax()
@ -339,8 +327,7 @@ class ConsoleOutput(generic.View):
@urls.register
class Servers(generic.View):
"""API over all servers.
"""
"""API over all servers."""
url_regex = r'nova/servers/$'
_optional_create = [
@ -415,8 +402,7 @@ class Servers(generic.View):
@urls.register
class Server(generic.View):
"""API for retrieving a single server
"""
"""API for retrieving a single server"""
url_regex = r'nova/servers/(?P<server_id>[^/]+|default)$'
@rest_utils.ajax()
@ -429,8 +415,7 @@ class Server(generic.View):
@rest_utils.ajax(data_required=True)
def post(self, request, server_id):
"""Perform a change to a server
"""
"""Perform a change to a server"""
operation = request.DATA.get('operation', 'none')
operations = {
'stop': api.nova.server_stop,
@ -451,8 +436,7 @@ class Server(generic.View):
@urls.register
class ServerGroups(generic.View):
"""API for nova server groups.
"""
"""API for nova server groups."""
url_regex = r'nova/servergroups/$'
@rest_utils.ajax()
@ -467,8 +451,7 @@ class ServerGroups(generic.View):
@urls.register
class ServerMetadata(generic.View):
"""API for server metadata.
"""
"""API for server metadata."""
url_regex = r'nova/servers/(?P<server_id>[^/]+|default)/metadata$'
@rest_utils.ajax()
@ -496,8 +479,7 @@ class ServerMetadata(generic.View):
@urls.register
class Extensions(generic.View):
"""API for nova extensions.
"""
"""API for nova extensions."""
url_regex = r'nova/extensions/$'
@rest_utils.ajax()
@ -516,8 +498,7 @@ class Extensions(generic.View):
@urls.register
class Flavors(generic.View):
"""API for nova flavors.
"""
"""API for nova flavors."""
url_regex = r'nova/flavors/$'
@rest_utils.ajax()
@ -580,8 +561,7 @@ class Flavors(generic.View):
@urls.register
class Flavor(generic.View):
"""API for retrieving a single flavor
"""
"""API for retrieving a single flavor"""
url_regex = r'nova/flavors/(?P<flavor_id>[^/]+)/$'
@rest_utils.ajax()
@ -654,8 +634,7 @@ class Flavor(generic.View):
@urls.register
class FlavorExtraSpecs(generic.View):
"""API for managing flavor extra specs
"""
"""API for managing flavor extra specs"""
url_regex = r'nova/flavors/(?P<flavor_id>[^/]+)/extra-specs/$'
@rest_utils.ajax()
@ -684,8 +663,7 @@ class FlavorExtraSpecs(generic.View):
@urls.register
class AggregateExtraSpecs(generic.View):
"""API for managing aggregate extra specs
"""
"""API for managing aggregate extra specs"""
url_regex = r'nova/aggregates/(?P<aggregate_id>[^/]+)/extra-specs/$'
@rest_utils.ajax()
@ -712,8 +690,7 @@ class AggregateExtraSpecs(generic.View):
@urls.register
class DefaultQuotaSets(generic.View):
"""API for getting default quotas for nova
"""
"""API for getting default quotas for nova"""
url_regex = r'nova/quota-sets/defaults/$'
@rest_utils.ajax()
@ -771,8 +748,7 @@ class DefaultQuotaSets(generic.View):
@urls.register
class EditableQuotaSets(generic.View):
"""API for editable quotas.
"""
"""API for editable quotas."""
url_regex = r'nova/quota-sets/editable/$'
@rest_utils.ajax()
@ -791,8 +767,7 @@ class EditableQuotaSets(generic.View):
@urls.register
class QuotaSets(generic.View):
"""API for setting quotas for a given project.
"""
"""API for setting quotas for a given project."""
url_regex = r'nova/quota-sets/(?P<project_id>[0-9a-f]+)$'
@rest_utils.ajax(data_required=True)

View File

@ -11,8 +11,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API for the swift service.
"""
"""API for the swift service."""
import os
from django import forms
@ -31,22 +31,19 @@ from openstack_dashboard.api import swift
@urls.register
class Info(generic.View):
"""API for information about the Swift installation.
"""
"""API for information about the Swift installation."""
url_regex = r'swift/info/$'
@rest_utils.ajax()
def get(self, request):
"""Get information about the Swift installation.
"""
"""Get information about the Swift installation."""
capabilities = api.swift.swift_get_capabilities(request)
return {'info': capabilities}
@urls.register
class Containers(generic.View):
"""API for swift container listing for an account
"""
"""API for swift container listing for an account"""
url_regex = r'swift/containers/$'
@rest_utils.ajax()
@ -71,15 +68,13 @@ class Containers(generic.View):
@urls.register
class Container(generic.View):
"""API for swift container level information
"""
"""API for swift container level information"""
url_regex = r'swift/containers/(?P<container>[^/]+)/metadata/$'
@rest_utils.ajax()
def get(self, request, container):
"""Get the container details
"""
"""Get the container details"""
return api.swift.swift_get_container(request, container).to_dict()
@rest_utils.ajax()
@ -117,8 +112,7 @@ class Container(generic.View):
@urls.register
class Objects(generic.View):
"""API for a list of swift objects
"""
"""API for a list of swift objects"""
url_regex = r'swift/containers/(?P<container>[^/]+)/objects/$'
@rest_utils.ajax()
@ -158,8 +152,7 @@ class UploadObjectForm(forms.Form):
@urls.register
class Object(generic.View):
"""API for a single swift object or pseudo-folder
"""
"""API for a single swift object or pseudo-folder"""
url_regex = r'swift/containers/(?P<container>[^/]+)/object/' \
'(?P<object_name>.+)$'
@ -219,8 +212,7 @@ class Object(generic.View):
api.swift.swift_delete_object(request, container, object_name)
def get(self, request, container, object_name):
"""Get the object contents.
"""
"""Get the object contents."""
obj = api.swift.swift_get_object(
request,
container,
@ -245,8 +237,7 @@ class Object(generic.View):
@urls.register
class ObjectMetadata(generic.View):
"""API for a single swift object
"""
"""API for a single swift object"""
url_regex = r'swift/containers/(?P<container>[^/]+)/metadata/' \
'(?P<object_name>.+)$'
@ -262,8 +253,7 @@ class ObjectMetadata(generic.View):
@urls.register
class ObjectCopy(generic.View):
"""API to copy a swift object
"""
"""API to copy a swift object"""
url_regex = r'swift/containers/(?P<container>[^/]+)/copy/' \
'(?P<object_name>.+)$'

View File

@ -20,13 +20,13 @@ urlpatterns = []
# @register below, and the import the endpoint module in the
# rest_api/__init__.py module
def register(view):
'''Register API views to respond to a regex pattern (url_regex on the
view class).
"""Register API views to respond to a regex pattern.
``url_regex`` on a wrapped view class is used as the regex pattern.
The view should be a standard Django class-based view implementing an
as_view() method. The url_regex attribute of the view should be a standard
Django URL regex pattern.
'''
"""
p = urls.url(view.url_regex, view.as_view())
urlpatterns.append(p)
return view

View File

@ -75,7 +75,9 @@ class JSONResponse(_RestResponse):
def ajax(authenticated=True, data_required=False,
json_encoder=json.JSONEncoder):
'''Provide a decorator to wrap a view method so that it may exist in an
"""Decorator to allow the wrappered view to exist in an AJAX environment.
Provide a decorator to wrap a view method so that it may exist in an
entirely AJAX environment:
- data decoded from JSON as input and data coded as JSON as output
@ -98,7 +100,7 @@ def ajax(authenticated=True, data_required=False,
Methods returning nothing (or None explicitly) will result in a 204 "NO
CONTENT" being returned to the caller.
'''
"""
def decorator(function, authenticated=authenticated,
data_required=data_required):
@functools.wraps(function,
@ -173,7 +175,9 @@ def parse_filters_kwargs(request, client_keywords=None):
def post2data(func):
"""The sole purpose of this decorator is to restore original form values
"""Decorator to restore original form values along with their types.
The sole purpose of this decorator is to restore original form values
along with their types stored on client-side under key $$originalJSON.
This in turn prevents the loss of field types when they are passed with
header 'Content-Type: multipart/form-data', which is needed to pass a

View File

@ -71,9 +71,9 @@ class HypervisorViewTest(test.BaseAdminViewTests):
'hypervisor_stats',
'service_list')})
def test_service_list_unavailable(self):
"""test that error message should be returned when
nova.service_list isn't available
"""
# test that error message should be returned when
# nova.service_list isn't available.
hypervisors = self.hypervisors.list()
stats = self.hypervisors.stats
api.nova.hypervisor_list(IsA(http.HttpRequest)).AndReturn(hypervisors)

View File

@ -45,9 +45,8 @@ class ImageURLField(forms.URLField):
def create_image_metadata(data):
"""Use the given dict of image form data to generate the metadata used for
creating the image in glance.
"""
"""Generate metadata dict for a new image from a given form data."""
# Glance does not really do anything with container_format at the
# moment. It requires it is set to the same disk_format for the three
# Amazon image types, otherwise it just treats them as 'bare.' As such

View File

@ -19,13 +19,12 @@ from openstack_dashboard.api import glance
def get_available_images(request, project_id=None, images_cache=None):
"""Returns a list of images that are public or owned by the given
project_id. If project_id is not specified, only public images
are returned.
"""Returns a list of images that are public or owned by the given project.
If project_id is not specified, only public images are returned.
:param images_cache: An optional dict-like object in which to
cache public and per-project id image metadata.
"""
if images_cache is None:
images_cache = {}

View File

@ -101,9 +101,6 @@ class DeleteInstance(policy.PolicyTargetMixin, tables.DeleteAction):
)
def allowed(self, request, instance=None):
"""Allow delete action if instance is in error state or not currently
being deleted.
"""
error_state = False
if instance:
error_state = (instance.status == 'ERROR')

View File

@ -3920,9 +3920,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
api.network: ('servers_update_addresses',),
})
def test_index_form_action_with_pagination(self):
"""The form action on the next page should have marker
object from the previous page last element.
"""
# The form action on the next page should have marker
# object from the previous page last element.
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
servers = self.servers.list()[:3]
@ -3984,9 +3984,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
api.glance: ('image_list_detailed',),
api.network: ('servers_update_addresses',)})
def test_delete_instance_with_pagination(self):
"""Instance should be deleted from
the next page.
"""
# Instance should be deleted from the next page.
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
servers = self.servers.list()[:3]
server = servers[-1]

View File

@ -35,10 +35,10 @@ def flavor_list(request):
def sort_flavor_list(request, flavors):
"""Utility method to sort a list of flavors.
By default, returns the available flavors, sorted by RAM
usage (ascending). Override these behaviours with a
CREATE_INSTANCE_FLAVOR_SORT dict
in local_settings.py.
By default, returns the available flavors, sorted by RAM usage (ascending).
Override these behaviours with a ``CREATE_INSTANCE_FLAVOR_SORT`` dict
in ``local_settings.py``.
"""
def get_key(flavor, sort_key):
try:

View File

@ -85,8 +85,10 @@ console_invalid_status = {
class TranslationHelper(object):
"""Helper class to provide the translations of instances, networks,
routers and ports from other parts of the code to the network topology
"""Helper class to provide the translations.
This allows the network topology to access the translated strings
for various resources defined in other parts of the code.
"""
def __init__(self):
# turn translation tuples into dicts for easy access

View File

@ -228,8 +228,7 @@ class SecurityGroupsViewTests(test.TestCase):
self._create_security_group(sec_group)
def test_create_security_groups_special_chars(self):
"""Ensure that a group name is not restricted to alphanumeric
characters.
"""Ensure non-alphanumeric characters can be used as a group name.
bug #1233501 Security group names cannot contain at characters
bug #1224576 Security group names cannot contain spaces

View File

@ -566,9 +566,6 @@ class DetachVolume(tables.BatchAction):
class AttachedInstanceColumn(tables.WrappingColumn):
"""Customized column class that does complex processing on the attachments
for a volume instance.
"""
def get_raw_data(self, attachment):
request = self.table.request
return safestring.mark_safe(get_attachment_name(request, attachment))

View File

@ -93,8 +93,9 @@ class BaseWebObject(unittest.TestCase):
self.driver.implicitly_wait(self.conf.selenium.implicit_wait)
def _wait_until(self, predicate, timeout=None, poll_frequency=0.5):
"""Wait until the value returned by predicate is not False or
the timeout is elapsed.
"""Wait until the value returned by predicate is not False.
It also returns when the timeout is elapsed.
'predicate' takes the driver as argument.
"""
if not timeout:
@ -103,10 +104,12 @@ class BaseWebObject(unittest.TestCase):
predicate)
def _wait_till_text_present_in_element(self, element, texts, timeout=None):
"""Waiting for a text to appear in a certain element very often is
actually waiting for a _different_ element with a different text to
appear in place of an old element. So a way to avoid capturing stale
element reference should be provided for this use case.
"""Waiting for a text to appear in a certain element.
Most frequent usage is actually to wait for a _different_ element
with a different text to appear in place of an old element.
So a way to avoid capturing stale element reference should be provided
for this use case.
Better to wrap getting entity status cell in a lambda
to avoid problems with cell being replaced with totally different

View File

@ -32,7 +32,9 @@ def _is_test_cls(cls):
def _mark_method_skipped(meth, reason):
"""Mark method as skipped by replacing the actual method with wrapper
"""Decorate to mark method as skipped.
This marks method as skipped by replacing the actual method with wrapper
that raises the testtools.testcase.TestSkipped exception.
"""
@ -71,8 +73,9 @@ def _get_skip_method(obj):
def services_required(*req_services):
"""Decorator for marking test's service requirements,
if requirements are not met in the configuration file
"""Decorator for marking test's service requirements.
If requirements are not met in the configuration file
test is marked as skipped.
Usage:
@ -110,8 +113,9 @@ def services_required(*req_services):
def _parse_compound_config_option_value(option_name):
"""Parses the value of a given config option where option's section name is
separated from option name by '.'.
"""Parses the value of a given config option.
The section name of the option is separated from option name by '.'.
"""
name_parts = option_name.split('.')
name_parts.reverse()
@ -163,8 +167,7 @@ def skip_because(**kwargs):
def attach_video(func):
"""Notify test runner to attach test video in any case
"""
"""Notify test runner to attach test video in any case"""
@functools.wraps(func)
def wrapper(self, *args, **kwgs):

View File

@ -200,8 +200,9 @@ class BaseTestCase(testtools.TestCase):
super(BaseTestCase, self).addOnException(wrapped_handler)
def _configure_log(self):
"""Configure log to capture test logs include selenium logs in order
to attach them if test will be broken.
"""Configure log to capture test logs include selenium logs.
This allows us to attach them if test will be broken.
"""
# clear other handlers to set target handler
ROOT_LOGGER.handlers[:] = []
@ -276,8 +277,10 @@ class BaseTestCase(testtools.TestCase):
return rec(_log)
def zoom_out(self, times=3):
"""Zooming out prevents different elements being driven out of xvfb
viewport (which in Selenium>=2.50.1 prevents interaction with them.
"""Zooming out a specified element.
It prevents different elements being driven out of xvfb viewport
(which in Selenium>=2.50.1 prevents interaction with them).
"""
html = self.driver.find_element(by.By.TAG_NAME, 'html')
html.send_keys(keys.Keys.NULL)

View File

@ -61,6 +61,7 @@ class MetadatadefinitionsPage(basepage.BaseNavigationPage):
def json_load_template(self, namespace_template_name):
"""Read template for namespace creation
:param namespace_template_name: Path to template
:return = json data container
"""

View File

@ -56,6 +56,7 @@ class PageObject(basewebobject.BaseWebObject):
def switch_window(self, window_name=None, window_index=None):
"""Switches focus between the webdriver windows.
Args:
- window_name: The name of the window to switch to.
- window_index: The index of the window handle to switch to.

View File

@ -42,15 +42,15 @@ class BaseRegion(basewebobject.BaseWebObject):
self._dynamic_properties = {}
def __getattr__(self, name):
"""It is not possible to create property bounded just to object
and not class at runtime, therefore it is necessary to
override __getattr__ and make fake 'properties' by storing them in
the protected attribute _dynamic_attributes and returning result
of the method associated with the specified attribute.
# It is not possible to create property bounded just to object
# and not class at runtime, therefore it is necessary to
# override __getattr__ and make fake 'properties' by storing them in
# the protected attribute _dynamic_attributes and returning result
# of the method associated with the specified attribute.
# This way the feeling of having regions accessed as 'properties'
# is created, which is one of the requirement of page object pattern.
This way the feeling of having regions accessed as 'properties'
is created, which is one of the requirement of page object pattern.
"""
try:
return self._dynamic_properties[name]
except KeyError:

View File

@ -287,9 +287,8 @@ class BaseFormRegion(baseregion.BaseRegion):
_default_form_locator = (by.By.CSS_SELECTOR, 'div.modal-dialog')
def __init__(self, driver, conf, src_elem=None):
"""In most cases forms can be located through _default_form_locator,
so specifying source element can be skipped.
"""
# In most cases forms can be located through _default_form_locator,
# so specifying source element can be skipped.
if src_elem is None:
# fake self.src_elem must be set up in order self._get_element work
self.src_elem = driver
@ -449,9 +448,10 @@ class TabbedFormRegion(FormRegion):
class DateFormRegion(BaseFormRegion):
"""Form that queries data to table that is regularly below the form,
typical example is located on Project/Compute/Overview page.
"""
"""Form that queries data to table that is regularly below the form.
A typical example is located on Project/Compute/Overview page.
"""
_from_field_locator = (by.By.CSS_SELECTOR, 'input#id_start')
_to_field_locator = (by.By.CSS_SELECTOR, 'input#id_end')

View File

@ -221,8 +221,9 @@ class DropDownMenuRegion(baseregion.BaseRegion):
class UserDropDownMenuRegion(DropDownMenuRegion):
"""Drop down menu located in the right side of the topbar,
contains links to settings and help.
"""Drop down menu located in the right side of the topbar.
This menu contains links to settings and help.
"""
_settings_link_locator = (by.By.CSS_SELECTOR,
'a[href*="/settings/"]')

View File

@ -208,6 +208,7 @@ class TableRegion(baseregion.BaseRegion):
def assert_definition(self, expected_table_definition, sorting=False):
"""Checks that actual table is expected one.
Items to compare: 'next' and 'prev' links, count of rows and names of
elements in list
:param expected_table_definition: expected values (dictionary)
@ -225,8 +226,7 @@ class TableRegion(baseregion.BaseRegion):
def bind_table_action(action_name):
"""A decorator to bind table region method to an actual table action
button.
"""Decorator to bind table region method to an actual table action button.
Many table actions when started (by clicking a corresponding button
in UI) lead to some form showing up. To further interact with this form,

View File

@ -43,6 +43,7 @@ class TestDownloadRCFile(helpers.AdminTestCase):
def test_download_rc_v2_file(self):
"""This is a basic scenario test:
Steps:
1) Login to Horizon Dashboard as admin user
2) Navigate to Project > Compute > Access & Security > API Access tab
@ -62,6 +63,7 @@ class TestDownloadRCFile(helpers.AdminTestCase):
@decorators.skip_because(bugs=['1584057'])
def test_download_rc_v3_file(self):
"""This is a basic scenario test:
Steps:
1) Login to Horizon Dashboard as admin user
2) Navigate to Project > Compute > Access & Security > API Access tab

View File

@ -25,6 +25,7 @@ class TestDefaults(helpers.AdminTestCase):
def test_update_defaults(self):
"""Tests the Update Default Quotas functionality:
1) Login as Admin and go to Admin > System > Defaults
2) Updates default Quotas by adding a random number between 1 and 10
3) Verifies that the updated values are present in the

View File

@ -80,6 +80,7 @@ class TestFlavors(helpers.AdminTestCase):
def test_flavor_create(self):
"""tests the flavor creation and deletion functionalities:
* creates a new flavor
* verifies the flavor appears in the flavors table
* deletes the newly created flavor
@ -89,8 +90,7 @@ class TestFlavors(helpers.AdminTestCase):
self._delete_flavor(self.FLAVOR_NAME)
def test_flavor_update_info(self):
"""Tests the flavor Edit row action functionality:
"""
"""Tests the flavor Edit row action functionality"""
self._create_flavor(self.FLAVOR_NAME)

View File

@ -20,6 +20,7 @@ class TestHostAggregates(helpers.AdminTestCase):
def test_host_aggregate_create(self):
"""tests the host aggregate creation and deletion functionalities:
* creates a new host aggregate
* verifies the host aggregate appears in the host aggregates table
* deletes the newly created host aggregate

View File

@ -74,6 +74,7 @@ class TestImagesBasic(TestImagesLegacy):
@decorators.skip_because(bugs=['1595335'])
def test_image_create_delete(self):
"""tests the image creation and deletion functionalities:
* creates a new image from horizon.conf http_image
* verifies the image appears in the images table as active
* deletes the newly created image
@ -84,6 +85,7 @@ class TestImagesBasic(TestImagesLegacy):
def test_image_create_delete_from_local_file(self):
"""tests the image creation and deletion functionalities:
* downloads image from horizon.conf stated in http_image
* creates the image from the downloaded file
* verifies the image appears in the images table as active
@ -96,20 +98,21 @@ class TestImagesBasic(TestImagesLegacy):
def test_images_pagination(self):
"""This test checks images pagination
Steps:
1) Login to Horizon Dashboard as horizon user
2) Navigate to user settings page
3) Change 'Items Per Page' value to 1
4) Go to Project -> Compute -> Images page
5) Check that only 'Next' link is available, only one image is
available (and it has correct name)
6) Click 'Next' and check that both 'Prev' and 'Next' links are
available, only one image is available (and it has correct name)
7) Click 'Next' and check that only 'Prev' link is available,
only one image is visible (and it has correct name)
8) Click 'Prev' and check results (should be the same as for step6)
9) Click 'Prev' and check results (should be the same as for step5)
10) Go to user settings page and restore 'Items Per Page'
Steps:
1) Login to Horizon Dashboard as horizon user
2) Navigate to user settings page
3) Change 'Items Per Page' value to 1
4) Go to Project -> Compute -> Images page
5) Check that only 'Next' link is available, only one image is
available (and it has correct name)
6) Click 'Next' and check that both 'Prev' and 'Next' links are
available, only one image is available (and it has correct name)
7) Click 'Next' and check that only 'Prev' link is available,
only one image is visible (and it has correct name)
8) Click 'Prev' and check results (should be the same as for step6)
9) Click 'Prev' and check results (should be the same as for step5)
10) Go to user settings page and restore 'Items Per Page'
"""
default_image_list = self.CONFIG.image.images_list
items_per_page = 1
@ -148,6 +151,7 @@ class TestImagesBasic(TestImagesLegacy):
def test_update_image_metadata(self):
"""Test update image metadata
* logs in as admin user
* creates image from locally downloaded file
* verifies the image appears in the images table as active
@ -176,6 +180,7 @@ class TestImagesBasic(TestImagesLegacy):
def test_remove_protected_image(self):
"""tests that protected image is not deletable
* logs in as admin user
* creates image from locally downloaded file
* verifies the image appears in the images table as active
@ -215,6 +220,7 @@ class TestImagesBasic(TestImagesLegacy):
def test_edit_image_description_and_name(self):
"""tests that image description is editable
* creates image from locally downloaded file
* verifies the image appears in the images table as active
* toggle edit action and adds some description
@ -263,12 +269,13 @@ class TestImagesAdvanced(TestImagesLegacy):
"""Login as demo user"""
def test_create_volume_from_image(self):
"""This test case checks create volume from image functionality:
Steps:
1. Login to Horizon Dashboard as regular user
2. Navigate to Project -> Compute -> Images
3. Create new volume from image
4. Check that volume is created with expected name
5. Check that volume status is Available
Steps:
1. Login to Horizon Dashboard as regular user
2. Navigate to Project -> Compute -> Images
3. Create new volume from image
4. Check that volume is created with expected name
5. Check that volume status is Available
"""
images_page = self.images_page
source_image = self.CONFIG.image.images_list[0]
@ -290,13 +297,14 @@ class TestImagesAdvanced(TestImagesLegacy):
def test_launch_instance_from_image(self):
"""This test case checks launch instance from image functionality:
Steps:
1. Login to Horizon Dashboard as regular user
2. Navigate to Project -> Compute -> Images
3. Launch new instance from image
4. Check that instance is create
5. Check that status of newly created instance is Active
6. Check that image_name in correct in instances table
Steps:
1. Login to Horizon Dashboard as regular user
2. Navigate to Project -> Compute -> Images
3. Launch new instance from image
4. Check that instance is create
5. Check that status of newly created instance is Active
6. Check that image_name in correct in instances table
"""
images_page = self.images_page
source_image = self.CONFIG.image.images_list[0]
@ -331,15 +339,16 @@ class TestImagesAdmin(helpers.AdminTestCase, TestImagesLegacy):
def test_filter_images(self):
"""This test checks filtering of images
Steps:
1) Login to Horizon dashboard as admin user
2) Go to Admin -> System -> Images
3) Use filter by Image Name
4) Check that filtered table has one image only (which name is
equal to filter value)
5) Check that no other images in the table
6) Clear filter and set nonexistent image name. Check that 0 rows
are displayed
Steps:
1) Login to Horizon dashboard as admin user
2) Go to Admin -> System -> Images
3) Use filter by Image Name
4) Check that filtered table has one image only (which name is
equal to filter value)
5) Check that no other images in the table
6) Clear filter and set nonexistent image name. Check that 0 rows
are displayed
"""
images_list = self.CONFIG.image.images_list
images_page = self.images_page

View File

@ -24,6 +24,7 @@ class TestInstances(helpers.TestCase):
def test_create_delete_instance(self):
"""tests the instance creation and deletion functionality:
* creates a new instance in Project > Compute > Instances page
* verifies the instance appears in the instances table as active
* deletes the newly created instance via proper page (depends on user)
@ -49,6 +50,7 @@ class TestInstances(helpers.TestCase):
@decorators.skip_because(bugs=['1584057'])
def test_instances_pagination(self):
"""This test checks instance pagination
Steps:
1) Login to Horizon Dashboard as regular user
2) Navigate to user settings page
@ -57,9 +59,9 @@ class TestInstances(helpers.TestCase):
5) Create 2 instances
6) Go to appropriate page (depends on user)
7) Check that only 'Next' link is available, only one instance is
available (and it has correct name) on the first page
available (and it has correct name) on the first page
8) Click 'Next' and check that on the second page only one instance is
available (and it has correct name), there is no 'Next' link on page
available (and it has correct name), there is no 'Next' link on page
9) Go to user settings page and restore 'Items Per Page'
10) Delete created instances via proper page (depends on user)
"""
@ -110,6 +112,7 @@ class TestInstances(helpers.TestCase):
def test_instances_pagination_and_filtration(self):
"""This test checks instance pagination and filtration
Steps:
1) Login to Horizon Dashboard as regular user
2) Go to to user settings page
@ -118,11 +121,11 @@ class TestInstances(helpers.TestCase):
5) Create 2 instances
6) Go to appropriate page (depends on user)
7) Check filter by Name of the first and the second instance in order
to have one instance in the list (and it should have correct name) and
no 'Next' link is available
to have one instance in the list (and it should have correct name)
and no 'Next' link is available
8) Check filter by common part of Name of in order to have one instance
in the list (and it should have correct name) and 'Next' link is
available on the first page and is not available on the second page
in the list (and it should have correct name) and 'Next' link is
available on the first page and is not available on the second page
9) Go to user settings page and restore 'Items Per Page'
10) Delete created instances via proper page (depends on user)
@ -181,6 +184,7 @@ class TestInstances(helpers.TestCase):
def test_filter_instances(self):
"""This test checks filtering of instances by Instance Name
Steps:
1) Login to Horizon dashboard as regular user
2) Go to Project > Compute > Instances
@ -188,9 +192,9 @@ class TestInstances(helpers.TestCase):
4) Go to appropriate page (depends on user)
5) Use filter by Instance Name
6) Check that filtered table has one instance only (which name is equal
to filter value) and no other instances in the table
to filter value) and no other instances in the table
7) Check that filtered table has both instances (search by common part
of instance names)
of instance names)
8) Set nonexistent instance name. Check that 0 rows are displayed
9) Clear filter and delete instances via proper page (depends on user)
"""

View File

@ -16,6 +16,7 @@ from openstack_dashboard.test.integration_tests.pages import loginpage
class TestLogin(helpers.BaseTestCase):
"""This is a basic scenario test:
* checks that the login page is available
* logs in as a regular user
* checks that the user home page loads without error

View File

@ -31,6 +31,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
is_public=True, is_protected=False, template_path=None,
checks=(PUBLIC, PROTECTED)):
"""Create NameSpace and run checks
:param namespace_name: Display name of namespace in template
:param page: Connection point
:param template_json_container: JSON container with NameSpace content
@ -71,6 +72,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
def namespace_delete_with_checks(self, namespace_name, page):
"""Delete NameSpace and run checks
:param namespace_name: Display name of namespace in template
:param page: Connection point
:return: Nothing
@ -83,6 +85,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
def test_namespace_create_delete(self):
"""Tests the NameSpace creation and deletion functionality:
* Actions:
* 1) Login to Horizon Dashboard as admin user.
* 2) Navigate to Admin -> System -> Metadata Definitions.

View File

@ -23,6 +23,7 @@ class TestNetworks(helpers.TestCase):
def test_private_network_create(self):
"""tests the network creation and deletion functionalities:
* creates a new private network and a new subnet associated with it
* verifies the network appears in the networks table as active
* deletes the newly created network

View File

@ -44,6 +44,7 @@ class TestRouters(helpers.TestCase):
def test_router_create(self):
"""tests the router creation and deletion functionalities:
* creates a new router for public network
* verifies the router appears in the routers table as active
* deletes the newly created router
@ -73,6 +74,7 @@ class TestRouters(helpers.TestCase):
def test_router_add_delete_interface(self):
"""Tests the router interface creation and deletion functionalities:
* Follows the steps to create a new router
* Clicks on the new router name from the routers table
* Moves to the Interfaces page/tab
@ -102,8 +104,8 @@ class TestRouters(helpers.TestCase):
self._delete_router()
def test_router_delete_interface_by_row(self):
"""Tests the router interface creation and deletion by
row action functionalities:
"""Tests the router interface creation and deletion by row action:
* Follows the steps to create a new router
* Clicks on the new router name from the routers table
* Moves to the Interfaces page/tab
@ -160,6 +162,7 @@ class TestAdminRouters(helpers.AdminTestCase):
@decorators.services_required("neutron")
def test_router_create_admin(self):
"""tests the router creation and deletion functionalities:
* creates a new router for public network
* verifies the router appears in the routers table as active
* edits router name

View File

@ -20,25 +20,26 @@ class TestRouters(helpers.TestCase):
@decorators.services_required("neutron")
def test_router_create(self):
"""This test case checks create, clear/set gateway,
delete router functionality
executed by non-admin user::
Steps:
1. Login to Horizon Dashboard as horizon user
2. Navigate to Project -> Network -> Routers page
3. Create new router
4. Check that the router appears in the routers table as active
5. Check that no Error messages present
6. Clear the gateway
7. Check that the router is still in the routers table
with no external network
8. Check that no Error messages present
9. Set the gateway to 'public' network
10. Check that no Error messages present
11. Check that router's external network is set to 'public'
12. Delete the router
13. Check that the router is absent in the routers table
14. Check that no Error messages present
"""Checks create, clear/set gateway, delete router functionality
Executed by non-admin user.
Steps:
1. Login to Horizon Dashboard as horizon user
2. Navigate to Project -> Network -> Routers page
3. Create new router
4. Check that the router appears in the routers table as active
5. Check that no Error messages present
6. Clear the gateway
7. Check that the router is still in the routers table
with no external network
8. Check that no Error messages present
9. Set the gateway to 'public' network
10. Check that no Error messages present
11. Check that router's external network is set to 'public'
12. Delete the router
13. Check that the router is absent in the routers table
14. Check that no Error messages present
"""
routers_page = self.home_pg.go_to_network_routerspage()

View File

@ -64,17 +64,19 @@ class TestSecuritygroup(helpers.TestCase):
def test_securitygroup_create_delete(self):
"""tests the security group creation and deletion functionalities:
* creates a new security group
* verifies the security group appears in the security groups table
* deletes the newly created security group
* verifies the security group does not appear in the table after
deletion
deletion
"""
self._create_securitygroup()
self._delete_securitygroup()
def test_managerules_create_delete_by_row(self):
"""tests the manage rules creation and deletion functionalities:
* create a new security group
* verifies the security group appears in the security groups table
* creates a new rule
@ -83,7 +85,7 @@ class TestSecuritygroup(helpers.TestCase):
* verifies the rule does not appear in the table after deletion
* deletes the newly created security group
* verifies the security group does not appear in the table after
deletion
deletion
"""
self._create_securitygroup()
self._add_rule()
@ -92,6 +94,7 @@ class TestSecuritygroup(helpers.TestCase):
def test_managerules_create_delete_by_table(self):
"""tests the manage rules creation and deletion functionalities:
* create a new security group
* verifies the security group appears in the security groups table
* creates a new rule
@ -100,7 +103,7 @@ class TestSecuritygroup(helpers.TestCase):
* verifies the rule does not appear in the table after deletion
* deletes the newly created security group
* verifies the security group does not appear in the table after
deletion
deletion
"""
self._create_securitygroup()
self._add_rule()

View File

@ -43,9 +43,10 @@ class TestStacks(helpers.AdminTestCase):
@decorators.services_required("heat")
def test_create_delete_stack(self):
"""tests the stack creation and deletion functionality
* creates a new stack
* verifies the stack appears in the stacks table in Create Complete
state
state
* deletes the newly created stack
* verifies the stack does not appear in the table after deletion
"""

View File

@ -56,9 +56,8 @@ class TestPasswordChange(helpers.TestCase):
"Failed to login with default password")
def test_password_change(self):
"""Changes the password, verifies it was indeed changed and resets to
default password.
"""
# Changes the password, verifies it was indeed changed and
# resets to default password.
passwordchange_page = self.home_pg.go_to_settings_changepasswordpage()
try:
@ -74,9 +73,8 @@ class TestPasswordChange(helpers.TestCase):
self._login()
def test_show_message_after_logout(self):
"""Ensure an informational message is shown on the login page after the
user is logged out.
"""
# Ensure an informational message is shown on the login page
# after the user is logged out.
passwordchange_page = self.home_pg.go_to_settings_changepasswordpage()
try:
@ -111,6 +109,7 @@ class TestUserSettings(helpers.TestCase):
def test_user_settings_change(self):
"""tests the user's settings options:
* changes the system's language
* changes the timezone
* changes the number of items per page (page size)

View File

@ -45,16 +45,17 @@ class TestVolumeSnapshotsBasic(helpers.TestCase):
def test_create_edit_delete_volume_snapshot(self):
"""Test checks create/delete volume snapshot action
Steps:
1. Login to Horizon Dashboard
2. Navigate to Project -> Compute -> Volumes page
3. Create snapshot for existed volume
4. Check that no ERROR appears
5. Check that snapshot is in the list
6. Check that snapshot has reference to correct volume
7. Edit snapshot name and description
8. Delete volume snapshot from proper page
9. Check that volume snapshot not in the list
Steps:
1. Login to Horizon Dashboard
2. Navigate to Project -> Compute -> Volumes page
3. Create snapshot for existed volume
4. Check that no ERROR appears
5. Check that snapshot is in the list
6. Check that snapshot has reference to correct volume
7. Edit snapshot name and description
8. Delete volume snapshot from proper page
9. Check that volume snapshot not in the list
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
volumes_snapshot_page = volumes_page.create_volume_snapshot(
@ -90,25 +91,26 @@ class TestVolumeSnapshotsBasic(helpers.TestCase):
def test_volume_snapshots_pagination(self):
"""This test checks volumes snapshots pagination
Steps:
1) Login to Horizon Dashboard
2) Go to Project -> Compute -> Volumes -> Volumes tab, create
volumes and 3 snapshots
3) Navigate to user settings page
4) Change 'Items Per Page' value to 1
5) Go to Project -> Compute -> Volumes -> Volumes Snapshot tab
or Admin -> System -> Volumes -> Volumes Snapshot tab
(depends on user)
6) Check that only 'Next' link is available, only one snapshot is
available (and it has correct name)
7) Click 'Next' and check that both 'Prev' and 'Next' links are
available, only one snapshot is available (and it has correct name)
8) Click 'Next' and check that only 'Prev' link is available,
only one snapshot is visible (and it has correct name)
9) Click 'Prev' and check result (should be the same as for step7)
10) Click 'Prev' and check result (should be the same as for step6)
11) Go to user settings page and restore 'Items Per Page'
12) Delete created snapshots and volumes
Steps:
1) Login to Horizon Dashboard
2) Go to Project -> Compute -> Volumes -> Volumes tab, create
volumes and 3 snapshots
3) Navigate to user settings page
4) Change 'Items Per Page' value to 1
5) Go to Project -> Compute -> Volumes -> Volumes Snapshot tab
or Admin -> System -> Volumes -> Volumes Snapshot tab
(depends on user)
6) Check that only 'Next' link is available, only one snapshot is
available (and it has correct name)
7) Click 'Next' and check that both 'Prev' and 'Next' links are
available, only one snapshot is available (and it has correct name)
8) Click 'Next' and check that only 'Prev' link is available,
only one snapshot is visible (and it has correct name)
9) Click 'Prev' and check result (should be the same as for step7)
10) Click 'Prev' and check result (should be the same as for step6)
11) Go to user settings page and restore 'Items Per Page'
12) Delete created snapshots and volumes
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
count = 3
@ -223,14 +225,15 @@ class TestVolumeSnapshotsAdvanced(helpers.TestCase):
def test_create_volume_from_snapshot(self):
"""Test checks possibility to create volume from snapshot
Steps:
1. Login to Horizon Dashboard as regular user
2. Navigate to Project -> Compute -> Volumes page
3. Create snapshot for existed volume
4. Create new volume from snapshot
5. Check the volume is created and has 'Available' status
6. Delete volume snapshot
7. Delete volume
Steps:
1. Login to Horizon Dashboard as regular user
2. Navigate to Project -> Compute -> Volumes page
3. Create snapshot for existed volume
4. Create new volume from snapshot
5. Check the volume is created and has 'Available' status
6. Delete volume snapshot
7. Delete volume
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
volumes_snapshot_page = volumes_page.create_volume_snapshot(

View File

@ -27,18 +27,19 @@ class TestVolumesBasic(helpers.TestCase):
def test_volume_create_edit_delete(self):
"""This test case checks create, edit, delete volume functionality:
Steps:
1. Login to Horizon Dashboard
2. Navigate to Project -> Compute -> Volumes page
3. Create new volume
4. Check that the volume is in the list
5. Check that no Error messages present
6. Edit the volume
7. Check that the volume is still in the list
8. Check that no Error messages present
9. Delete the volume via proper page (depends on user)
10. Check that the volume is absent in the list
11. Check that no Error messages present
Steps:
1. Login to Horizon Dashboard
2. Navigate to Project -> Compute -> Volumes page
3. Create new volume
4. Check that the volume is in the list
5. Check that no Error messages present
6. Edit the volume
7. Check that the volume is still in the list
8. Check that no Error messages present
9. Delete the volume via proper page (depends on user)
10. Check that the volume is absent in the list
11. Check that no Error messages present
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
volumes_page.create_volume(self.VOLUME_NAME)
@ -78,24 +79,25 @@ class TestVolumesBasic(helpers.TestCase):
def test_volumes_pagination(self):
"""This test checks volumes pagination
Steps:
1) Login to Horizon Dashboard
2) Go to Project -> Compute -> Volumes -> Volumes tab and create
three volumes
3) Navigate to user settings page
4) Change 'Items Per Page' value to 1
5) Go to Project -> Compute -> Volumes -> Volumes tab or
Admin -> System -> Volumes -> Volumes tab (depends on user)
6) Check that only 'Next' link is available, only one volume is
available (and it has correct name)
7) Click 'Next' and check that both 'Prev' and 'Next' links are
available, only one volume is available (and it has correct name)
8) Click 'Next' and check that only 'Prev' link is available,
only one volume is visible (and it has correct name)
9) Click 'Prev' and check result (should be the same as for step7)
10) Click 'Prev' and check result (should be the same as for step6)
11) Go to user settings page and restore 'Items Per Page'
12) Delete created volumes
Steps:
1) Login to Horizon Dashboard
2) Go to Project -> Compute -> Volumes -> Volumes tab and create
three volumes
3) Navigate to user settings page
4) Change 'Items Per Page' value to 1
5) Go to Project -> Compute -> Volumes -> Volumes tab or
Admin -> System -> Volumes -> Volumes tab (depends on user)
6) Check that only 'Next' link is available, only one volume is
available (and it has correct name)
7) Click 'Next' and check that both 'Prev' and 'Next' links are
available, only one volume is available (and it has correct name)
8) Click 'Next' and check that only 'Prev' link is available,
only one volume is visible (and it has correct name)
9) Click 'Prev' and check result (should be the same as for step7)
10) Click 'Prev' and check result (should be the same as for step6)
11) Go to user settings page and restore 'Items Per Page'
12) Delete created volumes
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
count = 3
@ -167,15 +169,16 @@ class TestVolumesAdvanced(helpers.TestCase):
@decorators.skip_because(bugs=['1584057'])
def test_manage_volume_attachments(self):
"""This test case checks attach/detach actions for volume
Steps:
1. Login to Horizon Dashboard as horizon user
2. Navigate to Project -> Compute -> Instances, create instance
3. Navigate to Project -> Compute -> Volumes, create volume
4. Attach volume to instance from step2
5. Check that volume status and link to instance
6. Detach volume from instance
7. Check volume status
8. Delete volume and instance
Steps:
1. Login to Horizon Dashboard as horizon user
2. Navigate to Project -> Compute -> Instances, create instance
3. Navigate to Project -> Compute -> Volumes, create volume
4. Attach volume to instance from step2
5. Check that volume status and link to instance
6. Detach volume from instance
7. Check volume status
8. Delete volume and instance
"""
instance_name = helpers.gen_random_resource_name('instance')
instances_page = self.home_pg.go_to_compute_instancespage()
@ -251,12 +254,13 @@ class TestVolumesActions(helpers.TestCase):
def test_volume_extend(self):
"""This test case checks extend volume functionality:
Steps:
1. Check current volume size
2. Extend volume
3. Check that no Error messages present
4. Check that the volume is still in the list
5. Check that the volume size is changed
Steps:
1. Check current volume size
2. Extend volume
3. Check that no Error messages present
4. Check that the volume is still in the list
5. Check that the volume size is changed
"""
orig_size = self.volumes_page.get_size(self.VOLUME_NAME)
self.volumes_page.extend_volume(self.VOLUME_NAME, orig_size + 1)
@ -272,12 +276,13 @@ class TestVolumesActions(helpers.TestCase):
@decorators.skip_because(bugs=['1584057'])
def test_volume_upload_to_image(self):
"""This test case checks upload volume to image functionality:
Steps:
1. Upload volume to image with some disk format
2. Check that image is created
3. Check that no Error messages present
4. Delete the image
5. Repeat actions for all disk formats
Steps:
1. Upload volume to image with some disk format
2. Check that image is created
3. Check that no Error messages present
4. Delete the image
5. Repeat actions for all disk formats
"""
self.volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
all_formats = {"qcow2": u'QCOW2', "raw": u'Raw', "vdi": u'VDI',
@ -306,13 +311,14 @@ class TestVolumesActions(helpers.TestCase):
def test_volume_launch_as_instance(self):
"""This test case checks launch volume as instance functionality:
Steps:
1. Launch volume as instance
2. Check that instance is created
3. Check that no Error messages present
4. Check that instance status is 'active'
5. Check that volume status is 'in use'
6. Delete instance
Steps:
1. Launch volume as instance
2. Check that instance is created
3. Check that no Error messages present
4. Check that instance status is 'active'
5. Check that volume status is 'in use'
6. Delete instance
"""
self.volumes_page.launch_instance(self.VOLUME_NAME, self.INSTANCE_NAME)
self.assertTrue(

View File

@ -19,15 +19,16 @@ class TestAdminVolumeTypes(helpers.AdminTestCase):
def test_volume_type_create_delete(self):
"""This test case checks create, delete volume type:
Steps:
1. Login to Horizon Dashboard as admin user
2. Navigate to Admin -> System -> Volumes -> Volume Types page
3. Create new volume type
4. Check that the volume type is in the list
5. Check that no Error messages present
6. Delete the volume type
7. Check that the volume type is absent in the list
8. Check that no Error messages present
Steps:
1. Login to Horizon Dashboard as admin user
2. Navigate to Admin -> System -> Volumes -> Volume Types page
3. Create new volume type
4. Check that the volume type is in the list
5. Check that no Error messages present
6. Delete the volume type
7. Check that the volume type is absent in the list
8. Check that no Error messages present
"""
volume_types_page = self.home_pg.go_to_system_volumes_volumetypespage()
@ -55,6 +56,7 @@ class TestQoSSpec(helpers.AdminTestCase):
def test_qos_spec_create_delete(self):
"""tests the QoS Spec creation and deletion functionality
* creates a new QoS Spec
* verifies the QoS Spec appears in the QoS Specs table
* deletes the newly created QoS Spec
@ -78,10 +80,11 @@ class TestQoSSpec(helpers.AdminTestCase):
def test_qos_spec_edit_consumer(self):
"""tests Edit Consumer of QoS Spec functionality
* creates a new QoS Spec
* verifies the QoS Spec appears in the QoS Specs table
* edit consumer of created QoS Spec (check all options - front-end,
both, back-end)
both, back-end)
* verifies current consumer of the QoS Spec in the QoS Specs table
* deletes the newly created QoS Spec
* verifies the QoS Spec does not appear in the table after deletion

View File

@ -43,9 +43,11 @@ def load_test_data(load_onto=None):
class TestData(object):
"""Holder object for test data. Any functions passed to the init method
will be called with the ``TestData`` object as their only argument. They
can then load data onto the object as desired.
"""Holder object for test data.
Any functions passed to the init method will be called with the
``TestData`` object as their only argument.
They can then load data onto the object as desired.
The idea is to use the instantiated object like this::
@ -93,9 +95,7 @@ class TestDataContainer(object):
return self._objects
def filter(self, filtered=None, **kwargs):
"""Returns objects in this container whose attributes match the given
keyword arguments.
"""
"""Returns objects whose attributes match the given kwargs."""
if filtered is None:
filtered = self._objects
try:
@ -111,8 +111,9 @@ class TestDataContainer(object):
return self.filter(filtered=filtered, **kwargs)
def get(self, **kwargs):
"""Returns the single object in this container whose attributes match
the given keyword arguments. An error will be raised if the arguments
"""Returns a single object whose attributes match the given kwargs.
An error will be raised if the arguments
provided don't return exactly one match.
"""
matches = self.filter(**kwargs)

View File

@ -396,6 +396,7 @@ def _get_tenant_volume_usages(request, usages, disabled_quotas, tenant_id):
@memoized
def tenant_quota_usages(request, tenant_id=None):
"""Get our quotas and construct our usage object.
If no tenant_id is provided, a the request.user.project_id
is assumed to be used
"""

View File

@ -30,7 +30,9 @@ def get_int_or_uuid(value):
def get_display_label(choices, status):
"""This method is used in places where a resource's status or
"""Get a display label for resource status.
This method is used in places where a resource's status or
admin state labels need to assigned before they are sent to the
view template.
"""

View File

@ -117,8 +117,7 @@ commands =
[flake8]
exclude = .venv,.git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,node_modules
# H405 multi line docstring summary not separated with an empty line
ignore = H405
ignore =
# Enable the following hacking rules which are disabled by default
# H203 Use assertIs(Not)None to check for None
# H904 Delay string interpolations at logging calls