Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flake8-bugbear: opt-in to a couple of opinionated warnings #6312

Merged
merged 3 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cylc/flow/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2463,21 +2463,21 @@ def get_taskdef(
'Duplicate task message in'
f' "[runtime][{name}][outputs]'
f'{output} = {message}" - messages must be unique'
)
) from None
valid, msg = TaskOutputValidator.validate(output)
if not valid:
raise WorkflowConfigError(
f'Invalid task output "'
f'[runtime][{name}][outputs]'
f'{output} = {message}" - {msg}'
) from None
)
valid, msg = TaskMessageValidator.validate(message)
if not valid:
raise WorkflowConfigError(
f'Invalid task message "'
f'[runtime][{name}][outputs]'
f'{output} = {message}" - {msg}'
) from None
)
self.taskdefs[name].add_output(output, message)

return self.taskdefs[name]
Expand Down
4 changes: 2 additions & 2 deletions cylc/flow/dbstatecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,15 @@
try:
self.db_point_fmt = self._get_db_point_format()
self.c7_back_compat_mode = False
except sqlite3.OperationalError:
except sqlite3.OperationalError as exc:
# BACK COMPAT: Cylc 7 DB (see method below).
try:
self.db_point_fmt = self._get_db_point_format_compat()
self.c7_back_compat_mode = True
except sqlite3.OperationalError:
with suppress(Exception):
self.conn.close()
raise
raise exc from None # original error

Check warning on line 89 in cylc/flow/dbstatecheck.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/dbstatecheck.py#L89

Added line #L89 was not covered by tests

def __enter__(self):
return self
Expand Down
4 changes: 2 additions & 2 deletions cylc/flow/main_loop/health_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ def _check_contact_file(scheduler):
scheduler.workflow)
if contact_data != scheduler.contact_data:
raise CylcError('contact file modified')
except (AssertionError, IOError, ValueError, ServiceFileError):
except (AssertionError, IOError, ValueError, ServiceFileError) as exc:
raise CylcError(
'%s: contact file corrupted/modified and may be left'
% workflow_files.get_contact_file_path(scheduler.workflow)
) from None
) from exc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, the context may be useful here.

25 changes: 14 additions & 11 deletions cylc/flow/network/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,14 @@
srv_prv_key_info.full_key_path)
except ValueError:
raise ServiceFileError(
f"Failed to find server's public "
f"key in "
"Failed to find server's public key in "
f"{srv_prv_key_info.full_key_path}."
) from None
except OSError:
except OSError as exc:

Check warning on line 182 in cylc/flow/network/__init__.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/network/__init__.py#L182

Added line #L182 was not covered by tests
raise ServiceFileError(
f"IO error opening server's private "
f"key from "
"IO error opening server's private key from "
f"{srv_prv_key_info.full_key_path}."
) from None
) from exc
if server_private_key is None: # this can't be caught by exception
raise ServiceFileError(
f"Failed to find server's private "
Expand Down Expand Up @@ -238,15 +236,20 @@
try:
client_public_key, client_priv_key = zmq.auth.load_certificate(
client_priv_key_info.full_key_path)
except (OSError, ValueError):
except ValueError:
raise ClientError(error_msg) from None
except OSError as exc:
raise ClientError(error_msg) from exc
if client_priv_key is None: # this can't be caught by exception
raise ClientError(error_msg)
self.socket.curve_publickey = client_public_key
self.socket.curve_secretkey = client_priv_key

# A client can only connect to the server if it knows its public key,
# so we grab this from the location it was created on the filesystem:
error_msg = (
"Failed to load the workflow's public key, so cannot connect."
)
try:
# 'load_certificate' will try to load both public & private keys
# from a provided file but will return None, not throw an error,
Expand All @@ -256,10 +259,10 @@
server_public_key = zmq.auth.load_certificate(
srv_pub_key_info.full_key_path)[0]
self.socket.curve_serverkey = server_public_key
except (OSError, ValueError): # ValueError raised w/ no public key
raise ClientError(
"Failed to load the workflow's public key, so cannot connect."
) from None
except ValueError: # ValueError raised w/ no public key
raise ClientError(error_msg) from None
except OSError as exc:
raise ClientError(error_msg) from exc

Check warning on line 265 in cylc/flow/network/__init__.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/network/__init__.py#L263-L265

Added lines #L263 - L265 were not covered by tests

self.socket.connect(f'tcp://{host}:{port}')

Expand Down
4 changes: 2 additions & 2 deletions cylc/flow/param_expand.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def _expand_name(self, results, tmpl, params, spec_vals=None):
results.append((tmpl % current_values, current_values))
except KeyError as exc:
raise ParamExpandError(
'parameter %s is not ' 'defined.' % str(exc.args[0])
'parameter %s is not defined.' % str(exc.args[0])
) from None
else:
for param_val in params[0][1]:
Expand Down Expand Up @@ -427,7 +427,7 @@ def _expand_graph(self, line, all_params,
repl = tmpl % param_values
except KeyError as exc:
raise ParamExpandError(
'parameter %s is not ' 'defined.' % str(exc.args[0])
'parameter %s is not defined.' % str(exc.args[0])
) from None
line = line.replace('<' + p_group + '>', repl)
if line:
Expand Down
4 changes: 2 additions & 2 deletions cylc/flow/scripts/cylc.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,14 +605,14 @@ def pycoverage(cmd_args): # pragma: no cover
data_file=str(cylc_wc / '.coverage'),
source=[str(cylc_wc / 'cylc')]
)
except coverage.misc.CoverageException:
except coverage.misc.CoverageException as exc:
raise Exception(
# make sure this exception is visible in the traceback
'\n\n*****************************\n\n'
'Could not initiate coverage, likely because Cylc was not '
'installed in editable mode.'
'\n\n*****************************\n\n'
) from None
) from exc

