Use Python 3.12 for python3-django job
With migration from ubuntu jammy to noble, python3.11 is not available anymore. This makes the job to fail on pre-install step. So let's use Python 3.12 which is available out of the box on Noble after switch. This also bumps pylint version, as older one does not work anymore with Python 3.12. New pylint brings quite some new rules with it. Some were disabled, some were fixed within this patch. Change-Id: I4ba288966c582910e8a822d4531e29c9c005e48f
This commit is contained in:
parent
1b15f51bab
commit
2ec0177edc
16
.pylintrc
16
.pylintrc
@ -15,12 +15,14 @@ disable=
|
|||||||
not-callable,
|
not-callable,
|
||||||
# "W" Warnings for stylistic problems or minor programming issues
|
# "W" Warnings for stylistic problems or minor programming issues
|
||||||
arguments-differ,
|
arguments-differ,
|
||||||
|
arguments-renamed,
|
||||||
attribute-defined-outside-init,
|
attribute-defined-outside-init,
|
||||||
bad-indentation,
|
bad-indentation,
|
||||||
broad-except,
|
broad-except,
|
||||||
fixme,
|
fixme,
|
||||||
# python3 way: pylint suggests to follow PEP 3102
|
# python3 way: pylint suggests to follow PEP 3102
|
||||||
keyword-arg-before-vararg, # TODO
|
keyword-arg-before-vararg, # TODO
|
||||||
|
missing-timeout,
|
||||||
pointless-string-statement,
|
pointless-string-statement,
|
||||||
protected-access,
|
protected-access,
|
||||||
# We should do it carefully considering PEP3134
|
# We should do it carefully considering PEP3134
|
||||||
@ -37,9 +39,8 @@ disable=
|
|||||||
# "C" Coding convention violations
|
# "C" Coding convention violations
|
||||||
abstract-method,
|
abstract-method,
|
||||||
anomalous-backslash-in-string,
|
anomalous-backslash-in-string,
|
||||||
bad-builtin,
|
consider-using-dict-items,
|
||||||
bad-continuation,
|
consider-using-f-string,
|
||||||
deprecated-lambda,
|
|
||||||
global-statement,
|
global-statement,
|
||||||
# Not a good idea to disable this globally
|
# Not a good idea to disable this globally
|
||||||
# Check one by one and add pylint disabled comment if needed
|
# Check one by one and add pylint disabled comment if needed
|
||||||
@ -52,19 +53,22 @@ disable=
|
|||||||
# import order is checked by flake8 (and pylint rule is incompatible with it)
|
# import order is checked by flake8 (and pylint rule is incompatible with it)
|
||||||
wrong-import-order,
|
wrong-import-order,
|
||||||
# "R" Refactor recommendations
|
# "R" Refactor recommendations
|
||||||
|
consider-using-generator,
|
||||||
duplicate-code,
|
duplicate-code,
|
||||||
inconsistent-return-statements, # TODO
|
inconsistent-return-statements, # TODO
|
||||||
interface-not-implemented,
|
|
||||||
no-self-use,
|
|
||||||
too-many-ancestors,
|
too-many-ancestors,
|
||||||
too-many-arguments,
|
too-many-arguments,
|
||||||
too-many-branches,
|
too-many-branches,
|
||||||
too-many-function-args,
|
too-many-function-args,
|
||||||
too-many-instance-attributes,
|
too-many-instance-attributes,
|
||||||
too-many-locals,
|
too-many-locals,
|
||||||
|
too-many-positional-arguments,
|
||||||
too-many-return-statements,
|
too-many-return-statements,
|
||||||
too-many-statements,
|
too-many-statements,
|
||||||
useless-object-inheritance
|
use-a-generator,
|
||||||
|
use-dict-literal,
|
||||||
|
use-yield-from,
|
||||||
|
useless-object-inheritance,
|
||||||
|
|
||||||
[Basic]
|
[Basic]
|
||||||
# Variable names can be 1 to 31 characters long, with lowercase and underscores
|
# Variable names can be 1 to 31 characters long, with lowercase and underscores
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
pre-run: playbooks/horizon-tox-django/pre.yaml
|
pre-run: playbooks/horizon-tox-django/pre.yaml
|
||||||
run: playbooks/horizon-tox-django/run.yaml
|
run: playbooks/horizon-tox-django/run.yaml
|
||||||
vars:
|
vars:
|
||||||
tox_envlist: py311
|
tox_envlist: py312
|
||||||
# The following should match the base openstack-tox-pyNN job.
|
# The following should match the base openstack-tox-pyNN job.
|
||||||
bindep_profile: test py311
|
bindep_profile: test py312
|
||||||
python_version: "3.11"
|
python_version: "3.12"
|
||||||
required-projects:
|
required-projects:
|
||||||
- name: openstack/horizon
|
- name: openstack/horizon
|
||||||
|
|
||||||
@ -42,7 +42,7 @@
|
|||||||
# sentinel to make this project template valid even when we support
|
# sentinel to make this project template valid even when we support
|
||||||
# only one version of Django used as the default. Zuul project
|
# only one version of Django used as the default. Zuul project
|
||||||
# template configuration requires at least one job included.
|
# template configuration requires at least one job included.
|
||||||
- openstack-tox-py311
|
- openstack-tox-py312
|
||||||
# Let's keep at least one job as a template even when we support
|
# Let's keep at least one job as a template even when we support
|
||||||
# only one version of Django covered by the default job.
|
# only one version of Django covered by the default job.
|
||||||
# Just comment it out for such case.
|
# Just comment it out for such case.
|
||||||
@ -50,5 +50,5 @@
|
|||||||
gate:
|
gate:
|
||||||
jobs:
|
jobs:
|
||||||
# Default python job in openstack-python3-antelope-jobs(-horizon)
|
# Default python job in openstack-python3-antelope-jobs(-horizon)
|
||||||
- openstack-tox-py311
|
- openstack-tox-py312
|
||||||
- horizon-tox-python3-django42
|
- horizon-tox-python3-django42
|
||||||
|
@ -595,6 +595,7 @@ class Dashboard(Registry, HorizonComponent):
|
|||||||
panel_group = PanelGroup(self, panels=panel_set)
|
panel_group = PanelGroup(self, panels=panel_set)
|
||||||
|
|
||||||
# Put our results into their appropriate places
|
# Put our results into their appropriate places
|
||||||
|
# pylint: disable-next=possibly-used-before-assignment
|
||||||
panels_to_discover.extend(panel_group.panels)
|
panels_to_discover.extend(panel_group.panels)
|
||||||
panel_groups.append((panel_group.slug, panel_group))
|
panel_groups.append((panel_group.slug, panel_group))
|
||||||
if panel_group.slug == DEFAULT_PANEL_GROUP:
|
if panel_group.slug == DEFAULT_PANEL_GROUP:
|
||||||
@ -615,6 +616,7 @@ class Dashboard(Registry, HorizonComponent):
|
|||||||
before_import_registry = copy.copy(self._registry)
|
before_import_registry = copy.copy(self._registry)
|
||||||
import_module('.%s.panel' % panel, package)
|
import_module('.%s.panel' % panel, package)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
# pylint: disable-next=used-before-assignment
|
||||||
self._registry = before_import_registry
|
self._registry = before_import_registry
|
||||||
if module_has_submodule(mod, panel):
|
if module_has_submodule(mod, panel):
|
||||||
raise
|
raise
|
||||||
@ -866,6 +868,7 @@ class Site(Registry, HorizonComponent):
|
|||||||
before_import_registry = copy.copy(self._registry)
|
before_import_registry = copy.copy(self._registry)
|
||||||
import_module('%s.%s' % (package, mod_name))
|
import_module('%s.%s' % (package, mod_name))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
# pylint: disable-next=used-before-assignment
|
||||||
self._registry = before_import_registry
|
self._registry = before_import_registry
|
||||||
if module_has_submodule(mod, mod_name):
|
if module_has_submodule(mod, mod_name):
|
||||||
raise
|
raise
|
||||||
@ -897,6 +900,7 @@ class Site(Registry, HorizonComponent):
|
|||||||
before_import_registry = copy.copy(self._registry)
|
before_import_registry = copy.copy(self._registry)
|
||||||
import_module('%s.%s' % (app, mod_name))
|
import_module('%s.%s' % (app, mod_name))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
# pylint: disable-next=used-before-assignment
|
||||||
self._registry = before_import_registry
|
self._registry = before_import_registry
|
||||||
if module_has_submodule(mod, mod_name):
|
if module_has_submodule(mod, mod_name):
|
||||||
raise
|
raise
|
||||||
|
@ -628,14 +628,14 @@ class ExternalUploadMeta(forms.DeclarativeFieldsMetaclass):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __prepare__(cls, name, bases):
|
def __prepare__(mcs, name, bases):
|
||||||
# Required in python 3 to keep the form fields order.
|
# Required in python 3 to keep the form fields order.
|
||||||
# Without this method, the __new__(cls, name, bases, attrs) method
|
# Without this method, the __new__(cls, name, bases, attrs) method
|
||||||
# receives a dict as attrs instead of OrderedDict.
|
# receives a dict as attrs instead of OrderedDict.
|
||||||
# This method will be ignored by Python 2.
|
# This method will be ignored by Python 2.
|
||||||
return collections.OrderedDict()
|
return collections.OrderedDict()
|
||||||
|
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(mcs, name, bases, attrs):
|
||||||
def get_double_name(name):
|
def get_double_name(name):
|
||||||
suffix = '__hidden'
|
suffix = '__hidden'
|
||||||
slen = len(suffix)
|
slen = len(suffix)
|
||||||
@ -660,4 +660,4 @@ class ExternalUploadMeta(forms.DeclarativeFieldsMetaclass):
|
|||||||
new_attrs[new_attr_name] = hidden_field
|
new_attrs[new_attr_name] = hidden_field
|
||||||
meth_name = 'clean_' + new_attr_name
|
meth_name = 'clean_' + new_attr_name
|
||||||
new_attrs[meth_name] = make_clean_method(new_attr_name)
|
new_attrs[meth_name] = make_clean_method(new_attr_name)
|
||||||
return super().__new__(cls, name, bases, new_attrs)
|
return super().__new__(mcs, name, bases, new_attrs)
|
||||||
|
@ -100,5 +100,5 @@ class Command(BaseCommand):
|
|||||||
# Ensure to use UTF-8 encoding
|
# Ensure to use UTF-8 encoding
|
||||||
new_po.encoding = 'utf-8'
|
new_po.encoding = 'utf-8'
|
||||||
|
|
||||||
with open(pofile, 'w+') as f:
|
with open(pofile, 'w+', encoding="utf-8") as f:
|
||||||
f.write(new_po.text)
|
f.write(new_po.text)
|
||||||
|
@ -69,6 +69,7 @@ class Command(TemplateCommand):
|
|||||||
|
|
||||||
target = options.pop("target", None)
|
target = options.pop("target", None)
|
||||||
if target == "auto":
|
if target == "auto":
|
||||||
|
# pylint: disable-next=possibly-used-before-assignment
|
||||||
target = os.path.join(os.path.dirname(dashboard_mod.__file__),
|
target = os.path.join(os.path.dirname(dashboard_mod.__file__),
|
||||||
panel_name)
|
panel_name)
|
||||||
if not os.path.exists(target):
|
if not os.path.exists(target):
|
||||||
|
@ -110,7 +110,7 @@ def _is_path(path):
|
|||||||
|
|
||||||
|
|
||||||
def _get_processed_messages(messages_path):
|
def _get_processed_messages(messages_path):
|
||||||
msgs = list()
|
msgs = list() # pylint: disable=use-list-literal
|
||||||
|
|
||||||
if not _is_path(messages_path):
|
if not _is_path(messages_path):
|
||||||
LOG.error('%s is not a valid messages path.', messages_path)
|
LOG.error('%s is not a valid messages path.', messages_path)
|
||||||
|
@ -48,7 +48,7 @@ class BaseActionMetaClass(type):
|
|||||||
parameters for the initializer of the object. The object is then
|
parameters for the initializer of the object. The object is then
|
||||||
initialized clean way. Similar principle is used in DataTableMetaclass.
|
initialized clean way. Similar principle is used in DataTableMetaclass.
|
||||||
"""
|
"""
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(mcs, name, bases, attrs):
|
||||||
# Options of action are set as class attributes, loading them.
|
# Options of action are set as class attributes, loading them.
|
||||||
options = {}
|
options = {}
|
||||||
if attrs:
|
if attrs:
|
||||||
@ -74,7 +74,7 @@ class BaseActionMetaClass(type):
|
|||||||
# instantiating of the specific Action.
|
# instantiating of the specific Action.
|
||||||
attrs['base_options'] = options
|
attrs['base_options'] = options
|
||||||
|
|
||||||
return type.__new__(cls, name, bases, attrs)
|
return type.__new__(mcs, name, bases, attrs)
|
||||||
|
|
||||||
def __call__(cls, *args, **kwargs):
|
def __call__(cls, *args, **kwargs):
|
||||||
cls.base_options.update(kwargs)
|
cls.base_options.update(kwargs)
|
||||||
|
@ -1175,7 +1175,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__(cls, name, bases, attrs):
|
def __new__(mcs, name, bases, attrs):
|
||||||
# Process options from Meta
|
# Process options from Meta
|
||||||
class_name = name
|
class_name = name
|
||||||
dt_attrs = {}
|
dt_attrs = {}
|
||||||
@ -1247,7 +1247,7 @@ class DataTableMetaclass(type):
|
|||||||
opts._filter_action = actions_dict[opts._filter_action.name]
|
opts._filter_action = actions_dict[opts._filter_action.name]
|
||||||
|
|
||||||
# Create our new class!
|
# Create our new class!
|
||||||
return type.__new__(cls, name, bases, dt_attrs)
|
return type.__new__(mcs, name, bases, dt_attrs)
|
||||||
|
|
||||||
|
|
||||||
class DataTable(object, metaclass=DataTableMetaclass):
|
class DataTable(object, metaclass=DataTableMetaclass):
|
||||||
|
@ -48,7 +48,7 @@ def read_from_file(key_file='.secret_key'):
|
|||||||
raise FilePermissionError(
|
raise FilePermissionError(
|
||||||
"Insecure permissions on key file %s, should be 0600." %
|
"Insecure permissions on key file %s, should be 0600." %
|
||||||
os.path.abspath(key_file))
|
os.path.abspath(key_file))
|
||||||
with open(key_file, 'r') as f:
|
with open(key_file, 'r', encoding="utf-8") as f:
|
||||||
key = f.readline()
|
key = f.readline()
|
||||||
return key
|
return key
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ def generate_or_read_from_file(key_file='.secret_key', key_length=64):
|
|||||||
if not os.path.exists(key_file):
|
if not os.path.exists(key_file):
|
||||||
key = generate_key(key_length)
|
key = generate_key(key_length)
|
||||||
old_umask = os.umask(0o177) # Use '0600' file permissions
|
old_umask = os.umask(0o177) # Use '0600' file permissions
|
||||||
with open(key_file, 'w') as f:
|
with open(key_file, 'w', encoding="utf-8") as f:
|
||||||
f.write(key)
|
f.write(key)
|
||||||
os.umask(old_umask)
|
os.umask(old_umask)
|
||||||
else:
|
else:
|
||||||
|
@ -54,28 +54,30 @@ class WorkflowContext(dict):
|
|||||||
return self.__setitem__(key, None)
|
return self.__setitem__(key, None)
|
||||||
|
|
||||||
def set(self, key, val):
|
def set(self, key, val):
|
||||||
|
# pylint: disable-next=unnecessary-dunder-call
|
||||||
return self.__setitem__(key, val)
|
return self.__setitem__(key, val)
|
||||||
|
|
||||||
def unset(self, key):
|
def unset(self, key):
|
||||||
|
# pylint: disable-next=unnecessary-dunder-call
|
||||||
return self.__delitem__(key)
|
return self.__delitem__(key)
|
||||||
|
|
||||||
|
|
||||||
class ActionMetaclass(forms.forms.DeclarativeFieldsMetaclass):
|
class ActionMetaclass(forms.forms.DeclarativeFieldsMetaclass):
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(mcs, name, bases, attrs):
|
||||||
# Pop Meta for later processing
|
# Pop Meta for later processing
|
||||||
opts = attrs.pop("Meta", None)
|
opts = attrs.pop("Meta", None)
|
||||||
# Create our new class
|
# Create our new class
|
||||||
cls_ = super().__new__(cls, name, bases, attrs)
|
mcs_ = super().__new__(mcs, name, bases, attrs)
|
||||||
# Process options from Meta
|
# Process options from Meta
|
||||||
cls_.name = getattr(opts, "name", name)
|
mcs_.name = getattr(opts, "name", name)
|
||||||
cls_.slug = getattr(opts, "slug", slugify(name))
|
mcs_.slug = getattr(opts, "slug", slugify(name))
|
||||||
cls_.permissions = getattr(opts, "permissions", ())
|
mcs_.permissions = getattr(opts, "permissions", ())
|
||||||
cls_.policy_rules = getattr(opts, "policy_rules", ())
|
mcs_.policy_rules = getattr(opts, "policy_rules", ())
|
||||||
cls_.progress_message = getattr(opts, "progress_message",
|
mcs_.progress_message = getattr(opts, "progress_message",
|
||||||
_("Processing..."))
|
_("Processing..."))
|
||||||
cls_.help_text = getattr(opts, "help_text", "")
|
mcs_.help_text = getattr(opts, "help_text", "")
|
||||||
cls_.help_text_template = getattr(opts, "help_text_template", None)
|
mcs_.help_text_template = getattr(opts, "help_text_template", None)
|
||||||
return cls_
|
return mcs_
|
||||||
|
|
||||||
|
|
||||||
class Action(forms.Form, metaclass=ActionMetaclass):
|
class Action(forms.Form, metaclass=ActionMetaclass):
|
||||||
@ -478,10 +480,10 @@ class Step(object):
|
|||||||
|
|
||||||
|
|
||||||
class WorkflowMetaclass(type):
|
class WorkflowMetaclass(type):
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(mcs, name, bases, attrs):
|
||||||
super().__new__(cls, name, bases, attrs)
|
super().__new__(mcs, name, bases, attrs)
|
||||||
attrs["_cls_registry"] = []
|
attrs["_cls_registry"] = []
|
||||||
return type.__new__(cls, name, bases, attrs)
|
return type.__new__(mcs, name, bases, attrs)
|
||||||
|
|
||||||
|
|
||||||
class UpdateMembersStep(Step):
|
class UpdateMembersStep(Step):
|
||||||
|
@ -90,7 +90,7 @@ def _load_default_rules(service, enforcer):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(policy_file) as f:
|
with open(policy_file, encoding="utf-8") as f:
|
||||||
policies = yaml.safe_load(f)
|
policies = yaml.safe_load(f)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
LOG.error('Failed to open the policy file for %(service)s %(path)s: '
|
LOG.error('Failed to open the policy file for %(service)s %(path)s: '
|
||||||
|
@ -280,6 +280,7 @@ class QuotaSet(collections.abc.Sequence):
|
|||||||
return match.pop() if match else Quota(key, default)
|
return match.pop() if match else Quota(key, default)
|
||||||
|
|
||||||
def add(self, other):
|
def add(self, other):
|
||||||
|
# pylint: disable-next=unnecessary-dunder-call
|
||||||
return self.__add__(other)
|
return self.__add__(other)
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
import json
|
import json
|
||||||
import json.encoder as encoder
|
from json import encoder
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
@ -76,8 +76,7 @@ def get_trace(trace_id):
|
|||||||
# finishes before the dependent requests do so, to we need to
|
# finishes before the dependent requests do so, to we need to
|
||||||
# normalize the duration of all requests by the finishing time of
|
# normalize the duration of all requests by the finishing time of
|
||||||
# the one which took longest
|
# the one which took longest
|
||||||
if child_finished > finished:
|
finished = max(finished, child_finished)
|
||||||
finished = child_finished
|
|
||||||
return _data, finished
|
return _data, finished
|
||||||
|
|
||||||
engine = _get_engine()
|
engine = _get_engine()
|
||||||
|
@ -137,9 +137,8 @@ class SubnetsTab(project_tabs_subnets_tab):
|
|||||||
subnet_id = subnet_usage.get("subnet_id")
|
subnet_id = subnet_usage.get("subnet_id")
|
||||||
subnet_used_ips = subnet_usage.get("used_ips")
|
subnet_used_ips = subnet_usage.get("used_ips")
|
||||||
subnet_total_ips = subnet_usage.get("total_ips")
|
subnet_total_ips = subnet_usage.get("total_ips")
|
||||||
subnet_free_ips = subnet_total_ips - subnet_used_ips
|
subnet_free_ips = max(subnet_total_ips - subnet_used_ips, 0)
|
||||||
if subnet_free_ips < 0:
|
|
||||||
subnet_free_ips = 0
|
|
||||||
for item in subnets_dict:
|
for item in subnets_dict:
|
||||||
id = item.get("id")
|
id = item.get("id")
|
||||||
if id == subnet_id:
|
if id == subnet_id:
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
import horizon.views as views
|
from horizon import views
|
||||||
|
|
||||||
|
|
||||||
class IndexView(views.HorizonTemplateView):
|
class IndexView(views.HorizonTemplateView):
|
||||||
|
@ -42,6 +42,7 @@ class QosSpecMixin(object):
|
|||||||
qos_spec_id = context['qos_spec_id']
|
qos_spec_id = context['qos_spec_id']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# pylint: disable-next=possibly-used-before-assignment
|
||||||
qos_list = api.cinder.qos_spec_get(self.request, qos_spec_id)
|
qos_list = api.cinder.qos_spec_get(self.request, qos_spec_id)
|
||||||
context['qos_spec_name'] = qos_list.name
|
context['qos_spec_name'] = qos_list.name
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -100,6 +100,7 @@ def download_ec2_bundle(request):
|
|||||||
# Create our file bundle
|
# Create our file bundle
|
||||||
template = 'project/api_access/ec2rc.sh.template'
|
template = 'project/api_access/ec2rc.sh.template'
|
||||||
try:
|
try:
|
||||||
|
# pylint: disable-next=consider-using-with
|
||||||
temp_zip = tempfile.NamedTemporaryFile(delete=True)
|
temp_zip = tempfile.NamedTemporaryFile(delete=True)
|
||||||
with closing(zipfile.ZipFile(temp_zip.name, mode='w')) as archive:
|
with closing(zipfile.ZipFile(temp_zip.name, mode='w')) as archive:
|
||||||
archive.writestr('ec2rc.sh', render_to_string(template, context))
|
archive.writestr('ec2rc.sh', render_to_string(template, context))
|
||||||
|
@ -95,16 +95,16 @@ class DeleteRule(tables.DeleteAction):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def action_present(count):
|
def action_present(count):
|
||||||
return ngettext_lazy(
|
return ngettext_lazy(
|
||||||
u"Delete Rule",
|
"Delete Rule",
|
||||||
u"Delete Rules",
|
"Delete Rules",
|
||||||
count
|
count
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def action_past(count):
|
def action_past(count):
|
||||||
return ngettext_lazy(
|
return ngettext_lazy(
|
||||||
u"Deleted Rule",
|
"Deleted Rule",
|
||||||
u"Deleted Rules",
|
"Deleted Rules",
|
||||||
count
|
count
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -121,8 +121,8 @@ class ReleaseIPsPortForwarding(ReleaseIPs):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def action_past(count):
|
def action_past(count):
|
||||||
return ngettext_lazy(
|
return ngettext_lazy(
|
||||||
u"Successfully redirected",
|
"Successfully redirected",
|
||||||
u"Successfully redirected",
|
"Successfully redirected",
|
||||||
count
|
count
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
# pylint: disable=no-name-in-module,import-error
|
# pylint: disable=no-name-in-module,import-error,deprecated-module
|
||||||
from distutils.command import install
|
from distutils.command import install
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,7 +52,9 @@ def _format_default_policy(default):
|
|||||||
|
|
||||||
|
|
||||||
def _write_yaml_file(policies, output_file):
|
def _write_yaml_file(policies, output_file):
|
||||||
stream = open(output_file, 'w') if output_file else sys.stdout
|
# pylint: disable-next=consider-using-with
|
||||||
|
stream = open(output_file, 'w',
|
||||||
|
encoding="utf-8") if output_file else sys.stdout
|
||||||
yaml.dump(policies, stream=stream)
|
yaml.dump(policies, stream=stream)
|
||||||
if output_file:
|
if output_file:
|
||||||
stream.close()
|
stream.close()
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error,deprecated-module
|
||||||
from distutils.dist import Distribution
|
from distutils.dist import Distribution
|
||||||
import os
|
import os
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
|
@ -26,7 +26,7 @@ from django import template
|
|||||||
# rendering it unreadable.
|
# rendering it unreadable.
|
||||||
warnings.simplefilter('ignore')
|
warnings.simplefilter('ignore')
|
||||||
|
|
||||||
cmd_name = __name__.split('.')[-1]
|
cmd_name = __name__.rsplit('.', maxsplit=1)[-1]
|
||||||
|
|
||||||
CURDIR = os.path.realpath(os.path.dirname(__file__))
|
CURDIR = os.path.realpath(os.path.dirname(__file__))
|
||||||
PROJECT_PATH = os.path.realpath(os.path.join(CURDIR, '../..'))
|
PROJECT_PATH = os.path.realpath(os.path.join(CURDIR, '../..'))
|
||||||
@ -301,11 +301,12 @@ location you desire, e.g.::
|
|||||||
# Generate the WSGI.
|
# Generate the WSGI.
|
||||||
if options.get('wsgi'):
|
if options.get('wsgi'):
|
||||||
with open(
|
with open(
|
||||||
os.path.join(CURDIR, 'horizon.wsgi.template'), 'r'
|
os.path.join(CURDIR, 'horizon.wsgi.template'), 'r',
|
||||||
|
encoding="utf-8"
|
||||||
) as fp:
|
) as fp:
|
||||||
wsgi_template = template.Template(fp.read())
|
wsgi_template = template.Template(fp.read())
|
||||||
if not os.path.exists(context['WSGI_FILE']) or force:
|
if not os.path.exists(context['WSGI_FILE']) or force:
|
||||||
with open(context['WSGI_FILE'], 'w') as fp:
|
with open(context['WSGI_FILE'], 'w', encoding="utf-8") as fp:
|
||||||
fp.write(wsgi_template.render(context))
|
fp.write(wsgi_template.render(context))
|
||||||
print('Generated "%s"' % context['WSGI_FILE'])
|
print('Generated "%s"' % context['WSGI_FILE'])
|
||||||
else:
|
else:
|
||||||
@ -319,7 +320,8 @@ location you desire, e.g.::
|
|||||||
context['WSGI_FILE'] = context['DEFAULT_WSGI_FILE']
|
context['WSGI_FILE'] = context['DEFAULT_WSGI_FILE']
|
||||||
|
|
||||||
with open(
|
with open(
|
||||||
os.path.join(CURDIR, 'apache_vhost.conf.template'), 'r'
|
os.path.join(CURDIR, 'apache_vhost.conf.template'), 'r',
|
||||||
|
encoding="utf-8"
|
||||||
) as fp:
|
) as fp:
|
||||||
wsgi_template = template.Template(fp.read())
|
wsgi_template = template.Template(fp.read())
|
||||||
sys.stdout.write(wsgi_template.render(context))
|
sys.stdout.write(wsgi_template.render(context))
|
||||||
|
@ -114,10 +114,13 @@ class Command(BaseCommand):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
with DirContext(self.local_settings_dir) as dircontext:
|
with DirContext(self.local_settings_dir) as dircontext:
|
||||||
if not os.path.exists(self.local_settings_diff) or force:
|
if not os.path.exists(self.local_settings_diff,
|
||||||
with open(self.local_settings_example, 'r') as fp:
|
encoding="utf-8") or force:
|
||||||
|
with open(self.local_settings_example, 'r',
|
||||||
|
encoding="utf-8") as fp:
|
||||||
example_lines = fp.readlines()
|
example_lines = fp.readlines()
|
||||||
with open(self.local_settings_file, 'r') as fp:
|
with open(self.local_settings_file, 'r',
|
||||||
|
encoding="utf-8") as fp:
|
||||||
local_settings_lines = fp.readlines()
|
local_settings_lines = fp.readlines()
|
||||||
local_settings_example_mtime = time.strftime(
|
local_settings_example_mtime = time.strftime(
|
||||||
self.time_fmt,
|
self.time_fmt,
|
||||||
@ -134,7 +137,8 @@ class Command(BaseCommand):
|
|||||||
dircontext.curdir,
|
dircontext.curdir,
|
||||||
self.local_settings_diff)
|
self.local_settings_diff)
|
||||||
)
|
)
|
||||||
with open(self.local_settings_diff, 'w') as fp:
|
with open(self.local_settings_diff, 'w',
|
||||||
|
encoding="utf-8") as fp:
|
||||||
for line in difflib.unified_diff(
|
for line in difflib.unified_diff(
|
||||||
example_lines, local_settings_lines,
|
example_lines, local_settings_lines,
|
||||||
fromfile=self.local_settings_example,
|
fromfile=self.local_settings_example,
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
import os
|
import os
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
|
|
||||||
import babel.messages.catalog as catalog
|
from babel.messages import catalog
|
||||||
import babel.messages.pofile as babel_pofile
|
from babel.messages import pofile as babel_pofile
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
@ -110,7 +110,7 @@ class Command(BaseCommand):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Pseudo translation logic
|
# Pseudo translation logic
|
||||||
with open(potfile, 'r') as f:
|
with open(potfile, 'r', encoding="utf-8") as f:
|
||||||
pot_cat = babel_pofile.read_po(f, ignore_obsolete=True)
|
pot_cat = babel_pofile.read_po(f, ignore_obsolete=True)
|
||||||
|
|
||||||
new_cat = catalog.Catalog(locale=locale,
|
new_cat = catalog.Catalog(locale=locale,
|
||||||
|
@ -272,7 +272,9 @@ if os.path.exists(LOCAL_SETTINGS_DIR_PATH):
|
|||||||
for filename in sorted(filenames):
|
for filename in sorted(filenames):
|
||||||
if filename.endswith(".py"):
|
if filename.endswith(".py"):
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(dirpath, filename)) as f:
|
with open(
|
||||||
|
os.path.join(dirpath, filename), encoding="utf-8"
|
||||||
|
) as f:
|
||||||
# pylint: disable=exec-used
|
# pylint: disable=exec-used
|
||||||
exec(f.read())
|
exec(f.read())
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -127,7 +127,7 @@ def record_video(request, report_dir, xdisplay):
|
|||||||
'-video_size', f'{width}x{height}',
|
'-video_size', f'{width}x{height}',
|
||||||
'-framerate', str(frame_rate),
|
'-framerate', str(frame_rate),
|
||||||
'-f', 'x11grab',
|
'-f', 'x11grab',
|
||||||
'-i', f':{display}',
|
'-i', f':{display}', # noqa: E231
|
||||||
filepath,
|
filepath,
|
||||||
]
|
]
|
||||||
fnull = open(os.devnull, 'w')
|
fnull = open(os.devnull, 'w')
|
||||||
|
@ -224,7 +224,7 @@ def new_instance_demo(complete_default_test_network, request, instance_name,
|
|||||||
yield instance
|
yield instance
|
||||||
if count > 1:
|
if count > 1:
|
||||||
for instance in range(0, count):
|
for instance in range(0, count):
|
||||||
openstack_demo.delete_server(f"{instance_name}-{instance+1}")
|
openstack_demo.delete_server(f"{instance_name}-{instance + 1}")
|
||||||
else:
|
else:
|
||||||
openstack_demo.delete_server(instance_name)
|
openstack_demo.delete_server(instance_name)
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ def test_edit_image_description_admin(login, driver, image_names,
|
|||||||
".//button[@class='btn btn-primary finish']").click()
|
".//button[@class='btn btn-primary finish']").click()
|
||||||
messages = widgets.get_and_dismiss_messages(driver)
|
messages = widgets.get_and_dismiss_messages(driver)
|
||||||
assert f"Success: Image {image_name} " \
|
assert f"Success: Image {image_name} " \
|
||||||
f"was successfully updated." in messages
|
f"was successfully updated." in messages
|
||||||
image_id = new_image_admin.id
|
image_id = new_image_admin.id
|
||||||
assert (openstack_admin.compute.get(f"/images/{image_id}").json(
|
assert (openstack_admin.compute.get(f"/images/{image_id}").json(
|
||||||
)['image']['metadata']['description'] == new_description)
|
)['image']['metadata']['description'] == new_description)
|
||||||
@ -471,7 +471,7 @@ def test_update_image_metadata_admin(login, driver,
|
|||||||
image_form.find_element_by_css_selector(
|
image_form.find_element_by_css_selector(
|
||||||
"button.btn span[class='fa fa-plus']").click()
|
"button.btn span[class='fa fa-plus']").click()
|
||||||
image_form.find_element_by_xpath(
|
image_form.find_element_by_xpath(
|
||||||
f"//span[@title='{name}']/parent::div/input").send_keys(value)
|
f"//span[@title='{name}']/parent::div/input").send_keys(value) # noqa: E231,E501
|
||||||
image_form.find_element_by_xpath(
|
image_form.find_element_by_xpath(
|
||||||
"//button[@ng-click='modal.save()']").click()
|
"//button[@ng-click='modal.save()']").click()
|
||||||
messages = widgets.get_and_dismiss_messages(driver)
|
messages = widgets.get_and_dismiss_messages(driver)
|
||||||
@ -548,7 +548,7 @@ def test_create_volume_from_image_admin(login, driver, volume_name,
|
|||||||
name_field.send_keys(volume_name)
|
name_field.send_keys(volume_name)
|
||||||
create_vol_btn = WebDriverWait(driver, config.selenium.page_timeout).until(
|
create_vol_btn = WebDriverWait(driver, config.selenium.page_timeout).until(
|
||||||
EC.element_to_be_clickable((By.XPATH, f"//button[@class='btn "
|
EC.element_to_be_clickable((By.XPATH, f"//button[@class='btn "
|
||||||
f"btn-primary finish']")))
|
f"btn-primary finish']")))
|
||||||
create_vol_btn.click()
|
create_vol_btn.click()
|
||||||
messages = widgets.get_and_dismiss_messages(driver)
|
messages = widgets.get_and_dismiss_messages(driver)
|
||||||
assert f"Info: Creating volume {volume_name}" in messages
|
assert f"Info: Creating volume {volume_name}" in messages
|
||||||
|
@ -42,7 +42,7 @@ def new_instance_admin(complete_default_test_network, request, instance_name,
|
|||||||
yield instance
|
yield instance
|
||||||
if count > 1:
|
if count > 1:
|
||||||
for instance in range(0, count):
|
for instance in range(0, count):
|
||||||
openstack_admin.delete_server(f"{instance_name}-{instance+1}")
|
openstack_admin.delete_server(f"{instance_name}-{instance + 1}")
|
||||||
else:
|
else:
|
||||||
openstack_admin.delete_server(instance_name)
|
openstack_admin.delete_server(instance_name)
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ def ensure_checkbox(required_state, element):
|
|||||||
current_state = element.is_selected()
|
current_state = element.is_selected()
|
||||||
if required_state != current_state:
|
if required_state != current_state:
|
||||||
element.find_element_by_xpath(
|
element.find_element_by_xpath(
|
||||||
f".//following-sibling::label").click()
|
f".//following-sibling::label").click() # noqa: E231
|
||||||
|
|
||||||
|
|
||||||
def test_create_network_without_subnet_demo(login, openstack_demo, driver,
|
def test_create_network_without_subnet_demo(login, openstack_demo, driver,
|
||||||
|
@ -120,8 +120,8 @@ def test_add_member_to_project(login, driver, project_name, openstack_admin,
|
|||||||
rows[0].find_element_by_css_selector(".data-table-action").click()
|
rows[0].find_element_by_css_selector(".data-table-action").click()
|
||||||
project_form = driver.find_element_by_css_selector("form .modal-content")
|
project_form = driver.find_element_by_css_selector("form .modal-content")
|
||||||
project_form.find_element_by_xpath(
|
project_form.find_element_by_xpath(
|
||||||
f".//*[text()='{admin_name}']//ancestor::li"
|
f".//*[text()='{admin_name}']//ancestor::li" # noqa: E231
|
||||||
f"/following-sibling::li/a[@href='#add_remove']").click()
|
f"/following-sibling::li/a[@href='#add_remove']").click() # noqa: E231
|
||||||
project_form.find_element_by_css_selector(
|
project_form.find_element_by_css_selector(
|
||||||
".btn-primary[value='Save']").click()
|
".btn-primary[value='Save']").click()
|
||||||
messages = widgets.get_and_dismiss_messages(driver)
|
messages = widgets.get_and_dismiss_messages(driver)
|
||||||
@ -151,8 +151,8 @@ def test_add_role_to_project_member(login, driver, openstack_admin, config,
|
|||||||
rows[0].find_element_by_css_selector(".data-table-action").click()
|
rows[0].find_element_by_css_selector(".data-table-action").click()
|
||||||
project_form = driver.find_element_by_css_selector("form .modal-content")
|
project_form = driver.find_element_by_css_selector("form .modal-content")
|
||||||
select_roles_dropdown = project_form.find_element_by_xpath(
|
select_roles_dropdown = project_form.find_element_by_xpath(
|
||||||
f".//*[text()='{admin_name}']//ancestor::li"
|
f".//*[text()='{admin_name}']//ancestor::li" # noqa: E231
|
||||||
f"/following-sibling::li[@class='dropdown role_options']")
|
f"/following-sibling::li[@class='dropdown role_options']") # noqa: E231
|
||||||
widgets.select_from_dropdown(select_roles_dropdown, admin_role_name)
|
widgets.select_from_dropdown(select_roles_dropdown, admin_role_name)
|
||||||
project_form.find_element_by_css_selector(
|
project_form.find_element_by_css_selector(
|
||||||
".btn-primary[value='Save']").click()
|
".btn-primary[value='Save']").click()
|
||||||
@ -188,8 +188,8 @@ def test_add_group_to_project(login, driver, openstack_admin,
|
|||||||
widgets.select_from_dropdown(actions_column, "Modify Groups")
|
widgets.select_from_dropdown(actions_column, "Modify Groups")
|
||||||
project_form = driver.find_element_by_css_selector("form .modal-content")
|
project_form = driver.find_element_by_css_selector("form .modal-content")
|
||||||
project_form.find_element_by_xpath(
|
project_form.find_element_by_xpath(
|
||||||
f".//*[text()='{group_name}']//ancestor::li"
|
f".//*[text()='{group_name}']//ancestor::li" # noqa: E231
|
||||||
f"/following-sibling::li/a[@href='#add_remove']").click()
|
f"/following-sibling::li/a[@href='#add_remove']").click() # noqa: E231
|
||||||
project_form.find_element_by_css_selector(
|
project_form.find_element_by_css_selector(
|
||||||
".btn-primary[value='Save']").click()
|
".btn-primary[value='Save']").click()
|
||||||
messages = widgets.get_and_dismiss_messages(driver)
|
messages = widgets.get_and_dismiss_messages(driver)
|
||||||
@ -220,8 +220,8 @@ def test_add_role_to_project_group(login, driver, openstack_admin, config,
|
|||||||
widgets.select_from_dropdown(actions_column, "Modify Groups")
|
widgets.select_from_dropdown(actions_column, "Modify Groups")
|
||||||
project_form = driver.find_element_by_css_selector("form .modal-content")
|
project_form = driver.find_element_by_css_selector("form .modal-content")
|
||||||
select_roles_dropdown = project_form.find_element_by_xpath(
|
select_roles_dropdown = project_form.find_element_by_xpath(
|
||||||
f".//*[text()='{group_name}']//ancestor::li"
|
f".//*[text()='{group_name}']//ancestor::li" # noqa: E231
|
||||||
f"/following-sibling::li[@class='dropdown role_options']")
|
f"/following-sibling::li[@class='dropdown role_options']") # noqa: E231
|
||||||
widgets.select_from_dropdown(select_roles_dropdown, admin_role_name)
|
widgets.select_from_dropdown(select_roles_dropdown, admin_role_name)
|
||||||
project_form.find_element_by_css_selector(
|
project_form.find_element_by_css_selector(
|
||||||
".btn-primary[value='Save']").click()
|
".btn-primary[value='Save']").click()
|
||||||
|
@ -157,7 +157,7 @@ def test_router_add_interface_demo(login, driver, router_name, openstack_demo,
|
|||||||
".modal-dialog form")
|
".modal-dialog form")
|
||||||
widgets.select_from_dropdown(
|
widgets.select_from_dropdown(
|
||||||
add_interface_form, f"{new_network_demo.name}: {new_subnet_demo.cidr} "
|
add_interface_form, f"{new_network_demo.name}: {new_subnet_demo.cidr} "
|
||||||
f"({new_subnet_demo.name})")
|
f"({new_subnet_demo.name})")
|
||||||
add_interface_form.find_element_by_id(
|
add_interface_form.find_element_by_id(
|
||||||
"id_ip_address").send_keys(fixed_ip_test)
|
"id_ip_address").send_keys(fixed_ip_test)
|
||||||
add_interface_form.find_element_by_css_selector(".btn-primary").click()
|
add_interface_form.find_element_by_css_selector(".btn-primary").click()
|
||||||
|
@ -145,7 +145,7 @@ def test_browse_left_panel(live_server, driver, user, dashboard_data,
|
|||||||
WebDriverWait(driver, config.selenium.implicit_wait).until(
|
WebDriverWait(driver, config.selenium.implicit_wait).until(
|
||||||
EC.element_to_be_clickable(
|
EC.element_to_be_clickable(
|
||||||
(By.CSS_SELECTOR, f"a[data-target='#sidebar-accordion"
|
(By.CSS_SELECTOR, f"a[data-target='#sidebar-accordion"
|
||||||
f"-{main_panel}-{sec_panel}']"))).click()
|
f"-{main_panel}-{sec_panel}']"))).click()
|
||||||
sidebar = driver.find_element_by_id(
|
sidebar = driver.find_element_by_id(
|
||||||
f"sidebar-accordion-{main_panel}-{sec_panel}")
|
f"sidebar-accordion-{main_panel}-{sec_panel}")
|
||||||
else:
|
else:
|
||||||
|
@ -53,24 +53,24 @@ def test_vcpu_pcpu_data_display(live_server, driver, user, dashboard_data):
|
|||||||
driver.get(live_server.url + '/admin/hypervisors')
|
driver.get(live_server.url + '/admin/hypervisors')
|
||||||
assert (driver.find_element_by_xpath(
|
assert (driver.find_element_by_xpath(
|
||||||
f"//*[normalize-space()='VCPU Usage']/"
|
f"//*[normalize-space()='VCPU Usage']/"
|
||||||
f"ancestor::div[contains(@class,'d3_quota_bar')]"
|
f"ancestor::div[contains(@class,'d3_quota_bar')]" # noqa: E231
|
||||||
f"/div[contains(@class,'h6')]/"
|
f"/div[contains(@class,'h6')]/" # noqa: E231
|
||||||
f"span[1]").text == str(p['vcpus_used']))
|
f"span[1]").text == str(p['vcpus_used']))
|
||||||
assert (driver.find_element_by_xpath(
|
assert (driver.find_element_by_xpath(
|
||||||
f"//*[normalize-space()='VCPU Usage']/"
|
f"//*[normalize-space()='VCPU Usage']/"
|
||||||
f"ancestor::div[contains(@class,'d3_quota_bar')]"
|
f"ancestor::div[contains(@class,'d3_quota_bar')]" # noqa: E231
|
||||||
f"/div[contains(@class,'h6')]/"
|
f"/div[contains(@class,'h6')]/" # noqa: E231
|
||||||
f"span[2]").text == str(p['vcpus_capacity']))
|
f"span[2]").text == str(p['vcpus_capacity']))
|
||||||
|
|
||||||
assert (driver.find_element_by_xpath(
|
assert (driver.find_element_by_xpath(
|
||||||
f"//*[normalize-space()='PCPU Usage']/"
|
f"//*[normalize-space()='PCPU Usage']/"
|
||||||
f"ancestor::div[contains(@class,'d3_quota_bar')]"
|
f"ancestor::div[contains(@class,'d3_quota_bar')]" # noqa: E231
|
||||||
f"/div[contains(@class,'h6')]/"
|
f"/div[contains(@class,'h6')]/" # noqa: E231
|
||||||
f"span[1]").text == str(p['pcpus_used']))
|
f"span[1]").text == str(p['pcpus_used']))
|
||||||
assert (driver.find_element_by_xpath(
|
assert (driver.find_element_by_xpath(
|
||||||
f"//*[normalize-space()='PCPU Usage']/"
|
f"//*[normalize-space()='PCPU Usage']/"
|
||||||
f"ancestor::div[contains(@class,'d3_quota_bar')]"
|
f"ancestor::div[contains(@class,'d3_quota_bar')]" # noqa: E231
|
||||||
f"/div[contains(@class,'h6')]/"
|
f"/div[contains(@class,'h6')]/" # noqa: E231
|
||||||
f"span[2]").text == str(p['pcpus_capacity']))
|
f"span[2]").text == str(p['pcpus_capacity']))
|
||||||
|
|
||||||
driver.find_element_by_link_text("Resource Provider").click()
|
driver.find_element_by_link_text("Resource Provider").click()
|
||||||
|
@ -55,7 +55,7 @@ def select_from_dropdown(element, label):
|
|||||||
|
|
||||||
def select_from_specific_dropdown_in_form(driver, dropdown_id, label):
|
def select_from_specific_dropdown_in_form(driver, dropdown_id, label):
|
||||||
dropdown = driver.find_element_by_xpath(
|
dropdown = driver.find_element_by_xpath(
|
||||||
f".//*[@for='{dropdown_id}']/following-sibling::div")
|
f".//*[@for='{dropdown_id}']/following-sibling::div") # noqa: E231
|
||||||
dropdown.click()
|
dropdown.click()
|
||||||
dropdown_options = dropdown.find_element_by_css_selector(
|
dropdown_options = dropdown.find_element_by_css_selector(
|
||||||
"ul.dropdown-menu")
|
"ul.dropdown-menu")
|
||||||
@ -128,12 +128,12 @@ def select_from_transfer_table(element, label):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
element.find_element_by_xpath(
|
element.find_element_by_xpath(
|
||||||
f".//*[text()='{label}']//ancestor::tr/td//*"
|
f".//*[text()='{label}']//ancestor::tr/td//*" # noqa: E231
|
||||||
f"[@class='btn btn-default fa fa-arrow-up']").click()
|
f"[@class='btn btn-default fa fa-arrow-up']").click()
|
||||||
except exceptions.NoSuchElementException:
|
except exceptions.NoSuchElementException:
|
||||||
try:
|
try:
|
||||||
element.find_element_by_xpath(
|
element.find_element_by_xpath(
|
||||||
f".//*[text()='{label}']//ancestor::tr/td//*"
|
f".//*[text()='{label}']//ancestor::tr/td//*" # noqa: E231
|
||||||
f"[@class='btn btn-default fa fa-arrow-down']")
|
f"[@class='btn btn-default fa fa-arrow-down']")
|
||||||
except exceptions.NoSuchElementException:
|
except exceptions.NoSuchElementException:
|
||||||
raise
|
raise
|
||||||
|
@ -163,9 +163,7 @@ class QuotaUsage(dict):
|
|||||||
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."""
|
||||||
quota = self.usages.get(name, {}).get('quota', float('inf'))
|
quota = self.usages.get(name, {}).get('quota', float('inf'))
|
||||||
available = quota - self.usages[name]['used']
|
available = max(quota - self.usages[name]['used'], 0)
|
||||||
if available < 0:
|
|
||||||
available = 0
|
|
||||||
self.usages[name]['available'] = available
|
self.usages[name]['available'] = available
|
||||||
|
|
||||||
|
|
||||||
|
@ -312,6 +312,7 @@ def get_xstatic_dirs(XSTATIC_MODULES, HORIZON_CONFIG):
|
|||||||
file = 'horizon/lib/' + module.NAME + '/' + file
|
file = 'horizon/lib/' + module.NAME + '/' + file
|
||||||
HORIZON_CONFIG['xstatic_lib_files'].append(file)
|
HORIZON_CONFIG['xstatic_lib_files'].append(file)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
# pylint: disable-next=broad-exception-raised
|
||||||
raise Exception(
|
raise Exception(
|
||||||
'%s: Nothing to include because files to include are not '
|
'%s: Nothing to include because files to include are not '
|
||||||
'defined (i.e., None) in BASE_XSTATIC_MODULES list and '
|
'defined (i.e., None) in BASE_XSTATIC_MODULES list and '
|
||||||
|
2
tox.ini
2
tox.ini
@ -37,7 +37,7 @@ commands = {posargs}
|
|||||||
deps =
|
deps =
|
||||||
{[testenv]deps}
|
{[testenv]deps}
|
||||||
flake8-import-order==0.12 # LGPLv3
|
flake8-import-order==0.12 # LGPLv3
|
||||||
pylint==2.6.0 # GPLv2
|
pylint==3.3.1 # GPLv2
|
||||||
bandit[baseline]>=1.7.7 # Apache-2.0
|
bandit[baseline]>=1.7.7 # Apache-2.0
|
||||||
setenv =
|
setenv =
|
||||||
DJANGO_SETTINGS_MODULE=openstack_dashboard.test.settings
|
DJANGO_SETTINGS_MODULE=openstack_dashboard.test.settings
|
||||||
|
Loading…
x
Reference in New Issue
Block a user