Skip to content

Commit ea6f6cf

Browse files
committed
chore: align pre-commit with tox/lint
1 parent e573f8f commit ea6f6cf

18 files changed

+94
-104
lines changed

.pre-commit-config.yaml

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v4.5.0
3+
rev: v5.0.0
44
hooks:
55
- id: check-added-large-files
66
- id: check-ast
@@ -15,18 +15,19 @@ repos:
1515
- id: mixed-line-ending
1616
- id: end-of-file-fixer
1717
- id: trailing-whitespace
18+
exclude: "test_pebble[.]py$"
1819
- id: detect-private-key
1920
# Run the Ruff linter.
2021
- repo: https://github.com/astral-sh/ruff-pre-commit
21-
rev: v0.4.5
22+
rev: v0.8.0
2223
hooks:
2324
- id: ruff
2425
args: [ --preview ]
2526
- id: ruff-format
2627
args: [ --preview ]
2728
# Spellcheck the code.
2829
- repo: https://github.com/codespell-project/codespell
29-
rev: v2.2.4
30+
rev: v2.3.0
3031
hooks:
3132
- id: codespell
3233
additional_dependencies:

HACKING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ The main improvements in this release are ...
466466
Read more in the [full release notes on GitHub](link to the GitHub release).
467467
```
468468

469-
In the post, outline the key improvements both in `ops` and `ops-scenario` -
469+
In the post, outline the key improvements both in `ops` and `ops-scenario` -
470470
the point here is to encourage people to check out the full notes and to upgrade
471471
promptly, so ensure that you entice them with the best that the new versions
472472
have to offer.

ops/_private/harness.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ class ExecResult:
159159
stderr: Union[str, bytes] = b''
160160

161161

162-
ExecHandler = Callable[[ExecArgs], Union[None, ExecResult]]
162+
ExecHandler = Callable[[ExecArgs], Union[ExecResult, None]]
163163

164164

165165
@dataclasses.dataclass(frozen=True)
@@ -1789,8 +1789,7 @@ def revoke_secret(self, secret_id: str, observer: AppUnitOrName):
17891789
# Model secrets:
17901790
if secret.owner_name in [self.model.app.name, self.model.unit.name]:
17911791
raise RuntimeError(
1792-
f'Secret {secret_id!r} owned by the charm under test, "'
1793-
f"can't call revoke_secret"
1792+
f'Secret {secret_id!r} owned by the charm under test, "can\'t call revoke_secret'
17941793
)
17951794

17961795
relation_id = self._secret_relation_id_to(secret)
@@ -2113,7 +2112,7 @@ def run_action(
21132112
f'given {{"{key}":{params[key]!r}}}'
21142113
)
21152114
action_under_test = _RunningAction(action_name, ActionOutput([], {}), params)
2116-
handler = getattr(self.charm.on, f"{action_name.replace('-', '_')}_action")
2115+
handler = getattr(self.charm.on, f'{action_name.replace("-", "_")}_action')
21172116
self._backend._running_action = action_under_test
21182117
self._action_id_counter += 1
21192118
handler.emit(str(self._action_id_counter))

ops/charm.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1682,9 +1682,9 @@ class RelationMeta:
16821682
VALID_SCOPES: ClassVar[List[str]] = ['global', 'container']
16831683

16841684
def __init__(self, role: RelationRole, relation_name: str, raw: '_RelationMetaDict'):
1685-
assert isinstance(
1686-
role, RelationRole
1687-
), f'role should be one of {list(RelationRole)!r}, not {role!r}'
1685+
assert isinstance(role, RelationRole), (
1686+
f'role should be one of {list(RelationRole)!r}, not {role!r}'
1687+
)
16881688
self._default_scope = self.VALID_SCOPES[0]
16891689
self.role = role
16901690
self.relation_name = relation_name

ops/framework.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ class SomeObject:
805805
method_name = observer.__name__
806806

807807
assert isinstance(observer.__self__, Object), (
808-
"can't register observers " "that aren't `Object`s"
808+
"can't register observers that aren't `Object`s"
809809
)
810810
observer_obj = observer.__self__
811811

ops/model.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ def __repr__(self):
13131313
fields.append(f'id={self._id!r}')
13141314
if self._label is not None:
13151315
fields.append(f'label={self._label!r}')
1316-
return f"<Secret {' '.join(fields)}>"
1316+
return f'<Secret {" ".join(fields)}>'
13171317

13181318
@staticmethod
13191319
def _canonicalize_id(id: str, model_uuid: Optional[str]) -> str:
@@ -2218,7 +2218,7 @@ def request(self, storage_name: str, count: int = 1):
22182218
"""
22192219
if storage_name not in self._storage_map:
22202220
raise ModelError(
2221-
f'cannot add storage {storage_name!r}:' ' it is not present in the charm metadata'
2221+
f'cannot add storage {storage_name!r}: it is not present in the charm metadata'
22222222
)
22232223
self._backend.storage_add(storage_name, count)
22242224

@@ -3879,12 +3879,12 @@ def validate_metric_label(cls, label_name: str):
38793879
def format_metric_value(cls, value: Union[int, float]):
38803880
if not isinstance(value, (int, float)):
38813881
raise ModelError(
3882-
f'invalid metric value {value!r} provided:' ' must be a positive finite float'
3882+
f'invalid metric value {value!r} provided: must be a positive finite float'
38833883
)
38843884

38853885
if math.isnan(value) or math.isinf(value) or value < 0:
38863886
raise ModelError(
3887-
f'invalid metric value {value!r} provided:' ' must be a positive finite float'
3887+
f'invalid metric value {value!r} provided: must be a positive finite float'
38883888
)
38893889
return str(value)
38903890

@@ -3895,7 +3895,7 @@ def validate_label_value(cls, label: str, value: str):
38953895
if not value:
38963896
raise ModelError(f'metric label {label} has an empty value, which is not allowed')
38973897
v = str(value)
3898-
if re.search('[,=]', v) is not None:
3898+
if re.search(r'[,=]', v) is not None:
38993899
raise ModelError(f'metric label values must not contain "," or "=": {label}={value!r}')
39003900

39013901

ops/pebble.py

+3-13
Original file line numberDiff line numberDiff line change
@@ -661,12 +661,7 @@ def from_dict(cls, d: _ProgressDict) -> TaskProgress:
661661
)
662662

663663
def __repr__(self):
664-
return (
665-
'TaskProgress('
666-
f'label={self.label!r}, '
667-
f'done={self.done!r}, '
668-
f'total={self.total!r})'
669-
)
664+
return f'TaskProgress(label={self.label!r}, done={self.done!r}, total={self.total!r})'
670665

671666

672667
class TaskID(str):
@@ -1083,12 +1078,7 @@ def from_dict(cls, d: _ServiceInfoDict) -> ServiceInfo:
10831078
)
10841079

10851080
def __repr__(self):
1086-
return (
1087-
'ServiceInfo('
1088-
f'name={self.name!r}, '
1089-
f'startup={self.startup}, '
1090-
f'current={self.current})'
1091-
)
1081+
return f'ServiceInfo(name={self.name!r}, startup={self.startup}, current={self.current})'
10921082

10931083

10941084
class Check:
@@ -2547,7 +2537,7 @@ def _encode_multipart(
25472537
source_io: _AnyStrFileLikeIO = source # type: ignore
25482538
boundary = binascii.hexlify(os.urandom(16))
25492539
path_escaped = path.replace('"', '\\"').encode('utf-8')
2550-
content_type = f"multipart/form-data; boundary=\"{boundary.decode('utf-8')}\""
2540+
content_type = f'multipart/form-data; boundary="{boundary.decode("utf-8")}"'
25512541

25522542
def generator() -> Generator[bytes, None, None]:
25532543
yield b''.join([

pyproject.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,10 @@ keep-runtime-typing = true
177177
"S106",
178178

179179
# "Useless" expression.
180-
"B018"
180+
"B018",
181+
182+
# Ruff prefers regular expressions as raw strings.
183+
"RUF039",
181184
]
182185
"ops/_private/timeconv.py" = [
183186
"RUF001", # String contains ambiguous `µ` (MICRO SIGN). Did you mean `μ` (GREEK SMALL LETTER MU)?

test/charms/test_main/src/charm.py

+30-30
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ def _on_db_relation_joined(self, event: ops.RelationJoinedEvent):
153153
self._stored.db_relation_joined_data = event.snapshot()
154154

155155
def _on_mon_relation_changed(self, event: ops.RelationChangedEvent):
156-
assert (
157-
event.app is not None
158-
), 'application name cannot be None for a relation-changed event'
156+
assert event.app is not None, (
157+
'application name cannot be None for a relation-changed event'
158+
)
159159
if os.environ.get('JUJU_REMOTE_UNIT'):
160160
assert event.unit is not None, (
161161
'a unit name cannot be None for a relation-changed event'
@@ -168,22 +168,22 @@ def _on_mon_relation_changed(self, event: ops.RelationChangedEvent):
168168
self._stored.mon_relation_changed_data = event.snapshot()
169169

170170
def _on_mon_relation_departed(self, event: ops.RelationDepartedEvent):
171-
assert (
172-
event.app is not None
173-
), 'application name cannot be None for a relation-departed event'
171+
assert event.app is not None, (
172+
'application name cannot be None for a relation-departed event'
173+
)
174174
assert event.relation.active, 'a departed relation is still active'
175175
assert self.model.relations['mon']
176176
self._stored.on_mon_relation_departed.append(type(event).__name__)
177177
self._stored.observed_event_types.append(type(event).__name__)
178178
self._stored.mon_relation_departed_data = event.snapshot()
179179

180180
def _on_ha_relation_broken(self, event: ops.RelationBrokenEvent):
181-
assert (
182-
event.app is None
183-
), 'relation-broken events cannot have a reference to a remote application'
184-
assert (
185-
event.unit is None
186-
), 'relation broken events cannot have a reference to a remote unit'
181+
assert event.app is None, (
182+
'relation-broken events cannot have a reference to a remote application'
183+
)
184+
assert event.unit is None, (
185+
'relation broken events cannot have a reference to a remote unit'
186+
)
187187
assert not event.relation.active, 'relation broken events always have a broken relation'
188188
assert not self.model.relations['ha']
189189
self._stored.on_ha_relation_broken.append(type(event).__name__)
@@ -218,56 +218,56 @@ def _on_test_pebble_check_recovered(self, event: ops.PebbleCheckRecoveredEvent):
218218
self._stored.test_pebble_check_recovered_data = event.snapshot()
219219

220220
def _on_start_action(self, event: ops.ActionEvent):
221-
assert (
222-
event.handle.kind == 'start_action'
223-
), 'event action name cannot be different from the one being handled'
221+
assert event.handle.kind == 'start_action', (
222+
'event action name cannot be different from the one being handled'
223+
)
224224
self._stored.on_start_action.append(type(event).__name__)
225225
self._stored.observed_event_types.append(type(event).__name__)
226226

227227
def _on_secret_changed(self, event: ops.SecretChangedEvent):
228228
# subprocess and isinstance don't mix well
229-
assert (
230-
type(event.secret).__name__ == 'Secret'
231-
), f'SecretEvent.secret must be a Secret instance, not {type(event.secret)}'
229+
assert type(event.secret).__name__ == 'Secret', (
230+
f'SecretEvent.secret must be a Secret instance, not {type(event.secret)}'
231+
)
232232
assert event.secret.id, 'secret must have an ID'
233233
self._stored.on_secret_changed.append(type(event).__name__)
234234
self._stored.observed_event_types.append(type(event).__name__)
235235
self._stored.secret_changed_data = event.snapshot()
236236

237237
def _on_secret_remove(self, event: ops.SecretRemoveEvent):
238238
# subprocess and isinstance don't mix well
239-
assert (
240-
type(event.secret).__name__ == 'Secret'
241-
), f'SecretEvent.secret must be a Secret instance, not {type(event.secret)}'
239+
assert type(event.secret).__name__ == 'Secret', (
240+
f'SecretEvent.secret must be a Secret instance, not {type(event.secret)}'
241+
)
242242
assert event.secret.id, 'secret must have an ID'
243243
self._stored.on_secret_remove.append(type(event).__name__)
244244
self._stored.observed_event_types.append(type(event).__name__)
245245
self._stored.secret_remove_data = event.snapshot()
246246

247247
def _on_secret_rotate(self, event: ops.SecretRotateEvent):
248248
# subprocess and isinstance don't mix well
249-
assert (
250-
type(event.secret).__name__ == 'Secret'
251-
), f'SecretEvent.secret must be a Secret instance, not {type(event.secret)}'
249+
assert type(event.secret).__name__ == 'Secret', (
250+
f'SecretEvent.secret must be a Secret instance, not {type(event.secret)}'
251+
)
252252
assert event.secret.id, 'secret must have an ID'
253253
self._stored.on_secret_rotate.append(type(event).__name__)
254254
self._stored.observed_event_types.append(type(event).__name__)
255255
self._stored.secret_rotate_data = event.snapshot()
256256

257257
def _on_secret_expired(self, event: ops.SecretExpiredEvent):
258258
# subprocess and isinstance don't mix well
259-
assert (
260-
type(event.secret).__name__ == 'Secret'
261-
), f'SecretEvent.secret must be a Secret instance, not {type(event.secret)}'
259+
assert type(event.secret).__name__ == 'Secret', (
260+
f'SecretEvent.secret must be a Secret instance, not {type(event.secret)}'
261+
)
262262
assert event.secret.id, 'secret must have an ID'
263263
self._stored.on_secret_expired.append(type(event).__name__)
264264
self._stored.observed_event_types.append(type(event).__name__)
265265
self._stored.secret_expired_data = event.snapshot()
266266

267267
def _on_foo_bar_action(self, event: ops.ActionEvent):
268-
assert (
269-
event.handle.kind == 'foo_bar_action'
270-
), 'event action name cannot be different from the one being handled'
268+
assert event.handle.kind == 'foo_bar_action', (
269+
'event action name cannot be different from the one being handled'
270+
)
271271
self._stored.on_foo_bar_action.append(type(event).__name__)
272272
self._stored.observed_event_types.append(type(event).__name__)
273273

test/test_framework.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1810,7 +1810,7 @@ def test_breakpoint_good_names(self, request: pytest.FixtureRequest, name: str):
18101810
'-',
18111811
'...foo',
18121812
'foo.bar',
1813-
'bar--' 'FOO',
1813+
'bar--FOO',
18141814
'FooBar',
18151815
'foo bar',
18161816
'foo_bar',

test/test_main.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@ def test_setup_event_links(
10461046
):
10471047
"""Test auto-creation of symlinks caused by initial events."""
10481048
all_event_hooks = [
1049-
f"hooks/{name.replace('_', '-')}"
1049+
f'hooks/{name.replace("_", "-")}'
10501050
for name, event_source in self.charm_module.Charm.on.events().items()
10511051
if issubclass(event_source.event_type, (ops.CommitEvent, ops.PreCommitEvent))
10521052
]
@@ -1138,7 +1138,7 @@ def test_setup_event_links(
11381138
Symlink creation caused by initial events should _not_ happen when using dispatch.
11391139
"""
11401140
all_event_hooks = [
1141-
f"hooks/{e.replace('_', '-')}" for e in self.charm_module.Charm.on.events()
1141+
f'hooks/{e.replace("_", "-")}' for e in self.charm_module.Charm.on.events()
11421142
]
11431143
initial_events = {
11441144
EventSpec(ops.InstallEvent, 'install'),
@@ -1150,9 +1150,9 @@ def test_setup_event_links(
11501150
def _assess_event_links(event_spec: EventSpec):
11511151
assert self.hooks_dir / event_spec.event_name not in self.hooks_dir.iterdir()
11521152
for event_hook in all_event_hooks:
1153-
assert not (
1154-
self.JUJU_CHARM_DIR / event_hook
1155-
).exists(), f'Spurious hook: {event_hook}'
1153+
assert not (self.JUJU_CHARM_DIR / event_hook).exists(), (
1154+
f'Spurious hook: {event_hook}'
1155+
)
11561156

11571157
for initial_event in initial_events:
11581158
self._setup_charm_dir(request)

test/test_model.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1397,9 +1397,9 @@ def test_recursive_push_and_pull(case: PushPullCase):
13971397
raise
13981398
errors = {src[len(push_src.name) :] for src, _ in err.errors}
13991399

1400-
assert (
1401-
case.errors == errors
1402-
), f'push_path gave wrong expected errors: want {case.errors}, got {errors}'
1400+
assert case.errors == errors, (
1401+
f'push_path gave wrong expected errors: want {case.errors}, got {errors}'
1402+
)
14031403
for fpath in case.want:
14041404
assert c.exists(fpath), f'push_path failed: file {fpath} missing at destination'
14051405
content = c.pull(fpath, encoding=None).read()
@@ -1424,9 +1424,9 @@ def test_recursive_push_and_pull(case: PushPullCase):
14241424
raise
14251425
errors = {src for src, _ in err.errors}
14261426

1427-
assert (
1428-
case.errors == errors
1429-
), f'pull_path gave wrong expected errors: want {case.errors}, got {errors}'
1427+
assert case.errors == errors, (
1428+
f'pull_path gave wrong expected errors: want {case.errors}, got {errors}'
1429+
)
14301430
for fpath in case.want:
14311431
assert c.exists(fpath), f'pull_path failed: file {fpath} missing at destination'
14321432
for fdir in case.want_dirs:

0 commit comments

Comments
 (0)