# start the coverage running
cov.start()
Expand Down
50 changes: 29 additions & 21 deletions cylc/flow/scripts/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,53 +51,62 @@
"""
import functools
import pkgutil
from pathlib import Path
import re
import sys
import shutil
import sys
from collections import Counter
from pathlib import Path
from typing import (
TYPE_CHECKING,
Any,
Callable,
Counter as CounterType,
Dict,
Iterator,
List,
Optional,
Union,
)

try:
# BACK COMPAT: tomli
# Support for Python versions before tomllib was added to the
# standard library.
# FROM: Python 3.7
# TO: Python: 3.10
from tomli import (
loads as toml_loads,
TOMLDecodeError,
)
from tomli import TOMLDecodeError, loads as toml_loads
except ImportError:
from tomllib import ( # type: ignore[no-redef]
loads as toml_loads,
TOMLDecodeError,
)
from typing import (
TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Optional, Union
)

from ansimarkup import parse as cparse

from cylc.flow import LOG
from cylc.flow.exceptions import CylcError
import cylc.flow.flags
from cylc.flow import job_runner_handlers
from cylc.flow import LOG, job_runner_handlers
from cylc.flow.cfgspec.workflow import SPEC, upg
from cylc.flow.exceptions import CylcError
from cylc.flow.id_cli import parse_id
from cylc.flow.job_runner_mgr import JobRunnerManager
from cylc.flow.loggingutil import set_timestamps
from cylc.flow.option_parsers import (
WORKFLOW_ID_OR_PATH_ARG_DOC,
CylcOptionParser as COP,
WORKFLOW_ID_OR_PATH_ARG_DOC
)
from cylc.flow.cfgspec.workflow import upg, SPEC
from cylc.flow.id_cli import parse_id
from cylc.flow.parsec.config import ParsecConfig
from cylc.flow.scripts.cylc import DEAD_ENDS
from cylc.flow.terminal import cli_function


if TYPE_CHECKING:
from optparse import Values

# BACK COMPAT: typing_extensions.Literal
# FROM: Python 3.7
# TO: Python 3.8
from typing_extensions import Literal
from optparse import Values


LINT_TABLE = ['tool', 'cylc', 'lint']
LINT_SECTION = '.'.join(LINT_TABLE)
Expand Down Expand Up @@ -1114,7 +1123,7 @@ def check_cylc_file(
file: Path,
file_rel: Path,
checks: Dict[str, dict],
counter: Dict[str, int],
counter: CounterType[str],
modify: bool = False,
):
"""Check A Cylc File for Cylc 7 Config"""
Expand Down Expand Up @@ -1172,7 +1181,7 @@ def lint(
file_rel: Path,
lines: Iterator[str],
checks: Dict[str, dict],
counter: Dict[str, int],
counter: CounterType[str],
modify: bool = False,
write: Callable = print
) -> Iterator[str]:
Expand All @@ -1186,7 +1195,7 @@ def lint(
Iterator which produces one line of text at a time
e.g. open(file) or iter(['foo\n', 'bar\n', 'baz\n'].
counter:
Dictionary for counting lint hits per category.
Counter for counting lint hits per category.
modify:
If True, this generator will yield the file one line at a time
with comments inserted to help users fix their lint.
Expand Down Expand Up @@ -1238,7 +1247,6 @@ def lint(
msg = check_meta['short'].format(**check)
else:
msg = check_meta['short']
counter.setdefault(check_meta['purpose'], 0)
counter[check_meta['purpose']] += 1
if modify:
# insert a command to help the user
Expand Down Expand Up @@ -1473,7 +1481,7 @@ def main(parser: COP, options: 'Values', target=None) -> None:
)

# Check each file matching a pattern:
counter: Dict[str, int] = {}
counter: CounterType[str] = Counter()
for file in get_cylc_files(target, mergedopts[EXCLUDE]):
LOG.debug(f'Checking {file}')
check_cylc_file(
Expand Down
6 changes: 3 additions & 3 deletions cylc/flow/scripts/report_timings.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@
the database query to obtain the timing information may take some time.
"""

