Skip to content

Commit

Permalink
Setup ruff rules + apply them
Browse files Browse the repository at this point in the history
  • Loading branch information
theroggy committed Sep 4, 2024
1 parent 3149ffd commit 3f1c288
Show file tree
Hide file tree
Showing 20 changed files with 257 additions and 236 deletions.
20 changes: 8 additions & 12 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
repos:
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
- repo: https://github.com/timothycrosley/isort
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.6.3"
hooks:
# Format the code
- id: ruff-format
# Lint the code
- id: ruff
# args: [ --fix ]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: 'v15.0.7'
hooks:
Expand Down
85 changes: 85 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,88 @@ wheel.packages=["python/src/exactextract"]
provider = "scikit_build_core.metadata.regex"
input = "cmake/VersionSource.cmake"
regex = "EXACTEXTRACT_VERSION_SOURCE \"(?P<value>.+)\""

[tool.ruff]
line-length = 88
extend-exclude = ["*.ipynb", "local_ignore/*"]

[tool.ruff.lint]
select = [
# pyflakes
"F",
# pycodestyle
"E",
"W",
# pyupgrade
"UP",
# flake8-bugbear
"B",
# flake8-debugger
"T10",
# flake8-simplify
# "SIM",
# pylint
"PLC",
"PLE",
"PLR",
"PLW",
# misc lints
"PIE",
# implicit string concatenation
"ISC",
# type-checking imports
"TCH",
# comprehensions
"C4",
# Ruff-specific rules
"RUF",
# isort
"I",
# pydocstyle
#"D",
]

ignore = [
### Intentionally disabled
# module level import not at top of file
"E402",
# do not assign a lambda expression, use a def
"E731",
# mutable-argument-default
"B006",
# unused-loop-control-variable
"B007",
# get-attr-with-constant
"B009",
# Only works with python >=3.10
"B905",
# dict literals
"C408",
# Too many arguments to function call
"PLR0913",
# Too many returns
"PLR0911",
# Too many branches
"PLR0912",
# Too many statements
"PLR0915",
# Magic number
"PLR2004",
# Consider `elif` instead of `else` then `if` to remove indentation level
"PLR5501",
# Redefined loop name
"PLW2901",
# Global statements are discouraged
"PLW0603",
# compare-to-empty-string
"PLC1901",
]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["D"]

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.lint.pyupgrade]
keep-runtime-typing = true
2 changes: 0 additions & 2 deletions python/doc/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
Expand Down Expand Up @@ -74,7 +73,6 @@


def autoapi_skip_member(app, what, name, obj, skip, options):

shortname = name.split(".")[-1]

# Don't emit documentation for anything named beginning with
Expand Down
4 changes: 2 additions & 2 deletions python/src/exactextract/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
""" Python bindings for exactextract """
"""Python bindings for exactextract."""
# ruff: noqa: F401

from ._exactextract import __version__
from .exact_extract import exact_extract
Expand Down
48 changes: 28 additions & 20 deletions python/src/exactextract/exact_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
import functools
import os
import warnings
from collections.abc import Mapping
from itertools import chain
from typing import Mapping, Optional
from typing import Optional

from .feature import (
FeatureSource,
Expand Down Expand Up @@ -40,7 +41,8 @@ def make_raster_names(root: str, nbands: int) -> list:

def prep_raster_gdal(rast, name_root=None) -> list:
try:
# eagerly import gdal_array to avoid possible ImportError when reading raster data
# eagerly import gdal_array to avoid possible ImportError when reading raster
# data
from osgeo import gdal, gdal_array # noqa: F401

if isinstance(rast, (str, os.PathLike)):
Expand Down Expand Up @@ -93,7 +95,6 @@ def prep_raster_rasterio(rast, name_root=None) -> list:


def prep_raster_xarray(rast, name_root=None) -> list:

try:
import rioxarray # noqa: F401
import xarray
Expand Down Expand Up @@ -240,7 +241,7 @@ def prep_ops(stats, values, weights=None, *, add_unique=False):
if "No weights provided" in str(e):
raise Exception(
f"No weights provided but {stat.__name__} expects 3 arguments"
)
) from None
else:
raise
elif isinstance(stat, Operation):
Expand Down Expand Up @@ -328,8 +329,10 @@ def warn_on_crs_mismatch(vec, ops):
if check_rast_vec and not crs_matches(vec, op.values):
check_rast_vec = False
warnings.warn(
"Spatial reference system of input features does not exactly match raster.",
"Spatial reference system of input features does not exactly match "
"raster.",
RuntimeWarning,
stacklevel=2,
)

if (
Expand All @@ -339,8 +342,10 @@ def warn_on_crs_mismatch(vec, ops):
):
check_rast_weights = False
warnings.warn(
"Spatial reference system of input features does not exactly match weighting raster.",
"Spatial reference system of input features does not exactly match "
"weighting raster.",
RuntimeWarning,
stacklevel=2,
)


Expand Down Expand Up @@ -396,22 +401,25 @@ def exact_extract(
a cost of higher memory usage.
max_cells_in_memory: Indicates the maximum number of raster cells that should be
loaded into memory at a given time.
grid_compat_tol: require value and weight grids to align within ``grid_compat_tol`` times the smaller of the two grid resolutions
grid_compat_tol: require value and weight grids to align within
``grid_compat_tol`` times the smaller of the two grid resolutions
output: An :py:class:`OutputWriter` or one of the following strings:
- "geojson" (the default): return a list of GeoJSON-like features
- "pandas": return a ``pandas.DataFrame`` or ``geopandas.GeoDataFrame``,
depending on the value of ``include_geom``
- "gdal": write results to disk using GDAL/OGR as they are written. This
option (with ``strategy="feature-sequential"``) avoids the need
to maintain results for all features in memory at a single time,
which may be significant for operations with large result sizes
such as ``cell_id``, ``values``, etc.
output_options: an optional dictionary of options passed to the :py:class:`writer.JSONWriter`, :py:class:`writer.PandasWriter`, or :py:class:`writer.GDALWriter`.
progress: if `True`, a progress bar will be displayed. Alternatively, a
function may be provided that will be called with the completion fraction
and a status message.
"""
- "geojson" (the default): return a list of GeoJSON-like features
- "pandas": return a ``pandas.DataFrame`` or ``geopandas.GeoDataFrame``,
depending on the value of ``include_geom``
- "gdal": write results to disk using GDAL/OGR as they are written. This
option (with ``strategy="feature-sequential"``) avoids the
need to maintain results for all features in memory at a
single time, which may be significant for operations with
large result sizes such as ``cell_id``, ``values``, etc.
output_options: an optional dictionary of options passed to the
:py:class:`writer.JSONWriter`, :py:class:`writer.PandasWriter`, or
:py:class:`writer.GDALWriter`.
progress: if `True`, a progress bar will be displayed. Alternatively, a function
may be provided that will be called with the completion fraction and a
status message.
""" # noqa: E501
rast = prep_raster(rast)
weights = prep_raster(weights, name_root="weight")
vec = prep_vec(vec)
Expand Down
38 changes: 18 additions & 20 deletions python/src/exactextract/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@


class FeatureSource(_FeatureSource):
"""
Source from which polygon features can be read.
"""Source from which polygon features can be read.
Several implementations are included in exactextract:
Expand All @@ -25,24 +24,26 @@ class FeatureSource(_FeatureSource):
"""

def __init__(self):
"""Constructor."""
super().__init__()


class GDALFeatureSource(FeatureSource):
"""
A FeatureSource using the GDAL/OGR Python interface to provide features.
"""
"""A FeatureSource using the GDAL/OGR Python interface to provide features."""

def __init__(self, src):
"""
"""Constructor.
Args:
src: one of the following
- string or Path to a file/datasource that can be opened with GDAL/OGR
- a ``gdal.Dataset``
- an ``ogr.DataSource``
- an ``ogr.Layer``
If the file has more than one layer, e.g., a GeoPackage, an
``ogr.Layer`` must be provided directly.
src: one of the following:
- string or Path to a file/datasource that can be opened with GDAL/OGR
- a ``gdal.Dataset``
- an ``ogr.DataSource``
- an ``ogr.Layer``
If the file has more than one layer, e.g., a GeoPackage, an
``ogr.Layer`` must be provided directly.
"""
super().__init__()

Expand All @@ -59,7 +60,8 @@ def __init__(self, src):
self.ds = src # keep a reference to ds
if nlayers > 1:
raise Exception(
"Can only process a single layer; call directly with ogr.Layer object."
"Can only process a single layer; call directly with ogr.Layer "
"object."
)

self.src = src.GetLayer(0)
Expand Down Expand Up @@ -124,9 +126,7 @@ def fields(self):


class JSONFeatureSource(FeatureSource):
"""
A FeatureSource providing GeoJSON-like features.
"""
"""A FeatureSource providing GeoJSON-like features."""

def __init__(self, src, *, srs_wkt=None):
super().__init__()
Expand Down Expand Up @@ -197,9 +197,7 @@ def fields(self):


class GeoPandasFeatureSource(FeatureSource):
"""
A FeatureSource using GeoPandas GeoDataFrame to provide features.
"""
"""A FeatureSource using GeoPandas GeoDataFrame to provide features."""

def __init__(self, src):
super().__init__()
Expand Down
Loading

0 comments on commit 3f1c288

Please sign in to comment.