From 6d7253994033b077aa745634a34a44f238b731de Mon Sep 17 00:00:00 2001 From: Domagoj Fijan <50439291+DomFijan@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:04:22 -0400 Subject: [PATCH] Switch linting to ruff (#203) * use ruff instead of flake8 and others * fine tune ruff to be more similar to what we used so far * enable E721 * ruff (pydocstyle) fixes for previously ignored rules * Fixed typo * update changelog and credits * fixes for B904 * apply B028 * change variable name from e to exception * update pre-commit ruff args so that it exits with 0 on successful fix * Updated doc/development.rst * Fixed ruff order for manual runs --------- Co-authored-by: janbridley --- .pre-commit-config.yaml | 42 +++----------------- ChangeLog.rst | 1 + Credits.rst | 1 + coxeter/families/common.py | 6 ++- coxeter/families/plane_shape_families.py | 21 ++++++---- coxeter/families/tabulated_shape_family.py | 9 +++-- coxeter/shape_getters.py | 5 ++- coxeter/shapes/base_classes.py | 16 +++++--- coxeter/shapes/circle.py | 3 +- coxeter/shapes/convex_polygon.py | 4 +- coxeter/shapes/convex_polyhedron.py | 5 ++- coxeter/shapes/convex_spheropolyhedron.py | 3 +- coxeter/shapes/ellipse.py | 3 +- coxeter/shapes/ellipsoid.py | 3 +- coxeter/shapes/polygon.py | 12 ++++-- coxeter/shapes/polyhedron.py | 21 ++++++---- coxeter/shapes/sphere.py | 3 +- coxeter/shapes/utils.py | 9 +++-- doc/source/development.rst | 8 +++- pyproject.toml | 45 ++++++++++++++-------- setup.cfg | 13 ------- 21 files changed, 124 insertions(+), 109 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 490cd8e3..e8710181 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,52 +19,20 @@ repos: - id: check-executables-have-shebangs - id: check-json - id: check-yaml - - repo: https://github.com/asottile/pyupgrade - rev: 'v3.8.0' + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.291 hooks: - - id: pyupgrade - args: - - --py38-plus - exclude: '(?:extern/.*)' - - repo: https://github.com/PyCQA/isort - rev: '5.12.0' - hooks: - - id: isort - exclude: '(?:extern/.*)' + - id: ruff + args: [ --fix ] + types_or: [python, pyi, jupyter] - repo: https://github.com/psf/black rev: '23.3.0' hooks: - id: black exclude: '(?:extern/.*)' - - repo: https://github.com/PyCQA/pydocstyle - rev: '6.3.0' - hooks: - - id: pydocstyle - exclude: '(?:extern/.*|tests/.*|setup.py|conf.py)' - additional_dependencies: [ - 'tomli' - ] - - repo: https://github.com/PyCQA/flake8 - rev: '6.0.0' - hooks: - - id: flake8 - additional_dependencies: [ - 'flake8-bugbear==22.1.11', - 'flake8-rst-docstrings==0.2.5', - 'pep8==1.7.1', - 'pep8-naming==0.12.1', - 'flake8-comprehensions==3.8.0', - ] - repo: https://github.com/nbQA-dev/nbQA rev: 1.7.0 hooks: - - id: nbqa-pyupgrade - args: - - --nbqa-mutate - - --py36-plus - - id: nbqa-isort - args: - - --nbqa-mutate - id: nbqa-black args: - --nbqa-mutate diff --git a/ChangeLog.rst b/ChangeLog.rst index 5c6ef0b2..a4d03401 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -11,6 +11,7 @@ Added Changed ~~~~~~~ +- Pre-commit now uses ruff instead of flake8, pydocstyle, pyupgrade and isort. - CI now uses GitHub Actions. - Docs ported to furo theme. diff --git a/Credits.rst b/Credits.rst index b3ec4562..530e8159 100644 --- a/Credits.rst +++ b/Credits.rst @@ -118,6 +118,7 @@ Domagoj Fijan * Rewrote point in polygon check to use NumPy vectorized operations. * Rewrote point in polyhedron check to use NumPy vectorized operations. +* Pre-commit now uses ruff instead of flake8, pydocstyle, pyupgrade and isort. * Ported CI to github actions. * Ported docs to Furo. diff --git a/coxeter/families/common.py b/coxeter/families/common.py index 0f5a9ce6..c232e325 100644 --- a/coxeter/families/common.py +++ b/coxeter/families/common.py @@ -35,7 +35,8 @@ def get_shape(cls, n): n (int): The number of vertices (greater than or equal to 3). - Returns: + Returns + ------- :class:`~.ConvexPolygon`: The corresponding regular polygon. """ return ConvexPolygon(cls.make_vertices(n)) @@ -48,7 +49,8 @@ def make_vertices(cls, n): n (int): An integer greater than or equal to 3. - Returns: + Returns + ------- :math:`(n, 3)` :class:`numpy.ndarray` of float: The vertices of the polygon. """ if n < 3: diff --git a/coxeter/families/plane_shape_families.py b/coxeter/families/plane_shape_families.py index 81989b0f..965f105f 100644 --- a/coxeter/families/plane_shape_families.py +++ b/coxeter/families/plane_shape_families.py @@ -42,7 +42,8 @@ class TruncationPlaneShapeFamily(ShapeFamily): def get_planes(cls): """Get the set of planes used to truncate the shape. - Returns: + Returns + ------- (:math:`N_{planes}`, 3) :class:`numpy.ndarray` of float: The planes defining this family """ @@ -58,7 +59,8 @@ def get_plane_types(cls): * type 1 corresponds to the parameter b. * type 2 corresponds to the parameter c. - Returns: + Returns + ------- (:math:`N_{planes}`, ) :class:`numpy.ndarray` of int: The plane types. """ @@ -73,7 +75,8 @@ def make_vertices(cls, a, b, c): b (float): The b parameter. c (float): The c parameter. - Returns: + Returns + ------- (:math:`N_{vertices}`, 3) :class:`numpy.ndarray` of float: The vertices of the shape generated by the provided parameters. """ @@ -174,7 +177,8 @@ def get_shape(cls, a, c): c (float): The parameter :math:`c \in [1, 3]`. - Returns: + Returns + ------- :class:`~coxeter.shapes.ConvexPolyhedron`: The desired shape. """ @@ -246,7 +250,8 @@ def get_shape(cls, a, c): c (float): The parameter :math:`c \in [2, 3]`. - Returns: + Returns + ------- :class:`~coxeter.shapes.ConvexPolyhedron`: The desired shape. """ @@ -426,7 +431,8 @@ def get_shape(cls, a, c): c (float): The parameter :math:`c \in [S^2, 3]`. - Returns: + Returns + ------- :class:`~coxeter.shapes.ConvexPolyhedron`: The desired shape. """ @@ -463,7 +469,8 @@ def get_shape(cls, truncation): truncation (float): The parameter :math:`truncation \in [0, 1]`. - Returns: + Returns + ------- :class:`~coxeter.shapes.ConvexPolyhedron`: The desired truncated tetrahedron. """ diff --git a/coxeter/families/tabulated_shape_family.py b/coxeter/families/tabulated_shape_family.py index 3f88a660..ac078050 100644 --- a/coxeter/families/tabulated_shape_family.py +++ b/coxeter/families/tabulated_shape_family.py @@ -48,7 +48,8 @@ def from_mapping(cls, mapping, classname=None, docstring=None): docstring (str, optional): The docstring to apply to the class. - Returns: + Returns + ------- A subclass of this one associated with the the provided data. """ @@ -79,7 +80,8 @@ def from_json_file(cls, filename, *args, **kwargs): \*\*kwargs: Passed on to :meth:`~.from_mapping`. - Returns: + Returns + ------- A subclass of this one associated with the the provided data. """ with open(filename) as f: @@ -108,7 +110,8 @@ def get_shape(cls, name): name (str): The key of the desired shape in the data dict. - Returns: + Returns + ------- :class:`~coxeter.shapes.Shape`: The requested shape. """ return from_gsd_type_shapes(cls.data[name]) diff --git a/coxeter/shape_getters.py b/coxeter/shape_getters.py index 42f37e52..472d8aa1 100644 --- a/coxeter/shape_getters.py +++ b/coxeter/shape_getters.py @@ -1,7 +1,7 @@ # Copyright (c) 2021 The Regents of the University of Michigan # All rights reserved. # This software is licensed under the BSD 3-Clause License. -"""This module defines various convenience functions for generating shapes. +"""Module for defining various convenience functions for shape generation. The methods here provide routes for generating instances of :class:`~coxeter.shapes.Shape` based on certain pre-specified mappings. @@ -42,7 +42,8 @@ def from_gsd_type_shapes(params, dimensions=3): # noqa: C901 instead of a :class:`~.shapes.Sphere` or :class:`~.shapes.Ellipsoid` (Default value: 3). - Returns: + Returns + ------- :class:`~coxeter.shapes.Shape`: The desired shape. """ diff --git a/coxeter/shapes/base_classes.py b/coxeter/shapes/base_classes.py index 1f15ed7f..e66506d2 100644 --- a/coxeter/shapes/base_classes.py +++ b/coxeter/shapes/base_classes.py @@ -57,7 +57,8 @@ def is_inside(self, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the shape. """ @@ -117,7 +118,8 @@ def distance_to_surface(self, angles): Angles between :math:`0` and :math:`2 \pi` over which to calculate the distances. :math:`d` is the number of dimensions. - Returns: + Returns + ------- :math:`(N,)` :class:`numpy.ndarray`: An array of distances from the center of the shape to its surface at each of the given angles. @@ -164,11 +166,13 @@ def to_plato_scene(self, backend="matplotlib", scene=None, scene_kwargs=None): (Default value: None). Only used if ``scene`` is not provided or None. - Returns: + Returns + ------- :class:`plato.draw.Scene`: A scene containing this shape. - Raises: + Raises + ------ NotImplementedError: If no plato primitive corresponds to this coxeter shape class. AttributeError: @@ -180,10 +184,10 @@ def to_plato_scene(self, backend="matplotlib", scene=None, scene_kwargs=None): import importlib backend = importlib.import_module(f"plato.draw.{backend}") - except ImportError: + except ImportError as exception: raise ImportError( f"Backend plato.draw.{backend} could not be imported." - ) + ) from exception if scene_kwargs is None: scene_kwargs = {} prim = self._plato_primitive(backend) diff --git a/coxeter/shapes/circle.py b/coxeter/shapes/circle.py index 0c5cf90e..219c95a9 100644 --- a/coxeter/shapes/circle.py +++ b/coxeter/shapes/circle.py @@ -166,7 +166,8 @@ def is_inside(self, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the circle. diff --git a/coxeter/shapes/convex_polygon.py b/coxeter/shapes/convex_polygon.py index b8898480..e4dee5ec 100644 --- a/coxeter/shapes/convex_polygon.py +++ b/coxeter/shapes/convex_polygon.py @@ -25,7 +25,8 @@ def _is_convex(vertices, normal): normal (:math:`(3, )` :class:`numpy.ndarray`): The normal to the vertices. - Returns: + Returns + ------- bool: ``True`` if ``vertices`` define a convex polygon. """ @@ -168,6 +169,7 @@ def incircle_from_center(self): "The incircle_from_center property is deprecated, use " "maximal_centered_bounded_circle instead.", DeprecationWarning, + stacklevel=2, ) return self.maximal_centered_bounded_circle diff --git a/coxeter/shapes/convex_polyhedron.py b/coxeter/shapes/convex_polyhedron.py index 2b3bcac6..6645f61e 100644 --- a/coxeter/shapes/convex_polyhedron.py +++ b/coxeter/shapes/convex_polyhedron.py @@ -143,7 +143,8 @@ def is_inside(self, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the polyhedron. @@ -157,6 +158,7 @@ def insphere_from_center(self): "The insphere_from_center property is deprecated, use " "maximal_centered_bounded_sphere instead", DeprecationWarning, + stacklevel=2, ) return self.maximal_centered_bounded_sphere @@ -172,6 +174,7 @@ def circumsphere_from_center(self): "The circumsphere_from_center property is deprecated, use " "minimal_centered_bounding_sphere instead", DeprecationWarning, + stacklevel=2, ) return self.minimal_centered_bounding_sphere diff --git a/coxeter/shapes/convex_spheropolyhedron.py b/coxeter/shapes/convex_spheropolyhedron.py index ac663c49..bd112740 100644 --- a/coxeter/shapes/convex_spheropolyhedron.py +++ b/coxeter/shapes/convex_spheropolyhedron.py @@ -190,7 +190,8 @@ def is_inside(self, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the spheropolyhedron. diff --git a/coxeter/shapes/ellipse.py b/coxeter/shapes/ellipse.py index 34bb6a47..39b366ea 100644 --- a/coxeter/shapes/ellipse.py +++ b/coxeter/shapes/ellipse.py @@ -242,7 +242,8 @@ def is_inside(self, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the ellipsoid. diff --git a/coxeter/shapes/ellipsoid.py b/coxeter/shapes/ellipsoid.py index 719adcab..18799e52 100644 --- a/coxeter/shapes/ellipsoid.py +++ b/coxeter/shapes/ellipsoid.py @@ -184,7 +184,8 @@ def is_inside(self, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the ellipsoid. diff --git a/coxeter/shapes/polygon.py b/coxeter/shapes/polygon.py index 75942dc1..0e16f759 100644 --- a/coxeter/shapes/polygon.py +++ b/coxeter/shapes/polygon.py @@ -39,7 +39,8 @@ def _align_points_by_normal(normal, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points that will be rotated and returned. - Returns: + Returns + ------- :math:`(N, 3)` :class:`numpy.ndarray`: The rotated points. """ # Since we are considering just a single vector, to avoid getting a pure @@ -465,6 +466,7 @@ def bounding_circle(self): "The bounding_circle property is deprecated, use " "minimal_bounding_circle instead", DeprecationWarning, + stacklevel=2, ) return self.minimal_bounding_circle @@ -516,7 +518,8 @@ def circumcircle(self): of linear equations defined by this constraint, and the circumcircle only exists if the resulting solution has no residual. - Raises: + Raises + ------ RuntimeError: If no circumcircle exists for this polygon. """ # The circumsphere is defined by center C and radius r. For vertex i @@ -664,7 +667,7 @@ def compute_form_factor_amplitude(self, q, density=1.0): # noqa: D102 return form_factor def is_inside(self, points): - r"""Simple point-in-polygon algorithm based on winding number. + r"""Implement a simple point-in-polygon algorithm based on winding number. The code in this function is based on implementation in :cite:`Dickinson2019` which is licensed under the BSD-3 license. @@ -703,7 +706,8 @@ def is_inside(self, points): points (:math:`(N, 3)` or :math:`(N, 2)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the polyhedron. diff --git a/coxeter/shapes/polyhedron.py b/coxeter/shapes/polyhedron.py index 4f0997cf..24114cfe 100644 --- a/coxeter/shapes/polyhedron.py +++ b/coxeter/shapes/polyhedron.py @@ -34,7 +34,8 @@ def _face_to_edges(face, reverse=False): reverse (bool): Whether to return the edges in reverse. - Returns: + Returns + ------- list[tuple[int, int]]: A list of edges where each is a tuple of a pair of vertices. """ @@ -426,7 +427,8 @@ def get_face_area(self, faces=None): find the area. If None, finds the area of all faces (Default value: None). - Returns: + Returns + ------- :class:`numpy.ndarray`: The area of each face. Example: @@ -443,7 +445,7 @@ def get_face_area(self, faces=None): """ if faces is None: faces = range(len(self.faces)) - elif type(faces) is int: + elif isinstance(faces, int): faces = [faces] areas = np.empty(len(faces)) @@ -481,7 +483,8 @@ def _point_plane_distances(self, points): Distances that are <= 0 are inside and > 0 are outside. - Returns: + Returns + ------- :math:`(N_{points}, N_{planes})` :class:`numpy.ndarray`: The distance from each point to each plane. """ @@ -588,6 +591,7 @@ def bounding_sphere(self): "The bounding_sphere property is deprecated, use " "minimal_bounding_sphere instead", DeprecationWarning, + stacklevel=2, ) return self.minimal_bounding_sphere @@ -638,7 +642,8 @@ def circumsphere(self): of linear equations defined by this constraint, and the circumsphere only exists if the resulting solution has no residual. - Raises: + Raises + ------ RuntimeError: If no circumsphere exists for this polyhedron. """ # The circumsphere is defined by center C and radius r. For vertex i @@ -713,7 +718,8 @@ def get_dihedral(self, a, b): b (int): The index of the second face. - Returns: + Returns + ------- float: The dihedral angle in radians. Example: @@ -867,7 +873,8 @@ def is_inside(self, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the polyhedron. diff --git a/coxeter/shapes/sphere.py b/coxeter/shapes/sphere.py index 163466a3..f0f92c59 100644 --- a/coxeter/shapes/sphere.py +++ b/coxeter/shapes/sphere.py @@ -131,7 +131,8 @@ def is_inside(self, points): points (:math:`(N, 3)` :class:`numpy.ndarray`): The points to test. - Returns: + Returns + ------- :math:`(N, )` :class:`numpy.ndarray`: Boolean array indicating which points are contained in the sphere. diff --git a/coxeter/shapes/utils.py b/coxeter/shapes/utils.py index 5501e316..71e74ef0 100644 --- a/coxeter/shapes/utils.py +++ b/coxeter/shapes/utils.py @@ -40,14 +40,17 @@ def _generate_ax(ax=None, axes3d=False): axes3d (bool): Whether to use 3D axes (Default value: False). - Returns: + Returns + ------- :class:`matplotlib.axes.Axes`: Axes to plot on. """ if ax is None: try: import matplotlib.pyplot as plt - except ImportError: - raise ImportError("matplotlib must be installed for plotting.") + except ImportError as exception: + raise ImportError( + "matplotlib must be installed for plotting." + ) from exception fig = plt.figure() if not axes3d: ax = fig.subplots() diff --git a/doc/source/development.rst b/doc/source/development.rst index 4e30863c..70a06bde 100644 --- a/doc/source/development.rst +++ b/doc/source/development.rst @@ -69,11 +69,15 @@ All code should of course also follow the principles in `PEP 20