Skip to content

refactor(client)!: apply ruff style checks, raise minimum Python to 3.9#83

Open
d3flex wants to merge 11 commits into
os-autoinst:mainfrom
d3flex:style/python_checks
Open

refactor(client)!: apply ruff style checks, raise minimum Python to 3.9#83
d3flex wants to merge 11 commits into
os-autoinst:mainfrom
d3flex:style/python_checks

Conversation

@d3flex

@d3flex d3flex commented May 15, 2026

Copy link
Copy Markdown
Contributor
  • Enforces a comprehensive ruff rule set across the codebase (FA, UP, PTH, FBT, TRY, PLR, TC, D, Q, N, A, and more)
  • Raises requires-python to >=3.9, removes typing_extensions fallback
  • Renames OpenQA_Client → OpenQAClient and exceptions.ConnectionError → OpenQAConnectionError; deprecated aliases in a single revertable commit
  • Replaces parse: bool on do_request with a transport/parse split, and boolean params on get_jobs/get_latest_build with enums (FilterDupes, FilterBuilds)

Aligning with other openQA projects' ruff configuration. The rule set exposed style debt, a naming conflict with
Python's builtin ConnectionError, and a latent JSONDecodeError on 204 responses. Tracked in
https://progress.opensuse.org/issues/198026.

@d3flex d3flex changed the title Style/python checks refactor(client)!: apply ruff style checks, raise minimum Python to 3.9 May 15, 2026
@d3flex d3flex force-pushed the style/python_checks branch 3 times, most recently from d63e45d to 8ed4e4d Compare May 15, 2026 13:43
@d3flex d3flex marked this pull request as ready for review May 15, 2026 13:47
@d3flex d3flex requested a review from AdamWill May 15, 2026 13:47
@AdamWill

Copy link
Copy Markdown
Contributor

Meh. Why?

We already have pylint and black enforced via CI. I'm not really a fan of expending the substantial amount of time and effort it would take to review this purely to switch to a different one. What is the benefit to anybody?

Sure, this is under the os-autoinst umbrella, but I wrote it initially as an external project and was never asked if I'm OK with it being subject to OpenQA Style Guides or whatever.

This would take me like a day to review and cause a lot of that annoying thing where you do git blame and run into a useless style commit like these ones, and I'm not sure I see the benefit. I also don't like the bump to Python 3.9 as a minimum without any clear improvement.

I'd be fine with a smaller PR that fixes concrete issues.

@okurz okurz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Meh. Why?

We already have pylint and black enforced via CI. I'm not really a fan of expending the substantial amount of time and effort it would take to review this purely to switch to a different one. What is the benefit to anybody?

ruff is getting adopted in multiple projects and provides benefits of much quicker and more extensive checks as well as allowing to automatically fix most style violations automatically.

This would take me like a day to review

You are surely exaggerating. I am sure you wouldn't need that long :)

and cause a lot of that annoying thing where you do git blame and run into a useless style commit like these ones, and I'm not sure I see the benefit.

The benefit is that you would see this one commit and after that there should be less or no style adjustement commits.

I also don't like the bump to Python 3.9 as a minimum without any clear improvement.

As older versions go EOL also tooling drops support for those older versions hence I assume this bump is necessary.

I'd be fine with a smaller PR that fixes concrete issues.

that of course is possible to keep the delta that needs to be reviewed low. However, I still approve the PR as a whole as it looks sound to me.


if not scheme:
if server in ("localhost", "127.0.0.1", "::1"):
if server in {"localhost", "127.0.0.1", "::1"}:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

that is, why change this from a tuple to a set?

@AdamWill

Copy link
Copy Markdown
Contributor

The benefit is that you would see this one commit and after that there should be less or no style adjustement commits.

But if we just keep the current black / pylint combination, I also wouldn't see any. Because we're already adjusted to black/pylint style and have been since day 1.

I'm already wasting more time than I'd like reviewing this, but for a start:

  • the commit message in 131156b does not match the content at all
  • I do not like 9318628 . As the commit message acknowledges, the aligned style is an intentional choice, not an error. It is clearly more readable that way. ruff not allowing this is a bug in ruff, not a bug in this project that should be "fixed" by making the file substantially less readable
  • 96c31a4 adds types to conftest.py without noting it or explaining why. It doesn't hurt anything but it also feels kinda unnecessary. I'm not sure I love this commit overall; the "modern" style doesn't seem appreciably better than the "boring old" style to me, why bother at least until a new Python release forces us into it something?
  • f092129 similar. Why is this better? Also os is only unused at this point in the commit series because the earlier Pathlib commit removed all uses of it but didn't drop the import; that should be fixed in that commit, not here
  • 17f3ab1 says "Bumping to 3.9 removes dead compatibility code and lets ruff and ty agree on a single baseline — the previous commits had to reconcile ruff (defaulting to py310) with ty (reading requires-python = ">=3.6"), requiring workarounds like pinning target-version = "py37"." - so if you want to do this anyway, why not do it before introducing ruff and ty and these "compatibility shims"? And yes, I "confirmed that breaking 3.6 compatibility is acceptable when there is a reason", but I meant a better reason than just "support the different style tools I want to use". This is a long commit message, but the practical changes it makes are small and not that exciting, implying that it is not really costing us much to maintain 3.6 compat. Basically, if you want to bump the baseline to 3.9, do it earlier in the patch series, and make a stronger argument for it
  • 974701e#r3249668129 fixes _parse_response to be a staticmethod as it does not use self, but it was introduced earlier in this patch series: why not just correct it there? (personally, I prefer to just take it out of the class entirely if it doesn't use self, but that's a subjective opinion I guess). Similarly, the change it makes to tests/conftest.py should just be moved to the commit that introduces that code in the first place
  • I don't like 32d4752 at all. The commit message describes perfectly well what the old code did - intentionally raise an exception in order to share the retry path - and I think that was fine. It works and it's efficient (the new code is substantially longer even though it drops my comment explaining the non-use of urllib3 Retry). The other change - to _parse_response - is entirely unrelated and also seems bogus. Whatever https://docs.astral.sh/ruff/rules/raise-vanilla-args/ says, I don't think there's anything wrong with raising TypeError with a short custom message. The ruff page says "This rule is not enforced for some built-in exceptions that are commonly raised with a message and would be unusual to subclass" - I think TypeError should be in that list
  • be3dba3 is yet another commit in the series that fixes stuff introduced by earlier commits in the series. Squash it
  • I also don't like a576782 . The objection is that "a call like get_jobs([1, 2], True) is opaque", but these are optional arguments, meaning it is standard practice to name them when calling, which in turn makes their meaning perfectly clear in the calling code (as you can see in the test cases). So this is just a lot of churn which produces zero practical benefit
  • The import order issue in 36ff33e is yet another thing introduced by an earlier commit in the series. Squash it. Other things in this might be the same; in general please check for all cases of this and fix them
  • 3dcbb1f is true, but the fact that it's a breaking change is unfortunate. Is it worth the effort?
  • 48ec428 I don't personally like ternaries in Python and don't often see them in other people's Python code, either. I'd be fine with dropping the else and just setting it to https first then changing to http with the if, though. The other change is completely unrelated; also it's yet another case of fixing something introduced by an earlier commit in the series (the original code does not use pathlib, so fix this in the commit that introduced pathlib)
  • 7b44a07 - please no. It's named what it's named. It's been named this for years and nobody died. At this point renaming it to make a style checker happy is dumb. Yes, I know the next commit adds a BC alias, I still don't like it
  • 8ed4e4d - the commit message says it's just changing the CI config, but it actually makes multiple unexplained code changes, mostly wrapping changes which look like they should be rolled into earlier commits in the series which made lines shorter but didn't re-wrap them