import collections
import contextlib
import io as StringIO
import sys
from collections import Counter
from typing import TYPE_CHECKING


from cylc.flow import LOG
from cylc.flow.exceptions import CylcError
from cylc.flow.id_cli import parse_id
Expand All @@ -66,6 +65,7 @@
from cylc.flow.rundb import CylcWorkflowDAO
from cylc.flow.terminal import cli_function


if TYPE_CHECKING:
from optparse import Values

Expand Down Expand Up @@ -278,7 +278,7 @@ def _reshape_timings(timings):
# there are duplicate entries in the index (see #2509). The
# best way around this seems to be to add an intermediate index
# level (in this case a retry counter) to de-duplicate indices.
counts = collections.defaultdict(int)
counts = Counter()
retry = []
for t in timings.index:
counts[t] += 1
Expand Down
4 changes: 2 additions & 2 deletions cylc/flow/workflow_db_mgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,10 +700,10 @@ def _get_last_run_version(cls, pri_dao: CylcWorkflowDAO) -> Version:
''', # nosec (table name is a code constant)
[cls.KEY_CYLC_VERSION]
).fetchone()[0]
except (TypeError, OperationalError):
except (TypeError, OperationalError) as exc:
raise ServiceFileError(
f"{INCOMPAT_MSG}, or is corrupted."
) from None
) from exc
return parse_version(last_run_ver)

@classmethod
Expand Down
4 changes: 2 additions & 2 deletions cylc/flow/workflow_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,8 @@ def load_contact_file(id_: str, run_dir=None) -> Dict[str, str]:
try:
with open(path) as f:
file_content = f.read()
except IOError:
raise ServiceFileError("Couldn't load contact file") from None
except IOError as exc:
raise ServiceFileError("Couldn't load contact file") from exc
data: Dict[str, str] = {}
for line in file_content.splitlines():
key, value = [item.strip() for item in line.split("=", 1)]
Expand Down
2 changes: 1 addition & 1 deletion cylc/flow/xtrigger_mgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@
bound_args = sig.bind(*fctx.func_args, **fctx.func_kwargs)
except TypeError:
# failed signature check for backcompat function
raise
raise err from None # original signature check error

Check warning on line 393 in cylc/flow/xtrigger_mgr.py

View check run for this annotation

Codecov / codecov/patch

cylc/flow/xtrigger_mgr.py#L393

Added line #L393 was not covered by tests

old_sig_str = fctx.get_signature()
upg_sig_str = "workflow_state({})".format(
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/scripts/test_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Tests `cylc lint` CLI Utility."""

from collections import Counter
import logging
from pathlib import Path
from pprint import pformat
Expand Down Expand Up @@ -190,7 +191,7 @@

def lint_text(text, checks, ignores=None, modify=False):
checks = parse_checks(checks, ignores)
counter = {}
counter = Counter()
messages = []
outlines = [
line
Expand Down
6 changes: 6 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
[flake8]
extend-select=
; Use `raise from` inside `except` for error handling
; https://docs.python.org/3/tutorial/errors.html#exception-chaining
B904
; Use Counter() instead of defaultdict(int) to avoid excessive memory use:
B910
ignore=
; module level import not at top of file
E402,
Expand Down
Loading