diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 91b00be..08bc8c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,63 +1,43 @@ +default_language_version: + python: python3 +default_stages: +- pre-commit +- pre-push repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + 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$ -- repo: https://github.com/PyCQA/isort - rev: 5.13.2 - hooks: - - id: isort - args: - - -l 120 - - --force-single-line-imports - - --profile black -- repo: https://github.com/psf/black - rev: 24.8.0 - hooks: - - id: black - args: [--line-length=120] -- repo: https://github.com/keewis/blackdoc - rev: v0.3.8 - hooks: - - id: blackdoc - additional_dependencies: [black==23.3.0] - exclude: xr_engine_profile_rst\.py + args: [--fix=lf] + - id: trailing-whitespace + - id: check-case-conflict - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.9 + rev: v0.15.4 hooks: - - id: ruff + - id: ruff-check exclude: '(dev/.*|.*_)\.py$' args: - --line-length=120 - --fix - --exit-non-zero-on-fix - --preview -- repo: https://github.com/executablebooks/mdformat - rev: 0.7.14 - hooks: - - id: mdformat - exclude: cruft-update-template.md + - id: ruff-format - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks - rev: v2.11.0 + rev: v2.16.0 hooks: - id: pretty-format-yaml args: [--autofix, --preserve-quotes] -- repo: https://github.com/sphinx-contrib/sphinx-lint - rev: v1.0.0 - hooks: - - id: sphinx-lint -- repo: https://github.com/tox-dev/pyproject-fmt - rev: "v2.8.0" - hooks: - - id: pyproject-fmt + - id: pretty-format-toml + args: [--autofix] +- repo: local + hooks: + - 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$' diff --git a/docs/tutorials/01_grib_file.ipynb b/docs/tutorials/01_grib_file.ipynb index e01c0df..5a54085 100644 --- a/docs/tutorials/01_grib_file.ipynb +++ b/docs/tutorials/01_grib_file.ipynb @@ -43,7 +43,9 @@ "outputs": [], "source": [ "import io\n", + "\n", "import matplotlib.pyplot as plt\n", + "\n", "from earthkit import data, regrid\n", "\n", "fs = data.from_source(\"file\", \"tz_1000.grib\")" @@ -57,7 +59,7 @@ "outputs": [], "source": [ "# define the interpolation job\n", - "job = regrid.Job(grid='0.2/0.2', area='70/-30/20/70')" + "job = regrid.Job(grid=\"0.2/0.2\", area=\"70/-30/20/70\")" ] }, { @@ -73,27 +75,27 @@ "# note: sel() first iterates through the messages and returns a\n", "# view to the ones matching the conditions\n", "for f in fs.sel(param=\"t\", level=1000):\n", - " # interpolate - \n", + " # interpolate -\n", " # the input is a GRIB message in memory\n", " # the output is a GRIB message in memory stored in a BytesIO object\n", " d = f.message()\n", " data_in = regrid.GribMemoryInput(d)\n", " data_out = io.BytesIO()\n", " job.execute(data_in, data_out)\n", - " \n", + "\n", " # load the resulting GRIB message\n", " g = data.from_source(\"memory\", data_out.getvalue())[0]\n", - " \n", + "\n", " if res is None:\n", " # start accumulation\n", " res = g.to_numpy()\n", - " \n", + "\n", " # get metadata for plotting\n", - " lat, lon = g.data(\"lat\",\"lon\")\n", + " lat, lon = g.data(\"lat\", \"lon\")\n", " else:\n", " # accumulation\n", " res += g.to_numpy()\n", - " \n", + "\n", " num += 1" ] }, @@ -133,7 +135,7 @@ } ], "source": [ - "res /= num \n", + "res /= num\n", "print(f\"num={num}\")\n", "print(res)" ] diff --git a/docs/tutorials/02_grib_fdb.ipynb b/docs/tutorials/02_grib_fdb.ipynb index 3767577..bf0ac2b 100644 --- a/docs/tutorials/02_grib_fdb.ipynb +++ b/docs/tutorials/02_grib_fdb.ipynb @@ -34,8 +34,10 @@ "outputs": [], "source": [ "import io\n", + "\n", "import matplotlib.pyplot as plt\n", "import pyfdb\n", + "\n", "from earthkit import data, regrid" ] }, @@ -64,16 +66,16 @@ "source": [ "# date must be adjusted since FDB only stores recent dates\n", "request = {\n", - " 'class': 'od',\n", - " 'expver': '0001',\n", - " 'stream': 'oper',\n", - " 'date': '20230219',\n", - " 'time': '0000',\n", - " 'domain': 'g',\n", - " 'type': 'fc',\n", - " 'levtype': 'sfc',\n", - " 'step': list(range(0,48,3)),\n", - " 'param': 167\n", + " \"class\": \"od\",\n", + " \"expver\": \"0001\",\n", + " \"stream\": \"oper\",\n", + " \"date\": \"20230219\",\n", + " \"time\": \"0000\",\n", + " \"domain\": \"g\",\n", + " \"type\": \"fc\",\n", + " \"levtype\": \"sfc\",\n", + " \"step\": list(range(0, 48, 3)),\n", + " \"param\": 167,\n", "}\n", "\n", "# Must be set correctly\n", @@ -117,34 +119,34 @@ "outputs": [], "source": [ "# define the interpolation job\n", - "job = regrid.Job(grid='0.2/0.2', area='70/-30/20/70')\n", + "job = regrid.Job(grid=\"0.2/0.2\", area=\"70/-30/20/70\")\n", "\n", "res = None\n", "num = 0\n", "\n", "# iterating through the GRIB fields from the stream\n", "for f in fs:\n", - " # interpolate - \n", + " # interpolate -\n", " # the input is a GRIB message in memory\n", - " # the output is a GRIB message in memory stored in a BytesIO object \n", + " # the output is a GRIB message in memory stored in a BytesIO object\n", " d = f.message()\n", " data_in = regrid.GribMemoryInput(d)\n", " data_out = io.BytesIO()\n", " job.execute(data_in, data_out)\n", - " \n", + "\n", " # load the resulting GRIB message\n", " g = data.from_source(\"memory\", data_out.getvalue())[0]\n", - " \n", + "\n", " if res is None:\n", " # start accumulation\n", " res = g.to_numpy()\n", - " \n", + "\n", " # get metadata for plotting\n", " lat, lon = g.data(\"lat\", \"lon\")\n", " else:\n", " # accumulation\n", " res += g.to_numpy()\n", - " \n", + "\n", " num += 1" ] }, @@ -173,7 +175,7 @@ } ], "source": [ - "res /= num \n", + "res /= num\n", "print(f\"num={num}\")\n", "print(res)" ] diff --git a/docs/tutorials/ensemble.ipynb b/docs/tutorials/ensemble.ipynb index 3a77737..5529387 100644 --- a/docs/tutorials/ensemble.ipynb +++ b/docs/tutorials/ensemble.ipynb @@ -69,8 +69,8 @@ "source": [ "import earthkit.data as ekd\n", "\n", - "ds_fc = ekd.from_source(\"sample\", \"fc_storm_st_jude.grib\") # hi-res forecast\n", - "ds_en = ekd.from_source(\"sample\", \"ens_storm_st_jude.grib\") # ensemble forecast" + "ds_fc = ekd.from_source(\"sample\", \"fc_storm_st_jude.grib\") # hi-res forecast\n", + "ds_en = ekd.from_source(\"sample\", \"ens_storm_st_jude.grib\") # ensemble forecast" ] }, { @@ -1162,15 +1162,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(crs=ccrs.PlateCarree(), \n", - " domain=[-15,15,65,45], size=(7, 6), rows=2, columns=2)\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", @@ -1195,7 +1195,7 @@ "\n", "# the ensemble mean, Xarray\n", "subplot = figure.add_map(1, 0)\n", - "subplot.contourf(fg_mean.sel(step=step), style=gust_style)\n", + "subplot.contourf(fg_mean.sel(step=step), style=gust_style)\n", "subplot.title(\"MEAN\")\n", "subplot.legend(label=\"\")\n", "\n", @@ -1249,14 +1249,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(crs=ccrs.PlateCarree(), domain=[-15,15,65,45], size=(7, 7), rows=8, columns=8)\n", + "figure = ekp.Figure(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7, 7), rows=8, columns=8)\n", "\n", "gust_style = ekp.styles.Style(\n", " colors=[\"#85AAEE\", \"#208EFC\", \"#6CA632\", \"#FFB000\", \"#FF0000\", \"#7A11B1\"],\n", @@ -1281,7 +1281,7 @@ "\n", "# perturbed members, GRIB\n", "for i, f in enumerate(fl_fg.sel({\"metadata.marsType\": \"pf\", \"time.step\": step})):\n", - " subplot = figure.add_map(1+i//8, i%8)\n", + " subplot = figure.add_map(1 + i // 8, i % 8)\n", " subplot.contourf(f, style=gust_style)\n", " subplot.title(\"PF {number}\")\n", "\n", @@ -1294,9 +1294,12 @@ "legends[0].ax.tick_params(labelsize=8)\n", "\n", "figure.title(\n", - " #\"ECMWF Run: {base_time!1:%Y-%m-%d %H} UTC (+{lead_time!1}h)\\n{variable_name!1}\",\n", + " # \"ECMWF Run: {base_time!1:%Y-%m-%d %H} UTC (+{lead_time!1}h)\\n{variable_name!1}\",\n", " \"ECMWF Run: {base_time:%Y-%m-%d %H} UTC (+{lead_time}h)\\n{variable_name}\",\n", - " fontsize=9, horizontalalignment=\"left\", x=0, y=0.96,\n", + " fontsize=9,\n", + " horizontalalignment=\"left\",\n", + " x=0,\n", + " y=0.96,\n", ")\n", "\n", "figure.show()" @@ -1359,30 +1362,27 @@ } ], "source": [ - "chart = ekp.Map(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7,7)) \n", + "chart = ekp.Map(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7, 7))\n", "\n", "# the isoline value\n", "cont_level = [12500]\n", "\n", "# perturbed members\n", "for f in z_en.sel({\"metadata.marsType\": \"pf\"}):\n", - " chart.contour(f, levels=cont_level, linewidths=[0.2, 0.2],colors=\"blue\", labels=False)\n", + " chart.contour(f, levels=cont_level, linewidths=[0.2, 0.2], colors=\"blue\", labels=False)\n", "\n", "# control forecast\n", - "chart.contour(z_en.sel({\"metadata.marsType\": \"cf\"}), levels=cont_level, linewidths=[3, 3],colors=\"red\", labels=False)\n", + "chart.contour(z_en.sel({\"metadata.marsType\": \"cf\"}), levels=cont_level, linewidths=[3, 3], colors=\"red\", labels=False)\n", "\n", "# hres forecasts\n", - "chart.contour(z_fc, levels=cont_level, linewidths=[3, 3],colors=\"orange\", labels=False)\n", - " \n", + "chart.contour(z_fc, levels=cont_level, linewidths=[3, 3], colors=\"orange\", labels=False)\n", + "\n", "chart.land()\n", "chart.coastlines()\n", "chart.borders()\n", "chart.gridlines()\n", "\n", - "chart.title(\n", - " \"ECMWF Run: {base_time:%Y-%m-%d %H} UTC (+{lead_time}h) {variable_name} {level} hPa\",\n", - " fontsize=9\n", - ")\n", + "chart.title(\"ECMWF Run: {base_time:%Y-%m-%d %H} UTC (+{lead_time}h) {variable_name} {level} hPa\", fontsize=9)\n", "\n", "chart.show()" ] @@ -1418,7 +1418,7 @@ "metadata": {}, "outputs": [], "source": [ - "threshold = 28 \n", + "threshold = 28\n", "prob = fl_fg.to_xarray() > threshold\n", "prob = prob.mean(dim=\"member\") * 100" ] @@ -1442,12 +1442,12 @@ ], "source": [ "# define step\n", - "step=78\n", + "step = 78\n", "\n", - "chart = ekp.Map(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7,7)) \n", + "chart = ekp.Map(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7, 7))\n", "\n", "prob_style = ekp.styles.Style(\n", - " levels=[10,20,30,40,50,60,72],\n", + " levels=[10, 20, 30, 40, 50, 60, 72],\n", ")\n", "\n", "chart.contourf(prob.sel(step=datetime.timedelta(hours=step)), style=prob_style)\n", @@ -1456,8 +1456,7 @@ "chart.borders()\n", "chart.gridlines()\n", "chart.legend()\n", - "chart.title(\"{variable_name} (+\" +str(step) + \" h) probability (> \" + str(threshold) + \" m/s)\", \n", - " fontsize=9)\n", + "chart.title(\"{variable_name} (+\" + str(step) + \" h) probability (> \" + str(threshold) + \" m/s)\", fontsize=9)\n", "\n", "chart.show()" ] @@ -1495,7 +1494,7 @@ "metadata": {}, "outputs": [], "source": [ - "perc = 0.8 # 80%\n", + "perc = 0.8 # 80%\n", "perc_xr = fl_fg.to_xarray().quantile(perc, dim=\"member\")" ] }, @@ -1518,9 +1517,9 @@ ], "source": [ "# define step\n", - "step=78\n", + "step = 78\n", "\n", - "chart = ekp.Map(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7,7)) \n", + "chart = ekp.Map(crs=ccrs.PlateCarree(), domain=[-15, 15, 65, 45], size=(7, 7))\n", "\n", "chart.contourf(perc_xr.sel(step=datetime.timedelta(hours=step)), style=gust_style)\n", "chart.land()\n", @@ -1528,8 +1527,7 @@ "chart.borders()\n", "chart.gridlines()\n", "chart.legend()\n", - "chart.title(\"{variable_name} (+\" +str(step) + \" h) percentile \" + str(perc*100) + \" %\", \n", - " fontsize=9)\n", + "chart.title(\"{variable_name} (+\" + str(step) + \" h) percentile \" + str(perc * 100) + \" %\", fontsize=9)\n", "\n", "chart.show()" ] @@ -1606,12 +1604,12 @@ " x = np.percentile(x, y)\n", "\n", " # make line plot object\n", - " line, = plt.plot(x, y, label=f\"step={step}h\", c=colours[step])\n", + " (line,) = plt.plot(x, y, label=f\"step={step}h\", c=colours[step])\n", " lines.append(line)\n", "\n", - "plt.legend(handles=lines, loc='lower right')\n", - "plt.xlabel('Wind gust (m/s)')\n", - "plt.ylabel('Percentage (%)')\n", + "plt.legend(handles=lines, loc=\"lower right\")\n", + "plt.xlabel(\"Wind gust (m/s)\")\n", + "plt.ylabel(\"Percentage (%)\")\n", "plt.show()" ] } diff --git a/docs/tutorials/polytope_polygon.ipynb b/docs/tutorials/polytope_polygon.ipynb index d040a12..9fad8ec 100644 --- a/docs/tutorials/polytope_polygon.ipynb +++ b/docs/tutorials/polytope_polygon.ipynb @@ -586,23 +586,20 @@ "\n", "request = {\n", " \"class\": \"od\",\n", - " \"stream\" : \"enfo\",\n", - " \"type\" : \"pf\",\n", - " \"date\" : -1,\n", - " \"time\" : \"1200\",\n", - " \"levtype\" : \"sfc\",\n", - " \"expver\" : 1,\n", - " \"domain\" : \"g\",\n", - " \"param\" : \"167/169\",\n", - " \"number\" : \"1\",\n", + " \"stream\": \"enfo\",\n", + " \"type\": \"pf\",\n", + " \"date\": -1,\n", + " \"time\": \"1200\",\n", + " \"levtype\": \"sfc\",\n", + " \"expver\": 1,\n", + " \"domain\": \"g\",\n", + " \"param\": \"167/169\",\n", + " \"number\": \"1\",\n", " \"step\": \"0\",\n", - " \"feature\": {\n", - " \"type\": \"polygon\",\n", - " \"shape\": coords\n", - " },\n", + " \"feature\": {\"type\": \"polygon\", \"shape\": coords},\n", "}\n", "\n", - "ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address='polytope.ecmwf.int')\n", + "ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\")\n", "da = ds.to_xarray()\n", "da" ] @@ -636,7 +633,7 @@ "import earthkit.plots as ekp\n", "\n", "chart = ekp.Map(domain=\"Portugal\")\n", - "chart.point_cloud(da['2t'], x=\"y\", y=\"x\")\n", + "chart.point_cloud(da[\"2t\"], x=\"y\", y=\"x\")\n", "\n", "chart.coastlines()\n", "chart.borders()\n", diff --git a/docs/tutorials/polytope_polygon_logo.ipynb b/docs/tutorials/polytope_polygon_logo.ipynb index 01eb1aa..830b8d9 100644 --- a/docs/tutorials/polytope_polygon_logo.ipynb +++ b/docs/tutorials/polytope_polygon_logo.ipynb @@ -1937,15 +1937,17 @@ "import earthkit.plots as ekp\n", "\n", "# define the polygons\n", - "shape1 = [\n", - " [7.258763811234218, 48.793723130601535],\n", - " [7.168488316250347, 49.83398497089428],\n", - " [8.21596726115746, 49.850900108140536],\n", - " [8.22477419294512, 49.63238869079714],\n", - " [7.425045773152021, 49.6375037902404],\n", - " [7.488604743081794, 48.76751542040529],\n", - " [7.262985428883866, 48.762974824632806],\n", - "],\n", + "shape1 = (\n", + " [\n", + " [7.258763811234218, 48.793723130601535],\n", + " [7.168488316250347, 49.83398497089428],\n", + " [8.21596726115746, 49.850900108140536],\n", + " [8.22477419294512, 49.63238869079714],\n", + " [7.425045773152021, 49.6375037902404],\n", + " [7.488604743081794, 48.76751542040529],\n", + " [7.262985428883866, 48.762974824632806],\n", + " ],\n", + ")\n", "\n", "shape2 = [\n", " [8.228175484385758, 49.62363905618946],\n", @@ -2070,39 +2072,37 @@ "\n", "request_pattern = {\n", " \"class\": \"od\",\n", - " \"stream\" : \"enfo\",\n", - " \"type\" : \"pf\",\n", - " \"date\" : -1,\n", - " \"time\" : \"1200\",\n", - " \"levtype\" : \"sfc\",\n", - " \"expver\" : 1,\n", - " \"domain\" : \"g\",\n", - " \"param\" : \"167\",\n", - " \"number\" : \"1\",\n", + " \"stream\": \"enfo\",\n", + " \"type\": \"pf\",\n", + " \"date\": -1,\n", + " \"time\": \"1200\",\n", + " \"levtype\": \"sfc\",\n", + " \"expver\": 1,\n", + " \"domain\": \"g\",\n", + " \"param\": \"167\",\n", + " \"number\": \"1\",\n", " \"step\": \"0\",\n", "}\n", "\n", "chart = ekp.Map(domain=\"Europe\")\n", "\n", "for shape in [shape1, shape2, shape3, shape4, shape5, shape6, shape7, shape8, shape9, shape10, shape11, shape12]:\n", - "\n", " # retrive the given coverage from polytope and convert into Xarray\n", " request = dict(**request_pattern)\n", " request[\"feature\"] = {\"type\": \"polygon\", \"shape\": shape}\n", "\n", - " ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, \n", - " address='polytope.ecmwf.int').to_xarray()\n", + " ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\").to_xarray()\n", "\n", " # add the Xarray dataset to the plot\n", - " chart.point_cloud(ds['2t'], x=\"x\", y=\"y\",s=0.1)\n", + " chart.point_cloud(ds[\"2t\"], x=\"x\", y=\"y\", s=0.1)\n", "\n", "# generate the plot\n", "chart.coastlines()\n", "chart.borders()\n", "chart.gridlines()\n", - " \n", + "\n", "chart.title(\"{variable_name} (number={number})\")\n", - " \n", + "\n", "chart.show()" ] } diff --git a/docs/tutorials/polytope_timeseries.ipynb b/docs/tutorials/polytope_timeseries.ipynb index f9d9ddc..b8f5aff 100644 --- a/docs/tutorials/polytope_timeseries.ipynb +++ b/docs/tutorials/polytope_timeseries.ipynb @@ -74,24 +74,24 @@ "\n", "request = {\n", " \"class\": \"od\",\n", - " \"stream\" : \"enfo\",\n", - " \"type\" : \"pf\",\n", - " \"date\" : -1,\n", - " \"time\" : \"0000\",\n", - " \"levtype\" : \"sfc\",\n", - " \"expver\" : 1, \n", - " \"domain\" : \"g\",\n", - " \"param\" : \"164/167/169\",\n", - " \"number\" : \"1/to/50\",\n", + " \"stream\": \"enfo\",\n", + " \"type\": \"pf\",\n", + " \"date\": -1,\n", + " \"time\": \"0000\",\n", + " \"levtype\": \"sfc\",\n", + " \"expver\": 1,\n", + " \"domain\": \"g\",\n", + " \"param\": \"164/167/169\",\n", + " \"number\": \"1/to/50\",\n", " \"step\": \"0/to/360\",\n", - " \"feature\" : {\n", - " \"type\" : \"timeseries\",\n", + " \"feature\": {\n", + " \"type\": \"timeseries\",\n", " \"points\": [location],\n", " \"axes\": \"step\",\n", " },\n", "}\n", "\n", - "ds = earthkit.data.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address='polytope.ecmwf.int')" + "ds = earthkit.data.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\")" ] }, { @@ -701,6 +701,7 @@ "source": [ "from earthkit.plots.interactive import Chart\n", "\n", + "\n", "def location_to_string(location):\n", " \"\"\"\n", " Converts latitude and longitude to a string representation with degrees\n", @@ -711,13 +712,14 @@ " lon_dir = \"E\" if lon >= 0 else \"W\"\n", " return f\"{abs(lat):.2f}°{lat_dir}, {abs(lon):.2f}°{lon_dir}\"\n", "\n", + "\n", "TIME_FREQUENCY = \"6h\"\n", "QUANTILES = [0, 0.1, 0.25, 0.5, 0.75, 0.9, 1]\n", "\n", "chart = Chart()\n", "chart.title(f\"ECMWF ensemble meteogram at {location_to_string(location)}\")\n", "chart.box(ds, time_frequency=TIME_FREQUENCY, quantiles=QUANTILES)\n", - "chart.line(ds,aggregation='mean', line_color='grey', time_frequency=TIME_FREQUENCY)\n", + "chart.line(ds, aggregation=\"mean\", line_color=\"grey\", time_frequency=TIME_FREQUENCY)\n", "chart.show(renderer=\"png\") # Replace with chart.show() in an interactive session!" ] }, diff --git a/docs/tutorials/polytope_vertical_profile.ipynb b/docs/tutorials/polytope_vertical_profile.ipynb index fb0161f..e0bb2a9 100644 --- a/docs/tutorials/polytope_vertical_profile.ipynb +++ b/docs/tutorials/polytope_vertical_profile.ipynb @@ -530,7 +530,7 @@ " },\n", "}\n", "\n", - "ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address='polytope.ecmwf.int')\n", + "ds = ekd.from_source(\"polytope\", \"ecmwf-mars\", request, stream=False, address=\"polytope.ecmwf.int\")\n", "ds.to_xarray()" ] }, diff --git a/pyproject.toml b/pyproject.toml index 597fce6..bb30e89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,17 +1,10 @@ [build-system] -requires = [ "setuptools>=77", "setuptools-scm[toml]>=8" ] +requires = ["setuptools>=77", "setuptools-scm[toml]>=8"] [project] -name = "earthkit" -description = "Toolkit for earth science workflows" -readme = "README.md" -license = "Apache-2.0" -license-files = [ "LICENSE" ] authors = [ - { name = "European Centre for Medium-Range Weather Forecasts (ECMWF)", email = "software.support@ecmwf.int" }, + {name = "European Centre for Medium-Range Weather Forecasts (ECMWF)", email = "software.support@ecmwf.int"} ] -requires-python = ">=3.10" - classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", @@ -25,9 +18,8 @@ classifiers = [ "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", - "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering" ] -dynamic = [ "version" ] dependencies = [ "earthkit-data[all]>=1rc0", "earthkit-geo[all]>=1rc0", @@ -35,27 +27,61 @@ dependencies = [ "earthkit-meteo>=1rc0", "earthkit-plots>=1rc0", "earthkit-transforms>=1rc0", - "earthkit-utils>=1rc0", + "earthkit-utils>=1rc0" ] -optional-dependencies.test = [ "pytest", "pytest-forked" ] +description = "Toolkit for earth science workflows" +dynamic = ["version"] +license = "Apache-2.0" +license-files = ["LICENSE"] +name = "earthkit" +readme = "README.md" +requires-python = ">=3.10" +optional-dependencies.test = ["pytest", "pytest-forked"] urls.Documentation = "https://earthkit.readthedocs.io/" urls.Homepage = "https://github.com/ecmwf/earthkit/" urls.Issues = "https://github.com/ecmwf/earthkit.issues" urls.Repository = "https://github.com/ecmwf/earthkit/" -[tool.setuptools] -packages = [ ] - -[tool.setuptools_scm] -version_file = "src/earthkit/_version.py" -local_scheme = "no-local-version" +[tool.coverage.run] +branch = "true" [tool.isort] profile = "black" -[tool.coverage.run] -branch = "true" - [tool.pydocstyle] -add_ignore = [ "D1", "D200", "D205", "D400", "D401" ] +add_ignore = ["D1", "D200", "D205", "D400", "D401"] convention = "numpy" + +[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.setuptools] +packages = [] + +[tool.setuptools_scm] +local_scheme = "no-local-version" +version_file = "src/earthkit/_version.py" diff --git a/tests/test_import.py b/tests/test_import.py index d79052e..f85b045 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -11,6 +11,7 @@ import pytest + def test_earthkit_data_import(): import earthkit.data # noqa from earthkit.data import from_source # noqa