From 3c7eaca74b74d86a1864071e2fe4a085f8750026 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 17:37:35 +0200 Subject: [PATCH 01/11] update --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee5a33f..ee59ffc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -57,7 +57,7 @@ repos: - --quiet-level=2 - repo: https://github.com/asottile/pyupgrade - rev: v3.17.0 + rev: v3.19.0 hooks: - id: pyupgrade args: From ba15f6fff1208f6cf298b4cd4ea1e674f6078309 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 17:37:41 +0200 Subject: [PATCH 02/11] move to pyproject.toml --- pyproject.toml | 65 +++++++++++++++++++++++++++++++++++++++++++++++++- setup.cfg | 50 -------------------------------------- setup.py | 12 ---------- 3 files changed, 64 insertions(+), 63 deletions(-) delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml index 92fc528..a52ee43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,70 @@ [build-system] -requires = ["setuptools>=41.2", "setuptools_scm", "wheel", "twine"] +requires = ["setuptools>=41.2", "setuptools_scm"] build-backend = "setuptools.build_meta" +[project] +name = "odvc" +description = "Ocean Dimensionless Vertical Coordinates" +readme = "README.md" +license = { file = "LICENSE.txt" } +maintainers = [ + { name = "Filipe Fernandes", email = "ocefpaf+odvc@gmail.com" }, +] +requires-python = ">=3.10" +classifiers = [ + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dynamic = [ + "dependencies", + "version", +] +urls.documentation = "https://pyoceans.github.io/odvc" +urls.homepage = "https://github.com/pyoceans/odvc" +urls.repository = "https://github.com/pyoceans/odvc" + +[tool.setuptools] +packages = [ + "odvc", +] +include-package-data = true + +[tool.setuptools.dynamic] +dependencies = { file = [ + "requirements.txt", +] } + +[tool.setuptools_scm] +write_to = "odvc/_version.py" +write_to_template = "__version__ = '{version}'" +tag_regex = "^(?Pv)?(?P[^\\+]+)(?P.*)?$" + +[tool.check-manifest] +ignore = [ + "*.yml", + ".coveragerc", + "Makefile", + "docs", + "docs/*", + "notebooks", + "notebooks/*", + "tests", + "tests/*", +] + +[tool.pytest.ini_options] +markers = [ + "web: marks tests require connection (deselect with '-m \"not web\"')", + "serial: marks tests that cannot be run in parallel (deselect with '-m \"not serial\"')", +] +filterwarnings = [ + "error:::odvc.*", + "ignore::UserWarning", + "ignore::RuntimeWarning", +] + [tool.interrogate] ignore-init-method = true ignore-init-module = false diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 7a5c164..0000000 --- a/setup.cfg +++ /dev/null @@ -1,50 +0,0 @@ -[metadata] -name = odvc -description = Ocean Dimensionless Vertical Coordinates -author = Filipe Fernandes -author_email = ocefpaf@gmail.com -url = https://github.com/pyoceans/odvc -long_description_content_type = text/markdown -long_description = file: README.md -license = BSD-3-Clause -license_files = LICENSE.txt -keywords = CF-conventions dimensionless coordinate vertical coordinate -project_urls = - Documentation = https://ioos.github.io/odvc - Bug Tracker = https://github.com/ioos/odvc/issues - Source Code = https://github.com/ioos/odvc -classifiers = - Development Status :: 5 - Production/Stable - Intended Audience :: Science/Research - Operating System :: OS Independent - License :: OSI Approved :: BSD License - Programming Language :: Python - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Topic :: Scientific/Engineering - -[options] -zip_safe = True -include_package_data = True -install_requires = - netcdf4 - numpy -python_requires = >=3.7 -packages = find: - -[sdist] -formats = gztar - -[check-manifest] -ignore = - *.yml - .coveragerc - docs - docs/* - notebooks - notebooks/* - tests - tests/* diff --git a/setup.py b/setup.py deleted file mode 100644 index 15290dd..0000000 --- a/setup.py +++ /dev/null @@ -1,12 +0,0 @@ -from setuptools import setup - -setup( - # The package metadata is specified in setup.cfg but GitHub's downstream dependency graph - # does not work unless we put the name this here too. - name="odvc", - use_scm_version={ - "write_to": "odvc/_version.py", - "write_to_template": '__version__ = "{version}"', - "tag_regex": r"^(?Pv)?(?P[^\+]+)(?P.*)?$", - }, -) From df8683baa296ac8d24fc3172c986be04dc5615ed Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 18:20:23 +0200 Subject: [PATCH 03/11] py313 --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e31456f..b08a270 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,8 +10,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] - os: [windows-latest, ubuntu-latest, macos-latest] + python-version: [ "3.10", "3.11", "3.12", "3.13" ] + os: [ windows-latest, ubuntu-latest, macos-latest ] fail-fast: false steps: @@ -23,7 +23,7 @@ jobs: environment-name: TEST init-shell: bash create-args: >- - python=3 pip + python=${{ matrix.python-version }} pip --file requirements.txt --file requirements-dev.txt --channel conda-forge From c82f483f7e0ac3564eb0913861c4fb472b90e093 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 18:20:36 +0200 Subject: [PATCH 04/11] use ruff --- .pre-commit-config.yaml | 58 +++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee59ffc..45ee7b0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,26 +13,6 @@ repos: - id: file-contents-sorter files: requirements-dev.txt -- repo: https://github.com/PyCQA/flake8 - rev: 7.1.1 - hooks: - - id: flake8 - exclude: docs/source/conf.py - args: [--max-line-length=105] - -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - additional_dependencies: [toml] - args: ["--profile", "black", "--filter-files"] - -- repo: https://github.com/psf/black - rev: 24.10.0 - hooks: - - id: black - language_version: python3 - - repo: https://github.com/keewis/blackdoc rev: v0.3.9 hooks: @@ -56,23 +36,39 @@ repos: args: - --quiet-level=2 -- repo: https://github.com/asottile/pyupgrade - rev: v3.19.0 - hooks: - - id: pyupgrade - args: - - --py36-plus - - repo: https://github.com/asottile/add-trailing-comma rev: v3.1.0 hooks: - id: add-trailing-comma -- repo: https://github.com/pycqa/pydocstyle - rev: 6.3.0 + +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.7.0 + hooks: + - id: ruff + args: ["--fix", "--show-fixes"] + - id: ruff-format + +- repo: https://github.com/nbQA-dev/nbQA + rev: 1.8.7 + hooks: + - id: nbqa-check-ast + - id: nbqa-black + - id: nbqa-ruff + args: [ + --fix, + --config=ruff.toml, + ] + +- repo: https://github.com/bdice/nb-strip-paths + rev: v0.1.0 + hooks: + - id: nb-strip-paths + +- repo: https://github.com/tox-dev/pyproject-fmt + rev: 2.4.3 hooks: - - id: pydocstyle - exclude: ^(docs|setup.py) + - id: pyproject-fmt ci: autofix_commit_msg: | From 875cabeeb45eacfc8369b0bb3759f3223d2b15b6 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 18:21:27 +0200 Subject: [PATCH 05/11] lint --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a52ee43..c1b0094 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,8 @@ [build-system] -requires = ["setuptools>=41.2", "setuptools_scm"] build-backend = "setuptools.build_meta" +requires = [ "setuptools>=41.2", "setuptools-scm" ] + [project] name = "odvc" description = "Ocean Dimensionless Vertical Coordinates" @@ -16,6 +17,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] dynamic = [ "dependencies", @@ -73,7 +75,7 @@ ignore-semiprivate = false ignore-private = false ignore-module = false fail-under = 85 -exclude = ["setup.py", "docs", "tests"] +exclude = [ "docs", "tests" ] verbose = 1 quiet = false color = true From 44e608ea7b308459ecf43bd6f248df7bb2d38644 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 18:21:36 +0200 Subject: [PATCH 06/11] add ruff config --- ruff.toml | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 ruff.toml diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..64fda2e --- /dev/null +++ b/ruff.toml @@ -0,0 +1,48 @@ +line-length = 82 + +lint.select = ["ALL"] + +lint.ignore = [ + "ANN", # No type check + "D203", # 1 blank line required before class docstring + "D205", # 1 blank line required between summary line and description + "D213", # incompatible. Ignoring `multi-line-summary-second-line` + "N806", # Variable in function should be lowercase + "PLR0913", # Too many arguments in function definition + "PLR2004", # Magic value used in comparison, consider replacing with a constant variable + "TRY003", # Avoid specifying long messages outside the exception class +] + +[lint.extend-per-file-ignores] +"docs/source/conf.py" = [ + "A001", # builtin-variable-shadowing + "D100", # Missing docstring in public module + "E402", # Module level import not at top of file + "ERA001", # Found commented-out code + "ERA001", # Found commented-out code + "EXE001", # Shebang is present but file is not executable +] +"test_*.py" = [ + "ANN001", # Missing type annotation for function argument + "ANN201", # Missing return type annotation for public function + "ANN202", # Missing return type annotation for private function + "INP001", # File is part of an implicit namespace package + "PD901", # Avoid using the generic variable name `df` for DataFrames + "S101", # Use of assert detected +] +# nbqa-ruff acts on converted .py so we cannot glob .ipynb :-/ +# https://github.com/nbQA-dev/nbQA/issues/823 +"notebooks/*" = [ + "ANN001", # Missing type annotation for function argument + "ANN201", # Missing return type annotation for public function + "B018", # Found useless expression. Either assign it to a variable or remove it + "D100", # Missing docstring in public module + "D103", # Missing docstring in public function + "E402", # Module level import not at top of file + "FBT003", # Boolean positional value in function call + "INP001", # File is part of an implicit namespace package + "PD901", # Avoid using the generic variable name `df` for DataFrames + "T201", # `print` found" +] +[lint.pycodestyle] +max-doc-length = 180 From 732994b73d541e83968d6addaa49e4deba8647a2 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 18:21:53 +0200 Subject: [PATCH 07/11] remove unused deps --- requirements-dev.txt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 2eea4f0..7bb4911 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,17 +1,4 @@ -black -dask -flake8-builtins -flake8-comprehensions -flake8-mutable -flake8-print -isort matplotlib nbsphinx -pycodestyle -pylint pytest -pytest-flake8 -pytest-xdist sphinx -twine -wheel From 608d03181b2ca01f0be166c61a9354fd4e14b83d Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 18:22:09 +0200 Subject: [PATCH 08/11] lint --- tests/test_parse_formula_terms.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_parse_formula_terms.py b/tests/test_parse_formula_terms.py index a3676b0..3d367d9 100644 --- a/tests/test_parse_formula_terms.py +++ b/tests/test_parse_formula_terms.py @@ -40,7 +40,9 @@ def setup(): def test_formula_terms_variables(setup): """Assert that the formula_terms_variables are correctly identified.""" assert hasattr(setup["formula_terms_variable"], "formula_terms") - assert setup["formula_terms_variable"].standard_name == "ocean_s_coordinate_g1" + assert ( + setup["formula_terms_variable"].standard_name == "ocean_s_coordinate_g1" + ) for k, v in setup["formula_terms"].items(): assert isinstance(v, str) From 67cc699276705d71e4f8d7a0fa08d914f7f45e43 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 20:13:16 +0200 Subject: [PATCH 09/11] lint --- notebooks/ocean_s_coordinate.ipynb | 17 ++++--- notebooks/ocean_s_coordinate_g1.ipynb | 28 ++++++----- notebooks/ocean_s_coordinate_g2.ipynb | 15 ++++-- notebooks/ocean_sigma_coordinate-FVCOM.ipynb | 19 ++++---- notebooks/ocean_sigma_coordinate-NYHOPS.ipynb | 19 +++----- odvc/formulas.py | 42 ++++++++--------- odvc/parse_formula_terms.py | 46 +++++++++---------- ruff.toml | 1 + tests/test_parse_formula_terms.py | 11 +++-- 9 files changed, 101 insertions(+), 97 deletions(-) diff --git a/notebooks/ocean_s_coordinate.ipynb b/notebooks/ocean_s_coordinate.ipynb index a16c028..3ae2397 100644 --- a/notebooks/ocean_s_coordinate.ipynb +++ b/notebooks/ocean_s_coordinate.ipynb @@ -21,6 +21,7 @@ "outputs": [], "source": [ "from netCDF4 import Dataset\n", + "\n", "from odvc.parse_formula_terms import get_formula_terms_variables\n", "\n", "nc = Dataset(url)\n", @@ -117,8 +118,12 @@ "metadata": {}, "outputs": [], "source": [ - "salt = nc.get_variables_by_attributes(long_name=\"averaged salinity\")[0]\n", - "temp = nc.get_variables_by_attributes(long_name=\"averaged potential temperature\")[0]\n", + "salt = nc.get_variables_by_attributes(\n", + " long_name=\"averaged salinity\",\n", + ")[0]\n", + "temp = nc.get_variables_by_attributes(\n", + " long_name=\"averaged potential temperature\",\n", + ")[0]\n", "\n", "s = salt[-1, :, 45, 137]\n", "t = temp[-1, :, 45, 137]\n", @@ -134,7 +139,7 @@ "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", - "import mpl_toolkits.axisartist as AA\n", + "from mpl_toolkits import axisartist\n", "from mpl_toolkits.axes_grid1 import host_subplot\n", "\n", "\n", @@ -145,7 +150,7 @@ "\n", "fig = plt.figure(figsize=(6, 9))\n", "fig.subplots_adjust(bottom=0.1, top=0.85)\n", - "ax0 = host_subplot(111, axes_class=AA.Axes)\n", + "ax0 = host_subplot(111, axes_class=axisartist.Axes)\n", "\n", "ax0.invert_yaxis()\n", "ax1 = ax0.twiny()\n", @@ -163,7 +168,7 @@ "ax0.set_xlabel(\"Temperature (\\xb0C)\")\n", "ax1.set_xlabel(r\"Salinity (g kg$^{-1}$)\")\n", "\n", - "kw = dict(linewidth=2.5)\n", + "kw = {\"linewidth\": 2.5}\n", "(l0,) = ax0.plot(t, -p, **kw)\n", "(l1,) = ax1.plot(s, -p, **kw)\n", "\n", @@ -191,7 +196,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/notebooks/ocean_s_coordinate_g1.ipynb b/notebooks/ocean_s_coordinate_g1.ipynb index 50dd4ab..32e16fa 100644 --- a/notebooks/ocean_s_coordinate_g1.ipynb +++ b/notebooks/ocean_s_coordinate_g1.ipynb @@ -23,6 +23,7 @@ "outputs": [], "source": [ "from netCDF4 import Dataset\n", + "\n", "from odvc.parse_formula_terms import get_formula_terms_variables\n", "\n", "nc = Dataset(url)\n", @@ -102,7 +103,11 @@ "from odvc import ocean_s_coordinate_g1\n", "\n", "z = ocean_s_coordinate_g1(\n", - " arrays[\"s\"], arrays[\"C\"], arrays[\"eta\"], arrays[\"depth\"], arrays[\"depth_c\"]\n", + " arrays[\"s\"],\n", + " arrays[\"C\"],\n", + " arrays[\"eta\"],\n", + " arrays[\"depth\"],\n", + " arrays[\"depth_c\"],\n", ")\n", "\n", "print(z.shape)" @@ -114,10 +119,12 @@ "metadata": {}, "outputs": [], "source": [ - "salt = nc.get_variables_by_attributes(standard_name=\"sea_water_salinity\")[0]\n", - "temp = nc.get_variables_by_attributes(standard_name=\"sea_water_potential_temperature\")[\n", - " 0\n", - "]\n", + "salt = nc.get_variables_by_attributes(\n", + " standard_name=\"sea_water_salinity\",\n", + ")[0]\n", + "temp = nc.get_variables_by_attributes(\n", + " standard_name=\"sea_water_potential_temperature\",\n", + ")[0]\n", "\n", "s = salt[-1, :, 5, 364]\n", "t = temp[-1, :, 5, 364]\n", @@ -133,12 +140,9 @@ "%matplotlib inline\n", "\n", "import matplotlib.pyplot as plt\n", - "import mpl_toolkits.axisartist as AA\n", - "import seaborn\n", + "from mpl_toolkits import axisartist\n", "from mpl_toolkits.axes_grid1 import host_subplot\n", "\n", - "seaborn.set(style=\"ticks\")\n", - "\n", "\n", "def adjust_xlim(ax, offset):\n", " x1, x2 = ax.get_xlim()\n", @@ -147,7 +151,7 @@ "\n", "fig = plt.figure(figsize=(6, 9))\n", "fig.subplots_adjust(bottom=0.1, top=0.85)\n", - "ax0 = host_subplot(111, axes_class=AA.Axes)\n", + "ax0 = host_subplot(111, axes_class=axisartist.Axes)\n", "\n", "ax0.invert_yaxis()\n", "ax1 = ax0.twiny()\n", @@ -165,7 +169,7 @@ "ax0.set_xlabel(\"Temperature (\\xb0C)\")\n", "ax1.set_xlabel(r\"Salinity (g kg$^{-1}$)\")\n", "\n", - "kw = dict(linewidth=2.5)\n", + "kw = {\"linewidth\": 2.5}\n", "(l0,) = ax0.plot(t, -p, **kw)\n", "(l1,) = ax1.plot(s, -p, **kw)\n", "\n", @@ -193,7 +197,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/notebooks/ocean_s_coordinate_g2.ipynb b/notebooks/ocean_s_coordinate_g2.ipynb index 6ada17c..ab1796b 100644 --- a/notebooks/ocean_s_coordinate_g2.ipynb +++ b/notebooks/ocean_s_coordinate_g2.ipynb @@ -24,6 +24,7 @@ "outputs": [], "source": [ "from netCDF4 import Dataset\n", + "\n", "from odvc.parse_formula_terms import get_formula_terms_variables\n", "\n", "nc = Dataset(url)\n", @@ -103,7 +104,11 @@ "from odvc import ocean_s_coordinate_g1\n", "\n", "z = ocean_s_coordinate_g1(\n", - " arrays[\"s\"], arrays[\"C\"], arrays[\"eta\"], arrays[\"depth\"], arrays[\"depth_c\"]\n", + " arrays[\"s\"],\n", + " arrays[\"C\"],\n", + " arrays[\"eta\"],\n", + " arrays[\"depth\"],\n", + " arrays[\"depth_c\"],\n", ")\n", "\n", "print(z.shape)" @@ -130,7 +135,7 @@ "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", - "import mpl_toolkits.axisartist as AA\n", + "from mpl_toolkits import axisartist\n", "from mpl_toolkits.axes_grid1 import host_subplot\n", "\n", "\n", @@ -141,7 +146,7 @@ "\n", "fig = plt.figure(figsize=(6, 9))\n", "fig.subplots_adjust(bottom=0.1, top=0.85)\n", - "ax0 = host_subplot(111, axes_class=AA.Axes)\n", + "ax0 = host_subplot(111, axes_class=axisartist.Axes)\n", "\n", "ax0.invert_yaxis()\n", "ax1 = ax0.twiny()\n", @@ -159,7 +164,7 @@ "ax0.set_xlabel(\"Temperature (\\xb0C)\")\n", "ax1.set_xlabel(r\"Salinity (g kg$^{-1}$)\")\n", "\n", - "kw = dict(linewidth=2.5)\n", + "kw = {\"linewidth\": 2.5}\n", "(l0,) = ax0.plot(t, -p, **kw)\n", "(l1,) = ax1.plot(s, -p, **kw)\n", "\n", @@ -187,7 +192,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/notebooks/ocean_sigma_coordinate-FVCOM.ipynb b/notebooks/ocean_sigma_coordinate-FVCOM.ipynb index dfa1c80..22bc8dc 100644 --- a/notebooks/ocean_sigma_coordinate-FVCOM.ipynb +++ b/notebooks/ocean_sigma_coordinate-FVCOM.ipynb @@ -24,6 +24,7 @@ "outputs": [], "source": [ "from netCDF4 import Dataset\n", + "\n", "from odvc.parse_formula_terms import get_formula_terms_variables\n", "\n", "nc = Dataset(url)\n", @@ -103,10 +104,12 @@ "metadata": {}, "outputs": [], "source": [ - "salt = nc.get_variables_by_attributes(standard_name=\"sea_water_salinity\")[0]\n", - "temp = nc.get_variables_by_attributes(standard_name=\"sea_water_potential_temperature\")[\n", - " 0\n", - "]\n", + "salt = nc.get_variables_by_attributes(\n", + " standard_name=\"sea_water_salinity\",\n", + ")[0]\n", + "temp = nc.get_variables_by_attributes(\n", + " standard_name=\"sea_water_potential_temperature\",\n", + ")[0]\n", "\n", "s = salt[-1, :, 175]\n", "t = temp[-1, :, 175]\n", @@ -120,7 +123,7 @@ "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", - "import mpl_toolkits.axisartist as AA\n", + "from mpl_toolkits import axisartist\n", "from mpl_toolkits.axes_grid1 import host_subplot\n", "\n", "\n", @@ -131,7 +134,7 @@ "\n", "fig = plt.figure(figsize=(6, 9))\n", "fig.subplots_adjust(bottom=0.1, top=0.85)\n", - "ax0 = host_subplot(111, axes_class=AA.Axes)\n", + "ax0 = host_subplot(111, axes_class=axisartist.Axes)\n", "\n", "ax0.invert_yaxis()\n", "ax1 = ax0.twiny()\n", @@ -149,7 +152,7 @@ "ax0.set_xlabel(\"Temperature (\\xb0C)\")\n", "ax1.set_xlabel(r\"Salinity (g kg$^{-1}$)\")\n", "\n", - "kw = dict(linewidth=2.5)\n", + "kw = {\"linewidth\": 2.5}\n", "(l0,) = ax0.plot(t, -p, **kw)\n", "(l1,) = ax1.plot(s, -p, **kw)\n", "\n", @@ -177,7 +180,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/notebooks/ocean_sigma_coordinate-NYHOPS.ipynb b/notebooks/ocean_sigma_coordinate-NYHOPS.ipynb index 694d8a1..406b590 100644 --- a/notebooks/ocean_sigma_coordinate-NYHOPS.ipynb +++ b/notebooks/ocean_sigma_coordinate-NYHOPS.ipynb @@ -10,8 +10,7 @@ "\n", "dask.config.set(scheduler=\"single-threaded\")\n", "\n", - "\n", - "url = \"http://colossus.dl.stevens-tech.edu:8080/thredds/dodsC/\" \"latest/Bight_gcmplt.nc\"" + "url = \"http://colossus.dl.stevens-tech.edu:8080/thredds/dodsC/latest/Bight_gcmplt.nc\"" ] }, { @@ -21,12 +20,11 @@ "outputs": [], "source": [ "from netCDF4 import Dataset\n", + "\n", "from odvc.parse_formula_terms import get_formula_terms_variables\n", "\n", "nc = Dataset(url)\n", - "\n", "var = get_formula_terms_variables(nc)\n", - "\n", "var" ] }, @@ -39,7 +37,6 @@ "from odvc import get_formula_terms\n", "\n", "formula_terms = get_formula_terms(var[0])\n", - "\n", "formula_terms" ] }, @@ -52,7 +49,6 @@ "from odvc import get_formula_terms_dims\n", "\n", "dims = get_formula_terms_dims(nc, formula_terms)\n", - "\n", "dims" ] }, @@ -65,7 +61,6 @@ "from odvc import z_shape\n", "\n", "new_shape = z_shape(nc, dims)\n", - "\n", "new_shape" ] }, @@ -78,7 +73,6 @@ "from odvc import prepare_arrays\n", "\n", "arrays = prepare_arrays(nc, formula_terms, new_shape)\n", - "\n", "arrays" ] }, @@ -100,7 +94,6 @@ "from odvc import ocean_sigma_coordinate\n", "\n", "z = ocean_sigma_coordinate(arrays[\"sigma\"], arrays[\"eta\"], arrays[\"depth\"])\n", - "\n", "print(z.shape)" ] }, @@ -125,7 +118,7 @@ "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", - "import mpl_toolkits.axisartist as AA\n", + "from mpl_toolkits import axisartist\n", "from mpl_toolkits.axes_grid1 import host_subplot\n", "\n", "\n", @@ -136,7 +129,7 @@ "\n", "fig = plt.figure(figsize=(6, 9))\n", "fig.subplots_adjust(bottom=0.1, top=0.85)\n", - "ax0 = host_subplot(111, axes_class=AA.Axes)\n", + "ax0 = host_subplot(111, axes_class=axisartist.Axes)\n", "\n", "ax0.invert_yaxis()\n", "ax1 = ax0.twiny()\n", @@ -154,7 +147,7 @@ "ax0.set_xlabel(\"Temperature (\\xb0C)\")\n", "ax1.set_xlabel(r\"Salinity (g kg$^{-1}$)\")\n", "\n", - "kw = dict(linewidth=2.5)\n", + "kw = {\"linewidth\": 2.5}\n", "(l0,) = ax0.plot(t, -p, **kw)\n", "(l1,) = ax1.plot(s, -p, **kw)\n", "\n", @@ -182,7 +175,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/odvc/formulas.py b/odvc/formulas.py index d55d0ce..33917fe 100644 --- a/odvc/formulas.py +++ b/odvc/formulas.py @@ -4,8 +4,7 @@ def ocean_double_sigma_coordinate(sigma, depth, z1, z2, a, href, k_c): - """ - Create a dimensioned version of ocean double sigma. + """Create a dimensioned version of ocean double sigma. Definition: for k <= k_c @@ -25,30 +24,28 @@ def ocean_double_sigma_coordinate(sigma, depth, z1, z2, a, href, k_c): def ocean_sigma_z_coordinate(sigma, eta, depth, depth_c, nsigma, zlev): - """ - Create a dimensioned version of ocean sigma over z. + """Create a dimensioned version of ocean sigma over z. Definition: - for k <= nsigma - z(n,k,j,i) = eta(n,j,i) + sigma(k)*(min(depth_c,depth(j,i))+eta(n,j,i)) - for k > nsigma - z(n,k,j,i) = zlev(k) - - where z(n,k,j,i) is height, positive upwards, relative to ocean datum - (e.g. mean sea level) at gridpoint (n,k,j,i) , eta(n,j,i) is the height - of the ocean surface, positive upwards, relative to ocean datum at - gridpoint (n,j,i) , sigma(k) is the dimensionless coordinate at - vertical gridpoint (k) for k <= nsigma , and depth(j,i) is the distance - from ocean datum to sea floor (positive value) at horizontal - gridpoint (j,i) . Above depth depth_c there are nsigma layers. + for k <= nsigma + z(n,k,j,i) = eta(n,j,i) + sigma(k)*(min(depth_c,depth(j,i))+eta(n,j,i)) + for k > nsigma + z(n,k,j,i) = zlev(k) + + where z(n,k,j,i) is height, positive upwards, relative to ocean datum + (e.g. mean sea level) at gridpoint (n,k,j,i) , eta(n,j,i) is the height + of the ocean surface, positive upwards, relative to ocean datum at + gridpoint (n,j,i) , sigma(k) is the dimensionless coordinate at + vertical gridpoint (k) for k <= nsigma , and depth(j,i) is the distance + from ocean datum to sea floor (positive value) at horizontal + gridpoint (j,i) . Above depth depth_c there are nsigma layers. """ raise NotImplementedError def ocean_sigma_coordinate(sigma, eta, depth): - """ - Create a dimensioned version of ocean sigma coordinate. + """Create a dimensioned version of ocean sigma coordinate. z(n, k, j, i) = eta(n, j, i) + sigma(k) * (depth(j, i) + eta(n, j, i)) @@ -58,8 +55,7 @@ def ocean_sigma_coordinate(sigma, eta, depth): def ocean_s_coordinate(s, eta, depth, a, b, depth_c): - """ - Create a dimensioned version of ocean s-coordinate. + """Create a dimensioned version of ocean s-coordinate. z(n,k,j,i) = eta(n,j,i)*(1+s(k)) + depth_c*s(k) + (depth(j,i)-depth_c)*C(k) @@ -76,8 +72,7 @@ def ocean_s_coordinate(s, eta, depth, a, b, depth_c): def ocean_s_coordinate_g1(s, c, eta, depth, depth_c): - """ - Create a dimensioned version of ocean s-coordinate generic form 1. + """Create a dimensioned version of ocean s-coordinate generic form 1. z(n,k,j,i) = S(k,j,i) + eta(n,j,i) * (1 + S(k,j,i) / depth(j,i)) @@ -90,8 +85,7 @@ def ocean_s_coordinate_g1(s, c, eta, depth, depth_c): def ocean_s_coordinate_g2(s, eta, depth, depth_c, c): - """ - Create a dimensioned version of s-coordinate generic form 2. + """Create a dimensioned version of s-coordinate generic form 2. z(n,k,j,i) = eta(n,j,i) + (eta(n,j,i) + depth(j,i)) * S(k,j,i) diff --git a/odvc/parse_formula_terms.py b/odvc/parse_formula_terms.py index e902794..babc718 100644 --- a/odvc/parse_formula_terms.py +++ b/odvc/parse_formula_terms.py @@ -6,8 +6,7 @@ def get_formula_terms(var): - """ - Return a `formula_terms` dict mapping var_names to variables. + """Return a `formula_terms` dict mapping var_names to variables. The input can be a netCDF variable (`var`) holding the `formula_terms` attribute or the attribute itself. @@ -39,7 +38,9 @@ def func(v): def get_formula_terms_dims(nc, formula_terms): - """Return an OrderedDict object `dims` holding the `formula_terms` dimensions.""" + """Return an OrderedDict object `dims` holding the + `formula_terms` dimensions. + """ dims = OrderedDict() for k, v in formula_terms.items(): dims.update({k: nc[v].dimensions}) @@ -47,7 +48,9 @@ def get_formula_terms_dims(nc, formula_terms): def z_shape(nc, dims): - """Return the vertical coordinate `shape` based on the formula_terms `dims`.""" + """Return the vertical coordinate `shape` based on the + `formula_terms` `dims`. + """ all_dims = ( dims.get("eta"), dims.get("depth"), @@ -61,13 +64,11 @@ def z_shape(nc, dims): z_dims = all_dims[:] z_dims.insert(1, z_dims.pop(-1)) - shape = [] - for dim in z_dims: - try: - shape.append(len(nc.dimensions.get(dim))) - except TypeError: - msg = "Could not get dimension size for dim {!r}".format - raise ValueError(msg(dim)) + try: + shape = [len(nc.dimensions.get(dim)) for dim in z_dims] + except TypeError as err: + msg = "Could not get dimension size" + raise ValueError(msg) from err return tuple(shape) @@ -75,7 +76,7 @@ def z_shape(nc, dims): def _reshape(arr, new_shape): """Reshape arrays according to the expected dimensions.""" shape = arr.shape - dims = [k for k in shape] + dims = list(shape) slicer = slice(None, None, None) def select(dim): @@ -92,19 +93,16 @@ def prepare_arrays(nc, formula_terms, new_shape): arrays = {} for term, var in formula_terms.items(): - var = nc[var] - if var.ndim == 0: - arr = var[:] + _var = nc[var] + if _var.ndim == 0: + arr = _var[:] else: - if var.ndim > 2: - chunks = (1,) + var.shape[1:] - else: - chunks = var.shape - if term == "sigma" and var.ndim == 2: - chunks = var.shape - if term == "eta" and var.ndim == 2: - chunks = (1,) + var.shape[1:] - arr = da.from_array(var, chunks=chunks) + chunks = (1,) + _var.shape[1:] if _var.ndim > 2 else _var.shape + if term == "sigma" and _var.ndim == 2: + chunks = _var.shape + if term == "eta" and _var.ndim == 2: + chunks = (1,) + _var.shape[1:] + arr = da.from_array(_var, chunks=chunks) arr = _reshape(arr, new_shape) arrays.update({term: arr}) return arrays diff --git a/ruff.toml b/ruff.toml index 64fda2e..25ce46f 100644 --- a/ruff.toml +++ b/ruff.toml @@ -7,6 +7,7 @@ lint.ignore = [ "D203", # 1 blank line required before class docstring "D205", # 1 blank line required between summary line and description "D213", # incompatible. Ignoring `multi-line-summary-second-line` + "ISC001", # single-line-implicit-string-concatenation "N806", # Variable in function should be lowercase "PLR0913", # Too many arguments in function definition "PLR2004", # Magic value used in comparison, consider replacing with a constant variable diff --git a/tests/test_parse_formula_terms.py b/tests/test_parse_formula_terms.py index 3d367d9..8e6cbd1 100644 --- a/tests/test_parse_formula_terms.py +++ b/tests/test_parse_formula_terms.py @@ -43,7 +43,7 @@ def test_formula_terms_variables(setup): assert ( setup["formula_terms_variable"].standard_name == "ocean_s_coordinate_g1" ) - for k, v in setup["formula_terms"].items(): + for v in setup["formula_terms"].values(): assert isinstance(v, str) @@ -60,7 +60,7 @@ def test_get_formula_terms_and_dims(setup): def test_arrays(setup): """Assert that the arrays are the right obj instance.""" - for k, v in setup["arrays"].items(): + for v in setup["arrays"].values(): if hasattr(v, "compute"): assert isinstance(v, da.Array) assert isinstance(v.compute(), np.ndarray) @@ -71,6 +71,7 @@ def test_arrays(setup): def test_no_formula_terms_variables(): """Test if it will fail as expected when formula terms are missing.""" no_formula_term = "no_formula_terms.nc" - with Dataset(data_path.joinpath(no_formula_term)) as nc: - with pytest.raises(ValueError): - get_formula_terms_variables(nc) + fname = data_path.joinpath(no_formula_term) + match = "Could not find the attribute `formula_terms`" + with Dataset(fname) as nc, pytest.raises(ValueError, match=match): + get_formula_terms_variables(nc) From 8880c6f124afdf3022121e56d163441f401e5692 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 20:30:05 +0200 Subject: [PATCH 10/11] pin dask --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 57d5d7e..d4595b0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -dask +dask-core>=2024 netcdf4 numpy From 1840f1f8aa4537b7570c69166c421cb918c2e611 Mon Sep 17 00:00:00 2001 From: Filipe Fernandes Date: Tue, 22 Oct 2024 20:39:46 +0200 Subject: [PATCH 11/11] PyPI vs conda names --- pyproject.toml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c1b0094..b18125c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,9 +20,13 @@ classifiers = [ "Programming Language :: Python :: 3.13", ] dynamic = [ - "dependencies", "version", ] +dependencies = [ + "dask>=2024", + "netcdf4", + "numpy", +] urls.documentation = "https://pyoceans.github.io/odvc" urls.homepage = "https://github.com/pyoceans/odvc" urls.repository = "https://github.com/pyoceans/odvc" @@ -33,11 +37,6 @@ packages = [ ] include-package-data = true -[tool.setuptools.dynamic] -dependencies = { file = [ - "requirements.txt", -] } - [tool.setuptools_scm] write_to = "odvc/_version.py" write_to_template = "__version__ = '{version}'"