Sigh. I really wish I hadn't had to waste all that time on this. And now you get to waste more.

@AdamWill AdamWill left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

see review in previous comment. it made more sense to review this commit-by-commit.

d3flex added 10 commits May 25, 2026 07:31
The `method` parameter in `RequestError.__init__` was annotated as
`str`, but `ty` flags it as possibly `None` at call sites. Using
`Optional[str]` from `typing` corrects the annotation without any
behavior change.

This fix was surfaced by an initial `ruff`/`ty` run as part of
aligning style tooling with other openQA-related projects.

No logic or API behavior changes.

Issue: https://progress.opensuse.org/issues/198026

Signed-off-by: Ioannis Bonatakis <ybonatakis@suse.com>
The CI matrix tests only Python 3.11+. RHEL 8 (the last reason to
keep the 3.6 floor) has reached EOL, and the Fedora maintainer
confirmed that breaking 3.6 compatibility is acceptable. No downstream
consumer requires Python older than 3.9.

Bumping requires-python here, before the ruff/ty configuration, lets
those tools use py39 as the single baseline from the start without
needing target-version workarounds.

A follow-up commit removes the now-dead sys.version_info guard and
moves Callable/MutableMapping/Sequence to collections.abc.
Configure ruff as the project linter with a broad rule set (E, F, D,
PL, B, SIM, UP, FBT, TRY, FA, PTH, TC, and more), ty for type
checking, and flake8-copyright with "Red Hat" author to match this
project's copyright notices.

Sets line-length = 120, preview mode, per-file ignores for tests,
and docstring code formatting.

Issue: https://progress.opensuse.org/issues/198026
Fix all violations surfaced by an initial ruff run before any further
manual changes:
- D100: missing module docstring in setup.py
- D107: missing __init__ docstrings
- D205: missing blank line between summary and description
- D400/D415: first line of docstring must end with punctuation

No logic or API behavior changes.

Issue: https://progress.opensuse.org/issues/198026
Fix PTH (flake8-use-pathlib) violations surfaced by the initial ruff run.
Replace all os.path and os.makedirs calls with pathlib.Path equivalents
across setup.py, client.py, and conftest.py.

- setup.py: Path(__file__).resolve().parent replaces
  path.abspath(path.dirname(__file__)); / operator replaces path.join;
  Path.read_text() replaces open()+read().
- client.py: Path.home() replaces os.path.expanduser('~'); the paths
  tuple now holds Path objects so config.read() receives them directly.
- conftest.py: confpath.mkdir(parents=True) replaces os.makedirs;
  Path(__file__).resolve().parent replaces the os.path chain for
  locating the test data directory; import os removed.
- Test mocks updated from os.path.expanduser to pathlib.Path.home
  because Python 3.12 reimplemented Path.expanduser() without calling
  os.path.expanduser internally, which silently broke the old mock.

No logic or API behavior changes.

Issue: https://progress.opensuse.org/issues/198026
The `parse: bool = True` parameter in `do_request` conflated two
unrelated concerns. Callers had to know the flag existed and pass
`parse=False` just to get a `requests.Response` back — adding
complexity with no real benefit. For type checkers the situation was
worse: the return type changes between `Any` and `requests.Response`
depending on the runtime value of `parse`, which required a pair of
`@overload` stubs with `Literal[True]`/`Literal[False]` discrimination
to make it expressible at all.

There was also a latent bug: `do_request(parse=True)` (the default) would
call `resp.json()` on every successful response, including HTTP 204 No
Content. A direct caller hitting a 204 endpoint would get a
`JSONDecodeError` instead of the response. The 204 guard only existed
in `openqa_request`, which always called `do_request(parse=False)` —
making the `parse=True` default effectively dead and misleading.

