Skip to content

Commit 751bc5a

Browse files
Merge remote-tracking branch 'origin/v4-dev' into bugfix/2239-oob-spatialhash
2 parents 51b33c7 + 5ccc0bc commit 751bc5a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2119
-1966
lines changed

docs/community/contributing.rst

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ There are two primary groups that contribute to Parcels; oceanographers who brin
1818

1919
.. note::
2020

21-
The first component of this documentation is geared to those new to open source. Already familiar with GitHub and open source? Skip ahead to the `Editing Parcels code`_ section.
21+
The first component of this documentation is geared to those new to open source. Already familiar with GitHub and open source? Skip ahead to the `Development`_ section.
2222

2323
What is open source?
2424
--------------------
@@ -55,26 +55,85 @@ In the `Projects panel <https://github.com/OceanParcels/parcels/projects?query=i
5555

5656
.. _editing-parcels-code:
5757

58-
Editing Parcels code
59-
---------------------
58+
Development
59+
-----------
6060

61-
Development environment setup
62-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61+
Environment setup
62+
~~~~~~~~~~~~~~~~~
63+
64+
.. note::
65+
66+
Parcels, alongside popular projects like `Xarray <https://github.com/pydata/xarray>`_, uses `Pixi <https://pixi.sh>`_ to manage environments and run developer tooling. Pixi is a modern alternative to Conda and also includes other powerful tooling useful for a project like Parcels (`read more <https://github.com/OceanParcels/Parcels/issues/2205>`_). It is our sole development workflow - we do not offer a Conda development workflow. Give Pixi a try, you won't regret it!
6367

6468
To get started contributing to Parcels:
6569

66-
- `fork the repo <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo#forking-a-repository>`_
67-
- install the developer version of Parcels following `our developer installation instructions <../installation.rst#installation-for-developers>`_
68-
- but instead of cloning the Parcels repo, you should clone your fork
70+
**Step 1:** `Install Pixi <https://pixi.sh/latest/>`_.
71+
72+
**Step 2:** `Fork the repository <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo#forking-a-repository>`_
73+
74+
**Step 3:** Clone your fork and ``cd`` into the repository.
75+
76+
**Step 4:** Install the Pixi environment
77+
78+
.. code-block:: bash
79+
80+
pixi install
81+
82+
Now you have a development installation of Parcels, as well as a bunch of developer tooling to run tests, check code quality, and build the documentation! Simple as that.
83+
84+
Pixi workflows
85+
~~~~~~~~~~~~~~
86+
87+
You can use the following Pixi commands to run common development tasks.
88+
89+
**Testing**
90+
91+
- ``pixi run tests`` - Run the full test suite using pytest
92+
- ``pixi run tests-notebooks`` - Run notebook tests (specifically Argo-related examples)
93+
94+
95+
**Documentation**
6996

70-
Now you have a cloned repo that you have full control over, and a conda environment where Parcels is installed in an editable mode (i.e., any changes that you make to the Parcels code will take effect when you use that conda environment to run Python code).
97+
- ``pixi run docs`` - Build the documentation using Sphinx
98+
- ``pixi run docs-watch`` - Build and auto-rebuild documentation when files change (useful for live editing)
99+
- ``pixi run docs-linkcheck`` - Check for broken links in the documentation
100+
101+
**Code quality**
102+
103+
- ``pixi run lint`` - Run pre-commit hooks on all files (includes formatting, linting, and other code quality checks)
104+
- ``pixi run typing`` - Run mypy type checking on the codebase
105+
106+
**Different environments**
107+
108+
Parcels supports testing against different environments (e.g., different Python versions) with different feature sets. In CI we test against these environments, and you can too locally. For example:
109+
110+
- ``pixi run -e test-py311 tests`` - Run tests using Python 3.11
111+
- ``pixi run -e test-py312 tests`` - Run tests using Python 3.12
112+
113+
The name of the workflow on GitHub contains the command you have to run locally to recreate the workflow - making it super easy to reproduce CI failures locally.
114+
115+
**Typical development workflow**
116+
117+
1. Make your code changes
118+
2. Run ``pixi run lint`` to ensure code formatting and style compliance
119+
3. Run ``pixi run tests`` to verify your changes don't break existing functionality
120+
4. If you've added new features, run ``pixi run typing`` to check type annotations
121+
5. If you've modified documentation, run ``pixi run docs`` to build and verify the docs
122+
123+
.. tip::
124+
125+
You can run ``pixi info`` to see all available environments and ``pixi task list`` to see all available tasks across environments.
126+
127+
128+
Changing code
129+
~~~~~~~~~~~~~
71130

