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

Replace flake8, isort, pylint and black by ruff #2149

Merged
merged 26 commits into from
Oct 28, 2024

Conversation

yury-fedotov
Copy link
Contributor

@yury-fedotov yury-fedotov commented Oct 23, 2024

Description

Closes #1670

Development notes

This PR brings ruff to kedro-viz to replace:

  • flake8
  • isort
  • pylint
  • black

It introduces a central ruff.toml file in repo root, to act as a single source of truth for Python codestyle management, and leverages ruff's hierarchical configuration feature to make this config applicable to both the demo-project and package parts of the codebase.

Note

Another enhancement is that linter/formatter configuration, such as:

  • Directories in scope
  • Active and ignored rulesets

Is now defined in a single file, once, as opposed to being duplicated in Makefile, pre-commit config etc., which should streamline further code quality management by simplifying addition of rulesets, or directories in scope.

Note for reviewers

While the diff from this PR is quite big (72 files), most of that is very simple auto-fixes from ruff format that are slightly different from black. So reviewing should not be very hard.

Testing plan

  • make lint passes locally
  • make pytest passes locally
  • Waiting for maintainers to release merge-gatekeeper to run full CI
  • CI to pass
  • Maintainers to test locally

Other tasks

  • Updated the documentation to reflect the code changes
  • Added new entries to the RELEASE.md file

Signed-off-by: Yury Fedotov <[email protected]>
Signed-off-by: Yury Fedotov <[email protected]>
Signed-off-by: Yury Fedotov <[email protected]>
Signed-off-by: Yury Fedotov <[email protected]>
Signed-off-by: Yury Fedotov <[email protected]>
@yury-fedotov yury-fedotov changed the title Chore/switch to ruff [WIP] Replace flake8, isort, pylint and black by ruff Oct 23, 2024
...
pass
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Otherwise, the ruff formatter reformats that to one liner:

def process_data(raw_data, train_test_split): ...

And test_task_node_metadata in package/tests/test_api/test_rest/test_responses.py fails. See my modification to that test, to make it compatible with pass, below.

Makefile Outdated
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note how this simplifies after we define all settings, including directories and rulesets, once, in a central ruff.toml configuration file. This allows all "parties" that use ruff:

  • Developers
  • CI
  • Pre-commit hooks

To run just ruff check and ruff format from anywhere in the repo, and it applies a corresponding configuration automatically.

@@ -14,31 +14,11 @@ repos:
- id: check-json # Checks json files for parseable syntax.
- id: check-case-conflict # Check for files that would conflict in case-insensitive filesystems
- id: check-merge-conflict # Check for files that contain merge conflict strings.
- id: debug-statements # Check for debugger imports and py37+ `breakpoint()` calls in python source.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ruff's T100 ruleset, which I'm enabling, checks and autofixes that, so this pre-commit hook becomes redundant.

Comment on lines +65 to +69
[lint.mccabe]
max-complexity = 18

[lint.pylint]
max-args = 12
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I checked all arguments that your pylint, isort and flake8 configs used, and they are all default except for those

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Diffs like this, or e.g. adding a blank line between module docstring and first import line, is what ruff format does automatically due to its minor differences with black. There's no config for ruff format to make it fully backwards compatible.

Comment on lines -37 to +38
name='apply_types_to_shuttles',
tags='shuttles'
name="apply_types_to_shuttles",
tags="shuttles",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another autofix from ruff format - makes sense, since now single and double quotes are mixes within the same node definition. I'm curious why previous formatter didn't flag that.

Copy link
Contributor

Choose a reason for hiding this comment

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

The formatter was run only on package/ . The demo-project is outside of the formatter.

Comment on lines +11 to -14
get_top_shuttles_data,
make_cancel_policy_bar_chart,
make_price_analysis_image,
make_price_histogram,
get_top_shuttles_data,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm curious why isort didn't catch that in the past...

@@ -42,7 +43,7 @@ def _create_base_api_app() -> FastAPI:
@app.middleware("http")
async def set_secure_headers(request, call_next):
response = await call_next(request)
secure_headers.framework.fastapi(response) # pylint: disable=no-member
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have deleted all pylint: disable... directives from the entire codebase.

Signed-off-by: Yury Fedotov <[email protected]>
@yury-fedotov yury-fedotov marked this pull request as ready for review October 23, 2024 05:15
@yury-fedotov yury-fedotov changed the title [WIP] Replace flake8, isort, pylint and black by ruff Replace flake8, isort, pylint and black by ruff Oct 23, 2024
@astrojuanlu
Copy link
Member

🔥 Thank you @yury-fedotov for this PR!

@ankatiyar ankatiyar self-requested a review October 23, 2024 10:15
extend = "../ruff.toml"

[lint.isort]
known-first-party = ["kedro_viz"]
Copy link
Contributor

Choose a reason for hiding this comment

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

should we also add kedro here as third party?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes - added.

@@ -0,0 +1,5 @@
extend = "../ruff.toml"

[lint.isort]
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a best practice to have ruff.toml ? Can we do this in demo-project/pyproject.toml -> table [tool.ruff.lint.isort] ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ruff supports both pyproject.toml section and dedicated ruff.toml - see here. So yes what you propose is feasible.

There is no explicit recommendation in ruff docs on which to prefer, and I have not heard of what's generally considered best practice. My thinking in general is that whenever possible, I'd prefer a dedicated config for every tool, because it:

  1. Makes each config file have isolated responsibility
  2. Simplifies version control a bit - e.g. 2 PRs where one changes dependencies and another changes the lint rulesets wouldn't touch the same file
  3. Makes pyproject.toml smaller and more manageable

So I use ruff.toml in all of my projects, and never put that in pyproject.toml because of above.

Let me know if you disagree & still prefer the pyproject.toml - I can change to that. If so, then probably we'd need to configure ruff via pyproject.toml not only in demo-project but also in repo root and package.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I came up with a better argument :)

  1. It's useful to have ruff configuration in repo root, so that both package, demo-project or other packages can inherit it
  2. Repo root is not a Python package, so ruff.toml is preferred over pyproject.toml in root
  3. (1 + 2) sort of require us to use ruff.toml in the root, so for consistency, I suggest using ruff.toml files in package and demo-project too.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, I am happy to have ruff.toml, I wanted to understand if this was a better practice suggested from ruff. Thanks for the PR

Copy link
Contributor

@rashidakanchwala rashidakanchwala left a comment

Choose a reason for hiding this comment

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

LGTM. thanks a lott @yury-fedotov

Copy link
Contributor

@ravi-kumar-pilla ravi-kumar-pilla left a comment

Choose a reason for hiding this comment

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

Thank you @yury-fedotov 💯

[lint.per-file-ignores]
"*/cli_steps.py" = ["B011"] # assert False instead of AssertionError
"*/base_deployer.py" = ["B024"] # ABCs without abstract methods
"package/kedro_viz/__init__.py" = ["B028"] # Risky usage of positional arguments
Copy link
Contributor

Choose a reason for hiding this comment

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

Q: does it make sense to ignore some of these specific issues in the code with noqa inline instead of here? Can keep the ignores that apply to multiple files here.

Copy link
Contributor

Choose a reason for hiding this comment

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

I definitely wouldn't want to ignore the 'broad exception' rule in general, because I think we should avoid it as much as possible. I guess some others like # noqa: ARG002 should be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rashidakanchwala

Broad exception rule has BLE code in ruff and is selected for entire repo ✅ (See line 14 of this file)

Copy link
Contributor Author

@yury-fedotov yury-fedotov Oct 24, 2024

Choose a reason for hiding this comment

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

@ankatiyar

Good question!

The way I implemented it is as follows:

  1. Whatever has an inline NOQA before that's applied to 1-2 places, stays as inline NOQA.
  2. Whatever was a file-level pylint: disable statement at the beginning of the file is moved to ruff.toml from that separate file.

Let me explain the rationale for (2).

Consider two implementations, using package/kedro_viz/integrations/kedro/sqlite_store.py as an example:

Before

# pylint: broad-exception-caught

At the beginning of that particular file.

After

"package/kedro_viz/integrations/kedro/sqlite_store.py" = ["BLE"]

In ruff.toml


  • In both cases, we essentially store the same directive - disable a particular rule in a particular file.
  • However (2) makes it more explicit and centralizes all those directives, which would otherwise be scattered across tens of files, in a single file.
  • Long term, that helps gradually make the codebase adhere to those rulesets, and delete those per-file-ignores. As opposed to distributed inline NOQAs that typically just never addressed.

Copy link
Contributor

@ankatiyar ankatiyar left a comment

Choose a reason for hiding this comment

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

Overall looks good but left a question regarding the ignoring of errors.
Thanks @yury-fedotov! 💯

@rashidakanchwala
Copy link
Contributor

@yury-fedotov , feel free to merge this PR :)

@yury-fedotov
Copy link
Contributor Author

yury-fedotov commented Oct 25, 2024

@yury-fedotov , feel free to merge this PR :)

I don't have write access @rashidakanchwala

@rashidakanchwala
Copy link
Contributor

no worries, let me merge. Once again Thank you!, this is big improvement to our dev workflow!

@rashidakanchwala rashidakanchwala merged commit 02ce770 into kedro-org:main Oct 28, 2024
23 checks passed
@jitu5 jitu5 mentioned this pull request Nov 20, 2024
5 tasks
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.

Introducing ruff as a linter to replace pylint, flake8, isort and black.
5 participants