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

Swapped to ruff for formatting and checking #68

Merged
merged 1 commit into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading