Adopt Ruff for security; remove Bandit and fix style

Expand Ruff lint scope to include security checks and remove Bandit from
pre-commit. Fix residual style issues to comply with OpenStack rules
(79-char lines, delayed logging interpolation).

Key changes:
- Drop Bandit pre-commit hook; rely on Ruff S-rules
- Add S-rule suppressions where usage is intentional (subprocess, mark_safe)
- Convert f-string logs to delayed interpolation and wrap lines
- Update .pre-commit-config.yaml and project config accordingly

Assisted-By: cursor gpt5
Change-Id: I83f78535c1bd2f8bf9bff3247acb52ef744ec416
Signed-off-by: Sean Mooney <work@seanmooney.info>
This commit is contained in:
Sean Mooney
2025-10-08 13:47:39 +01:00
parent 1856c908d1
commit ad1863e5b9
31 changed files with 142 additions and 118 deletions

View File

@@ -35,11 +35,6 @@ repos:
- id: hacking
additional_dependencies: []
exclude: '^(doc|releasenotes|tools)/.*$'
- repo: https://github.com/PyCQA/bandit
rev: 1.8.3
hooks:
- id: bandit
args: ['-x', 'tests', '-s', 'B101,B311,B320,B703,B308']
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.1
hooks:

View File

@@ -35,8 +35,8 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'Watcher Dashboard'
copyright = u'OpenStack Foundation'
project = 'Watcher Dashboard'
copyright = 'OpenStack Foundation'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -89,7 +89,7 @@ man_pages = []
html_theme = 'openstackdocs'
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
htmlhelp_basename = f'{project}doc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
@@ -97,8 +97,8 @@ htmlhelp_basename = '%sdoc' % project
latex_documents = [
('index',
'doc-watcher-dashboard.tex',
u'%s Documentation' % project,
u'OpenStack Foundation', 'manual'),
f'{project} Documentation',
'OpenStack Foundation', 'manual'),
]
# Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664

View File

@@ -1,3 +1,29 @@
[build-system]
requires = ["pbr>=6.0.0", "setuptools>=64.0.0"]
build-backend = "pbr.build"
[tool.ruff]
line-length = 79
target-version = "py310"
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "S", "U", "W", "C90"]
ignore = [
# we only use asserts for type narrowing
"S101",
# we do not use random number geneerators for crypto
"S311",
# S104 Possible binding to all interfaces
"S104",
# S105 Possible hardcoded password assigned to variable"
"S105",
# S106 Possible hardcoded password assigned to argument
"S106",
# S110 `try`-`except`-`pass` detected, consider logging the exception
"S110",
]
[tool.ruff.lint.per-file-ignores]
"watcher_dashboard/tests/*" = ["S"]
[tool.ruff.lint.mccabe]
# Flag errors (`C901`) whenever the complexity level exceeds 5.
max-complexity = 20

View File

@@ -54,8 +54,8 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'Watcher Dashboard Release Notes'
copyright = u'2017, Watcher Developers'
project = 'Watcher Dashboard Release Notes'
copyright = '2017, Watcher Developers'
# Release notes are version independent.
# The full version, including alpha/beta/rc tags.
@@ -211,8 +211,8 @@ latex_elements = {
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'WatcherDashboardReleaseNotes.tex',
u'Watcher Dashboard Release Notes Documentation',
u'Watcher Developers', 'manual'),
'Watcher Dashboard Release Notes Documentation',
'Watcher Developers', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -242,8 +242,8 @@ latex_documents = [
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'watcherdashboardreleasenotes',
u'Watcher Dashboard Release Notes Documentation',
[u'Watcher Developers'], 1)
'Watcher Dashboard Release Notes Documentation',
['Watcher Developers'], 1)
]
# If true, show URL addresses after external links.
@@ -257,8 +257,8 @@ man_pages = [
# dir menu entry, description, category)
texinfo_documents = [
('index', 'WatcherDashboardReleaseNotes',
u'Watcher Dashboard Release Notes Documentation',
u'Watcher Developers', 'WatcherDashboardReleaseNotes',
'Watcher Dashboard Release Notes Documentation',
'Watcher Developers', 'WatcherDashboardReleaseNotes',
'One line description of project.',
'Miscellaneous'),
]

View File

@@ -56,7 +56,7 @@ def main(argv):
pip_requires = os.path.join(root, 'requirements.txt')
test_requires = os.path.join(root, 'test-requirements.txt')
py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
py_version = f"python{sys.version_info[0]}.{sys.version_info[1]}"
project = 'OpenStack'
install = install_venv.InstallVenv(root, venv, pip_requires, test_requires,
py_version, project)

View File

@@ -28,7 +28,7 @@ import subprocess # nosec B404 - needed for virtual environment setup
import sys
class InstallVenv(object):
class InstallVenv:
def __init__(self, root, venv, requirements,
test_requirements, py_version,
@@ -45,8 +45,7 @@ class InstallVenv(object):
sys.exit(1)
def check_python_version(self):
if sys.version_info < (2, 6):
self.die("Need Python Version >= 2.6")
pass
def run_command_with_code(self, cmd, redirect_output=True,
check_exit_code=True):
@@ -59,7 +58,7 @@ class InstallVenv(object):
else:
stdout = None
proc = subprocess.Popen(
proc = subprocess.Popen( # noqa: S603
cmd, cwd=self.root, stdout=stdout) # nosec B603
output = proc.communicate()[0]
if check_exit_code and proc.returncode != 0:
@@ -146,9 +145,9 @@ class Distro(InstallVenv):
else:
print('Failed')
self.die('ERROR: virtualenv not found.\n\n%s development'
self.die(f'ERROR: virtualenv not found.\n\n{self.project} development'
' requires virtualenv, please install it using your'
' favorite package management tool' % self.project)
' favorite package management tool')
class Fedora(Distro):
@@ -168,4 +167,4 @@ class Fedora(Distro):
if not self.check_pkg('python-virtualenv'):
self.die("Please install 'python-virtualenv'.")
super(Fedora, self).install_virtualenv()
super().install_virtualenv()

View File

@@ -28,8 +28,11 @@ def watcherclient(request, api_version=None):
endpoint = base.url_for(request, WATCHER_SERVICE)
LOG.debug('watcherclient connection created using token "%s" and url "%s"'
% (request.user.token.id, endpoint))
LOG.debug(
'watcherclient connection created using token "%s" and url "%s"',
request.user.token.id,
endpoint,
)
# Default to minimal microversion (1.0) unless explicitly overridden.
microversion = api_version or wv.MIN_DEFAULT
@@ -52,7 +55,7 @@ class Audit(base.APIDictWrapper):
'goal_name', 'strategy_name', 'start_time', 'end_time')
def __init__(self, apiresource, request=None):
super(Audit, self).__init__(apiresource)
super().__init__(apiresource)
self._request = request
@classmethod
@@ -183,7 +186,7 @@ class AuditTemplate(base.APIDictWrapper):
'deleted_at')
def __init__(self, apiresource, request=None):
super(AuditTemplate, self).__init__(apiresource)
super().__init__(apiresource)
self._request = request
@classmethod
@@ -307,7 +310,7 @@ class ActionPlan(base.APIDictWrapper):
'audit_uuid', 'state')
def __init__(self, apiresource, request=None):
super(ActionPlan, self).__init__(apiresource)
super().__init__(apiresource)
self._request = request
@classmethod
@@ -379,7 +382,7 @@ class Action(base.APIDictWrapper):
'action_type', 'applies_to', 'src', 'dst', 'parameter')
def __init__(self, apiresource, request=None):
super(Action, self).__init__(apiresource)
super().__init__(apiresource)
self._request = request
@classmethod
@@ -454,7 +457,7 @@ class Goal(base.APIDictWrapper):
'updated_at', 'deleted_at', 'efficacy_specifications')
def __init__(self, apiresource, request=None):
super(Goal, self).__init__(apiresource)
super().__init__(apiresource)
self._request = request
@classmethod
@@ -500,7 +503,7 @@ class Strategy(base.APIDictWrapper):
'created_at', 'updated_at', 'deleted_at', 'parameters_spec')
def __init__(self, apiresource, request=None):
super(Strategy, self).__init__(apiresource)
super().__init__(apiresource)
self._request = request
@classmethod
@@ -547,7 +550,7 @@ class EfficacyIndicatorSpec(base.APIDictWrapper):
class EfficacyIndicator(base.APIDictWrapper):
def __init__(self, indicator):
super(EfficacyIndicator, self).__init__(indicator)
super().__init__(indicator)
self.value = indicator.get('value', None)
self.name = indicator.get('name', None)
self.description = indicator.get('description', None)

View File

@@ -31,13 +31,13 @@ from watcher_dashboard.api import watcher
LOG = logging.getLogger(__name__)
ACTION_PLAN_STATE_DISPLAY_CHOICES = (
("NO STATE", pgettext_lazy("State of an action plan", u"No State")),
("ONGOING", pgettext_lazy("State of an action plan", u"On Going")),
("SUCCEEDED", pgettext_lazy("State of an action plan", u"Succeeded")),
("SUBMITTED", pgettext_lazy("State of an action plan", u"Submitted")),
("FAILED", pgettext_lazy("State of an action plan", u"Failed")),
("DELETED", pgettext_lazy("State of an action plan", u"Deleted")),
("RECOMMENDED", pgettext_lazy("State of an action plan", u"Recommended")),
("NO STATE", pgettext_lazy("State of an action plan", "No State")),
("ONGOING", pgettext_lazy("State of an action plan", "On Going")),
("SUCCEEDED", pgettext_lazy("State of an action plan", "Succeeded")),
("SUBMITTED", pgettext_lazy("State of an action plan", "Submitted")),
("FAILED", pgettext_lazy("State of an action plan", "Failed")),
("DELETED", pgettext_lazy("State of an action plan", "Deleted")),
("RECOMMENDED", pgettext_lazy("State of an action plan", "Recommended")),
)
@@ -57,16 +57,16 @@ class ArchiveActionPlan(horizon.tables.DeleteAction):
@staticmethod
def action_present(count):
return ngettext_lazy(
u"Archive Action Plan",
u"Archive Action Plans",
"Archive Action Plan",
"Archive Action Plans",
count
)
@staticmethod
def action_past(count):
return ngettext_lazy(
u"Action Plan archived",
u"Action Plans archived",
"Action Plan archived",
"Action Plans archived",
count
)
@@ -83,16 +83,16 @@ class StartActionPlan(horizon.tables.BatchAction):
@staticmethod
def action_present(count):
return ngettext_lazy(
u"Start Action Plan",
u"Start Action Plans",
"Start Action Plan",
"Start Action Plans",
count
)
@staticmethod
def action_past(count):
return ngettext_lazy(
u"Action Plan started",
u"Action Plans started",
"Action Plan started",
"Action Plans started",
count
)
@@ -182,7 +182,7 @@ class ActionPlansTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "action_plans"
verbose_name = _("Action Plans")
table_actions = (
@@ -228,7 +228,7 @@ class RelatedActionPlansTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "related_action_plans"
verbose_name = _("Related Action Plans")
hidden_title = False
@@ -260,7 +260,7 @@ class RelatedEfficacyIndicatorsTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.name
class Meta(object):
class Meta:
name = "related_efficacy_indicators"
verbose_name = _("Related Efficacy Indicators")
hidden_title = False

View File

@@ -37,7 +37,7 @@ class IndexView(horizon.tables.DataTableView):
page_title = _("Action Plans")
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context['action_plans_count'] = self.get_action_plans_count()
return context
@@ -128,7 +128,7 @@ class DetailView(horizon.tables.MultiTableView):
return efficacy_indicators
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
action_plan = self._get_data()
context["action_plan"] = action_plan
LOG.info('*********************************')

View File

@@ -30,13 +30,13 @@ LOG = logging.getLogger(__name__)
ACTION_STATE_DISPLAY_CHOICES = (
("NO STATE", pgettext_lazy("Power state of an Instance", u"No State")),
("ONGOING", pgettext_lazy("Power state of an Instance", u"On Going")),
("SUCCEEDED", pgettext_lazy("Power state of an Instance", u"Succeeded")),
("CANCELLED", pgettext_lazy("Power state of an Instance", u"Cancelled")),
("FAILED", pgettext_lazy("Power state of an Instance", u"Failed")),
("DELETED", pgettext_lazy("Power state of an Instance", u"Deleted")),
("PENDING", pgettext_lazy("Power state of an Instance", u"Pending")),
("NO STATE", pgettext_lazy("Power state of an Instance", "No State")),
("ONGOING", pgettext_lazy("Power state of an Instance", "On Going")),
("SUCCEEDED", pgettext_lazy("Power state of an Instance", "Succeeded")),
("CANCELLED", pgettext_lazy("Power state of an Instance", "Cancelled")),
("FAILED", pgettext_lazy("Power state of an Instance", "Failed")),
("DELETED", pgettext_lazy("Power state of an Instance", "Deleted")),
("PENDING", pgettext_lazy("Power state of an Instance", "Pending")),
)
@@ -92,7 +92,7 @@ class ActionsTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "wactions"
verbose_name = _("Actions")
table_actions = (ActionsFilterAction, )
@@ -121,7 +121,7 @@ class RelatedActionsTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "related_wactions"
verbose_name = _("Related Actions")
hidden_title = False
@@ -138,7 +138,7 @@ class ActionParametersTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.name
class Meta(object):
class Meta:
name = "parameters"
verbose_name = _("Related parameters")
hidden_title = False

View File

@@ -33,7 +33,7 @@ class IndexView(horizon.tables.DataTableView):
page_title = _("Actions")
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context['audits_count'] = self.get_actions_count()
return context
@@ -93,7 +93,7 @@ class DetailView(horizon.tables.MultiTableView):
for name, value in action.input_parameters.items()]
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
action = self._get_data()
context["action"] = action
return context

