Skip to content

Commit

Permalink
Swapped to ruff for formatting and checking (#68)
Browse files Browse the repository at this point in the history
* Fixed some complaints
  • Loading branch information
david-zwicker authored Aug 16, 2024
1 parent 17f97ac commit 7e1f6a4
Show file tree
Hide file tree
Showing 18 changed files with 104 additions and 59 deletions.
8 changes: 4 additions & 4 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@
import os.path
import sys

sys.path.insert(0, os.path.abspath("../.."))
sys.path.insert(0, os.path.abspath("../../../py-pde"))
sys.path.insert(0, os.path.abspath("../..")) # noqa: PTH100
sys.path.insert(0, os.path.abspath("../../../py-pde")) # noqa: PTH100
sys.path.insert(0, ".")

from datetime import date

import sphinx_simplify_typehints # @UnresolvedImport @UnusedImport
import sphinx_simplify_typehints

# -- Project information -----------------------------------------------------

project = "py-droplets"
module_name = "droplets"
author = "David Zwicker"
copyright = f"{date.today().year}, {author}" # @ReservedAssignment
copyright = f"{date.today().year}, {author}" # noqa: A001

# The short X.Y version
import droplets
Expand Down
5 changes: 3 additions & 2 deletions docs/source/quickstart/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ define a droplet class that stores additional information by subclassing

Coding style
""""""""""""
The coding style is enforced using `isort <https://timothycrosley.github.io/isort/>`_
and `black <https://black.readthedocs.io/>`_. Moreover, we use `Google Style docstrings
The coding style is enforced using `ruff <https://docs.astral.sh/ruff/>`_, based on the
styles suggest by `isort <https://timothycrosley.github.io/isort/>`_ and
`black <https://black.readthedocs.io/>`_. Moreover, we use `Google Style docstrings
<https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings>`_,
which might be best `learned by example
<https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html>`_.
Expand Down
15 changes: 8 additions & 7 deletions docs/source/run_autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import logging
import os
import subprocess as sp
from pathlib import Path

logging.basicConfig(level=logging.INFO)

OUTPUT_PATH = "packages"
OUTPUT_PATH = Path("packages")


def replace_in_file(infile, replacements, outfile=None):
Expand All @@ -26,21 +27,21 @@ def replace_in_file(infile, replacements, outfile=None):
if outfile is None:
outfile = infile

with open(infile) as fp:
with infile.open() as fp:
content = fp.read()

for key, value in replacements.items():
content = content.replace(key, value)

with open(outfile, "w") as fp:
with outfile.open("w") as fp:
fp.write(content)


def main(folder="droplets"):
# remove old files
for path in glob.glob(f"{OUTPUT_PATH}/*.rst"):
for path in OUTPUT_PATH.glob("*.rst"):
logging.info("Remove file `%s`", path)
os.remove(path)
path.unlink()

# run sphinx-apidoc
sp.check_call(
Expand All @@ -50,7 +51,7 @@ def main(folder="droplets"):
"--maxdepth",
"4",
"--output-dir",
OUTPUT_PATH,
str(OUTPUT_PATH),
"--module-first",
f"../../{folder}", # path of the package
f"../../{folder}/tests", # ignored path
Expand All @@ -59,7 +60,7 @@ def main(folder="droplets"):
)

# replace unwanted information
for path in glob.glob(f"{OUTPUT_PATH}/*.rst"):
for path in OUTPUT_PATH.glob("*.rst"):
logging.info("Patch file `%s`", path)
replace_in_file(path, {"Submodules\n----------\n\n": ""})

Expand Down
8 changes: 4 additions & 4 deletions droplets/droplet_tracks.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ def _write_hdf_dataset(self, hdf_path, key: str = "droplet_track"):

else:
# create empty dataset to indicate empty emulsion
dataset = hdf_path.create_dataset(key, shape=tuple())
dataset = hdf_path.create_dataset(key, shape=())
dataset.attrs["droplet_class"] = "None"

return dataset
Expand Down Expand Up @@ -549,7 +549,7 @@ def match_tracks(
tracks.append(DropletTrack(droplets=[droplet], times=[time]))

if found_multiple_overlap:
logger.debug(f"Found multiple overlapping droplet(s) at t={time}")
logger.debug("Found multiple overlapping droplet(s) at t=%g", time)

elif method == "distance":
# track droplets by their physical distance
Expand Down Expand Up @@ -591,11 +591,11 @@ def match_tracks(
tracks.append(DropletTrack(droplets=[droplet], times=[time]))

else:
raise ValueError(f"Unknown tracking method {method}")
raise ValueError("Unknown tracking method `%s`", method)

# check kwargs
if kwargs:
logger.warning(f"Unused keyword arguments: {kwargs}")
logger.warning("Unused keyword arguments: %s", kwargs)

# add all emulsions successively using the given algorithm
t_last = None
Expand Down
7 changes: 4 additions & 3 deletions droplets/droplets.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ def __eq__(self, other):

def check_data(self):
"""Method that checks the validity and consistency of self.data."""
pass

@property
def _args(self):
Expand Down Expand Up @@ -1092,8 +1091,10 @@ def __init__(
opt_modes = spherical.spherical_index_count(l) - 1
logger.warning(
"The length of `amplitudes` should be such that all orders are "
f"captured for the perturbations with the highest degree ({l}). "
f"Consider increasing the size of the array to {opt_modes}."
"captured for the perturbations with the highest degree (%d). "
"Consider increasing the size of the array to %d.",
l,
opt_modes,
)

@preserve_scalars
Expand Down
12 changes: 6 additions & 6 deletions droplets/emulsions.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ def _write_hdf_dataset(self, hdf_path, key: str = "emulsion"):

else:
# create empty dataset to indicate empty emulsion
dataset = hdf_path.create_dataset(key, shape=tuple())
dataset = hdf_path.create_dataset(key, shape=())
dataset.attrs["droplet_class"] = "None"

return dataset
Expand Down Expand Up @@ -675,15 +675,15 @@ def plot(
if len(self) == 0:
# empty emulsions can be plotted in all dimensions :)
return PlotReference(ax, [], {})

if self.dim is None or self.dim <= 1:
raise NotImplementedError(
f"Plotting emulsions in {self.dim} dimensions is not implemented."
)
elif self.dim > 2:
if Emulsion._show_projection_warning:
logger = logging.getLogger(self.__class__.__name__)
logger.warning("A projection on the first two axes is shown.")
Emulsion._show_projection_warning = False
elif self.dim > 2 and Emulsion._show_projection_warning:
logger = logging.getLogger(self.__class__.__name__)
logger.warning("A projection on the first two axes is shown.")
Emulsion._show_projection_warning = False

# plot background and determine bounds for the droplets
if field is not None:
Expand Down
22 changes: 11 additions & 11 deletions droplets/image_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def _locate_droplets_in_mask_cartesian(mask: ScalarField) -> Emulsion:

# locate individual clusters in the padded image
labels, num_labels = ndimage.label(mask.data)
grid._logger.info(f"Found {num_labels} cluster(s) in image")
grid._logger.info("Found %d cluster(s) in image", num_labels)
if num_labels == 0:
example_drop = SphericalDroplet(np.zeros(grid.dim), radius=0)
return Emulsion.empty(example_drop)
Expand Down Expand Up @@ -164,11 +164,11 @@ def _locate_droplets_in_mask_cartesian(mask: ScalarField) -> Emulsion:
emulsion = Emulsion(droplets)
num_candidates = len(emulsion)
if num_candidates < num_labels:
grid._logger.info(f"Only {num_candidates} candidate(s) inside bounds")
grid._logger.info("Only %d candidate(s) inside bounds", num_candidates)

emulsion.remove_overlapping(grid=grid)
if len(emulsion) < num_candidates:
grid._logger.info(f"Only {num_candidates} candidate(s) not overlapping")
grid._logger.info("Only %d candidate(s) not overlapping", num_candidates)

return emulsion

Expand Down Expand Up @@ -212,8 +212,6 @@ def _locate_droplets_in_mask_spherical(mask: ScalarField) -> Emulsion:
class _SpanningDropletSignal(RuntimeError):
"""Exception signaling that an untypical droplet spanning the system was found."""

...


def _locate_droplets_in_mask_cylindrical_single(
grid: CylindricalSymGrid, mask: np.ndarray
Expand Down Expand Up @@ -299,7 +297,7 @@ def _locate_droplets_in_mask_cylindrical(mask: ScalarField) -> Emulsion:
except _SpanningDropletSignal:
pass
else:
grid._logger.info(f"Found {len(candidates)} droplet candidates.")
grid._logger.info("Found %d droplet candidates.", len(candidates))

# keep droplets that are inside the central area
droplets = Emulsion()
Expand All @@ -310,7 +308,7 @@ def _locate_droplets_in_mask_cylindrical(mask: ScalarField) -> Emulsion:
if z_min <= droplet.position[2] <= z_max:
droplets.append(droplet)

grid._logger.info(f"Kept {len(droplets)} central droplets.")
grid._logger.info("Kept %d central droplets.", len(droplets))

# filter overlapping droplets (e.g. due to duplicates)
droplets.remove_overlapping()
Expand Down Expand Up @@ -373,7 +371,7 @@ def locate_droplets(
field,
threshold="auto",
refine=True,
refine_args={'vmin': None, 'vmax': None},
refine_args={"vmin": None, "vmax": None},
)
:code:`field` is the scalar field, in which the droplets are located. The
Expand Down Expand Up @@ -840,8 +838,9 @@ def get_length_scale(
for window_size in [5, 1, 0.2]:
bracket = [max_est / window_size, max_est, max_est * window_size]
logger.debug(
f"Search maximum of structure factor in interval {bracket} with "
f"window_size={window_size}"
"Seek maximal structure factor in interval %s with window_size=%g",
bracket,
window_size,
)
try:
result = optimize.minimize_scalar(
Expand All @@ -854,7 +853,8 @@ def get_length_scale(
if not result.success:
logger.warning(
"Maximization of structure factor resulted in the "
f"following message: {result.message}"
"following message: %s",
result.message,
)
length_scale = 2 * np.pi / result.x
break # found some answer, which we will use
Expand Down
2 changes: 1 addition & 1 deletion droplets/resources/make_spheres_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@
num_list.add(num)

# store the number of generated spheres
f.attrs["num_list"] = list(sorted(num_list))
f.attrs["num_list"] = sorted(num_list)
5 changes: 3 additions & 2 deletions droplets/trackers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from __future__ import annotations

import math
from pathlib import Path
from typing import Any, Callable, Literal

from pde.fields.base import FieldBase
Expand Down Expand Up @@ -112,7 +113,7 @@ def finalize(self, info: InfoDict | None = None) -> None:
import json

data = {"times": self.times, "length_scales": self.length_scales}
with open(self.filename, "w") as fp:
with Path(self.filename).open("w") as fp:
json.dump(data, fp)


Expand Down Expand Up @@ -153,7 +154,7 @@ def __init__(
.. code-block:: python
droplet_tracker = DropletTracker(
1, refine=True, refine_args={'vmin': None, 'vmax': None}
1, refine=True, refine_args={"vmin": None, "vmax": None}
)
:code:`field` is the scalar field, in which the droplets are located. The
Expand Down
1 change: 1 addition & 0 deletions examples/tutorial/Using the py-droplets package.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"\n",
"# import necessary packages\n",
"import pde\n",
"\n",
"import droplets"
]
},
Expand Down
35 changes: 35 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,41 @@ namespaces = false

[tool.setuptools_scm]
write_to = "droplets/_version.py"
[tool.ruff]
target-version = "py38"
exclude = ["scripts/templates"]

[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint]
select = [
"UP", # pyupgrade
"I", # isort
"A", # flake8-builtins
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"FA", # flake8-future-annotations
"ISC", # flake8-implicit-str-concat
"ICN", # flake8-import-conventions
"LOG", # flake8-logging
"G", # flake8-logging-format
"PIE", # flake8-pie
"PT", # flake8-pytest-style
"Q", # flake8-quotes
"RSE", # flake8-raise
"RET", # flake8-return
"SIM", # flake8-simplify
"PTH", # flake8-use-pathlib
]
ignore = ["B007", "B027", "B028", "SIM108", "ISC001", "PT006", "PT011", "RET504", "RET505", "RET506"]

[tool.ruff.lint.isort]
section-order = ["future", "standard-library", "third-party", "first-party", "my-modules", "self", "local-folder"]

[tool.ruff.lint.isort.sections]
my-modules = ["pde"]
self = ["droplets"]

[tool.black]
target_version = ["py39"]
Expand Down
4 changes: 2 additions & 2 deletions scripts/format_code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ find . -name '*.py' -exec pyupgrade --py39-plus {} +
popd > /dev/null

echo "Formating import statements..."
isort ..
ruff check --fix --config=../pyproject.toml ..

echo "Formating docstrings..."
docformatter --in-place --black --recursive ..

echo "Formating source code..."
black ..
ruff format --config=../pyproject.toml ..
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pde.tools.numba import random_seed


@pytest.fixture(scope="function", autouse=False, name="rng")
@pytest.fixture(autouse=False, name="rng")
def init_random_number_generators():
"""Get a random number generator and set the seed of the random number generator.
Expand All @@ -21,8 +21,8 @@ def init_random_number_generators():
return np.random.default_rng(0)


@pytest.fixture(scope="function", autouse=True)
def setup_and_teardown():
@pytest.fixture(autouse=True)
def _setup_and_teardown():
"""Helper function adjusting environment before and after tests."""
# ensure we use the Agg backend, so figures are not displayed
plt.switch_backend("agg")
Expand Down
3 changes: 1 addition & 2 deletions tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
-r ../requirements.txt
black>=24
docformatter>=1.7
isort>=5.1
pyupgrade>=3
pytest>=5.4
pytest-cov>=2.8
pytest-xdist>=1.30
mypy>=0.770
ruff>=0.6
types-PyYAML
types-tqdm
Loading

0 comments on commit 7e1f6a4

Please sign in to comment.