The fix makes `do_request` a pure transport/retry layer that always
returns a raw `requests.Response`. A new `_parse_response` private
method handles JSON/YAML content negotiation. `openqa_request` calls
`do_request`, checks for 204 No Content (a server constraint, not a
caller choice), then delegates to `_parse_response`. The `@overload`
stubs and the `assert False` dead-code guard are removed.
…type errors

Internal callers (find_clones, get_jobs, get_latest_build) subscript
the result of openqa_request like a dict, but openqa_request returns
OpenQAResponse = Union[Dict[str, Any], requests.Response] because of
the 204 No Content path. ty flags requests.Response as
non-subscriptable, making these call sites type errors.

The fix introduces two helpers:

- _build_request holds the shared logic (settings conversion, path
  prefixing, do_request delegation) that was previously inlined in
  openqa_request. Both public and internal entry points call it.

- _openqa_request_json is an internal method that always calls
  _parse_response and returns Dict[str, Any]. It is for callers that
  know the endpoint will never return 204 and need a concrete dict type.

openqa_request keeps its existing OpenQAResponse return type and
handles the 204 case. Internal callers are switched to
_openqa_request_json. Tests updated to mock the new internal method.
Add the future import to client.py and exceptions.py to allow PEP 604
union syntax (X | Y) in annotations without a Python 3.10 minimum.
Modernise the Dict[str, str] annotation in the Job TypedDict.

conftest.py is left without type annotations; they are not needed for
test fixtures and the reviewer noted they are unnecessary.
FA100/FA102 are suppressed in the ruff config so the rule is not
enforced going forward.

Issue: https://progress.opensuse.org/issues/198026
Raise max-positional-args and max-args to 7 instead of restructuring
the request methods. Alternatives (TypedDict with Unpack, positional-
only / keyword-only split) would break downstream callers like
os-autoinst-scripts for no functional gain — the signatures are
stable public API with all-defaulted parameters.

Use HTTPStatus.NO_CONTENT instead of bare 204 so the meaning is
clear without knowing HTTP codes.

Set scheme = "https" unconditionally, then override to "http" for
localhost; avoids a ternary assignment that ruff SIM108 would flag,
and reads more clearly than an if/else with two branches. The extra
branch raises mccabe complexity of __init__ from 9 to 10, so bump
max-complexity accordingly.

Issue: https://progress.opensuse.org/issues/198026
The old name shadows the Python builtin ConnectionError. Renaming
avoids confusion and fixes ruff A001. This is a breaking change
for downstream code that imports ConnectionError from this package.

Issue: https://progress.opensuse.org/issues/198026
@d3flex d3flex force-pushed the style/python_checks branch from 8ed4e4d to 6a3af88 Compare May 25, 2026 05:38
@d3flex

d3flex commented May 25, 2026

Copy link
Copy Markdown
Contributor Author

The benefit is that you would see this one commit and after that there should be less or no style adjustement commits.

But if we just keep the current black / pylint combination, I also wouldn't see any. Because we're already adjusted to black/pylint style and have been since day 1.

I'm already wasting more time than I'd like reviewing this, but for a start:

  • the commit message in 131156b does not match the content at all
  • I do not like 9318628 . As the commit message acknowledges, the aligned style is an intentional choice, not an error. It is clearly more readable that way. ruff not allowing this is a bug in ruff, not a bug in this project that should be "fixed" by making the file substantially less readable
  • 96c31a4 adds types to conftest.py without noting it or explaining why. It doesn't hurt anything but it also feels kinda unnecessary. I'm not sure I love this commit overall; the "modern" style doesn't seem appreciably better than the "boring old" style to me, why bother at least until a new Python release forces us into it something?
  • f092129 similar. Why is this better? Also os is only unused at this point in the commit series because the earlier Pathlib commit removed all uses of it but didn't drop the import; that should be fixed in that commit, not here
  • 17f3ab1 says "Bumping to 3.9 removes dead compatibility code and lets ruff and ty agree on a single baseline — the previous commits had to reconcile ruff (defaulting to py310) with ty (reading requires-python = ">=3.6"), requiring workarounds like pinning target-version = "py37"." - so if you want to do this anyway, why not do it before introducing ruff and ty and these "compatibility shims"? And yes, I "confirmed that breaking 3.6 compatibility is acceptable when there is a reason", but I meant a better reason than just "support the different style tools I want to use". This is a long commit message, but the practical changes it makes are small and not that exciting, implying that it is not really costing us much to maintain 3.6 compat. Basically, if you want to bump the baseline to 3.9, do it earlier in the patch series, and make a stronger argument for it
  • 974701e#r3249668129 fixes _parse_response to be a staticmethod as it does not use self, but it was introduced earlier in this patch series: why not just correct it there? (personally, I prefer to just take it out of the class entirely if it doesn't use self, but that's a subjective opinion I guess). Similarly, the change it makes to tests/conftest.py should just be moved to the commit that introduces that code in the first place
  • I don't like 32d4752 at all. The commit message describes perfectly well what the old code did - intentionally raise an exception in order to share the retry path - and I think that was fine. It works and it's efficient (the new code is substantially longer even though it drops my comment explaining the non-use of urllib3 Retry). The other change - to _parse_response - is entirely unrelated and also seems bogus. Whatever https://docs.astral.sh/ruff/rules/raise-vanilla-args/ says, I don't think there's anything wrong with raising TypeError with a short custom message. The ruff page says "This rule is not enforced for some built-in exceptions that are commonly raised with a message and would be unusual to subclass" - I think TypeError should be in that list
  • be3dba3 is yet another commit in the series that fixes stuff introduced by earlier commits in the series. Squash it
  • I also don't like a576782 . The objection is that "a call like get_jobs([1, 2], True) is opaque", but these are optional arguments, meaning it is standard practice to name them when calling, which in turn makes their meaning perfectly clear in the calling code (as you can see in the test cases). So this is just a lot of churn which produces zero practical benefit
  • The import order issue in 36ff33e is yet another thing introduced by an earlier commit in the series. Squash it. Other things in this might be the same; in general please check for all cases of this and fix them
  • 3dcbb1f is true, but the fact that it's a breaking change is unfortunate. Is it worth the effort?
  • 48ec428 I don't personally like ternaries in Python and don't often see them in other people's Python code, either. I'd be fine with dropping the else and just setting it to https first then changing to http with the if, though. The other change is completely unrelated; also it's yet another case of fixing something introduced by an earlier commit in the series (the original code does not use pathlib, so fix this in the commit that introduced pathlib)
  • 7b44a07 - please no. It's named what it's named. It's been named this for years and nobody died. At this point renaming it to make a style checker happy is dumb. Yes, I know the next commit adds a BC alias, I still don't like it
  • 8ed4e4d - the commit message says it's just changing the CI config, but it actually makes multiple unexplained code changes, mostly wrapping changes which look like they should be rolled into earlier commits in the series which made lines shorter but didn't re-wrap them

Sigh. I really wish I hadn't had to waste all that time on this. And now you get to waste more.

Many suggestions make sense. As such I have reverted some changes, in order to come to an alignment with your arguments. I also tried to squash all it was asked and even more wherever I thought it is sensible. So it might be a bit different PR to review. I tested it and the changes look ok and you should not expect any serious disruptions. The main goal I think is the adaption of the tooling which brings significant benefits over black/pylint — ruff replaces both with a single, faster tool with more rules, already adopted across the os-autoinst ecosystem — and keeps sanity between all the projects.

Here a summary of the accepted changes on your requests:

  • const.py alignment: reverted, E221/E222/Q000 per-file-ignored
  • conftest.py annotations: reverted, FA100/FA102 ignored
  • TRY refactor: dropped entirely, TRY rules ignored
  • OpenQA_Client rename: reverted, suppressed with # noqa: N801
  • Boolean enum (FBT): reverted, FBT001/FBT002 ignored and you're right, named kwargs are clear enough
  • Python 3.9 bump: moved to commit pass retries and wait also for openqa_request #2 (before ruff config). CI tests 3.11+ only, RHEL 8 is EOL, no downstream consumer needs < 3.9
  • @staticmethod, FURB101, import order, ruff format wrapping: all squashed into originating commits, to prevent more fix-on-fix
  • SIM108 ternary: dropped; using your preferred scheme = "https" then override for localhost
  • Commit message mismatch: fixed
  • UP006/UP007: kept the existing modernizations but won't enforce the style going forward

I keep the openqa_client.exceptions.ConnectionError as from my point of view is not about whether it is worth the effort but to do the right thing in the long. it shadows the Python builtin, and I really do not think this is a good think overall. It is an easy adaption btw.

I hope this is in the direction that you want. otherwise what would be the minumum changes which you would see as acceptable

@AdamWill

Copy link
Copy Markdown
Contributor

Thanks for revising, will take another look as I have time.

Ruff already handles linting; its formatter covers the same role as
black, making black a redundant dependency.

Issue: https://progress.opensuse.org/issues/198026
Signed-off-by: Ioannis Bonatakis <ybonatakis@suse.com>
@d3flex d3flex force-pushed the style/python_checks branch from 6a3af88 to f6b30b9 Compare May 29, 2026 07:14
@AdamWill

AdamWill commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

The claim that "RHEL 8 has reached EOL" is not correct. It won't be officially EOL until 2029. Please adjust that commit message.

Comment thread pyproject.toml
where = ["src"]

[tool.ruff]
line-length = 120

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Our line length for black was 100, this is the line length I generally use. Why change it?

