Skip to content

Conversation

@JDBetteridge
Copy link
Contributor

@JDBetteridge JDBetteridge commented Oct 16, 2025

I'm trying to automate detection a lot of the "nitpick" code review comments and providing a route to automatically fixing the issues apriori.

What I have added to CI is equivalent to locally running:

isort --check-only --sort-reexports --multi-line VERTICAL_GRID_GROUPED --line-length 90 --force-alphabetical-sort-within-sections --project devito,examples .
ruff check --preview  --select E,W,F,B,UP,SIM,I,RUF022 --ignore F403,E226,E731,E275,F405,E722,E741,W605 --line-length=90 --output-format concise

Most command line arguments are included in the pyproject.toml and checking out this branch you can just run

isort --check-only .
ruff check --output-format concise

Fixing most linting issues is as simple as

isort .
ruff check --fix

if you trust the auto-formatter!

This PR also extends linting to Dockerfiles and Github actions too.

An excerpt from CONTRIBUTING.md:

Coding guidelines

Some coding rules are "enforced" (and automatically checked by our Continuous Integration systems), some are "strongly recommended", others are "optional" but welcome.

  • We enforce PEP8, with a few exceptions, listed here
  • We enforce a maximum line length of 90 characters.
  • We enforce indentation via 4 spaces.
  • We suggest to use flake8 to check the above points locally, before filing a Pull Request.
  • We strongly recommend to document any new module, class, routine, ... with NumPy-like docstrings ("numpydoc").
  • We strongly recommend imports to be at the top of a module, logically grouped and, within each group, to be alphabetically ordered. As an example, condider our init.py: the first group is imports from the standard library; then imports from third-party dependencies; finally, imports from devito modules.
  • We strongly recommend to follow standard Python coding guidelines:
    • Use camel caps for class names, e.g. class FooBar.
    • Method names must start with a small letter; use underscores to separate words, e.g. def _my_meth_....
    • Private class attributes and methods must start with an underscore.
    • Variable names should be explicative (Devito prefers "long and clear" over "short but unclear").
    • Comment your code, and do not be afraid of being verbose. The first letter must be capitalized. Do not use punctuation (unless the comment consists of multiple sentences).
  • We like that blank lines are used to logically split blocks of code implementing different (possibly sequential) tasks.

@JDBetteridge JDBetteridge requested a review from EdCaunt October 16, 2025 23:17
@JDBetteridge JDBetteridge added CI continuous integration misc python Pull requests that update python code github_actions Pull requests that update GitHub Actions code labels Oct 16, 2025
@codecov
Copy link

codecov bot commented Oct 16, 2025

Codecov Report

❌ Patch coverage is 77.51736% with 259 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.97%. Comparing base (3e6c852) to head (8d1fa60).

Files with missing lines Patch % Lines
devito/mpi/routines.py 13.55% 51 Missing ⚠️
devito/mpi/distributed.py 46.87% 17 Missing ⚠️
benchmarks/user/benchmark.py 46.66% 16 Missing ⚠️
devito/arch/compiler.py 50.00% 15 Missing and 1 partial ⚠️
devito/types/dense.py 75.00% 10 Missing ⚠️
devito/data/data.py 42.85% 8 Missing ⚠️
devito/tools/data_structures.py 50.00% 8 Missing ⚠️
devito/types/grid.py 75.75% 8 Missing ⚠️
devito/types/sparse.py 75.86% 7 Missing ⚠️
devito/ir/stree/tree.py 40.00% 6 Missing ⚠️
... and 55 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2771      +/-   ##
==========================================
- Coverage   83.01%   78.97%   -4.04%     
==========================================
  Files         248      248              
  Lines       51074    50826     -248     
  Branches     4491     4393      -98     
==========================================
- Hits        42401    40142    -2259     
- Misses       7902     9881    +1979     
- Partials      771      803      +32     
Flag Coverage Δ
pytest-gpu-aomp-amdgpuX ?
pytest-gpu-nvc-nvidiaX ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

# But ignore these inconvenient rules
ignore = ["F403", "E226", "E731", "E275", "F405", "E722", "E741", "W605"]

[tool.isort]
Copy link
Contributor

Choose a reason for hiding this comment

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

you look back 10 years ago or so there's a commit with message "FREEEEEEEEEEEEEDOOOMM" in which we are essentially removing isort from devito 😂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What was the motivation for removing?

[tool.isort]
line_length = 90
known_first_party = ["devito", "examples"]
multi_line_output = "VERTICAL_GRID_GROUPED"
Copy link
Contributor

Choose a reason for hiding this comment

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

if this is for

from X import (
A,
B,
C,
...
)

then I vote no

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No this is in direct response to your comment on my other PR. This is specifically to avoid using ruff for the import formatting (see this issue)

@JDBetteridge JDBetteridge self-assigned this Nov 7, 2025
@JDBetteridge JDBetteridge force-pushed the JDBetteridge/use_ruff branch 4 times, most recently from a4609a1 to 43a044d Compare November 13, 2025 18:29
@review-notebook-app
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@JDBetteridge JDBetteridge force-pushed the JDBetteridge/use_ruff branch 4 times, most recently from 70151d8 to b19cb9d Compare December 24, 2025 16:53
@JDBetteridge
Copy link
Contributor Author

This is almost ready, it doesn't look like it, but I will merge these two auxiliary branches in once I've tidied the commits and the second is green...

#2813

#2814

@JDBetteridge JDBetteridge force-pushed the JDBetteridge/use_ruff branch from 9b5069c to 1ec3c7f Compare January 6, 2026 11:25
'Cpu64AdvOmpOperator', 'Cpu64FsgCOperator', 'Cpu64FsgOmpOperator',
'Cpu64CustomOperator', 'Cpu64CustomCXXOperator', 'Cpu64AdvCXXOperator',
'Cpu64AdvCXXOmpOperator', 'Cpu64FsgCXXOperator', 'Cpu64FsgCXXOmpOperator']
__all__ = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are some one per line and some are not (like archinfo.py)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because I put a # noqa: RUF022 around the line in archinfo.py since the list is carefully arranged and documented.

Note that isort fixes the imports and ruff formats the __all__.

import mmap
import os
import sys
from ctypes.util import find_library
Copy link
Contributor

Choose a reason for hiding this comment

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

Slightly weird that it import ctypes then others then ctypes.util

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It [ruff/isort] did not do that, we imported both in this way and then it just got formatted like so. We should just fix it 😅 (which I will takes as the action to this comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nevermind! There is a good reason for it being the way it was! (util is a module and is not automatically imported when you import ctypes)

@JDBetteridge JDBetteridge force-pushed the JDBetteridge/use_ruff branch from 795c02b to ac035e1 Compare January 6, 2026 17:15
@JDBetteridge JDBetteridge force-pushed the JDBetteridge/use_ruff branch from ac035e1 to b19bb09 Compare January 6, 2026 17:22
@JDBetteridge JDBetteridge force-pushed the JDBetteridge/use_ruff branch from b19bb09 to 8d1fa60 Compare January 6, 2026 17:33
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: this file is a .yaml whilst all the others are .yml

"""
Initialize any necessary input and run the operator associated with the solver.
"""
# Get the operator if exist
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick, but whilst we're fixing all the typos "Get the operator if it exists"


if oo['mpi'] and oo['mpi'] not in cls.MPI_MODES:
raise InvalidOperator("Unsupported MPI mode `%s`" % oo['mpi'])
raise InvalidOperator("Unsupported MPI mode `{}`".format(oo['mpi']))
Copy link
Contributor

@EdCaunt EdCaunt Jan 7, 2026

Choose a reason for hiding this comment

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

Suggested change
raise InvalidOperator("Unsupported MPI mode `{}`".format(oo['mpi']))
raise InvalidOperator(f"Unsupported MPI mode `{oo['mpi']}`")

psubs = {}
nx0 = x0.copy()
for d, d0 in x0.items():
for d, _ in x0.items():
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
for d, _ in x0.items():
for d in x0:

func, mode = args
else:
assert False
raise AssertionError('Too many args')
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
raise AssertionError('Too many args')
raise ValueError(f"Either 1 or 2 arguments permitted, {len(args)} provided")


def __repr__(self):
return "<SyncSpot (%s)>" % ",".join(str(i) for i in self.sync_ops)
return "<SyncSpot ({})>".format(",".join(str(i) for i in self.sync_ops))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return "<SyncSpot ({})>".format(",".join(str(i) for i in self.sync_ops))
return f"<SyncSpot ({','.join(str(i) for i in self.sync_ops)})>"

def __repr__(self):
functions = "(%s)" % ",".join(i.name for i in self.functions)
return "<%s%s>" % (self.__class__.__name__, functions)
functions = "({})".format(",".join(i.name for i in self.functions))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
functions = "({})".format(",".join(i.name for i in self.functions))
functions = f"({','.join(i.name for i in self.functions)})"

v = f._C_name
else:
assert False
raise AssertionError('rvalue is not a recognised type')
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
raise AssertionError('rvalue is not a recognised type')
raise TypeError('rvalue is not a recognised type')

v = f._C_field_dmap
else:
assert False
raise AssertionError('rvalue is not a recognised type')
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
raise AssertionError('rvalue is not a recognised type')
raise TypeError('rvalue is not a recognised type')

Comment on lines 231 to +235
try:
assert not queue
except AssertionError:
except AssertionError as e:
if options['mpi']:
raise RuntimeError("Unsupported MPI for the given equations")
raise RuntimeError("Unsupported MPI for the given equations") from e
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
try:
assert not queue
except AssertionError:
except AssertionError as e:
if options['mpi']:
raise RuntimeError("Unsupported MPI for the given equations")
raise RuntimeError("Unsupported MPI for the given equations") from e
if not queue and options['mpi']:
raise RuntimeError("Unsupported MPI for the given equations")

Copy link
Contributor

@EdCaunt EdCaunt left a comment

Choose a reason for hiding this comment

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

Looks mainly good to me - feel free to ignore any and all of my comments since they don't affect functionality and it's still an improvement over the existing code.

We should just get this merged to avoid hellish rebasing and then fix the quibbles later

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

Labels

CI continuous integration github_actions Pull requests that update GitHub Actions code misc python Pull requests that update python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants