From 3617a0d60ccd029aa820a1734aef817b69e6f459 Mon Sep 17 00:00:00 2001 From: oisin-m Date: Thu, 30 Jul 2026 13:31:03 +0200 Subject: [PATCH 1/2] feat: update pre-commit to align with rest of ek --- .pre-commit-config.yaml | 43 ++++++++++++++++++++++------------------- pyproject.toml | 28 +++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ef9babe..659dbe5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,32 +1,30 @@ +default_language_version: + python: python3 +default_stages: +- pre-commit +- pre-push repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - - id: trailing-whitespace # Trailing whitespace checker - - id: end-of-file-fixer # Ensure files end in a newline - - id: check-json - - id: check-yaml # Check YAML files for syntax errors only - args: [--unsafe, --allow-multiple-documents] - - id: check-toml - # - id: check-added-large-files - - id: debug-statements # Check for debugger imports and py37+ breakpoint() + - id: detect-private-key + - id: check-ast + - id: end-of-file-fixer - id: mixed-line-ending - - id: no-commit-to-branch # Prevent committing to main / master - - id: check-merge-conflict # Check for files that contain merge conflict - exclude: /README\.rst$|^docs/.*\.rst$ + args: [--fix=lf] + - id: trailing-whitespace + - id: check-case-conflict - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.9 + rev: v0.15.4 hooks: - id: ruff-check + exclude: '(dev/.*|.*_)\.py$' args: + - --line-length=120 - --fix - --exit-non-zero-on-fix + - --preview - id: ruff-format -- repo: https://github.com/executablebooks/mdformat - rev: 0.7.14 - hooks: - - id: mdformat - exclude: cruft-update-template.md - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks rev: v2.16.0 hooks: @@ -34,7 +32,12 @@ repos: args: [--autofix, --preserve-quotes] - id: pretty-format-toml args: [--autofix] -- repo: https://github.com/sphinx-contrib/sphinx-lint - rev: v1.0.0 +- repo: local hooks: - - id: sphinx-lint + - id: forbid-to-commit + name: Don't commit rej files + entry: | + Cannot commit .rej files. These indicate merge conflicts that arise during automated template updates. + Fix the merge conflicts manually and remove the .rej files. + language: fail + files: '.*\.rej$' \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 13258c8..b4b7126 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,8 +45,32 @@ urls.Repository = "https://github.com/ecmwf/earthkit/" [tool.coverage.run] branch = "true" -[tool.isort] -profile = "black" +[tool.ruff] +line-length = 120 +preview = true + +[tool.ruff.lint] +ignore = [ + "D1", # pydocstyle: Missing Docstrings + "D107", # pydocstyle: numpy convention + "D203", + "D205", + "D212", + "D213", + "D401", + "D402", + "D413", + "D415", + "D416", + "D417" +] +select = [ + "F", # pyflakes + "E", # pycodestyle + "W", # pycodestyle warnings + "I", # isort + "D" # pydocstyle +] [tool.pydocstyle] add_ignore = ["D1", "D200", "D205", "D400", "D401"] From 90206706be415296ebdc2ca4e4ec45fd519e0169 Mon Sep 17 00:00:00 2001 From: oisin-m Date: Fri, 31 Jul 2026 14:27:24 +0200 Subject: [PATCH 2/2] chore: please qa --- .pre-commit-config.yaml | 2 +- docs/conf.py | 20 +++------- .../comparing-models-solutions.ipynb | 16 +++----- docs/tutorials/ensemble.ipynb | 37 ++++++------------- docs/tutorials/polytope_polygon.ipynb | 4 +- docs/tutorials/polytope_timeseries.ipynb | 10 ++--- .../tutorials/polytope_vertical_profile.ipynb | 4 +- docs/tutorials/time-series-solutions.ipynb | 24 +++--------- pyproject.toml | 8 ++-- 9 files changed, 37 insertions(+), 88 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 659dbe5..08bc8c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,4 +40,4 @@ repos: Cannot commit .rej files. These indicate merge conflicts that arise during automated template updates. Fix the merge conflicts manually and remove the .rej files. language: fail - files: '.*\.rej$' \ No newline at end of file + files: '.*\.rej$' diff --git a/docs/conf.py b/docs/conf.py index 1851bc8..a58a976 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -30,9 +30,7 @@ else: source_branch = "main" -src_path = os.path.normpath( - os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "src") -) +src_path = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "src")) sys.path.insert(0, src_path) # Adds path to the folder _ext, where extensions are stored @@ -128,19 +126,11 @@ # clean_autodocs.py feature flags # Set to False/None to disable or soften the corresponding processing step. autodocs_delete_hidden = True # delete RST files for private/hidden modules -autodocs_replace_automodule = ( - True # replace automodule directives with autosummary tables -) -autodocs_short_display_names = ( - True # shorten toctree labels to the last module component -) -autodocs_top_level_maxdepth = ( - 1 # :maxdepth: on top-level page (None = keep sphinx-apidoc value) -) +autodocs_replace_automodule = True # replace automodule directives with autosummary tables +autodocs_short_display_names = True # shorten toctree labels to the last module component +autodocs_top_level_maxdepth = 1 # :maxdepth: on top-level page (None = keep sphinx-apidoc value) autodocs_rename_titles = False # strip " package"/" module" from RST page headings -autodocs_top_level_title = ( - "API Reference" # top-level page heading (used when rename_titles=True) -) +autodocs_top_level_title = "API Reference" # top-level page heading (used when rename_titles=True) autodocs_titlesonly = False # inject :titlesonly: into toctree directives # List of patterns, relative to source directory, that match files and diff --git a/docs/tutorials/comparing-models-solutions.ipynb b/docs/tutorials/comparing-models-solutions.ipynb index 18596fb..d7c6b2e 100644 --- a/docs/tutorials/comparing-models-solutions.ipynb +++ b/docs/tutorials/comparing-models-solutions.ipynb @@ -49,8 +49,8 @@ "outputs": [], "source": [ "import earthkit.data as ekd\n", - "import earthkit.transforms as ekt\n", - "import earthkit.plots as ekp" + "import earthkit.plots as ekp\n", + "import earthkit.transforms as ekt" ] }, { @@ -1899,9 +1899,7 @@ "# We can directly access the underlying matplotlib objects to do this\n", "x = [-180, -180, 180, 180, -180]\n", "y = [-90, 90, 90, -90, -90]\n", - "figure[0].ax.fill(\n", - " x, y, transform=ccrs.PlateCarree(), hatch=\"///////\", fill=False, zorder=0\n", - ")\n", + "figure[0].ax.fill(x, y, transform=ccrs.PlateCarree(), hatch=\"///////\", fill=False, zorder=0)\n", "\n", "figure.show()" ] @@ -2066,9 +2064,7 @@ "# We can directly access the underlying matplotlib objects to do this\n", "x = [-180, -180, 180, 180, -180]\n", "y = [-90, 90, 90, -90, -90]\n", - "figure[0].ax.fill(\n", - " x, y, transform=ccrs.PlateCarree(), hatch=\"///////\", fill=False, zorder=0\n", - ")\n", + "figure[0].ax.fill(x, y, transform=ccrs.PlateCarree(), hatch=\"///////\", fill=False, zorder=0)\n", "\n", "figure.show()" ] @@ -2138,9 +2134,7 @@ "# We can directly access the underlying matplotlib objects to do this\n", "x = [-180, -180, 180, 180, -180]\n", "y = [-90, 90, 90, -90, -90]\n", - "figure[0].ax.fill(\n", - " x, y, transform=ccrs.PlateCarree(), hatch=\"///////\", fill=False, zorder=0\n", - ")\n", + "figure[0].ax.fill(x, y, transform=ccrs.PlateCarree(), hatch=\"///////\", fill=False, zorder=0)\n", "\n", "figure.show()" ] diff --git a/docs/tutorials/ensemble.ipynb b/docs/tutorials/ensemble.ipynb index 525329f..ac7d987 100644 --- a/docs/tutorials/ensemble.ipynb +++ b/docs/tutorials/ensemble.ipynb @@ -1203,16 +1203,15 @@ } ], "source": [ - "import cartopy.crs as ccrs\n", "import datetime\n", "\n", + "import cartopy.crs as ccrs\n", + "\n", "# define step\n", "step_hours = 78\n", "step = datetime.timedelta(hours=step_hours)\n", "\n", - "figure = ekp.Figure(\n", - " crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7, 6), rows=2, columns=2\n", - ")\n", + "figure = ekp.Figure(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7, 6), rows=2, columns=2)\n", "\n", "gust_style = ekp.styles.Style(\n", " colors=[\"#85AAEE\", \"#208EFC\", \"#6CA632\", \"#FFB000\", \"#FF0000\", \"#7A11B1\"],\n", @@ -1224,17 +1223,13 @@ "\n", "# the hres forecast, GRIB\n", "subplot = figure.add_map(0, 0)\n", - "subplot.contourf(\n", - " fl_fc.sel({\"parameter.variable\": \"10fg3\", \"time.step\": step}), style=gust_style\n", - ")\n", + "subplot.contourf(fl_fc.sel({\"parameter.variable\": \"10fg3\", \"time.step\": step}), style=gust_style)\n", "subplot.title(\"HRES {base_time:%Y-%m-%d %H} UTC (+{lead_time}h)\")\n", "subplot.legend(label=\"\")\n", "\n", "# the control forecast, GRIB\n", "subplot = figure.add_map(0, 1)\n", - "subplot.contourf(\n", - " fl_fg.sel({\"metadata.marsType\": \"cf\", \"time.step\": step}), style=gust_style\n", - ")\n", + "subplot.contourf(fl_fg.sel({\"metadata.marsType\": \"cf\", \"time.step\": step}), style=gust_style)\n", "subplot.title(\"CF {base_time:%Y-%m-%d %H} UTC (+{lead_time}h)\")\n", "subplot.legend(label=\"\")\n", "\n", @@ -1301,16 +1296,14 @@ } ], "source": [ - "import matplotlib.pyplot as plt\n", "import cartopy.crs as ccrs\n", + "import matplotlib.pyplot as plt\n", "\n", "# define step\n", "step_hours = 78\n", "step = datetime.timedelta(hours=step_hours)\n", "\n", - "figure = ekp.Figure(\n", - " crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], figsize=(7, 7), rows=8, columns=8\n", - ")\n", + "figure = ekp.Figure(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], figsize=(7, 7), rows=8, columns=8)\n", "\n", "gust_style = ekp.styles.Style(\n", " colors=[\"#85AAEE\", \"#208EFC\", \"#6CA632\", \"#FFB000\", \"#FF0000\", \"#7A11B1\"],\n", @@ -1325,16 +1318,12 @@ "\n", "# HRES forecast, GRIB\n", "subplot = figure.add_map(0, 6)\n", - "subplot.contourf(\n", - " fl_fc.sel({\"parameter.variable\": \"10fg3\", \"time.step\": step}), style=gust_style\n", - ")\n", + "subplot.contourf(fl_fc.sel({\"parameter.variable\": \"10fg3\", \"time.step\": step}), style=gust_style)\n", "subplot.title(\"HRES\")\n", "\n", "# control forecast, GRIB\n", "subplot = figure.add_map(0, 7)\n", - "subplot.contourf(\n", - " fl_fg.sel({\"metadata.marsType\": \"cf\", \"time.step\": step}), style=gust_style\n", - ")\n", + "subplot.contourf(fl_fg.sel({\"metadata.marsType\": \"cf\", \"time.step\": step}), style=gust_style)\n", "subplot.title(\"CF\")\n", "\n", "# perturbed members, GRIB\n", @@ -1427,9 +1416,7 @@ "\n", "# perturbed members\n", "for f in z_en.sel({\"metadata.marsType\": \"pf\"}):\n", - " chart.contour(\n", - " f, levels=cont_level, linewidths=[0.2, 0.2], colors=\"blue\", labels=False\n", - " )\n", + " chart.contour(f, levels=cont_level, linewidths=[0.2, 0.2], colors=\"blue\", labels=False)\n", "\n", "# control forecast\n", "chart.contour(\n", @@ -1567,9 +1554,7 @@ "outputs": [], "source": [ "perc = 0.8 # 80%\n", - "perc_xr = fl_fg.to_xarray(ensure_dims=\"forecast_reference_time\").quantile(\n", - " perc, dim=\"member\"\n", - ")" + "perc_xr = fl_fg.to_xarray(ensure_dims=\"forecast_reference_time\").quantile(perc, dim=\"member\")" ] }, { diff --git a/docs/tutorials/polytope_polygon.ipynb b/docs/tutorials/polytope_polygon.ipynb index 8f6edae..bd96bd4 100644 --- a/docs/tutorials/polytope_polygon.ipynb +++ b/docs/tutorials/polytope_polygon.ipynb @@ -582,9 +582,7 @@ " \"feature\": {\"type\": \"polygon\", \"shape\": coords},\n", "}\n", "\n", - "ds = ekd.from_source(\n", - " \"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\"\n", - ").to_xarray()\n", + "ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\").to_xarray()\n", "ds" ] }, diff --git a/docs/tutorials/polytope_timeseries.ipynb b/docs/tutorials/polytope_timeseries.ipynb index 804ef32..a6214dd 100644 --- a/docs/tutorials/polytope_timeseries.ipynb +++ b/docs/tutorials/polytope_timeseries.ipynb @@ -721,9 +721,7 @@ " },\n", "}\n", "\n", - "ds = ekd.from_source(\n", - " \"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\"\n", - ").to_xarray()\n", + "ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\").to_xarray()\n", "ds" ] }, @@ -753,8 +751,8 @@ } ], "source": [ - "import earthkit.transforms as ekt\n", "import earthkit.plots as ekp\n", + "import earthkit.transforms as ekt\n", "\n", "mean_ds = ekt.ensemble.mean(ds)\n", "\n", @@ -795,9 +793,7 @@ "TIME_FREQUENCY = \"6h\"\n", "QUANTILES = [0, 0.1, 0.25, 0.5, 0.75, 0.9, 1]\n", "\n", - "ekp.timeseries.multiboxplot(ds, resample=TIME_FREQUENCY, quantiles=QUANTILES).line(\n", - " ds.mean(dim=\"number\")\n", - ")" + "ekp.timeseries.multiboxplot(ds, resample=TIME_FREQUENCY, quantiles=QUANTILES).line(ds.mean(dim=\"number\"))" ] } ], diff --git a/docs/tutorials/polytope_vertical_profile.ipynb b/docs/tutorials/polytope_vertical_profile.ipynb index cedc68a..c046b35 100644 --- a/docs/tutorials/polytope_vertical_profile.ipynb +++ b/docs/tutorials/polytope_vertical_profile.ipynb @@ -613,9 +613,7 @@ " },\n", "}\n", "\n", - "ds = ekd.from_source(\n", - " \"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\"\n", - ").to_xarray()\n", + "ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\").to_xarray()\n", "ds" ] } diff --git a/docs/tutorials/time-series-solutions.ipynb b/docs/tutorials/time-series-solutions.ipynb index 1b1c433..8dc0017 100644 --- a/docs/tutorials/time-series-solutions.ipynb +++ b/docs/tutorials/time-series-solutions.ipynb @@ -828,9 +828,7 @@ "\n", "chart.line(data, units=\"celsius\", color=\"red\")\n", "\n", - "chart.title(\n", - " \"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\"\n", - ")\n", + "chart.title(\"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\")\n", "\n", "chart.ylabel()\n", "\n", @@ -880,9 +878,7 @@ "chart.line(data, units=\"celsius\", label=\"hourly\")\n", "chart.line(daily_min, units=\"celsius\", label=\"{name}\")\n", "\n", - "chart.title(\n", - " \"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\"\n", - ")\n", + "chart.title(\"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\")\n", "\n", "chart.ylabel()\n", "\n", @@ -968,9 +964,7 @@ "chart.line(data, units=\"celsius\", label=\"hourly\")\n", "chart.line(daily_min, units=\"celsius\", label=\"{name}\")\n", "\n", - "chart.title(\n", - " \"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\"\n", - ")\n", + "chart.title(\"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\")\n", "\n", "chart.ylabel()\n", "\n", @@ -1019,9 +1013,7 @@ "chart.line(daily_mean, units=\"celsius\", label=\"{name}\")\n", "chart.line(daily_min, units=\"celsius\", label=\"{name}\")\n", "\n", - "chart.title(\n", - " \"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\"\n", - ")\n", + "chart.title(\"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\")\n", "\n", "chart.ylabel()\n", "\n", @@ -1087,9 +1079,7 @@ "import numpy as np\n", "\n", "daily_precip = ekt.temporal.daily_mean(ds)\n", - "daily_precip = daily_precip.assign_coords(\n", - " valid_time=daily_precip.valid_time + np.timedelta64(12, \"h\")\n", - ")" + "daily_precip = daily_precip.assign_coords(valid_time=daily_precip.valid_time + np.timedelta64(12, \"h\"))" ] }, { @@ -1114,9 +1104,7 @@ "\n", "chart.bar(daily_precip, units=\"mm\")\n", "\n", - "chart.title(\n", - " \"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\"\n", - ")\n", + "chart.title(\"ERA5 hourly {variable_name} at {latitude:%Lt} {longitude:%Ln} ({location:%c}, {location:%C})\")\n", "\n", "chart.ylabel()\n", "\n", diff --git a/pyproject.toml b/pyproject.toml index b4b7126..c52d3b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,10 @@ urls.Repository = "https://github.com/ecmwf/earthkit/" [tool.coverage.run] branch = "true" +[tool.pydocstyle] +add_ignore = ["D1", "D200", "D205", "D400", "D401"] +convention = "numpy" + [tool.ruff] line-length = 120 preview = true @@ -72,10 +76,6 @@ select = [ "D" # pydocstyle ] -[tool.pydocstyle] -add_ignore = ["D1", "D200", "D205", "D400", "D401"] -convention = "numpy" - [tool.setuptools] packages = []