72131
From there:
73132

74133
- create a git branch, implement, commit, and push your changes
75134
- `create a pull request <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork>`_ (PR) into ``main`` of the original repo making sure to link to the issue that you are working on. Not yet finished with your feature but still want feedback on how you're going? Then mark it as "draft" and ``@ping`` a maintainer. See our `maintainer notes <maintainer.md>`_ to see our PR review workflow.
76135

77-
Look at the ``[tool.pixi.tasks]`` section of ``pyproject.toml`` for a list of tasks that are useful for development.
136+
78137

79138
Code guidelines
80139
~~~~~~~~~~~~~~~
@@ -85,10 +144,8 @@ Code guidelines
85144

86145
- Write clear commit messages that explain the changes you've made.
87146
- Include tests for any new code you write. Tests are implemented using pytest and are located in the ``tests`` directory.
88-
- Follow the `NumPy docstring conventions <https://numpydoc.readthedocs.io/en/latest/format.html>`_ when adding or modifying docstrings.
89-
- Follow the `PEP 8 <https://peps.python.org/pep-0008/>`_ style guide when writing code. This codebase also uses `flake8 <https://flake8.pycqa.org/en/latest/>`_ and `isort <https://pycqa.github.io/isort/>`_ to ensure a consistent code style.
90-
91-
If you're comfortable with these code guidelines, and want to enforce them on your local machine before pushing, you can install the Git hooks for the repo by running ``pre-commit install``. This will run tools to check your changes adhere to these guidelines as you make commits.
147+
- Follow the `NumPy docstring conventions <https://numpydoc.readthedocs.io/en/latest/format.html>`_ when adding or modifying public API docstrings.
148+
- Follow the `PEP 8 <https://peps.python.org/pep-0008/>`_ style guide when writing code. This codebase also uses additional tooling to enforce additional style guidelines. You can run this tooling with ``pixi run lint``, and see which tooling is run in the ``.pre-commit-config.yaml`` file.
92149

93150
----
94151

docs/installation.rst

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,41 +56,4 @@ The steps below are the installation instructions for Linux, macOS and Windows.
5656
Installation for developers
5757
===========================
5858

59-
Using Miniconda
60-
---------------
61-
62-
If you would prefer to have a development installation of Parcels (i.e., where the code can be actively edited), you can do so by setting up Miniconda (as detailed in step 1 above), cloning the Parcels repo, installing dependencies using the environment file, and then installing Parcels in an editable mode such that changes to the cloned code can be tested during development.
63-
64-
**Step 1:** Same as `step 1 above`_.
65-
66-
**Step 2:** Clone the Parcels repo and create a new environment with the development dependencies:
67-
68-
.. code-block:: bash
69-
70-
git clone https://github.com/OceanParcels/parcels.git
71-
cd parcels
72-
conda env create -n parcels-dev -f environment.yml
73-
74-
**Step 3:** Activate the environment and install Parcels in editable mode:
75-
76-
.. code-block:: bash
77-
78-
conda activate parcels-dev
79-
pip install --no-build-isolation --no-deps -e .
80-
81-
82-
Using Pixi
83-
----------
84-
For developers who want to use Pixi (a modern alternative to Anaconda - see `"Transitioning from the conda or mamba to pixi" <https://pixi.sh/latest/switching_from/conda/>`_) to manage their development environment, the following steps can be followed:
85-
86-
**Step 1:** `Install Pixi <https://pixi.sh/latest/>`_.
87-
88-
**Step 2:** Clone the Parcels repo and create a new environment with the development dependencies:
89-
90-
.. code-block:: bash
91-
92-
git clone https://github.com/OceanParcels/parcels.git
93-
cd parcels
94-
pixi install
95-
96-
Now you can use ``pixi run`` for a list of available tasks useful for development, such as running tests, checking code coverage, and building the documentation. You can also do ``pixi shell`` to "activate" the environment (and do ``exit`` to deactivate it). See `here <https://pixi.sh/latest/switching_from/conda/#key-differences-at-a-glance>`_ for a comparison between Pixi and Conda commands.
59+
See the `development section in our contributing guide <./community/contributing.rst#development>`_ for development instructions.

parcels/__init__.py

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,89 @@
22

33
__version__ = version
44

5-
import warnings as _warnings
5+
import warnings as _stdlib_warnings
66

7-
from parcels.application_kernels import *
8-
from parcels.field import *
9-
from parcels.fieldset import *
10-
from parcels.interaction import *
11-
from parcels.kernel import *
12-
from parcels.particle import *
13-
from parcels.particlefile import *
14-
from parcels.particleset import *
15-
from parcels.tools import *
7+
from parcels._core.basegrid import BaseGrid
8+
from parcels._core.converters import (
9+
Geographic,
10+
GeographicPolar,
11+
GeographicPolarSquare,
12+
GeographicSquare,
13+
UnitConverter,
14+
)
15+
from parcels._core.field import Field, VectorField
16+
from parcels._core.fieldset import FieldSet
17+
from parcels._core.kernel import Kernel
18+
from parcels._core.particle import (
19+
KernelParticle, # ? remove?
20+
Particle,
21+
ParticleClass,
22+
Variable,
23+
)
24+
from parcels._core.particlefile import ParticleFile
25+
from parcels._core.particleset import ParticleSet
26+
from parcels._core.statuscodes import (
27+
AllParcelsErrorCodes,
28+
FieldInterpolationError,
29+
FieldOutOfBoundError,
30+
FieldSamplingError,
31+
KernelError,
32+
StatusCode,
33+
TimeExtrapolationError,
34+
)
35+
from parcels._core.uxgrid import UxGrid
36+
from parcels._core.warnings import (
37+
FieldSetWarning,
38+
FileWarning,
39+
KernelWarning,
40+
ParticleSetWarning,
41+
)
42+
from parcels._core.xgrid import XGrid
43+
from parcels._logger import logger
44+
from parcels._tutorial import download_example_dataset, list_example_datasets
45+
46+
__all__ = [ # noqa: RUF022
47+
# Core classes
48+
"BaseGrid",
49+
"Field",
50+
"VectorField",
51+
"FieldSet",
52+
"Kernel",
53+
"Particle",
54+
"ParticleClass",
55+
"ParticleFile",
56+
"ParticleSet",
57+
"Variable",
58+
"XGrid",
59+
"UxGrid",
60+
# Converters
61+
"Geographic",
62+
"GeographicPolar",
63+
"GeographicPolarSquare",
64+
"GeographicSquare",
65+
"UnitConverter",
66+
# Status codes and errors
67+
"AllParcelsErrorCodes",
68+
"FieldInterpolationError",
69+
"FieldOutOfBoundError",
70+
"FieldSamplingError",
71+
"KernelError",
72+
"StatusCode",
73+
"TimeExtrapolationError",
74+
# Warnings
75+
"FieldSetWarning",
76+
"FileWarning",
77+
"KernelWarning",
78+
"ParticleSetWarning",
79+
# Utilities
80+
"logger",
81+
"download_example_dataset",
82+
"list_example_datasets",
83+
# (marked for potential removal)
84+
"KernelParticle",
85+
]
1686