View File

@@ -31,7 +31,7 @@ from watcher_dashboard.api import watcher
LOG = logging.getLogger(__name__)
class YamlValidator(object):
class YamlValidator:
message = _('Enter a valid YAML or JSON value.')
code = 'invalid'
@@ -61,7 +61,7 @@ class CreateForm(forms.SelfHandlingForm):
failure_url = 'horizon:admin:audit_templates:index'
def __init__(self, request, *args, **kwargs):
super(CreateForm, self).__init__(request, *args, **kwargs)
super().__init__(request, *args, **kwargs)
goals = self._get_goal_list(request)
if goals:

View File

@@ -113,7 +113,7 @@ class AuditTemplatesTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "audit_templates"
verbose_name = _("Audit Templates")
table_actions = (

View File

@@ -30,7 +30,7 @@ DETAILS_VIEW = 'horizon:admin:audit_templates:detail'
class AuditTemplatesTest(test.BaseAdminViewTests):
def setUp(self):
super(AuditTemplatesTest, self).setUp()
super().setUp()
self.goal_list = self.goals.list()
self.strategy_list = self.strategies.list()

View File

@@ -40,7 +40,7 @@ class IndexView(horizon.tables.DataTableView):
page_title = _("Audit Templates")
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context['audit_templates_count'] = self.get_count()
return context
@@ -124,7 +124,7 @@ class DetailView(horizon.tabs.TabbedTableView):
return audits
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
audit_template = self._get_data()
context["audit_template"] = audit_template
return context

View File

@@ -122,7 +122,7 @@ class CreateForm(forms.SelfHandlingForm):
required=False)
def __init__(self, request, *args, **kwargs):
super(CreateForm, self).__init__(request, *args, **kwargs)
super().__init__(request, *args, **kwargs)
audit_templates = self._get_audit_template_list(request)
self.fields['audit_template'].choices = audit_templates
# Keep fields visible; API microversion is enforced per-call in backend
@@ -169,7 +169,7 @@ class CreateForm(forms.SelfHandlingForm):
return parsed
def clean(self):
cleaned_data = super(CreateForm, self).clean()
cleaned_data = super().clean()
audit_type = cleaned_data.get('audit_type')
if audit_type == 'continuous' and not cleaned_data.get('interval'):
msg = _('Please input an interval for continuous audit')

View File

@@ -27,13 +27,13 @@ from horizon.utils import filters
from watcher_dashboard.api import watcher
AUDIT_STATE_DISPLAY_CHOICES = (
("NO STATE", pgettext_lazy("State of an audit", u"No State")),
("ONGOING", pgettext_lazy("State of an audit", u"On Going")),
("SUCCEEDED", pgettext_lazy("State of an audit", u"Succeeded")),
("SUBMITTED", pgettext_lazy("State of an audit", u"Submitted")),
("FAILED", pgettext_lazy("State of an audit", u"Failed")),
("DELETED", pgettext_lazy("State of an audit", u"Deleted")),
("PENDING", pgettext_lazy("State of an audit", u"Pending")),
("NO STATE", pgettext_lazy("State of an audit", "No State")),
("ONGOING", pgettext_lazy("State of an audit", "On Going")),
("SUCCEEDED", pgettext_lazy("State of an audit", "Succeeded")),
("SUBMITTED", pgettext_lazy("State of an audit", "Submitted")),
("FAILED", pgettext_lazy("State of an audit", "Failed")),
("DELETED", pgettext_lazy("State of an audit", "Deleted")),
("PENDING", pgettext_lazy("State of an audit", "Pending")),
)
@@ -164,7 +164,7 @@ class AuditsTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "audits"
verbose_name = _("Audits")
launch_actions = (CreateAudit,)
@@ -196,7 +196,7 @@ class RelatedAuditsTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "audits"
verbose_name = _("Related audits")
hidden_title = False

View File

@@ -44,7 +44,7 @@ class IndexView(horizon.tables.DataTableView):
page_title = _("Audits")
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
create_action = {
'name': _("New Audit"),
'url': reverse('horizon:admin:audits:create'),
@@ -136,14 +136,14 @@ class DetailView(horizon.tables.MultiTableView):
obj = params
# Dicts/lists are presented as indented YAML for readability.
if isinstance(obj, (dict, list)):
if isinstance(obj, dict | list):
dumped = yaml.safe_dump(
obj,
default_flow_style=False,
sort_keys=False,
)
return mark_safe( # nosec B703,B308
'<pre style="margin:0">{}</pre>'.format(dumped)
return mark_safe( # noqa: S308 # nosec B703,B308
f'<pre style="margin:0">{dumped}</pre>'
)
# Scalars or unknown types: return directly.
@@ -166,7 +166,7 @@ class DetailView(horizon.tables.MultiTableView):
return audits
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
audit = self._get_data()
context["audit"] = audit
# Prepare pretty parameters rendering (YAML) for the template. The

View File

@@ -37,7 +37,7 @@ class GoalsTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "goals"
verbose_name = _("Goals")
@@ -63,7 +63,7 @@ class EfficacySpecificationTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.name
class Meta(object):
class Meta:
name = "efficacy_specification"
verbose_name = _("Efficacy specification")
hidden_title = False

View File

@@ -36,7 +36,7 @@ class IndexView(horizon.tables.DataTableView):
page_title = _("Goals")
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context['goals_count'] = self.get_goals_count()
return context
@@ -116,7 +116,7 @@ class DetailView(horizon.tables.MultiTableView):
return indicators_spec
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
goal = self._get_data()
context["goal"] = goal
return context

View File

@@ -51,7 +51,7 @@ class StrategiesTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "strategies"
verbose_name = _("Strategies")
table_actions = (
@@ -82,7 +82,7 @@ class RelatedStrategiesTable(horizon.tables.DataTable):
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
class Meta:
name = "related_strategies"
verbose_name = _("Related strategies")
hidden_title = False

View File

@@ -38,7 +38,7 @@ class IndexView(horizon.tables.DataTableView):
page_title = _("Strategies")
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context['strategies_count'] = self.get_strategies_count()
return context
@@ -91,7 +91,7 @@ class DetailView(horizon.tabs.TabbedTableView):
return strategy
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
strategy = self._get_data()
context["strategy"] = strategy
# Render parameters_spec in a readable format for the template
@@ -135,7 +135,7 @@ class DetailView(horizon.tabs.TabbedTableView):
obj = obj['properties']
# Pretty print dict/list as YAML-like preformatted block
if isinstance(obj, (dict, list)):
if isinstance(obj, dict | list):
try:
import yaml # Lazy import
dumped = yaml.safe_dump(
@@ -145,8 +145,8 @@ class DetailView(horizon.tabs.TabbedTableView):
)
except Exception:
dumped = json.dumps(obj, indent=2, ensure_ascii=False)
return mark_safe( # nosec B703,B308
'<pre style="margin:0">{}</pre>'.format(dumped)
return mark_safe( # noqa: S308 # nosec B703,B308
f'<pre style="margin:0">{dumped}</pre>'
)
# Scalars

View File

@@ -24,9 +24,9 @@ from watcher_dashboard import api
from watcher_dashboard.test.test_data import utils
class WatcherTestsMixin(object):
class WatcherTestsMixin:
def _setup_test_data(self):
super(WatcherTestsMixin, self)._setup_test_data()
super()._setup_test_data()
utils.load_test_data(self)
@@ -36,7 +36,7 @@ class TestCase(WatcherTestsMixin, helpers.TestCase):
class APITestCase(WatcherTestsMixin, helpers.APITestCase):
def setUp(self):
super(APITestCase, self).setUp()
super().setUp()
self._original_watcherclient = api.watcher.watcherclient
@@ -44,7 +44,7 @@ class APITestCase(WatcherTestsMixin, helpers.APITestCase):
lambda request, *args, **kwargs: self.stub_watcherclient())
def tearDown(self):
super(APITestCase, self).tearDown()
super().tearDown()
api.watcher.watcherclient = self._original_watcherclient
def stub_watcherclient(self):

View File

@@ -46,7 +46,7 @@ class AuditsPage(basepage.BaseNavigationPage):
AUDIT_TABLE_TEMPLATE_COLUMN_INDEX = 1
def __init__(self, driver, conf):
super(AuditsPage, self).__init__(driver, conf)
super().__init__(driver, conf)
self._page_title = "Audits"
@property

View File

@@ -59,7 +59,7 @@ class AudittemplatesPage(basepage.BaseNavigationPage):
_audittemplates_info_title_locator = (by.By.CSS_SELECTOR, 'div.detail>h4')
def __init__(self, driver, conf):
super(AudittemplatesPage, self).__init__(driver, conf)
super().__init__(driver, conf)
self._page_title = "Audit Templates"
@property

View File

@@ -26,7 +26,7 @@ class AuditTemplateCreatePanelTests(helpers.AdminTestCase):
* Deletes this audit template (in tearDown)
* Checks that the audit template is removed
"""
audit_template_name = "audit_template_%s" % uuid.uuid1()
audit_template_name = f"audit_template_{uuid.uuid1()}"
audit_template_page = \
self.home_pg.go_to_optimization_audittemplatespage()
audit_template_page.create_audit_template(audit_template_name)
@@ -37,8 +37,8 @@ class AuditTemplateCreatePanelTests(helpers.AdminTestCase):
class AuditTemplatePanelTests(helpers.AdminTestCase):
def setUp(self):
super(AuditTemplatePanelTests, self).setUp()
self.audit_template_name = "audit_template_%s" % uuid.uuid1()
super().setUp()
self.audit_template_name = f"audit_template_{uuid.uuid1()}"
audit_template_page = \
self.home_pg.go_to_optimization_audittemplatespage()
audit_template_page.create_audit_template(self.audit_template_name)
@@ -50,7 +50,7 @@ class AuditTemplatePanelTests(helpers.AdminTestCase):
# Uncomment this line when <Delete> button will be implemented
self.assertFalse(audit_template_page.is_audit_template_present(
self.audit_template_name))
super(AuditTemplatePanelTests, self).tearDown()
super().tearDown()
def test_show_audit_template_info(self):
"""Test the audit template panel information page

View File

@@ -21,7 +21,7 @@ from selenium.common import exceptions as selenium_exceptions
class BrowserTests(test.SeleniumTestCase):
def test_jasmine(self):
url = "%s%s" % (self.live_server_url, "/jasmine/")
url = "{}{}".format(self.live_server_url, "/jasmine/")
self.selenium.get(url)
wait = self.ui.WebDriverWait(self.selenium, 10)
@@ -48,5 +48,9 @@ class BrowserTests(test.SeleniumTestCase):
continue
message = elem.find_element_by_class_name("test-message").text
source = elem.find_element_by_tag_name("pre").text
logger.error("Module: %s, message: %s, source: %s" % (
module, message, source))
logger.error(
"Module: %s, message: %s, source: %s",
module,
message,
source,
)

View File

@@ -25,7 +25,7 @@ class FormsetTableTests(test.TestCase):
def test_populate(self):
"""Create a FormsetDataTable and populate it with data."""
class TableObj(object):
class TableObj:
pass
obj = TableObj()
@@ -46,7 +46,7 @@ class FormsetTableTests(test.TestCase):
name = tables.Column('name')
value = tables.Column('value')
class Meta(object):
class Meta:
name = 'table'
table = Table(self.request)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain

View File

@@ -1,4 +1,3 @@
# -*- coding: utf8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain

View File

@@ -1,4 +1,3 @@
# -*- coding: utf8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain