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

Add more pre-commit checks (mccabe, bandit, mypy, etc) #557

Merged
merged 24 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d2c252e
Add more pre-commit checks (mccabe, bandit, mypy, etc) and initial run
djhoese Nov 17, 2023
f07a571
Fix bandit issues
djhoese Nov 17, 2023
14331e4
Fix tests expecting AssertionErrors
djhoese Nov 17, 2023
33f8198
Fix various type annotations
djhoese Nov 18, 2023
db6eaf9
Move BaseDefinition.get_edge_bbox_in_projection_coordinates to AreaDe…
djhoese Nov 18, 2023
b1698bd
Fix type annotations in area_config.py
djhoese Nov 18, 2023
c3edc72
Fix more type annotation issues
djhoese Nov 18, 2023
e278c17
Reduce code complexity in CF utilities
djhoese Nov 18, 2023
4362138
Reduce code complexity in spherical code
djhoese Nov 18, 2023
bedf264
More complexity fixes
djhoese Nov 18, 2023
28c7a2d
Refactor unit handling in area_config.py
djhoese Nov 19, 2023
a960a79
Refactor legacy area file parsing
djhoese Nov 19, 2023
a88f9f8
Refactor subargument handling in area_config.py
djhoese Nov 19, 2023
216a7f0
Refactor BaseDefinition.__eq__
djhoese Nov 19, 2023
f2c7801
Refactor nearest neighbour numpy function
djhoese Nov 19, 2023
9e549ab
Refactor xarray nearest neighbor
djhoese Nov 19, 2023
e1595a5
Fix use of undefined stddev and count
djhoese Nov 19, 2023
cedad85
Fix kdtree final output shape handling
djhoese Nov 20, 2023
ab1296d
Resolve some ruff errors
djhoese Nov 20, 2023
80c4445
Rework CF utilities to provide more useful exceptions
djhoese Nov 20, 2023
aac558c
Fix more ruff issues
djhoese Nov 20, 2023
9d846db
Fix missing docstring arguments
djhoese Nov 20, 2023
0c64ed5
Remove unnecessary flake8 plugins and old bumpversion config
djhoese Nov 21, 2023
a7e1f25
Merge branch 'main' into precommit-mypy
djhoese Nov 21, 2023
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
3 changes: 3 additions & 0 deletions .bandit
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[bandit]
skips: B506
exclude: pyresample/test,pyresample/version.py,versioneer.py
9 changes: 4 additions & 5 deletions .bumpversion.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ current_version = 1.10.2a0.dev0
commit = True
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((?P<pre>[a-z]+)(?P<num>\d+))?(\.(?P<release>dev)(?P<dev>\d+))?
serialize =
djhoese marked this conversation as resolved.
Show resolved Hide resolved
serialize =
{major}.{minor}.{patch}{pre}{num}.{release}{dev}
{major}.{minor}.{patch}{pre}{num}
{major}.{minor}.{patch}.{release}{dev}
Expand All @@ -13,12 +13,12 @@ serialize =

[bumpversion:part:release]
optional_value = gamma
values =
values =
dev
gamma

[bumpversion:part:dev]
values =
values =
0
1
2
Expand All @@ -28,9 +28,8 @@ optional_value = 4

[bumpversion:part:pre]
optional_value = final
values =
values =
a
b
rc
final

2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
```
#### Problem description

[this should also explain **why** the current behaviour is a problem and why the
[this should also explain **why** the current behaviour is a problem and why the
expected output is a better solution.]

#### Expected Output
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,3 @@ jobs:
uses: AndreMiras/coveralls-python-action@develop
with:
parallel-finished: true

28 changes: 26 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,31 @@ repos:
rev: 6.1.0
hooks:
- id: flake8
additional_dependencies: [flake8-docstrings, flake8-debugger, flake8-bugbear]
additional_dependencies: [flake8-docstrings, flake8-debugger, flake8-bugbear, mccabe]
args: [--max-complexity, "10"]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
args: [--unsafe]
- repo: https://github.com/PyCQA/bandit
rev: '1.7.5' # Update me!
hooks:
- id: bandit
args: [--ini, .bandit]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.6.1' # Use the sha / tag you want to point at
hooks:
- id: mypy
additional_dependencies:
- types-docutils
- types-pkg-resources
- types-PyYAML
- types-requests
- type_extensions
args: ["--python-version", "3.9", "--ignore-missing-imports"]
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
Expand All @@ -14,4 +38,4 @@ repos:
ci:
# To trigger manually, comment on a pull request with "pre-commit.ci autofix"
autofix_prs: false

skip: [bandit]
2 changes: 1 addition & 1 deletion CITATION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
To find out how to reference pyresample, go to https://doi.org/10.5281/zenodo.3372769 and choose your favourite citation format on the bottom of the right hand side-bar.
To find out how to reference pyresample, go to https://doi.org/10.5281/zenodo.3372769 and choose your favourite citation format on the bottom of the right hand side-bar.
3 changes: 2 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ recursive-include docs/source *
include pyresample/test/test_files/*
include LICENSE.txt
include pyresample/ewa/_fornav_templates.*
include pyresample/py.typed
include versioneer.py
include pyresample/version.py
include README.md
recursive-include pyresample *.pyx
recursive-include pyresample *.pyx
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Pyresample offers multiple resampling algorithms including:
- Bilinear

For nearest neighbor and bilinear interpolation pyresample uses a kd-tree
approach by using the fast KDTree implementation provided by the
approach by using the fast KDTree implementation provided by the
[pykdtree](https://github.com/storpipfugl/pykdtree) library.
Pyresample works with numpy arrays and numpy masked arrays. Interfaces to
XArray objects (including dask array support) are provided in separate
Expand All @@ -38,4 +38,3 @@ PyTroll group and related packages.
Citation
----------
Hoese, D., Raspaud, M., Lahtinen, P., Roberts, W., Lavergne, et al. (2020). pytroll/pyresample: Version 1.16.0. Zenodo. [https://doi.org/10.5281/zenodo.3372769](https://doi.org/10.5281/zenodo.3372769)

3 changes: 0 additions & 3 deletions changelog_pre1.9.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,3 @@ Other
- No commit message. [StorPipfugl]
- Moved to Google Code under GPLv3 license. [StorPipfugl]
- moved to Google Code. [StorPipfugl]



2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ Pyresample's API has changed (new functions, modules, classes, etc) then the
API documentation should be regenerated before running the above make
command.

sphinx-apidoc -f -T -o source/api ../pyresample ../pyresample/test
sphinx-apidoc -f -T -o source/api ../pyresample ../pyresample/test
3 changes: 2 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
"""Sphinx documentation configuration."""
from __future__ import annotations

import os
import sys
Expand Down Expand Up @@ -111,7 +112,7 @@

# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = []
exclude_trees: list[str] = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does mypy really need to run on this file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but I also don't mind it. I noticed in a new project that sphinx now removes all unnecessary/optional arguments from conf.py when you run the quickstart command. We could consider comparing that to what is in this conf.py and clearing unused things out.


# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None
Expand Down
2 changes: 1 addition & 1 deletion docs/source/dev_guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ The documentation is split into 4 main groups:
Put another way, the user knows what they want to do, the how-to shows them
how to do it. How-tos should still not go into any more detail than
necessary and try to depend on :doc:`../concepts/index`.
4. Reference: API docs and other low-level information.
4. Reference: API docs and other low-level information.
23 changes: 11 additions & 12 deletions docs/source/howtos/data_reduce.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Reduction of swath data
=======================
Given a swath and a cartesian grid or grid lons and lats, pyresample can reduce the swath data
to only the relevant part covering the grid area. The reduction is coarse in order not to risk removing
to only the relevant part covering the grid area. The reduction is coarse in order not to risk removing
relevant data.

From **data_reduce** the function **swath_from_lonlat_grid** can be used to reduce the swath data set to the
From **data_reduce** the function **swath_from_lonlat_grid** can be used to reduce the swath data set to the
area covering the lon lat grid

.. doctest::
Expand All @@ -14,7 +14,7 @@ area covering the lon lat grid
>>> area_def = geometry.AreaDefinition('areaD', 'Europe (3km, HRV, VTC)', 'areaD',
... {'a': '6378144.0', 'b': '6356759.0',
... 'lat_0': '50.00', 'lat_ts': '50.00',
... 'lon_0': '8.00', 'proj': 'stere'},
... 'lon_0': '8.00', 'proj': 'stere'},
... 800, 800,
... [-1370912.72, -909968.64,
... 1029087.28, 1490031.36])
Expand All @@ -23,32 +23,31 @@ area covering the lon lat grid
>>> lats = np.fromfunction(lambda y, x: 75 - y, (50, 10))
>>> grid_lons, grid_lats = area_def.get_lonlats()
>>> reduced_lons, reduced_lats, reduced_data = \
... data_reduce.swath_from_lonlat_grid(grid_lons, grid_lats,
... lons, lats, data,
... data_reduce.swath_from_lonlat_grid(grid_lons, grid_lats,
... lons, lats, data,
... radius_of_influence=3000)

**radius_of_influence** is used to calculate a buffer zone around the grid where swath data points
are not reduced.

The function **get_valid_index_from_lonlat_grid** returns a boolean array of same size as the swath
indicating the relevant swath data points compared to the grid

.. doctest::

>>> import numpy as np
>>> from pyresample import geometry, data_reduce
>>> area_def = geometry.AreaDefinition('areaD', 'Europe (3km, HRV, VTC)', 'areaD',
... {'a': '6378144.0', 'b': '6356759.0',
... 'lat_0': '50.00', 'lat_ts': '50.00',
... 'lon_0': '8.00', 'proj': 'stere'},
... 'lon_0': '8.00', 'proj': 'stere'},
... 800, 800,
... [-1370912.72, -909968.64,
... 1029087.28, 1490031.36])
>>> data = np.fromfunction(lambda y, x: y*x, (50, 10))
>>> lons = np.fromfunction(lambda y, x: 3 + x, (50, 10))
>>> lats = np.fromfunction(lambda y, x: 75 - y, (50, 10))
>>> grid_lons, grid_lats = area_def.get_lonlats()
>>> valid_index = data_reduce.get_valid_index_from_lonlat_grid(grid_lons, grid_lats,
... lons, lats,
>>> valid_index = data_reduce.get_valid_index_from_lonlat_grid(grid_lons, grid_lats,
... lons, lats,
... radius_of_influence=3000)

1 change: 0 additions & 1 deletion docs/source/howtos/geo_def.rst
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,3 @@ using the **projection_x_coord** or **projection_y_coords** property of a geogra
>>> area_def = AreaDefinition(area_id, description, proj_id, projection,
... width, height, area_extent)
>>> proj_x_range = area_def.projection_x_coords

8 changes: 4 additions & 4 deletions docs/source/howtos/geo_filter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ a full globe Plate Carrée projection using an 8x8 filter mask
>>> import numpy as np
>>> from pyresample import geometry, geo_filter
>>> lons = np.array([-170, -30, 30, 170])
>>> lats = np.array([20, -40, 50, -80])
>>> lats = np.array([20, -40, 50, -80])
>>> swath_def = geometry.SwathDefinition(lons, lats)
>>> data = np.array([1, 2, 3, 4])
>>> filter_area = geometry.AreaDefinition('test', 'test', 'test',
>>> filter_area = geometry.AreaDefinition('test', 'test', 'test',
... {'proj' : 'eqc', 'lon_0' : 0.0, 'lat_0' : 0.0},
... 8, 8,
... 8, 8,
... (-20037508.34, -10018754.17, 20037508.34, 10018754.17)
... )
>>> filter = np.array([[1, 1, 1, 1, 0, 0, 0, 0],
Expand All @@ -38,4 +38,4 @@ a full globe Plate Carrée projection using an 8x8 filter mask
Input swath_def and data must match as described in :ref:`swath`.

The returned data will always have a 1D geometry_def and if multiple channels are present the filtered
data will have the shape (number_of_points, channels).
data will have the shape (number_of_points, channels).
26 changes: 12 additions & 14 deletions docs/source/howtos/grid.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ using the method **get_array_from_linesample**
Resampling can be done using descendants of **ImageContainer** and calling their **resample** method.

An **ImageContainerQuick** object allows for the grid to be resampled to a new area defintion
using an approximate (but fast) nearest neighbour method.
Resampling an object of type **ImageContainerQuick** returns a new object of type **ImageContainerQuick**.
using an approximate (but fast) nearest neighbour method.
Resampling an object of type **ImageContainerQuick** returns a new object of type **ImageContainerQuick**.

An **ImageContainerNearest** object allows for the grid to be resampled to a new area defintion (or swath definition)
using an accurate kd-tree method.
Resampling an object of type **ImageContainerNearest** returns a new object of
type **ImageContainerNearest**.
Resampling an object of type **ImageContainerNearest** returns a new object of
type **ImageContainerNearest**.

.. doctest::

Expand All @@ -32,7 +32,7 @@ type **ImageContainerNearest**.
>>> area_def = geometry.AreaDefinition('areaD', 'Europe (3km, HRV, VTC)', 'areaD',
... {'a': '6378144.0', 'b': '6356759.0',
... 'lat_0': '50.00', 'lat_ts': '50.00',
... 'lon_0': '8.00', 'proj': 'stere'},
... 'lon_0': '8.00', 'proj': 'stere'},
... 800, 800,
... [-1370912.72, -909968.64,
... 1029087.28, 1490031.36])
Expand All @@ -54,7 +54,7 @@ type **ImageContainerNearest**.

Data is assumed to be a numpy array of shape (rows, cols) or (rows, cols, channels).

Masked arrays can be used as data input. In order to have undefined pixels masked out instead of
Masked arrays can be used as data input. In order to have undefined pixels masked out instead of
assigned a fill value set **fill_value=None** when calling **resample_area_***.

Using **ImageContainerQuick** the risk of image artifacts increases as the distance
Expand All @@ -81,7 +81,7 @@ The constructor arguments of an ImageContainer object can be changed as attribut
>>> msg_con_nn = image.ImageContainerNearest(data, msg_area, radius_of_influence=50000)
>>> msg_con_nn.radius_of_influence = 45000
>>> msg_con_nn.fill_value = -99

Multi channel images
********************

Expand All @@ -104,23 +104,23 @@ If the dataset has several channels the last index of the data array specifies t
>>> channel3 = np.ones((3712, 3712)) * 3
>>> data = np.dstack((channel1, channel2, channel3))
>>> msg_con_nn = image.ImageContainerNearest(data, msg_area, radius_of_influence=50000)


Segmented resampling
********************

Pyresample calculates the result in segments in order to reduce memory footprint. This is controlled by the **segments** contructor keyword argument. If no **segments** argument is given pyresample will estimate the number of segments to use.

Forcing quick resampling to use 4 resampling segments:

.. doctest::

>>> import numpy as np
>>> from pyresample import image, geometry
>>> area_def = geometry.AreaDefinition('areaD', 'Europe (3km, HRV, VTC)', 'areaD',
... {'a': '6378144.0', 'b': '6356759.0',
... 'lat_0': '50.00', 'lat_ts': '50.00',
... 'lon_0': '8.00', 'proj': 'stere'},
... 'lon_0': '8.00', 'proj': 'stere'},
... 800, 800,
... [-1370912.72, -909968.64,
... 1029087.28, 1490031.36])
Expand All @@ -141,7 +141,7 @@ Constructor arguments
The full list of constructor arguments:

**ImageContainerQuick**:

* image_data : Dataset. Masked arrays can be used.
* geo_def : Geometry definition.
* fill_value (optional) : Fill value for undefined pixels. Defaults to 0. If set to **None** they will be masked out.
Expand All @@ -162,5 +162,3 @@ The full list of constructor arguments:
Preprocessing of grid resampling
*********************************
For preprocessing of grid resampling see :ref:`preproc`


12 changes: 6 additions & 6 deletions docs/source/howtos/multi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ Using multiple processor cores
Multi core processing
*********************

Bottlenecks of pyresample can be executed in parallel. Parallel computing can be executed if the
pyresample function has the **nprocs** keyword argument. **nprocs** specifies the number of processes
Bottlenecks of pyresample can be executed in parallel. Parallel computing can be executed if the
pyresample function has the **nprocs** keyword argument. **nprocs** specifies the number of processes
to be used for calculation. If a class takes the constructor argument **nprocs** this sets **nprocs** for
all methods of this class

Expand All @@ -20,7 +20,7 @@ Example of resampling in parallel using 4 processes:
>>> area_def = geometry.AreaDefinition('areaD', 'Europe (3km, HRV, VTC)', 'areaD',
... {'a': '6378144.0', 'b': '6356759.0',
... 'lat_0': '50.00', 'lat_ts': '50.00',
... 'lon_0': '8.00', 'proj': 'stere'},
... 'lon_0': '8.00', 'proj': 'stere'},
... 800, 800,
... [-1370912.72, -909968.64,
... 1029087.28, 1490031.36])
Expand All @@ -31,9 +31,9 @@ Example of resampling in parallel using 4 processes:
>>> result = kd_tree.resample_nearest(swath_def, data.ravel(),
... area_def, radius_of_influence=50000, nprocs=4)

Note: Do not use more processes than available processor cores. As there is a process creation overhead
there might be neglible performance improvement using say 8 compared to 4 processor cores.
Test on the actual system to determine the most sensible number of processes to use.
Note: Do not use more processes than available processor cores. As there is a process creation overhead
there might be neglible performance improvement using say 8 compared to 4 processor cores.
Test on the actual system to determine the most sensible number of processes to use.

Here is an example of the performance for a varying number of processors on a 64-bit ubuntu 14.04, 32 GB RAM, 2 x Intel Xeon E5-2630 with 6 physical cores each:

Expand Down
10 changes: 5 additions & 5 deletions docs/source/howtos/plot.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,18 @@ file that defines the :code:`ease_sh` area, or see
>>> result = resample_nearest(swath_def, tb37v, area_def,
... radius_of_influence=20000, fill_value=None)
>>> save_quicklook('tb37v_quick.png', area_def, result, label='Tb 37v (K)')

Assuming **lons**, **lats** and **tb37v** are initialized with real data (as in
the above Satpy_ example) the result might look something like this:

.. image:: /_static/images/tb37v_quick.png

The data passed to the functions is a 2D array matching the AreaDefinition.

.. include:: plot_projections.rst
.. include:: plot_cartopy_basemap.rst
.. include:: plot_cartopy_basemap.rst


.. _Satpy: http://www.github.com/pytroll/satpy
.. _zenodo: https://doi.org/10.5281/zenodo.3553696
.. _`Cartopy gallery example`: http://scitools.org.uk/cartopy/docs/v0.16/gallery/geostationary.html
Expand Down
Loading
Loading