Skip to content

Commit 00881dd

Browse files
[DPE-3881] Use ruff as a formatter and linter (#461)
* ruff as linter and formatter * Use the ruff formatter * Address PR feedback + fix lint warnings * Address PR feedback + fix failing tests * Select all I rules for ruff linting * Fix failing tests while keeping linter happy * Add inline comments for all ignore rules --------- Co-authored-by: Paulo Machado <[email protected]>
1 parent 7d807f6 commit 00881dd

File tree

12 files changed

+101
-348
lines changed

12 files changed

+101
-348
lines changed

poetry.lock

Lines changed: 27 additions & 269 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,14 @@ opentelemetry-exporter-otlp-proto-http = "1.21.0"
3636
optional = true
3737

3838
[tool.poetry.group.format.dependencies]
39-
black = "^24.0.0"
40-
isort = "^5.12.0"
39+
ruff = "^0.4.5"
4140

4241
[tool.poetry.group.lint]
4342
optional = true
4443

4544
[tool.poetry.group.lint.dependencies]
46-
black = "^24.0.0"
47-
isort = "^5.12.0"
48-
flake8 = "^7.0.0"
49-
flake8-docstrings = "^1.7.0"
50-
flake8-copyright = "^0.2.4"
51-
flake8-builtins = "^2.1.0"
52-
pyproject-flake8 = "^7.0.0"
53-
pep8-naming = "^0.13.3"
54-
codespell = "^2.2.5"
45+
ruff = "^0.4.5"
46+
codespell = "^2.3.0"
5547
shellcheck-py = "^0.9.0.5"
5648

5749
[tool.poetry.group.unit.dependencies]
@@ -92,30 +84,43 @@ log_cli_level = "INFO"
9284
markers = ["unstable", "juju3", "only_with_juju_secrets", "only_without_juju_secrets"]
9385
asyncio_mode = "auto"
9486

95-
# Formatting tools configuration
96-
[tool.black]
87+
# Linting tools configuration
88+
[tool.ruff]
89+
# preview and explicit preview are enabled for CPY001
90+
preview = true
91+
target-version = "py38"
92+
src = ["src", "."]
9793
line-length = 99
98-
target-version = ["py38"]
9994

100-
[tool.isort]
101-
profile = "black"
102-
known_third_party = "mysql.connector"
103-
line_length = 99
95+
[tool.ruff.lint]
96+
explicit-preview-rules = true
97+
select = ["A", "E", "W", "F", "C", "N", "D", "I", "CPY001"]
98+
ignore = [
99+
"D107", # Ignore D107 Missing docstring in __init__
100+
"D203", # Ignore D203 1 blank line required before class docstring
101+
"D204", # Ignore D204 1 blank line required after class docstring
102+
"D213", # Ignore D213 Multi-line docstring summary should start at the second line
103+
"D215", # Ignore D215 Section underline is over-indented
104+
"D400", # Ignore D400 First line should end with a period
105+
"D404", # Ignore D404 First word of the docstring should not be "This"
106+
"D406", # Ignore D406 Section name should end with a newline
107+
"D407", # Ignore D407 Missing dashed underline after section
108+
"D408", # Ignore D408 Section underline should be in the line following section's name
109+
"D409", # Ignore D409 Section underline should match the length of its name
110+
"D413", # Ignore D413 Missing blank line after last section
111+
"E501", # Ignore E501 Line too long
112+
]
104113

105-
# Linting tools configuration
106-
[tool.flake8]
107-
max-line-length = 99
108-
max-doc-length = 99
109-
max-complexity = 10
110-
exclude = [".git", "__pycache__", ".tox", "build", "dist", "*.egg_info", "venv"]
111-
select = ["E", "W", "F", "C", "N", "R", "D", "H"]
112-
# Ignore W503, E501 because using black creates errors with this
113-
# Ignore D107 Missing docstring in __init__
114-
ignore = ["W503", "E501", "D107"]
115-
# D100, D101, D102, D103: Ignore missing docstrings in tests
116-
per-file-ignores = ["tests/*:D100,D101,D102,D103,D104"]
117-
docstring-convention = "google"
114+
[tool.ruff.lint.per-file-ignores]
115+
"tests/*" = ["D1"]
116+
117+
[tool.ruff.lint.flake8-copyright]
118118
# Check for properly formatted copyright header in each file
119-
copyright-check = "True"
120-
copyright-author = "Canonical Ltd."
121-
copyright-regexp = "Copyright\\s\\d{4}([-,]\\d{4})*\\s+%(author)s"
119+
author = "Canonical Ltd."
120+
notice-rgx = "Copyright\\s\\d{4}([-,]\\d{4})*\\s+"
121+
122+
[tool.ruff.lint.mccabe]
123+
max-complexity = 10
124+
125+
[tool.ruff.lint.pydocstyle]
126+
convention = "google"

src/charm.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -201,17 +201,11 @@ def _mysql(self) -> MySQL:
201201
self.app_peer_data["cluster-set-domain-name"],
202202
self.get_secret("app", ROOT_PASSWORD_KEY), # pyright: ignore [reportArgumentType]
203203
SERVER_CONFIG_USERNAME,
204-
self.get_secret(
205-
"app", SERVER_CONFIG_PASSWORD_KEY
206-
), # pyright: ignore [reportArgumentType]
204+
self.get_secret("app", SERVER_CONFIG_PASSWORD_KEY), # pyright: ignore [reportArgumentType]
207205
CLUSTER_ADMIN_USERNAME,
208-
self.get_secret(
209-
"app", CLUSTER_ADMIN_PASSWORD_KEY
210-
), # pyright: ignore [reportArgumentType]
206+
self.get_secret("app", CLUSTER_ADMIN_PASSWORD_KEY), # pyright: ignore [reportArgumentType]
211207
MONITORING_USERNAME,
212-
self.get_secret(
213-
"app", MONITORING_PASSWORD_KEY
214-
), # pyright: ignore [reportArgumentType]
208+
self.get_secret("app", MONITORING_PASSWORD_KEY), # pyright: ignore [reportArgumentType]
215209
BACKUPS_USERNAME,
216210
self.get_secret("app", BACKUPS_PASSWORD_KEY), # pyright: ignore [reportArgumentType]
217211
self.unit.get_container(CONTAINER_NAME),

src/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# See LICENSE file for licensing details.
44

55
"""Structured configuration for the MySQL charm."""
6+
67
import configparser
78
import logging
89
import re

src/mysql_k8s_helpers.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,6 @@ class MySQLDeleteTempBackupDirectoryError(Error):
112112
"""Exception raised when there is an error deleting the temp backup directory."""
113113

114114

115-
class MySQLDeleteTempRestoreDirectory(Error):
116-
"""Exception raised when there is an error deleting the temp restore directory."""
117-
118-
119115
class MySQL(MySQLBase):
120116
"""Class to encapsulate all operations related to the MySQL instance and cluster.
121117
@@ -190,9 +186,12 @@ def fix_data_dir(self, container: Container) -> None:
190186
if paths[0].user != MYSQL_SYSTEM_USER or paths[0].group != MYSQL_SYSTEM_GROUP:
191187
logger.debug(f"Changing ownership to {MYSQL_SYSTEM_USER}:{MYSQL_SYSTEM_GROUP}")
192188
try:
193-
container.exec(
194-
["chown", "-R", f"{MYSQL_SYSTEM_USER}:{MYSQL_SYSTEM_GROUP}", MYSQL_DATA_DIR]
195-
)
189+
container.exec([
190+
"chown",
191+
"-R",
192+
f"{MYSQL_SYSTEM_USER}:{MYSQL_SYSTEM_GROUP}",
193+
MYSQL_DATA_DIR,
194+
])
196195
except ExecError as e:
197196
logger.error(f"Exited with code {e.exit_code}. Stderr:\n{e.stderr}")
198197
raise MySQLInitialiseMySQLDError(e.stderr or "")
@@ -586,6 +585,7 @@ def _run_mysqlsh_script(
586585
Args:
587586
script: mysql-shell python script string
588587
verbose: mysqlsh verbosity level
588+
timeout: timeout to wait for the script
589589
590590
Returns:
591591
stdout of the script

src/upgrade.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,12 @@ def log_rollback_instructions(self) -> None:
156156
run_action = "run-action"
157157
wait = " --wait"
158158
logger.critical(
159-
"\n".join(
160-
(
161-
"Upgrade failed, follow the instructions below to rollback:",
162-
f" 1 - Run `juju {run_action} {self.charm.app.name}/leader pre-upgrade-check{wait}` to configure rollback",
163-
f" 2 - Run `juju refresh --revision <previous-revision> {self.charm.app.name}` to initiate the rollback",
164-
f" 3 - Run `juju {run_action} {self.charm.app.name}/leader resume-upgrade{wait}` to resume the rollback",
165-
)
166-
)
159+
"\n".join((
160+
"Upgrade failed, follow the instructions below to rollback:",
161+
f" 1 - Run `juju {run_action} {self.charm.app.name}/leader pre-upgrade-check{wait}` to configure rollback",
162+
f" 2 - Run `juju refresh --revision <previous-revision> {self.charm.app.name}` to initiate the rollback",
163+
f" 3 - Run `juju {run_action} {self.charm.app.name}/leader resume-upgrade{wait}` to resume the rollback",
164+
))
167165
)
168166

169167
def _pre_upgrade_prepare(self) -> None:

tests/integration/helpers.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ async def fetch_credentials(unit: Unit, username: str = None) -> Dict:
216216
217217
Args:
218218
unit: The juju unit on which to run the get-password action for credentials
219+
username: The username for which to fetch credentials
219220
220221
Returns:
221222
A dictionary with the server config username and password
@@ -231,6 +232,8 @@ async def rotate_credentials(unit: Unit, username: str = None, password: str = N
231232
232233
Args:
233234
unit: The juju unit on which to run the set-password action for credentials
235+
username: The username for which to rotate credentials
236+
password: The password with which to rotate credentials
234237
235238
Returns:
236239
A dictionary with the action result
@@ -625,7 +628,7 @@ async def ls_la_in_unit(
625628
Args:
626629
ops_test: The ops test framework
627630
unit_name: The name of unit in which to run ls -la
628-
path: The path from which to run ls -la
631+
directory: The directory from which to run ls -la
629632
container_name: The container where to run ls -la
630633
631634
Returns:
@@ -719,7 +722,7 @@ async def dispatch_custom_event_for_logrotate(ops_test: OpsTest, unit_name: str)
719722
dispatch_command = juju_exec.strip() or juju_run.strip()
720723
unit_label = unit_name.replace("/", "-")
721724

722-
return_code, stdout, stderr = await ops_test.juju(
725+
return_code, _, _ = await ops_test.juju(
723726
"ssh",
724727
unit_name,
725728
dispatch_command,

tests/integration/high_availability/high_availability_helpers.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,10 @@ def deploy_chaos_mesh(namespace: str) -> None:
248248
logger.info("Deploying Chaos Mesh")
249249

250250
subprocess.check_output(
251-
" ".join(
252-
[
253-
"tests/integration/high_availability/scripts/deploy_chaos_mesh.sh",
254-
namespace,
255-
]
256-
),
251+
" ".join([
252+
"tests/integration/high_availability/scripts/deploy_chaos_mesh.sh",
253+
namespace,
254+
]),
257255
shell=True,
258256
env=env,
259257
)

tests/integration/high_availability/test_async_replication.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ def first_model(ops_test: OpsTest) -> Optional[Model]:
4949

5050

5151
@pytest.fixture(scope="module")
52-
async def second_model(
53-
ops_test: OpsTest, first_model, request
54-
) -> Model: # pyright: ignore [reportInvalidTypeForm]
52+
async def second_model(ops_test: OpsTest, first_model, request) -> Model: # pyright: ignore [reportInvalidTypeForm]
5553
"""Create and return the second model."""
5654
second_model_name = f"{first_model.info.name}-other"
5755
await ops_test._controller.add_model(second_model_name)
@@ -426,7 +424,7 @@ async def get_max_written_value(first_model: Model, second_model: Model) -> list
426424
await juju_.run_action(application_unit, "stop-continuous-writes")
427425

428426
sleep(5)
429-
results = list()
427+
results = []
430428

431429
logger.info("Querying max value on all units")
432430
for unit in first_model_units + second_model_units:

tests/integration/high_availability/test_self_healing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ async def test_network_cut_affecting_an_instance(
382382
@pytest.mark.unstable
383383
async def test_graceful_full_cluster_crash_test(ops_test: OpsTest, continuous_writes) -> None:
384384
"""Test to send SIGTERM to all units and then ensure that the cluster recovers."""
385-
mysql_application_name, application_name = await high_availability_test_setup(ops_test)
385+
mysql_application_name, _ = await high_availability_test_setup(ops_test)
386386

387387
logger.info("Ensure there are 3 online mysql members")
388388
assert await ensure_n_online_mysql_members(

0 commit comments

Comments
 (0)