Added additional Ruff rule sets and fixed all violations.
CI / Formatting (push) Successful in 11s
CI / Linting (push) Successful in 13s
CI / Tests (Python 3.12) (push) Successful in 25s
CI / Tests (Python 3.13) (push) Successful in 25s
CI / Tests (Python 3.14) (push) Successful in 24s
CI / Type Checking (push) Successful in 25s
CI / Formatting (push) Successful in 11s
CI / Linting (push) Successful in 13s
CI / Tests (Python 3.12) (push) Successful in 25s
CI / Tests (Python 3.13) (push) Successful in 25s
CI / Tests (Python 3.14) (push) Successful in 24s
CI / Type Checking (push) Successful in 25s
This commit is contained in:
@@ -324,7 +324,7 @@ class Config:
|
||||
logger.debug(f"Loading configuration from: {self.config_path.absolute()}")
|
||||
if self.config_path.exists():
|
||||
try:
|
||||
with open(self.config_path) as f:
|
||||
with self.config_path.open() as f:
|
||||
self._data = yaml.safe_load(f) or {}
|
||||
except yaml.YAMLError as e:
|
||||
logger.error(f"Failed to parse config file: {e}")
|
||||
@@ -385,7 +385,7 @@ class Config:
|
||||
"""Write current configuration to the YAML file."""
|
||||
logger.debug(f"Saving configuration to: {self.config_path.absolute()}")
|
||||
try:
|
||||
with open(self.config_path, "w") as f:
|
||||
with self.config_path.open("w") as f:
|
||||
yaml.safe_dump(
|
||||
self._ordered_data(), f, default_flow_style=False, sort_keys=False
|
||||
)
|
||||
|
||||
@@ -273,7 +273,9 @@ def _parse_placeholder_date(date_str: str) -> datetime | None:
|
||||
return None
|
||||
|
||||
try:
|
||||
dt = datetime.strptime(date_part, "%b %d %Y %I:%M:%S %p")
|
||||
# Intentionally naive: tz abbreviation is resolved separately via
|
||||
# TIMEZONE_OFFSETS since strptime's %z only handles numeric offsets.
|
||||
dt = datetime.strptime(date_part, "%b %d %Y %I:%M:%S %p") # noqa: DTZ007
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
@@ -369,7 +371,6 @@ async def _evaluate_count(
|
||||
(counter_name, delta, delta),
|
||||
)
|
||||
return str(result)
|
||||
else:
|
||||
try:
|
||||
value = int(modifier_str)
|
||||
except ValueError as e:
|
||||
@@ -377,8 +378,7 @@ async def _evaluate_count(
|
||||
"Invalid $(count): modifier must be an integer (e.g., +5, -1, 0)"
|
||||
) from e
|
||||
result = await ctx.storage.fetch_value(
|
||||
"INSERT OR REPLACE INTO counters (name, value) VALUES (?, ?) "
|
||||
"RETURNING value",
|
||||
"INSERT OR REPLACE INTO counters (name, value) VALUES (?, ?) RETURNING value",
|
||||
(counter_name, value),
|
||||
)
|
||||
return str(result)
|
||||
@@ -429,7 +429,7 @@ async def _evaluate_rand(
|
||||
raise PlaceholderError(
|
||||
"Invalid $(rand): arguments must be integers, e.g., $(rand 1 100)"
|
||||
) from e
|
||||
return str(random.randint(min(start, stop), max(start, stop)))
|
||||
return str(random.randint(min(start, stop), max(start, stop))) # noqa: S311
|
||||
|
||||
|
||||
async def _evaluate_countdown(
|
||||
@@ -455,7 +455,6 @@ async def _evaluate_countdown(
|
||||
seconds = int(delta.total_seconds())
|
||||
if seconds > 0:
|
||||
return _format_duration(seconds)
|
||||
else:
|
||||
return "0 seconds"
|
||||
|
||||
|
||||
|
||||
@@ -186,7 +186,6 @@ def _parse_placeholder(
|
||||
)
|
||||
if found_close:
|
||||
return PlaceholderNode(name, child_nodes), new_pos
|
||||
else:
|
||||
# Unclosed placeholder, degrade to literal. Return None so
|
||||
# the caller emits "$(" as literal and re-scans the rest.
|
||||
return None
|
||||
|
||||
@@ -401,11 +401,11 @@ class RouteDispatcher:
|
||||
|
||||
if result is None:
|
||||
return web.Response(status=204) # No Content.
|
||||
elif isinstance(result, web.StreamResponse):
|
||||
if isinstance(result, web.StreamResponse):
|
||||
return result
|
||||
elif isinstance(result, dict):
|
||||
if isinstance(result, dict):
|
||||
return web.json_response(result)
|
||||
else: # pragma: no branch — defensive against untyped handlers
|
||||
# pragma: no branch — defensive against untyped handlers
|
||||
mod_logger.error( # type: ignore[unreachable]
|
||||
f"Route handler '{route_info.full_path}' returned "
|
||||
f"unsupported type: {type(result).__name__}"
|
||||
|
||||
+41
-6
@@ -68,16 +68,49 @@ extend-exclude = ["owlbot/_version.py"] # auto-generated by hatch-vcs
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
# Core
|
||||
"F", # Pyflakes
|
||||
"E", # pycodestyle errors
|
||||
"W", # pycodestyle warnings
|
||||
"I", # isort
|
||||
"UP", # pyupgrade
|
||||
"B", # flake8-bugbear
|
||||
"SIM", # flake8-simplify
|
||||
"TCH", # flake8-type-checking
|
||||
"RUF", # Ruff-specific rules
|
||||
"N", # pep8-naming
|
||||
"D", # pydocstyle
|
||||
"I", # isort
|
||||
"ICN", # flake8-import-conventions
|
||||
|
||||
# Correctness & bugs
|
||||
"B", # flake8-bugbear
|
||||
"ASYNC", # flake8-async
|
||||
"DTZ", # flake8-datetimez
|
||||
"RSE", # flake8-raise
|
||||
"RET", # flake8-return
|
||||
"A", # flake8-builtins
|
||||
"PIE", # flake8-pie
|
||||
|
||||
# Modernization & simplification
|
||||
"UP", # pyupgrade
|
||||
"SIM", # flake8-simplify
|
||||
"C4", # flake8-comprehensions
|
||||
"FLY", # flynt (f-string conversion)
|
||||
"PTH", # flake8-use-pathlib
|
||||
|
||||
# Performance
|
||||
"PERF", # Perflint
|
||||
|
||||
# Security
|
||||
"S", # flake8-bandit
|
||||
|
||||
# Code hygiene
|
||||
"T10", # flake8-debugger
|
||||
"T20", # flake8-print
|
||||
"ERA", # eradicate
|
||||
"PGH", # pygrep-hooks
|
||||
"TCH", # flake8-type-checking
|
||||
|
||||
# Testing
|
||||
"PT", # flake8-pytest-style
|
||||
|
||||
# Ruff-specific
|
||||
"RUF", # Ruff-specific rules
|
||||
]
|
||||
ignore = [
|
||||
"D203", # incompatible with D211 (no blank line before class docstring)
|
||||
@@ -86,6 +119,8 @@ ignore = [
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"owlbot/__init__.py" = ["E402"] # constants defined before imports intentionally
|
||||
"owlbot/__main__.py" = ["T201"] # CLI entry point uses print() for user output
|
||||
"tests/**" = ["S101", "S311"] # assert is standard for pytest; random is fine in tests
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ["owlbot"]
|
||||
|
||||
+16
-19
@@ -117,7 +117,7 @@ class TestOnCommandDecorator:
|
||||
"""Tests the @on_command decorator from owlbot.api.commands."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"name,aliases,auth,mod,cooldown",
|
||||
("name", "aliases", "auth", "mod", "cooldown"),
|
||||
[
|
||||
pytest.param("ping", None, False, False, 0, id="defaults"),
|
||||
pytest.param("cmd", ["c", "cm"], False, False, 0, id="with-aliases"),
|
||||
@@ -284,12 +284,11 @@ class TestCommandRegistry:
|
||||
pass
|
||||
|
||||
registry.register("ping", handler, module_name="mod_a")
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match=r"Command trigger 'ping' conflicts with existing command 'ping'",
|
||||
):
|
||||
registry.register("ping", handler, module_name="mod_b")
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== "Command trigger 'ping' conflicts with existing command 'ping'"
|
||||
)
|
||||
|
||||
def test_register_conflict_alias_with_name(self) -> None:
|
||||
"""Alias that conflicts with an existing command name raises ValueError."""
|
||||
@@ -299,12 +298,11 @@ class TestCommandRegistry:
|
||||
pass
|
||||
|
||||
registry.register("ping", handler, module_name="mod_a")
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match=r"Command trigger 'ping' conflicts with existing command 'ping'",
|
||||
):
|
||||
registry.register("other", handler, aliases=["ping"], module_name="mod_b")
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== "Command trigger 'ping' conflicts with existing command 'ping'"
|
||||
)
|
||||
|
||||
def test_register_conflict_alias_with_alias(self) -> None:
|
||||
"""Alias that conflicts with an existing alias raises ValueError."""
|
||||
@@ -314,12 +312,11 @@ class TestCommandRegistry:
|
||||
pass
|
||||
|
||||
registry.register("cmd1", handler, aliases=["c"], module_name="mod_a")
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match=r"Command trigger 'c' conflicts with existing command 'cmd1'",
|
||||
):
|
||||
registry.register("cmd2", handler, aliases=["c"], module_name="mod_b")
|
||||
assert (
|
||||
str(exc_info.value)
|
||||
== "Command trigger 'c' conflicts with existing command 'cmd1'"
|
||||
)
|
||||
|
||||
def test_exists_true(self) -> None:
|
||||
"""Registered command returns True."""
|
||||
@@ -447,7 +444,7 @@ class TestCommandRegistry:
|
||||
assert registry.unregister_by_module("no_such") == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"message,prefix,expected",
|
||||
("message", "prefix", "expected"),
|
||||
[
|
||||
pytest.param("!ping", "!", ("ping", ""), id="simple-command"),
|
||||
pytest.param(
|
||||
@@ -921,7 +918,7 @@ class TestModuleCommands:
|
||||
assert mod_cmds["mod_a"].module_commands == {}
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"owner,other_setup,call_module,trigger,expected",
|
||||
("owner", "other_setup", "call_module", "trigger", "expected"),
|
||||
[
|
||||
pytest.param("mod_a", None, "mod_a", "ping", True, id="own-command"),
|
||||
pytest.param(
|
||||
@@ -1020,7 +1017,7 @@ class TestCommandContext:
|
||||
return cmd_ctx, module_ctx, cmd_event, event_ctx
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"prop,use_is",
|
||||
("prop", "use_is"),
|
||||
[
|
||||
pytest.param("module_name", False, id="module-name"),
|
||||
pytest.param("storage", True, id="storage"),
|
||||
|
||||
@@ -137,7 +137,7 @@ class TestParseTimestamp:
|
||||
"""Exercises _parse_timestamp() with various input formats."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"ts,expected",
|
||||
("ts", "expected"),
|
||||
[
|
||||
pytest.param(None, None, id="none-input"),
|
||||
pytest.param("", None, id="empty-string"),
|
||||
@@ -221,7 +221,7 @@ class TestUser:
|
||||
assert user.scopes == []
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"scopes,expected",
|
||||
("scopes", "expected"),
|
||||
[
|
||||
pytest.param(["MODERATOR"], True, id="has-moderator"),
|
||||
pytest.param(["OTHER"], False, id="other-scope"),
|
||||
@@ -255,7 +255,7 @@ class TestChatEvent:
|
||||
assert event.timestamp == datetime(2026, 1, 15, 12, 0, tzinfo=UTC)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"raw,expected",
|
||||
("raw", "expected"),
|
||||
[
|
||||
pytest.param("<p>hello</p>", "hello", id="strips-p-tags"),
|
||||
pytest.param("hello", "hello", id="no-tags"),
|
||||
@@ -518,7 +518,7 @@ class TestParseEvent:
|
||||
"""Exercises the top-level parse_event() dispatcher."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"type_str,expected_type,expected_class",
|
||||
("type_str", "expected_type", "expected_class"),
|
||||
[
|
||||
pytest.param("CHAT", EventType.CHAT, ChatEvent, id="chat"),
|
||||
pytest.param(
|
||||
@@ -592,7 +592,7 @@ class TestLogEvent:
|
||||
"""Exercises log_event() output via caplog."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"event_type,event,expected_message",
|
||||
("event_type", "event", "expected_message"),
|
||||
[
|
||||
pytest.param(
|
||||
EventType.CHAT,
|
||||
|
||||
@@ -110,7 +110,7 @@ class TestOnEventDecorator:
|
||||
"""Tests the @on_event decorator from owlbot.api.events."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"event_types,priority,expected_types,expected_priority",
|
||||
("event_types", "priority", "expected_types", "expected_priority"),
|
||||
[
|
||||
pytest.param(
|
||||
(EventType.CHAT,),
|
||||
@@ -173,7 +173,7 @@ class TestPriority:
|
||||
"""Tests the Priority IntEnum from owlbot.api.events."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"member,value",
|
||||
("member", "value"),
|
||||
[
|
||||
pytest.param(Priority.HIGHEST, 100, id="highest"),
|
||||
pytest.param(Priority.HIGH, 75, id="high"),
|
||||
@@ -294,7 +294,7 @@ class TestEventRegistry:
|
||||
assert registry.get_handler_module(handler) is None
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"setup_types,expected_return,expected_remaining",
|
||||
("setup_types", "expected_return", "expected_remaining"),
|
||||
[
|
||||
pytest.param(
|
||||
(EventType.CHAT,),
|
||||
@@ -795,7 +795,7 @@ class TestCommandDispatchPhase:
|
||||
"""Tests Phase 2 (command dispatch) in EventDispatcher.dispatch()."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"event_type,event_factory,expected_calls",
|
||||
("event_type", "event_factory", "expected_calls"),
|
||||
[
|
||||
pytest.param(
|
||||
EventType.CHAT,
|
||||
@@ -945,7 +945,7 @@ class TestModuleEvents:
|
||||
assert mod_events.module_events == {}
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"register_on,unregister_from,expected",
|
||||
("register_on", "unregister_from", "expected"),
|
||||
[
|
||||
pytest.param("mod_a", "mod_a", True, id="own-handler"),
|
||||
pytest.param("mod_b", "mod_a", False, id="other-modules-handler"),
|
||||
@@ -1028,7 +1028,7 @@ class TestEventContext:
|
||||
"""Tests EventContext from owlbot.api.context."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"prop,use_is",
|
||||
("prop", "use_is"),
|
||||
[
|
||||
pytest.param("module_name", False, id="module-name"),
|
||||
pytest.param("storage", True, id="storage"),
|
||||
|
||||
+17
-17
@@ -70,7 +70,7 @@ class TestSimpleSubstitution:
|
||||
"""Basic happy-path usage of placeholders and plain text."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,kwargs,expected",
|
||||
("template", "kwargs", "expected"),
|
||||
[
|
||||
pytest.param(
|
||||
"Just a plain message.", {}, "Just a plain message.", id="plain-text"
|
||||
@@ -154,7 +154,7 @@ class TestArgPlaceholders:
|
||||
"""Positional arguments $(1) through $(9)."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,args,expected",
|
||||
("template", "args", "expected"),
|
||||
[
|
||||
pytest.param(
|
||||
"$(1)$(2)$(3)$(4)$(5)$(6)$(7)$(8)$(9)",
|
||||
@@ -186,7 +186,7 @@ class TestArgPlaceholders:
|
||||
assert await process(template, placeholder_storage, args=args) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,args,expected",
|
||||
("template", "args", "expected"),
|
||||
[
|
||||
pytest.param("$(0)", ["first"], "$(0)", id="index-zero"),
|
||||
pytest.param("$(10)", ["a"] * 10, "$(10)", id="index-ten"),
|
||||
@@ -205,7 +205,7 @@ class TestArgPlaceholders:
|
||||
assert result == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,args,expected",
|
||||
("template", "args", "expected"),
|
||||
[
|
||||
pytest.param(
|
||||
"$(1 extra)",
|
||||
@@ -269,7 +269,7 @@ class TestNamedCounters:
|
||||
assert row["value"] == 5
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"counter_values,template,expected,db_name,db_value",
|
||||
("counter_values", "template", "expected", "db_name", "db_value"),
|
||||
[
|
||||
pytest.param(
|
||||
{"deaths": 10},
|
||||
@@ -310,7 +310,7 @@ class TestNamedCounters:
|
||||
assert row["value"] == db_value
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"counter_values,template,expected",
|
||||
("counter_values", "template", "expected"),
|
||||
[
|
||||
pytest.param({}, "$(count deaths +5)", "5", id="plus-five"),
|
||||
pytest.param(
|
||||
@@ -425,7 +425,7 @@ class TestCounterNameValidation:
|
||||
"""Counter names are lowercased and must match ^[a-z0-9_]+$."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,expected,db_name,db_value",
|
||||
("template", "expected", "db_name", "db_value"),
|
||||
[
|
||||
pytest.param("$(count Deaths)", "1", "deaths", 1, id="uppercase-name"),
|
||||
pytest.param("$(count 123)", "1", "123", 1, id="numeric-name"),
|
||||
@@ -509,7 +509,7 @@ class TestRand:
|
||||
assert result == f"Alice rolled a {expected_roll}!"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,expected",
|
||||
("template", "expected"),
|
||||
[
|
||||
pytest.param("$(rand 5 5)", "5", id="equal-bounds"),
|
||||
pytest.param("$(rand 0 0)", "0", id="zero-bounds"),
|
||||
@@ -606,7 +606,7 @@ class TestCountdownCountup:
|
||||
assert await process(template, placeholder_storage) == "0 seconds"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"placeholder,bad_date",
|
||||
("placeholder", "bad_date"),
|
||||
[
|
||||
pytest.param("countdown", "not a real date", id="gibberish"),
|
||||
pytest.param("countdown", "monday", id="weekday-only"),
|
||||
@@ -640,7 +640,7 @@ class TestCountdownCountup:
|
||||
assert result == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"seconds,expected",
|
||||
("seconds", "expected"),
|
||||
[
|
||||
pytest.param(0, "0 seconds", id="zero"),
|
||||
pytest.param(1, "1 second", id="one-second"),
|
||||
@@ -775,7 +775,7 @@ class TestNesting:
|
||||
assert result == "$(test)"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,args",
|
||||
("template", "args"),
|
||||
[
|
||||
pytest.param("$(rand $(1) $(2))", [], id="no-args"),
|
||||
pytest.param("$(rand $(1) $(2))", ["5"], id="one-arg"),
|
||||
@@ -805,7 +805,7 @@ class TestEscaping:
|
||||
"""Escape sequences and backslash boundary conditions."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,kwargs,expected",
|
||||
("template", "kwargs", "expected"),
|
||||
[
|
||||
pytest.param(
|
||||
r"Use \$(user) to insert your name.",
|
||||
@@ -856,7 +856,7 @@ class TestCaseInsensitivity:
|
||||
"""Placeholder names are lowercased before handler lookup."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,kwargs,expected",
|
||||
("template", "kwargs", "expected"),
|
||||
[
|
||||
pytest.param("$(USER)", {}, "Alice", id="all-upper-user"),
|
||||
pytest.param("$(User)", {}, "Alice", id="title-case-user"),
|
||||
@@ -986,7 +986,7 @@ class TestParserBoundaries:
|
||||
"""Parser edge cases around incomplete or unusual $( sequences."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,expected",
|
||||
("template", "expected"),
|
||||
[
|
||||
pytest.param("$(rand 1", "$(rand 1", id="unclosed-rand"),
|
||||
pytest.param(
|
||||
@@ -1017,7 +1017,7 @@ class TestUnknownPlaceholders:
|
||||
"""Unknown placeholder names pass through unchanged."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,expected",
|
||||
("template", "expected"),
|
||||
[
|
||||
pytest.param("$(madeup stuff)", "$(madeup stuff)", id="with-args"),
|
||||
pytest.param("$(banana)", "$(banana)", id="bare-name"),
|
||||
@@ -1043,7 +1043,7 @@ class TestEvaluationSafety:
|
||||
"""Verify that resolved text is never re-parsed as placeholders."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,kwargs,expected",
|
||||
("template", "kwargs", "expected"),
|
||||
[
|
||||
pytest.param(
|
||||
"$(1)", {"args": ["$(user)"]}, "$(user)", id="arg-contains-user"
|
||||
@@ -1093,7 +1093,7 @@ class TestRuntimeErrors:
|
||||
"""A PlaceholderError cancels the entire render and returns the message."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"template,expected_error",
|
||||
("template", "expected_error"),
|
||||
[
|
||||
pytest.param(
|
||||
"$(rand 1)",
|
||||
|
||||
@@ -119,7 +119,7 @@ class TestFetchOne:
|
||||
"""fetch_one() returns a Row or None."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"accessor, expected",
|
||||
("accessor", "expected"),
|
||||
[
|
||||
pytest.param(lambda row: row["name"], "a", id="key-access"),
|
||||
pytest.param(lambda row: row[1], "a", id="index-access"),
|
||||
@@ -288,7 +288,7 @@ class TestTransaction:
|
||||
self, storage_with_table: ModuleStorage
|
||||
) -> None:
|
||||
"""Writes inside transaction() are discarded if an exception is raised."""
|
||||
with pytest.raises(RuntimeError, match="boom"):
|
||||
with pytest.raises(RuntimeError, match="boom"): # noqa: PT012
|
||||
async with storage_with_table._checkout(), storage_with_table.transaction():
|
||||
await storage_with_table.execute(
|
||||
"INSERT INTO items (name, value) VALUES (?, ?)",
|
||||
@@ -335,7 +335,7 @@ class TestStorageError:
|
||||
"""Invalid SQL raises StorageError wrapping the underlying error."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"method, args",
|
||||
("method", "args"),
|
||||
[
|
||||
pytest.param(
|
||||
"execute",
|
||||
@@ -372,7 +372,7 @@ class TestStorageError:
|
||||
await getattr(storage, method)(*args)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"method, args",
|
||||
("method", "args"),
|
||||
[
|
||||
pytest.param("execute", ("SELECT 1",), id="execute"),
|
||||
pytest.param("fetch_one", ("SELECT 1",), id="fetch-one"),
|
||||
|
||||
Reference in New Issue
Block a user