Comment thread pyproject.toml
# D: pydocstyle (for D100, D101, etc.)
# Q: flake8-quotes (for Q000)
# PL: Pylint
extend-select =[

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why a space before the = but not after?

Comment thread pyproject.toml
"PLR", # https://docs.astral.sh/ruff/rules/#refactor-plr
"PLW", # https://docs.astral.sh/ruff/rules/#warning-plw
"FA", # https://docs.astral.sh/ruff/rules/#flake8-future-annotations-fa
"UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't really love this massive laundry list...how is it to be maintained / reasoned about? Do we have to add new rules to it regularly? Does ruff not support some sort of profile concept or something?

Comment thread pyproject.toml
"DOC201", # docstring-missing-returns
"DOC501", # docstring-missing-exception
"COM812", # missing-trailing-comma
# Retry logic: intentional raise-inside-try pattern; TypeError("msg") is idiomatic

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can we not ignore the specific cases of these that we are OK with, instead of disabling the rules for the entire codebase? other linters/formatters support this, it seems weird ruff doesn't, if it doesn't.

Comment thread pyproject.toml
[tool.ruff.lint.mccabe]
max-complexity = 9

[tool.ruff.lint.per-file-ignores]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

so we can at least ignore per file...maybe we should move the TRY ignores commented on above down here so they're at least just per-file, not codebase-wide?

Comment thread pyproject.toml
docstring-code-format = true

[tool.ty.analysis]
allowed-unresolved-imports = ["netsnmp"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

huh? we don't import netsnmp anywhere. what's this for?

def __init__(
self, server: str = "", scheme: str = "", retries: int = 5, wait: int = 10
) -> None:
"""Initialize the client, reading config and setting up the session."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

requiring docstrings for __init__ seems weird. we all know what __init__ is for, this is just wasted text. I usually only add docstrings for __init__ functions if there's some actual reason to document something in the __init__ that isn't already covered in the class docstring.

Comment thread src/openqa_client/client.py Outdated
do whatever it likes with). You can use this directly instead
"""Prepare and submit a requests.Request, returning the parsed output.

Unless parse is False, in which case return the response for the caller to

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This reads weirdly. You've cut up a single sentence into two sentences to try and adhere to the 'summary and description' docstring layout (which is just a choice, btw, not a rule written down anywhere, but apparently ruff requires it?), but that breaks the meaning and makes this read weirdly; I would never start a paragraph with "Unless".

I'd suggest changing the summary line to "Prepare and submit a Request, returning the parsed output or response" or similar.

cloned as 4 and 4 was cloned as 5, you'll wind up with 5. If both
a job and its clone are already in the iterable, the original will
be removed.
"""Replace cloned jobs with their clones in an iterable of job dicts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This reads like it mutates the sequence it is passed, but it does not.

"""

def __init__(self, method: Optional[str], url: str, status_code: int, text: str) -> None:
"""Store the method, URL, status code, and response text of the failed request."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

again, pointless wastes of texts to satisfy a bizarre "rule".


"""Main client functionality."""

import configparser

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the changes to import order here aren't related to the main purpose of the commit they're in, nor are they mentioned in the commit message. they're correct, but I think they should either be in a separate commit or at least acknowledged as an 'along-the-way' change in the commit message.

Comment thread src/openqa_client/exceptions.py Outdated
from requests.exceptions import ConnectionError as RConnectionError
from typing import Optional

from requests.exceptions import ConnectionError as RConnectionError

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

again, import order fix unrelated to the commit it's in. this case is worse because it's in a file the commit does not otherwise touch.

Comment thread tests/test_client.py
import openqa_client.exceptions as oqe


class TestClient:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why are we removing the class wrapper here? I like to keep all tests in classes, and there's no justification for the change. It also makes it more or less impossible to see what, if anything, this PR really changes in the tests.

@AdamWill

AdamWill commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

I think "refactor(client): add _build_request and _openqa_request_json to fix type errors" should be squashed into "refactor: split do_request into transport and parse layers" because it's resolving issues that only exist because of the split.

Comment thread pyproject.toml
# Retry logic: intentional raise-inside-try pattern; TypeError("msg") is idiomatic
"TRY201", "TRY300", "TRY301", "TRY003",
# Don't enforce future-annotations import or pyupgrade annotation style
"FA100", "FA102",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"style: add from __future__ import annotations to source modules" notes that FA100 and FA102 are ignored in order to allow us to not bother with annotations in conftest.py , so maybe these should be per-file ignores?

"""
resp = self._build_request(method, path, params, retries, wait, data, json)
if resp.status_code == 204:
if resp.status_code == HTTPStatus.NO_CONTENT:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this should be merged into "refactor: split do_request into transport and parse layers", because that commit introduced this code.

@AdamWill

AdamWill commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

why is there an exclamation point in the commit message "fix(exceptions)!: rename ConnectionError to OpenQAConnectionError (A001)"?

"""
if not build and not jobs:
raise TypeError("iterate_jobs: either 'jobs' or 'build' must be specified")
raise openqa_client.exceptions.MissingArgumentError

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this change is not to do with OpenQAConnectionError and is not documented in the commit message. I think introducing MissingArgumentError and raising it here should be a separate commit from the OpenQAConnectionError rename.

@AdamWill

AdamWill commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

"style(client): fix PLR0913, PLR0917, PLR2004" adds four lines to the imports of conftest.py for no apparent reason; "fix(exceptions)!: rename ConnectionError to OpenQAConnectionError (A001)" removes them again. please remove this nonsense churn from both commits.

Comment thread pyproject.toml

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["PLR2004", "ANN401", "PLR0913", "S101", "S105", "S106", "PLR0917", "D103"]
"tests/*" = ["PLR2004", "ANN401", "ANN001", "ANN201", "ANN202", "PLR0913", "S101", "S105", "S106", "PLR0917", "D103"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

these additional ignores are not explained in the commit message. please explain them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants