Skip to content

Commit

Permalink
style: Use ruff format instead of black . for improved user exper…
Browse files Browse the repository at this point in the history
…ience (#5023)

* style: Disable Flake8 line length checks as handled by our formatting tools

* Apply `ruff format` to potentially unexpected tuples in gui/wxpython/rlisetup/wizard.py

* style: Apply `ruff format`-specific formatting for 2025 style

* style: Disable Flake8 line length checks as handled by our formatting tools

* checks: Replace black with ruff format in pre-commit

* CI: Implement checks and PR suggestions for `ruff format`

* python: Address misplace to and from comments for Rast_copy_cats

* gui: Remove potentially unexpected and unused tuple for SetSelection in rlisetup.wizard
  • Loading branch information
echoix authored Feb 2, 2025
1 parent d7949c5 commit 09f9235
Show file tree
Hide file tree
Showing 32 changed files with 138 additions and 175 deletions.
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
ignore =
# whitespace before ':' (Black)
E203,
# E501 line too long
E501,
# line break before binary operator (Black)
W503,

Expand Down
25 changes: 8 additions & 17 deletions .github/workflows/python-code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ jobs:
# renovate: datasource=python-version depName=python
PYTHON_VERSION: "3.13"
MIN_PYTHON_VERSION: "3.9"
# renovate: datasource=pypi depName=black
BLACK_VERSION: "25.1.0"
# renovate: datasource=pypi depName=flake8
FLAKE8_VERSION: "7.1.1"
# renovate: datasource=pypi depName=pylint
Expand Down Expand Up @@ -73,6 +71,14 @@ jobs:
continue-on-error: true
- name: Run Ruff (apply fixes for suggestions)
run: ruff check . --preview --fix --unsafe-fixes
- name: Run `ruff format` showing diff without failing
continue-on-error: true
if: ${{ !cancelled() }}
run: ruff format --diff
- name: Run `ruff format` fixing files
# Run `ruff format` even when `ruff check` fixed files: fixes can require formatting
if: ${{ !cancelled() }}
run: ruff format --diff
- name: Create and uploads code suggestions to apply for Ruff
# Will fail fast here if there are changes required
id: diff-ruff
Expand All @@ -84,21 +90,6 @@ jobs:
# To keep repo's file structure in formatted changes artifact
extra-upload-changes: pyproject.toml

- name: Install Black only
run: pip install black[jupyter]==${{ env.BLACK_VERSION }}

- name: Run Black
run: black .

- name: Create and uploads code suggestions to apply for Black
# Will fail fast here if there are changes required
id: diff-black
uses: ./.github/actions/create-upload-suggestions
with:
tool-name: black
# To keep repo's file structure in formatted changes artifact
extra-upload-changes: .clang-format

- name: Install non-Python dependencies
run: |
sudo apt-get update -y
Expand Down
11 changes: 2 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,12 @@ repos:
# Run the linter.
- id: ruff
args: [--fix, --preview]
# Run the formatter.
- id: ruff-format
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.44.0
hooks:
- id: markdownlint-fix
# Using this mirror lets us use mypyc-compiled black, which is about 2x faster
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 25.1.0
hooks:
- id: black-jupyter
exclude: |
(?x)^(
python/libgrass_interface_generator/
)
- repo: https://github.com/pycqa/flake8
rev: 7.1.1
hooks:
Expand Down
42 changes: 21 additions & 21 deletions general/g.version/tests/g_version_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,36 @@
def test_g_version_no_flag(session):
"""Test that g.version output contains the word 'GRASS'."""
output = gs.read_command("g.version", env=session.env).strip()
assert (
"GRASS" in output
), "Expected 'GRASS' in g.version output, but it was not found."
assert "GRASS" in output, (
"Expected 'GRASS' in g.version output, but it was not found."
)


def test_c_flag(session):
"""Test the output of g.version -c for Copyright and License Statement."""
expected_text = "Copyright and License Statement"
output = gs.read_command("g.version", flags="c", env=session.env).strip()
assert (
expected_text in output
), f"Expected '{expected_text}' in g.version -c output, but got: '{output}'"
assert expected_text in output, (
f"Expected '{expected_text}' in g.version -c output, but got: '{output}'"
)


def test_e_flag(session):
"""Test that g.version -e contains the expected keys."""
expected_keys = ["PROJ:", "GDAL/OGR:", "SQLite:"]
output = gs.read_command("g.version", flags="e", env=session.env).strip()
for key in expected_keys:
assert (
key in output
), f"Expected key '{key}' in g.version -e output, but it was not found."
assert key in output, (
f"Expected key '{key}' in g.version -e output, but it was not found."
)


def test_b_flag(session):
"""Test that g.version -b output contains the word 'GRASS'."""
output = gs.read_command("g.version", flags="b", env=session.env).strip()
assert (
"GRASS" in output
), "Expected 'GRASS' in g.version -b output, but it was not found."
assert "GRASS" in output, (
"Expected 'GRASS' in g.version -b output, but it was not found."
)


def test_g_flag(session):
Expand All @@ -48,19 +48,19 @@ def test_g_flag(session):
]
output = gs.parse_command("g.version", flags="g", env=session.env)
for key in expected_keys:
assert (
key in output
), f"Expected key '{key}' in g.version -g output, but it was not found."
assert key in output, (
f"Expected key '{key}' in g.version -g output, but it was not found."
)


def test_r_flag(session):
"""Test that g.version -r contains the expected keys."""
expected_texts = ["libgis revision:", "libgis date:"]
output = gs.read_command("g.version", flags="r", env=session.env).strip()
for text in expected_texts:
assert (
text in output
), f"Expected key '{text}' in g.version -r output, but it was not found."
assert text in output, (
f"Expected key '{text}' in g.version -r output, but it was not found."
)


def test_x_flag(session):
Expand All @@ -78,6 +78,6 @@ def curly_brackets_paired(text):
return False
return counter == 0

assert curly_brackets_paired(
output
), "Curly brackets are not properly paired in the g.version -x output."
assert curly_brackets_paired(output), (
"Curly brackets are not properly paired in the g.version -x output."
)
6 changes: 3 additions & 3 deletions gui/wxpython/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -816,9 +816,9 @@ def _internalSettings(self):
)

self.internalSettings["display"]["driver"]["choices"] = ["cairo", "png"]
self.internalSettings["display"]["statusbarMode"][
"choices"
] = None # set during MapFrame init
self.internalSettings["display"]["statusbarMode"]["choices"] = (
None # set during MapFrame init
)
self.internalSettings["display"]["mouseWheelZoom"]["choices"] = (
_("Zoom and recenter"),
_("Zoom to mouse cursor"),
Expand Down
8 changes: 5 additions & 3 deletions gui/wxpython/dbmgr/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2223,9 +2223,11 @@ def ValidateSelectStatement(self, statement):

tablelen = len(self.dbMgrData["mapDBInfo"].layers[self.selLayer]["table"])

if statement[index + 1 : index + 6].lower() != "from " or statement[
index + 6 : index + 6 + tablelen
] != "%s" % (self.dbMgrData["mapDBInfo"].layers[self.selLayer]["table"]):
if (
statement[index + 1 : index + 6].lower() != "from "
or statement[index + 6 : index + 6 + tablelen]
!= "%s" % (self.dbMgrData["mapDBInfo"].layers[self.selLayer]["table"])
):
return None

if len(statement[index + 7 + tablelen :]) > 0:
Expand Down
4 changes: 1 addition & 3 deletions gui/wxpython/gmodeler/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3307,9 +3307,7 @@ def _writePython(self):
# %module
# % description: {description}
# %end
""".format(
description=" ".join(properties["description"].splitlines())
)
""".format(description=" ".join(properties["description"].splitlines()))
)

modelItems = self.model.GetItems(ModelAction)
Expand Down
4 changes: 1 addition & 3 deletions gui/wxpython/gui_core/vselect.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,7 @@ def OnExportMap(self, event):
GMessage(_("No features selected"))
return
lst = ""
for (
cat
) in (
for cat in (
self.selectedFeatures
): # build text string of categories for v.extract input
lst += str(cat["Category"]) + ","
Expand Down
24 changes: 12 additions & 12 deletions gui/wxpython/nviz/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -1610,12 +1610,12 @@ def _createVectorPage(self, parent):
checkThematicWidth = wx.CheckBox(
parent=panel, id=wx.ID_ANY, label=_("use width for thematic mapping")
)
self.win["vector"]["lines"]["thematic"][
"checkcolor"
] = checkThematicColor.GetId()
self.win["vector"]["lines"]["thematic"][
"checkwidth"
] = checkThematicWidth.GetId()
self.win["vector"]["lines"]["thematic"]["checkcolor"] = (
checkThematicColor.GetId()
)
self.win["vector"]["lines"]["thematic"]["checkwidth"] = (
checkThematicWidth.GetId()
)
checkThematicColor.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
checkThematicWidth.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
checkThematicColor.SetValue(False)
Expand Down Expand Up @@ -1825,12 +1825,12 @@ def _createVectorPage(self, parent):
checkThematicSize = wx.CheckBox(
parent=panel, id=wx.ID_ANY, label=_("use size for thematic mapping")
)
self.win["vector"]["points"]["thematic"][
"checkcolor"
] = checkThematicColor.GetId()
self.win["vector"]["points"]["thematic"][
"checksize"
] = checkThematicSize.GetId()
self.win["vector"]["points"]["thematic"]["checkcolor"] = (
checkThematicColor.GetId()
)
self.win["vector"]["points"]["thematic"]["checksize"] = (
checkThematicSize.GetId()
)
checkThematicColor.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
checkThematicSize.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
checkThematicColor.SetValue(False)
Expand Down
10 changes: 6 additions & 4 deletions gui/wxpython/nviz/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,9 @@ def SetDecorDefaultProp(self, type):
# arrow
if type == "arrow":
data["arrow"] = copy.deepcopy(UserSettings.Get(group="nviz", key="arrow"))
data["arrow"]["color"] = "%d:%d:%d" % (
UserSettings.Get(group="nviz", key="arrow", subkey="color")[:3]
data["arrow"]["color"] = (
"%d:%d:%d"
% (UserSettings.Get(group="nviz", key="arrow", subkey="color")[:3])
)
data["arrow"].update(
copy.deepcopy(
Expand All @@ -402,8 +403,9 @@ def SetDecorDefaultProp(self, type):
data["scalebar"] = copy.deepcopy(
UserSettings.Get(group="nviz", key="scalebar")
)
data["scalebar"]["color"] = "%d:%d:%d" % (
UserSettings.Get(group="nviz", key="scalebar", subkey="color")[:3]
data["scalebar"]["color"] = (
"%d:%d:%d"
% (UserSettings.Get(group="nviz", key="scalebar", subkey="color")[:3])
)
data["scalebar"].update(
copy.deepcopy(
Expand Down
4 changes: 2 additions & 2 deletions gui/wxpython/rlisetup/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ def __init__(self, wizard, parent):
def OnEnterPage(self, event: WizardEvent | None = None) -> None:
"""Function during entering"""
# This is an hack to force the user to choose Rectangle or Circle
self.typeBox.SetSelection(2),
self.typeBox.SetSelection(2)
self.typeBox.ShowItem(2, False)
self.panelSizer.Layout()

Expand Down Expand Up @@ -1608,7 +1608,7 @@ def __init__(self, wizard, parent):
choices=[_("Rectangle"), _("Circle"), ("")],
)
# This is an hack to force the user to choose Rectangle or Circle
self.typeBox.SetSelection(2),
self.typeBox.SetSelection(2)
self.typeBox.ShowItem(2, False)
self.sizer.Add(self.typeBox, flag=wx.ALIGN_LEFT, pos=(0, 0), span=(1, 2))

Expand Down
8 changes: 2 additions & 6 deletions gui/wxpython/timeline/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,7 @@ def _draw3dFigure(self):
self.axes3d.clear()
self.axes3d.grid(False)
# self.axes3d.grid(True)
convert = (
mdates.date2num if self.temporalType == "absolute" else lambda x: x
) # noqa: E731
convert = mdates.date2num if self.temporalType == "absolute" else lambda x: x # noqa: E731

colors = cycle(COLORS)
plots = []
Expand Down Expand Up @@ -319,9 +317,7 @@ def _draw2dFigure(self):
"""Draws 2D plot (temporal extents)"""
self.axes2d.clear()
self.axes2d.grid(True)
convert = (
mdates.date2num if self.temporalType == "absolute" else lambda x: x
) # noqa: E731
convert = mdates.date2num if self.temporalType == "absolute" else lambda x: x # noqa: E731

colors = cycle(COLORS)

Expand Down
6 changes: 3 additions & 3 deletions imagery/i.atcorr/create_iwave.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ def interpolate_band(values, step=2.5):

wavelengths = values_clean[:, 0] # 1st column of input array
responses = values_clean[:, 1] # 2nd column
assert len(wavelengths) == len(
responses
), "Number of wavelength slots and spectral responses are not equal!"
assert len(wavelengths) == len(responses), (
"Number of wavelength slots and spectral responses are not equal!"
)

# spectral responses are written out with .4f in pretty_print()
# anything smaller than 0.0001 will become 0.0000 -> discard with ...
Expand Down
15 changes: 4 additions & 11 deletions lib/init/grass.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,13 +603,10 @@ def read_gui(gisrc, default_gui):

def create_initial_gisrc(filename):
# for convenience, define GISDBASE as pwd:
s = (
r"""GISDBASE: %s
s = r"""GISDBASE: %s
LOCATION_NAME: <UNKNOWN>
MAPSET: <UNKNOWN>
"""
% Path.cwd()
)
""" % Path.cwd()
writefile(filename, s)


Expand Down Expand Up @@ -1662,9 +1659,7 @@ def sh_like_startup(location, location_name, grass_env_file, sh):
fc -R
_grass_old_mapset="$MAPSET_PATH"
fi
""".format(
sh_history=sh_history
)
""".format(sh_history=sh_history)
elif sh == "bash":
# Append existing history to file ("flush").
# Clear the (in-memory) history.
Expand All @@ -1678,9 +1673,7 @@ def sh_like_startup(location, location_name, grass_env_file, sh):
history -r
_grass_old_mapset="$MAPSET_PATH"
fi
""".format(
sh_history=sh_history
)
""".format(sh_history=sh_history)
# Ubuntu sudo creates a file .sudo_as_admin_successful and bash checks
# for this file in the home directory from /etc/bash.bashrc and prints a
# message if it's not detected. This can be suppressed with either
Expand Down
4 changes: 1 addition & 3 deletions python/grass/experimental/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ def unique_id():


@pytest.fixture
def xy_mapset_session(
xy_session_for_module, unique_id
): # pylint: disable=redefined-outer-name
def xy_mapset_session(xy_session_for_module, unique_id): # pylint: disable=redefined-outer-name
"""Active session in a mapset of an XY location
Mapset scope is function, while the location scope is module.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ def test_create_multiple(xy_session):
assert sorted(collected) == sorted(create_names)
existing_mapsets = get_mapset_names(env=xy_session.env)
assert sorted(existing_mapsets) == sorted(create_names + original_mapsets)
assert (
len(set(top_level_collected)) == 1
), f"Top level mapset changed: {top_level_collected}"
assert len(set(top_level_collected)) == 1, (
f"Top level mapset changed: {top_level_collected}"
)


def test_nested_top_env(xy_session):
Expand Down
4 changes: 1 addition & 3 deletions python/grass/jupyter/interactivemap.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,7 @@ class InteractiveRegionController:
changed_region (dict): The dictionary to store the changed region.
"""

def __init__(
self, map_object, ipyleaflet, ipywidgets, **kwargs
): # pylint: disable=unused-argument
def __init__(self, map_object, ipyleaflet, ipywidgets, **kwargs): # pylint: disable=unused-argument
"""Initializes the InteractiveRegionController.
:param map_object: The map object.
Expand Down
Loading

0 comments on commit 09f9235

Please sign in to comment.