17-
_warnings.warn(
87+
_stdlib_warnings.warn(
1888
"This is an alpha version of Parcels v4. The API is not stable and may change without deprecation warnings.",
1989
UserWarning,
2090
stacklevel=2,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import numpy as np
88

9-
from parcels.spatialhash import SpatialHash
9+
from parcels._core.spatialhash import SpatialHash
1010

1111
if TYPE_CHECKING:
1212
import numpy as np
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
"GeographicPolarSquare",
1212
"GeographicSquare",
1313
"UnitConverter",
14-
"convert_to_flat_array",
15-
"unitconverters_map",
14+
"_convert_to_flat_array",
15+
"_unitconverters_map",
1616
]
1717

1818

19-
def convert_to_flat_array(var: npt.ArrayLike) -> npt.NDArray:
19+
def _convert_to_flat_array(var: npt.ArrayLike) -> npt.NDArray:
2020
"""Convert lists and single integers/floats to one-dimensional numpy arrays
2121
2222
Parameters
@@ -96,7 +96,7 @@ def to_source(self, value, z, y, x):
9696
return value * pow(1000.0 * 1.852 * 60.0 * np.cos(y * pi / 180), 2)
9797

9898

99-
unitconverters_map = {
99+
_unitconverters_map = {
100100
"U": GeographicPolar(),
101101
"V": Geographic(),
102102
"Kh_zonal": GeographicPolarSquare(),
Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,28 @@
88
import uxarray as ux
99
import xarray as xr
1010

11+
from parcels._core.converters import (
12+
UnitConverter,
13+
_unitconverters_map,
14+
)
15+
from parcels._core.index_search import GRID_SEARCH_ERROR, LEFT_OUT_OF_BOUNDS, RIGHT_OUT_OF_BOUNDS, _search_time_index
16+
from parcels._core.particle import KernelParticle
17+
from parcels._core.statuscodes import (
18+
AllParcelsErrorCodes,
19+
StatusCode,
20+
)
1121
from parcels._core.utils.time import TimeInterval
22+
from parcels._core.uxgrid import UxGrid
23+
from parcels._core.xgrid import XGrid, _transpose_xfield_data_to_tzyx
1224
from parcels._reprs import default_repr
1325
from parcels._typing import VectorType
14-
from parcels.application_kernels.interpolation import (
26+
from parcels.interpolators import (
1527
UXPiecewiseLinearNode,
1628
XLinear,
1729
ZeroInterpolator,
1830
ZeroInterpolator_Vector,
1931
)
20-
from parcels.particle import KernelParticle
21-
from parcels.tools._helpers import _assert_same_function_signature
22-
from parcels.tools.converters import (
23-
UnitConverter,
24-
unitconverters_map,
25-
)
26-
from parcels.tools.statuscodes import (
27-
AllParcelsErrorCodes,
28-
StatusCode,
29-
)
30-
from parcels.uxgrid import UxGrid
31-
from parcels.xgrid import LEFT_OUT_OF_BOUNDS, RIGHT_OUT_OF_BOUNDS, XGrid, _transpose_xfield_data_to_tzyx
32-
33-
from ._index_search import GRID_SEARCH_ERROR, _search_time_index
32+
from parcels.utils._helpers import _assert_same_function_signature
3433

3534
__all__ = ["Field", "VectorField"]
3635

@@ -143,10 +142,10 @@ def __init__(
143142

144143
self.igrid = -1 # Default the grid index to -1
145144

146-
if self.grid._mesh == "flat" or (self.name not in unitconverters_map.keys()):
145+
if self.grid._mesh == "flat" or (self.name not in _unitconverters_map.keys()):
147146
self.units = UnitConverter()
148147
elif self.grid._mesh == "spherical":
149-
self.units = unitconverters_map[self.name]
148+
self.units = _unitconverters_map[self.name]
150149

151150
if self.data.shape[0] > 1:
152151
if "time" not in self.data.coords:
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@
99
import xarray as xr
1010
import xgcm
1111

12+
from parcels._core.converters import Geographic, GeographicPolar
13+
from parcels._core.field import Field, VectorField
1214
from parcels._core.utils.time import get_datetime_type_calendar
1315
from parcels._core.utils.time import is_compatible as datetime_is_compatible
16+
from parcels._core.xgrid import _DEFAULT_XGCM_KWARGS, XGrid
17+
from parcels._logger import logger
1418
from parcels._typing import Mesh
15-
from parcels.field import Field, VectorField
16-
from parcels.tools.converters import Geographic, GeographicPolar
17-
from parcels.tools.loggers import logger
18-
from parcels.xgrid import _DEFAULT_XGCM_KWARGS, XGrid
1919

2020
if TYPE_CHECKING:
21+
from parcels._core.basegrid import BaseGrid
2122
from parcels._typing import TimeLike
22-
from parcels.basegrid import BaseGrid
2323
__all__ = ["FieldSet"]
2424

2525

0 commit comments

Comments
 (0)