eo-tides 0.7.6.dev1__tar.gz → 0.7.6.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/PKG-INFO +2 -2
  2. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/eo_tides/model.py +14 -3
  3. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/eo_tides/utils.py +30 -10
  4. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/pyproject.toml +4 -1
  5. eo_tides-0.7.6.dev2/tests/data/extra_database.json +32 -0
  6. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/test_model.py +61 -0
  7. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/test_utils.py +141 -15
  8. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/testing.ipynb +235 -13
  9. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/uv.lock +7 -7
  10. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.editorconfig +0 -0
  11. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  12. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  13. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/actions/setup-python-env/action.yml +0 -0
  14. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/dependabot.yml +0 -0
  15. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/release.yml +0 -0
  16. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/workflows/check-links.yml +0 -0
  17. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/workflows/paper.yml +0 -0
  18. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/workflows/publish.yml +0 -0
  19. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/workflows/tests.yml +0 -0
  20. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/workflows/update-changelog.yml +0 -0
  21. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.github/workflows/update-version.yml +0 -0
  22. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.gitignore +0 -0
  23. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/.pre-commit-config.yaml +0 -0
  24. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/CITATION.cff +0 -0
  25. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/CONTRIBUTING.md +0 -0
  26. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/Dockerfile +0 -0
  27. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/LICENSE +0 -0
  28. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/Makefile +0 -0
  29. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/README.md +0 -0
  30. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/codecov.yaml +0 -0
  31. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/api.md +0 -0
  32. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/dtu23_download.jpg +0 -0
  33. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/eo-tides-abstract.gif +0 -0
  34. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/eo-tides-logo-128.png +0 -0
  35. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/eo-tides-logo-256.png +0 -0
  36. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/eo-tides-logo.gif +0 -0
  37. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/eo-tides-logo.png +0 -0
  38. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/eot20_download.jpg +0 -0
  39. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/fes_ftp.jpg +0 -0
  40. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/fes_myproducts.jpg +0 -0
  41. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/fes_productselection.jpg +0 -0
  42. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/fes_subscriptions.jpg +0 -0
  43. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/got_download.jpg +0 -0
  44. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/tide_models_clipped.jpg +0 -0
  45. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/assets/tpxo_download.jpg +0 -0
  46. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/changelog.md +0 -0
  47. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/credits.md +0 -0
  48. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/index.md +0 -0
  49. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/install.md +0 -0
  50. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/migration.md +0 -0
  51. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/notebooks/Case_study_intertidal.ipynb +0 -0
  52. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/notebooks/Model_tides.ipynb +0 -0
  53. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/notebooks/Satellite_data.ipynb +0 -0
  54. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/notebooks/Tide_statistics.ipynb +0 -0
  55. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/notebooks/Validating_tides.ipynb +0 -0
  56. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/setup.md +0 -0
  57. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/docs/stylesheets/extra.css +0 -0
  58. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/eo_tides/__init__.py +0 -0
  59. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/eo_tides/eo.py +0 -0
  60. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/eo_tides/stats.py +0 -0
  61. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/eo_tides/validation.py +0 -0
  62. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/mkdocs.yml +0 -0
  63. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/10.21105.joss.07786.pdf +0 -0
  64. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/benchmarking.ipynb +0 -0
  65. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/figures/joss_abstract.png +0 -0
  66. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/figures/joss_fig_gesla.png +0 -0
  67. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/figures/joss_fig_list.png +0 -0
  68. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/figures/joss_fig_pixel.png +0 -0
  69. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/figures/joss_fig_stats.png +0 -0
  70. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/paper.bib +0 -0
  71. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/paper/paper.md +0 -0
  72. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/conftest.py +0 -0
  73. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/data/GESLA3.0_ALL/broome-62650-aus-bom +0 -0
  74. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/data/GESLA3.0_ALL/san_diego_ca-569a-usa-uhslc +0 -0
  75. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/data/GESLA3.0_ALL/sydney_fort_denison-60370-aus-bom +0 -0
  76. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/data/GESLA3_ALL 2.csv +0 -0
  77. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/data/IDO71013_2020.csv +0 -0
  78. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/data/tide_models.tar.gz +0 -0
  79. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/test_eo.py +0 -0
  80. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/test_stats.py +0 -0
  81. {eo_tides-0.7.6.dev1 → eo_tides-0.7.6.dev2}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eo-tides
3
- Version: 0.7.6.dev1
3
+ Version: 0.7.6.dev2
4
4
  Summary: Tide modelling tools for large-scale satellite earth observation analysis
5
5
  Project-URL: Homepage, https://GeoscienceAustralia.github.io/eo-tides/
6
6
  Project-URL: Repository, https://github.com/GeoscienceAustralia/eo-tides
@@ -32,7 +32,7 @@ Requires-Dist: pandas>=2.2.0
32
32
  Requires-Dist: psutil>=5.8.0
33
33
  Requires-Dist: pyogrio>=0.10.0
34
34
  Requires-Dist: pyproj>=3.7.0
35
- Requires-Dist: pytmd<2.2.5,>=2.2.2
35
+ Requires-Dist: pytmd>=2.2.5
36
36
  Requires-Dist: scikit-learn>=1.4.0
37
37
  Requires-Dist: scipy>=1.14.1
38
38
  Requires-Dist: shapely>=2.0.6
@@ -81,13 +81,15 @@ def _model_tides(
81
81
  crop,
82
82
  crop_buffer,
83
83
  append_node,
84
+ extra_databases,
84
85
  ):
85
86
  """Worker function applied in parallel by `model_tides`. Handles the
86
87
  extraction of tide modelling constituents and tide modelling using
87
88
  `pyTMD`.
88
89
  """
89
- # Obtain model details
90
- pytmd_model = pyTMD.io.model(directory).elevation(model)
90
+ # Load models from pyTMD database
91
+ extra_databases = [] if extra_databases is None else extra_databases
92
+ pytmd_model = pyTMD.io.model(directory=directory, extra_databases=extra_databases).elevation(model)
91
93
 
92
94
  # Reproject x, y to latitude/longitude
93
95
  transformer = pyproj.Transformer.from_crs(crs, "EPSG:4326", always_xy=True)
@@ -437,6 +439,7 @@ def model_tides(
437
439
  parallel_splits: int | str = "auto",
438
440
  parallel_max: int | None = None,
439
441
  ensemble_models: list[str] | None = None,
442
+ extra_databases: str | os.PathLike | list | None = None,
440
443
  **ensemble_kwargs,
441
444
  ) -> pd.DataFrame:
442
445
  """
@@ -575,6 +578,11 @@ def model_tides(
575
578
  `["EOT20", "FES2012", "FES2014_extrapolated", "FES2022_extrapolated",
576
579
  "GOT4.10", "GOT5.5_extrapolated", "GOT5.6_extrapolated",
577
580
  "TPXO10-atlas-v2-nc", "TPXO8-atlas-nc", "TPXO9-atlas-v5-nc"]`.
581
+ extra_databases : str or path or list, optional
582
+ Additional custom tide model definitions to load, provided as
583
+ dictionaries or paths to JSON database files. Use this to
584
+ enable custom tide models not included with `pyTMD`.
585
+ See: https://pytmd.readthedocs.io/en/latest/getting_started/Getting-Started.html#model-database
578
586
  **ensemble_kwargs :
579
587
  Keyword arguments used to customise the generation of optional
580
588
  ensemble tide models if "ensemble" modelling are requested.
@@ -621,11 +629,13 @@ def model_tides(
621
629
  # provided, try global environment variable.
622
630
  directory = _set_directory(directory)
623
631
 
624
- # Standardise model list, handling "all" and "ensemble" functionality
632
+ # Standardise model list, handling "all" and "ensemble" functionality,
633
+ # and any custom tide model definitions
625
634
  models_to_process, models_requested, ensemble_models = _standardise_models(
626
635
  model=model,
627
636
  directory=directory,
628
637
  ensemble_models=ensemble_models,
638
+ extra_databases=extra_databases,
629
639
  )
630
640
 
631
641
  # Update tide modelling func to add default keyword arguments that
@@ -642,6 +652,7 @@ def model_tides(
642
652
  crop=crop,
643
653
  crop_buffer=crop_buffer,
644
654
  append_node=append_node,
655
+ extra_databases=extra_databases,
645
656
  )
646
657
 
647
658
  # If automatic parallel splits, calculate optimal value
@@ -12,11 +12,11 @@ from typing import TypeAlias
12
12
  import numpy as np
13
13
  import odc.geo
14
14
  import pandas as pd
15
+ import pyTMD
15
16
  import xarray as xr
16
17
  from colorama import Style, init
17
18
  from odc.geo.geom import BoundingBox
18
19
  from pyTMD.io.model import load_database
19
- from pyTMD.io.model import model as pytmd_model
20
20
  from scipy.spatial import cKDTree as KDTree
21
21
  from tqdm import tqdm
22
22
 
@@ -80,6 +80,7 @@ def _standardise_models(
80
80
  model: str | list[str],
81
81
  directory: str | os.PathLike,
82
82
  ensemble_models: list[str] | None = None,
83
+ extra_databases: str | os.PathLike | list | None = None,
83
84
  ) -> tuple[list[str], list[str], list[str] | None]:
84
85
  """
85
86
  Take an input model name or list of names, and return a list
@@ -89,7 +90,7 @@ def _standardise_models(
89
90
  Handles two special values passed to `model`: "all", which
90
91
  will model tides for all models available in `directory`, and
91
92
  "ensemble", which will model tides for all models in a list
92
- of custom ensemble models.
93
+ of ensemble models.
93
94
  """
94
95
 
95
96
  # Turn inputs into arrays for consistent handling
@@ -100,9 +101,13 @@ def _standardise_models(
100
101
  if len(duplicates) > 0:
101
102
  raise ValueError(f"The model parameter contains duplicate values: {duplicates}")
102
103
 
103
- # Get full list of supported models from pyTMD database
104
+ # Load supported models from pyTMD database
104
105
  available_models, valid_models = list_models(
105
- directory, show_available=False, show_supported=False, raise_error=True
106
+ directory,
107
+ show_available=False,
108
+ show_supported=False,
109
+ raise_error=True,
110
+ extra_databases=extra_databases,
106
111
  )
107
112
  custom_options = ["ensemble", "all"]
108
113
 
@@ -433,8 +438,10 @@ def clip_models(
433
438
  nc_clipped.to_netcdf(output_directory / file, mode="w")
434
439
 
435
440
  # Verify that models are ready
436
- pytmd_model(directory=output_directory).elevation(m=m).verify
437
- print(" ✅ Clipped model exported and verified")
441
+ if pyTMD.io.model(directory=output_directory).elevation(m=m).verify:
442
+ print(" ✅ Clipped model exported and verified")
443
+ else:
444
+ print(" ❌ Clipped model exported but unable to be verified")
438
445
 
439
446
  print(f"\nOutputs exported to {output_directory}")
440
447
  list_models(directory=output_directory, show_available=True, show_supported=False)
@@ -445,6 +452,7 @@ def list_models(
445
452
  show_available: bool = True,
446
453
  show_supported: bool = True,
447
454
  raise_error: bool = False,
455
+ extra_databases: str | os.PathLike | list | None = None,
448
456
  ) -> tuple[list[str], list[str]]:
449
457
  """
450
458
  List all tide models available for tide modelling.
@@ -474,6 +482,11 @@ def list_models(
474
482
  raise_error : bool, optional
475
483
  If True, raise an error if no available models are found.
476
484
  If False, raise a warning.
485
+ extra_databases : str or path or list, optional
486
+ Additional custom tide model definitions to load, provided as
487
+ dictionaries or paths to JSON database files. Use this to
488
+ enable custom tide models not included with `pyTMD`.
489
+ See: https://pytmd.readthedocs.io/en/latest/getting_started/Getting-Started.html#model-database
477
490
 
478
491
  Returns
479
492
  -------
@@ -488,8 +501,11 @@ def list_models(
488
501
  # provided, try global environment variable.
489
502
  directory = _set_directory(directory)
490
503
 
491
- # Get full list of supported models from pyTMD database
492
- model_database = load_database()["elevation"]
504
+ # Load supported models from pyTMD database, adding extras if required
505
+ extra_databases = [] if extra_databases is None else extra_databases
506
+ model_database = load_database(extra_databases=extra_databases)["elevation"]
507
+
508
+ # Get full list of supported models
493
509
  supported_models = list(model_database.keys())
494
510
 
495
511
  # Extract expected model paths
@@ -503,7 +519,7 @@ def list_models(
503
519
  else:
504
520
  model_file = model_file[0] if isinstance(model_file, list) else model_file
505
521
 
506
- # Add path to dict
522
+ # Add expected path to dict, adding directory prefix
507
523
  expected_paths[m] = str(directory / pathlib.Path(model_file).expanduser().parent)
508
524
 
509
525
  # Define column widths
@@ -522,13 +538,17 @@ def list_models(
522
538
  available_models = []
523
539
  for m in supported_models:
524
540
  try:
525
- model_file = pytmd_model(directory=directory).elevation(m=m)
541
+ # Load model
542
+ model_file = pyTMD.io.model(directory=directory, extra_databases=extra_databases).elevation(m=m)
543
+
544
+ # Append model to list of available model
526
545
  available_models.append(m)
527
546
 
528
547
  if show_available:
529
548
  # Mark available models with a green tick
530
549
  status = "✅"
531
550
  print(f"{status:^{status_width}}│ {m:<{name_width}} │ {expected_paths[m]:<{path_width}}")
551
+
532
552
  except FileNotFoundError:
533
553
  if show_supported:
534
554
  # Mark unavailable models with a red cross
@@ -45,7 +45,7 @@ dependencies = [
45
45
  "psutil>=5.8.0",
46
46
  "pyogrio>=0.10.0",
47
47
  "pyproj>=3.7.0",
48
- "pyTMD>=2.2.2,<2.2.5",
48
+ "pyTMD>=2.2.5",
49
49
  "scikit-learn>=1.4.0",
50
50
  "scipy>=1.14.1",
51
51
  "shapely>=2.0.6",
@@ -97,6 +97,9 @@ source = "vcs"
97
97
  [tool.hatch.version.raw-options]
98
98
  local_scheme = "no-local-version"
99
99
 
100
+ [tool.hatch.metadata]
101
+ allow-direct-references = true
102
+
100
103
  [tool.mypy]
101
104
  files = ["eo_tides"]
102
105
  python_version = "3.10"
@@ -0,0 +1,32 @@
1
+ {
2
+ "elevation": {
3
+ "EOT20_custom": {
4
+ "format": "FES-netcdf",
5
+ "model_file": [
6
+ "EOT20/ocean_tides/2N2_ocean_eot20.nc",
7
+ "EOT20/ocean_tides/J1_ocean_eot20.nc",
8
+ "EOT20/ocean_tides/K1_ocean_eot20.nc",
9
+ "EOT20/ocean_tides/K2_ocean_eot20.nc",
10
+ "EOT20/ocean_tides/M2_ocean_eot20.nc",
11
+ "EOT20/ocean_tides/M4_ocean_eot20.nc",
12
+ "EOT20/ocean_tides/MF_ocean_eot20.nc",
13
+ "EOT20/ocean_tides/MM_ocean_eot20.nc",
14
+ "EOT20/ocean_tides/N2_ocean_eot20.nc",
15
+ "EOT20/ocean_tides/O1_ocean_eot20.nc",
16
+ "EOT20/ocean_tides/P1_ocean_eot20.nc",
17
+ "EOT20/ocean_tides/Q1_ocean_eot20.nc",
18
+ "EOT20/ocean_tides/S1_ocean_eot20.nc",
19
+ "EOT20/ocean_tides/S2_ocean_eot20.nc",
20
+ "EOT20/ocean_tides/SA_ocean_eot20.nc",
21
+ "EOT20/ocean_tides/SSA_ocean_eot20.nc",
22
+ "EOT20/ocean_tides/T2_ocean_eot20.nc"
23
+ ],
24
+ "name": "EOT20_custom",
25
+ "reference": "https://doi.org/10.17882/79489",
26
+ "scale": 0.01,
27
+ "type": "z",
28
+ "variable": "tide_ocean",
29
+ "version": "EOT20"
30
+ }
31
+ }
32
+ }
@@ -462,6 +462,67 @@ def test_model_tides_ensemble_dtype(dtype):
462
462
  assert ensemble_df.tide_height.dtype == modelled_tides_df.tide_height.dtype
463
463
 
464
464
 
465
+ # Test listing extra_databases models from dict and file
466
+ @pytest.mark.parametrize(
467
+ "extra_databases",
468
+ [
469
+ # Extra database as a JSON file
470
+ ["./tests/data/extra_database.json"],
471
+ # Extra database as a dictionary
472
+ [
473
+ {
474
+ "elevation": {
475
+ "EOT20_custom": {
476
+ "format": "FES-netcdf",
477
+ "model_file": [
478
+ "EOT20/ocean_tides/2N2_ocean_eot20.nc",
479
+ "EOT20/ocean_tides/J1_ocean_eot20.nc",
480
+ "EOT20/ocean_tides/K1_ocean_eot20.nc",
481
+ "EOT20/ocean_tides/K2_ocean_eot20.nc",
482
+ "EOT20/ocean_tides/M2_ocean_eot20.nc",
483
+ "EOT20/ocean_tides/M4_ocean_eot20.nc",
484
+ "EOT20/ocean_tides/MF_ocean_eot20.nc",
485
+ "EOT20/ocean_tides/MM_ocean_eot20.nc",
486
+ "EOT20/ocean_tides/N2_ocean_eot20.nc",
487
+ "EOT20/ocean_tides/O1_ocean_eot20.nc",
488
+ "EOT20/ocean_tides/P1_ocean_eot20.nc",
489
+ "EOT20/ocean_tides/Q1_ocean_eot20.nc",
490
+ "EOT20/ocean_tides/S1_ocean_eot20.nc",
491
+ "EOT20/ocean_tides/S2_ocean_eot20.nc",
492
+ "EOT20/ocean_tides/SA_ocean_eot20.nc",
493
+ "EOT20/ocean_tides/SSA_ocean_eot20.nc",
494
+ "EOT20/ocean_tides/T2_ocean_eot20.nc",
495
+ ],
496
+ "name": "EOT20_custom",
497
+ "reference": "https://doi.org/10.17882/79489",
498
+ "scale": 0.01,
499
+ "type": "z",
500
+ "variable": "tide_ocean",
501
+ "version": "EOT20",
502
+ }
503
+ }
504
+ }
505
+ ],
506
+ ],
507
+ ids=["file", "dict"],
508
+ )
509
+ def test_model_tides_extra_databases(extra_databases):
510
+ # Run modelling for custom tide model in extra database
511
+ modelled_tides_df = model_tides(
512
+ x=[GAUGE_X],
513
+ y=[GAUGE_Y],
514
+ time=pd.date_range("2020-01-01", "2020-01-02", freq="h"),
515
+ model=["EOT20_custom", "EOT20"],
516
+ extra_databases=extra_databases,
517
+ output_format="wide",
518
+ )
519
+
520
+ # Verify custom column exists and contains data
521
+ assert "EOT20_custom" in modelled_tides_df
522
+ assert modelled_tides_df["EOT20_custom"].notna().any()
523
+ assert np.allclose(modelled_tides_df["EOT20_custom"], modelled_tides_df["EOT20"])
524
+
525
+
465
526
  @pytest.mark.parametrize("time_offset", ["15 min", "20 min"])
466
527
  def test_model_phases(time_offset):
467
528
  phase_df = model_phases(
@@ -6,7 +6,13 @@ import pandas as pd
6
6
  import pytest
7
7
 
8
8
  from eo_tides.model import model_tides
9
- from eo_tides.utils import _standardise_models, _standardise_time, clip_models, idw, list_models
9
+ from eo_tides.utils import (
10
+ _standardise_models,
11
+ _standardise_time,
12
+ clip_models,
13
+ idw,
14
+ list_models,
15
+ )
10
16
 
11
17
 
12
18
  @pytest.mark.parametrize(
@@ -16,11 +22,35 @@ from eo_tides.utils import _standardise_models, _standardise_time, clip_models,
16
22
  ("EOT20", None, ["EOT20"], ["EOT20"], None),
17
23
  (["EOT20"], None, ["EOT20"], ["EOT20"], None),
18
24
  # Case 3, 4: Using "all" to request all available models
19
- ("all", None, ["EOT20", "GOT5.5", "HAMTIDE11"], ["EOT20", "GOT5.5", "HAMTIDE11"], None),
20
- (["all"], None, ["EOT20", "GOT5.5", "HAMTIDE11"], ["EOT20", "GOT5.5", "HAMTIDE11"], None),
25
+ (
26
+ "all",
27
+ None,
28
+ ["EOT20", "GOT5.5", "HAMTIDE11"],
29
+ ["EOT20", "GOT5.5", "HAMTIDE11"],
30
+ None,
31
+ ),
32
+ (
33
+ ["all"],
34
+ None,
35
+ ["EOT20", "GOT5.5", "HAMTIDE11"],
36
+ ["EOT20", "GOT5.5", "HAMTIDE11"],
37
+ None,
38
+ ),
21
39
  # Case 5, 6: Using "ensemble" to model tides for specific set of ensemble models
22
- ("ensemble", ["EOT20", "HAMTIDE11"], ["EOT20", "HAMTIDE11"], ["ensemble"], ["EOT20", "HAMTIDE11"]),
23
- (["ensemble"], ["EOT20", "HAMTIDE11"], ["EOT20", "HAMTIDE11"], ["ensemble"], ["EOT20", "HAMTIDE11"]),
40
+ (
41
+ "ensemble",
42
+ ["EOT20", "HAMTIDE11"],
43
+ ["EOT20", "HAMTIDE11"],
44
+ ["ensemble"],
45
+ ["EOT20", "HAMTIDE11"],
46
+ ),
47
+ (
48
+ ["ensemble"],
49
+ ["EOT20", "HAMTIDE11"],
50
+ ["EOT20", "HAMTIDE11"],
51
+ ["ensemble"],
52
+ ["EOT20", "HAMTIDE11"],
53
+ ),
24
54
  # Case 7: Modelling tides using ensemble set and an additional model
25
55
  (
26
56
  ["ensemble", "GOT5.5"],
@@ -97,14 +127,44 @@ def test_clip_models():
97
127
  @pytest.mark.parametrize(
98
128
  "model, bbox, point, name",
99
129
  [
100
- ("EOT20", (-166, 14, -151, 29), (19.60, -155.46), "hawaii"), # entirely W of prime meridian
130
+ (
131
+ "EOT20",
132
+ (-166, 14, -151, 29),
133
+ (19.60, -155.46),
134
+ "hawaii",
135
+ ), # entirely W of prime meridian
101
136
  ("EOT20", (-13, 49, 6, 60), (51.47, 0.84), "uk"), # crossing prime meridian
102
- ("EOT20", (105, -48, 160, -5), (-25.59, 153.03), "aus"), # entirely E of prime meridian
103
- ("EOT20", (-257, 7, -120, 63), (19.59, -155.45), "pacific"), # crossing antimeridian
104
- ("HAMTIDE11", (-166, 14, -151, 29), (19.60, -155.46), "hawaii"), # entirely W of prime meridian
137
+ (
138
+ "EOT20",
139
+ (105, -48, 160, -5),
140
+ (-25.59, 153.03),
141
+ "aus",
142
+ ), # entirely E of prime meridian
143
+ (
144
+ "EOT20",
145
+ (-257, 7, -120, 63),
146
+ (19.59, -155.45),
147
+ "pacific",
148
+ ), # crossing antimeridian
149
+ (
150
+ "HAMTIDE11",
151
+ (-166, 14, -151, 29),
152
+ (19.60, -155.46),
153
+ "hawaii",
154
+ ), # entirely W of prime meridian
105
155
  ("HAMTIDE11", (-13, 49, 6, 60), (51.47, 0.84), "uk"), # crossing prime meridian
106
- ("HAMTIDE11", (105, -48, 160, -5), (-25.59, 153.03), "aus"), # entirely E of prime meridian
107
- ("HAMTIDE11", (-257, 7, -120, 63), (19.59, -155.45), "pacific"), # crossing antimeridian
156
+ (
157
+ "HAMTIDE11",
158
+ (105, -48, 160, -5),
159
+ (-25.59, 153.03),
160
+ "aus",
161
+ ), # entirely E of prime meridian
162
+ (
163
+ "HAMTIDE11",
164
+ (-257, 7, -120, 63),
165
+ (19.59, -155.45),
166
+ "pacific",
167
+ ), # crossing antimeridian
108
168
  ],
109
169
  )
110
170
  def test_clip_models_bbox(model, bbox, point, name):
@@ -151,11 +211,20 @@ def test_clip_models_bbox(model, bbox, point, name):
151
211
  # Case 1: None
152
212
  (None, None),
153
213
  # Case 2: Single datetime.datetime object
154
- (datetime(2020, 1, 12, 21, 14), np.array(["2020-01-12T21:14:00"], dtype="datetime64[ns]")),
214
+ (
215
+ datetime(2020, 1, 12, 21, 14),
216
+ np.array(["2020-01-12T21:14:00"], dtype="datetime64[ns]"),
217
+ ),
155
218
  # Case 3: Single pandas.Timestamp
156
- (pd.Timestamp("2020-01-12 21:14"), np.array(["2020-01-12T21:14:00"], dtype="datetime64[ns]")),
219
+ (
220
+ pd.Timestamp("2020-01-12 21:14"),
221
+ np.array(["2020-01-12T21:14:00"], dtype="datetime64[ns]"),
222
+ ),
157
223
  # Case 4: np.datetime64 scalar
158
- (np.datetime64("2020-01-12T21:14:00"), np.array(["2020-01-12T21:14:00"], dtype="datetime64[ns]")),
224
+ (
225
+ np.datetime64("2020-01-12T21:14:00"),
226
+ np.array(["2020-01-12T21:14:00"], dtype="datetime64[ns]"),
227
+ ),
159
228
  # Case 5: 1D numpy array of np.datetime64
160
229
  (
161
230
  np.array(["2020-01-12T21:14:00", "2021-02-14T15:30:00"], dtype="datetime64[ns]"),
@@ -169,7 +238,10 @@ def test_clip_models_bbox(model, bbox, point, name):
169
238
  # Case 7: pandas.DatetimeIndex
170
239
  (
171
240
  pd.date_range(start="2000-01-01", end="2000-01-02", periods=3),
172
- np.array(["2000-01-01T00:00:00", "2000-01-01T12:00:00", "2000-01-02T00:00:00"], dtype="datetime64[ns]"),
241
+ np.array(
242
+ ["2000-01-01T00:00:00", "2000-01-01T12:00:00", "2000-01-02T00:00:00"],
243
+ dtype="datetime64[ns]",
244
+ ),
173
245
  ),
174
246
  # Case 8: Mixed array with datetime.datetime and np.datetime64
175
247
  (
@@ -214,6 +286,60 @@ def test_list_models():
214
286
  assert available_models == ["EOT20", "GOT5.5", "HAMTIDE11"]
215
287
 
216
288
 
289
+ # Test running extra_databases models from dict and file
290
+ @pytest.mark.parametrize(
291
+ "extra_databases",
292
+ [
293
+ # Extra database as a JSON file
294
+ ["./tests/data/extra_database.json"],
295
+ # Extra database as a dictionary
296
+ [
297
+ {
298
+ "elevation": {
299
+ "EOT20_custom": {
300
+ "format": "FES-netcdf",
301
+ "model_file": [
302
+ "EOT20/ocean_tides/2N2_ocean_eot20.nc",
303
+ "EOT20/ocean_tides/J1_ocean_eot20.nc",
304
+ "EOT20/ocean_tides/K1_ocean_eot20.nc",
305
+ "EOT20/ocean_tides/K2_ocean_eot20.nc",
306
+ "EOT20/ocean_tides/M2_ocean_eot20.nc",
307
+ "EOT20/ocean_tides/M4_ocean_eot20.nc",
308
+ "EOT20/ocean_tides/MF_ocean_eot20.nc",
309
+ "EOT20/ocean_tides/MM_ocean_eot20.nc",
310
+ "EOT20/ocean_tides/N2_ocean_eot20.nc",
311
+ "EOT20/ocean_tides/O1_ocean_eot20.nc",
312
+ "EOT20/ocean_tides/P1_ocean_eot20.nc",
313
+ "EOT20/ocean_tides/Q1_ocean_eot20.nc",
314
+ "EOT20/ocean_tides/S1_ocean_eot20.nc",
315
+ "EOT20/ocean_tides/S2_ocean_eot20.nc",
316
+ "EOT20/ocean_tides/SA_ocean_eot20.nc",
317
+ "EOT20/ocean_tides/SSA_ocean_eot20.nc",
318
+ "EOT20/ocean_tides/T2_ocean_eot20.nc",
319
+ ],
320
+ "name": "EOT20_custom",
321
+ "reference": "https://doi.org/10.17882/79489",
322
+ "scale": 0.01,
323
+ "type": "z",
324
+ "variable": "tide_ocean",
325
+ "version": "EOT20",
326
+ }
327
+ }
328
+ }
329
+ ],
330
+ ],
331
+ ids=["file", "dict"],
332
+ )
333
+ def test_list_models_extra_databases(extra_databases):
334
+ # Verify that custom models are added to lists of
335
+ # available and supported models
336
+ available_models, supported_models = list_models(
337
+ extra_databases=extra_databases,
338
+ )
339
+ assert "EOT20_custom" in available_models
340
+ assert "EOT20_custom" in supported_models
341
+
342
+
217
343
  # Test Inverse Distance Weighted function
218
344
  def test_idw():
219
345
  # Basic psuedo-1D example
@@ -16,7 +16,7 @@
16
16
  "metadata": {},
17
17
  "outputs": [],
18
18
  "source": [
19
- "!pip install pyTMD==2.2.4"
19
+ "# !pip install pyTMD==2.2.4"
20
20
  ]
21
21
  },
22
22
  {
@@ -30,7 +30,7 @@
30
30
  },
31
31
  {
32
32
  "cell_type": "code",
33
- "execution_count": 1,
33
+ "execution_count": null,
34
34
  "metadata": {},
35
35
  "outputs": [],
36
36
  "source": [
@@ -55,17 +55,9 @@
55
55
  },
56
56
  {
57
57
  "cell_type": "code",
58
- "execution_count": 2,
58
+ "execution_count": null,
59
59
  "metadata": {},
60
- "outputs": [
61
- {
62
- "name": "stdout",
63
- "output_type": "stream",
64
- "text": [
65
- "/home/jovyan/Robbi/eo-tides\n"
66
- ]
67
- }
68
- ],
60
+ "outputs": [],
69
61
  "source": [
70
62
  "cd .."
71
63
  ]
@@ -268,7 +260,7 @@
268
260
  "metadata": {},
269
261
  "outputs": [],
270
262
  "source": [
271
- "!export EO_TIDES_TIDE_MODELS=./tests/data/tide_models && pytest tests/test_model.py --verbose -k test_parallel_splits"
263
+ "!export EO_TIDES_TIDE_MODELS=./tests/data/tide_models && pytest tests/test_model.py --verbose -k test_model_tides_extra_databases"
272
264
  ]
273
265
  },
274
266
  {
@@ -298,6 +290,236 @@
298
290
  "!export EO_TIDES_TIDE_MODELS=./tests/data/tide_models && pytest tests/test_utils.py --verbose -k test_clip_models"
299
291
  ]
300
292
  },
293
+ {
294
+ "cell_type": "code",
295
+ "execution_count": null,
296
+ "metadata": {},
297
+ "outputs": [],
298
+ "source": [
299
+ "!export EO_TIDES_TIDE_MODELS=./tests/data/tide_models && pytest tests/test_utils.py --verbose -k test_list_models_extra_databases"
300
+ ]
301
+ },
302
+ {
303
+ "cell_type": "markdown",
304
+ "metadata": {},
305
+ "source": [
306
+ "## Tests for custom models"
307
+ ]
308
+ },
309
+ {
310
+ "cell_type": "code",
311
+ "execution_count": null,
312
+ "metadata": {},
313
+ "outputs": [],
314
+ "source": [
315
+ "import pyTMD\n",
316
+ "\n",
317
+ "custom_dict = {\n",
318
+ " \"format\": \"FES-netcdf\",\n",
319
+ " \"model_file\": [\n",
320
+ " \"EOT20/ocean_tides/2N2_ocean_eot20.nc\",\n",
321
+ " \"EOT20/ocean_tides/J1_ocean_eot20.nc\",\n",
322
+ " \"EOT20/ocean_tides/K1_ocean_eot20.nc\",\n",
323
+ " \"EOT20/ocean_tides/K2_ocean_eot20.nc\",\n",
324
+ " \"EOT20/ocean_tides/M2_ocean_eot20.nc\",\n",
325
+ " \"EOT20/ocean_tides/M4_ocean_eot20.nc\",\n",
326
+ " \"EOT20/ocean_tides/MF_ocean_eot20.nc\",\n",
327
+ " \"EOT20/ocean_tides/MM_ocean_eot20.nc\",\n",
328
+ " \"EOT20/ocean_tides/N2_ocean_eot20.nc\",\n",
329
+ " \"EOT20/ocean_tides/O1_ocean_eot20.nc\",\n",
330
+ " \"EOT20/ocean_tides/P1_ocean_eot20.nc\",\n",
331
+ " \"EOT20/ocean_tides/Q1_ocean_eot20.nc\",\n",
332
+ " \"EOT20/ocean_tides/S1_ocean_eot20.nc\",\n",
333
+ " \"EOT20/ocean_tides/S2_ocean_eot20.nc\",\n",
334
+ " \"EOT20/ocean_tides/SA_ocean_eot20.nc\",\n",
335
+ " \"EOT20/ocean_tides/SSA_ocean_eot20.nc\",\n",
336
+ " \"EOT20/ocean_tides/T2_ocean_eot20.nc\"\n",
337
+ " ],\n",
338
+ " \"name\": \"EOT20_custom\",\n",
339
+ " \"reference\": \"https://doi.org/10.17882/79489\",\n",
340
+ " \"scale\": 0.01,\n",
341
+ " \"type\": \"z\",\n",
342
+ " \"variable\": \"tide_ocean\",\n",
343
+ " \"version\": \"EOT20\"\n",
344
+ "}\n",
345
+ "\n",
346
+ "\n",
347
+ "\n",
348
+ "pyTMD.io.model(\"/gdata1/data/tide_models\").from_dict(custom_dict).to_dict()"
349
+ ]
350
+ },
351
+ {
352
+ "cell_type": "code",
353
+ "execution_count": null,
354
+ "metadata": {},
355
+ "outputs": [],
356
+ "source": [
357
+ "# Import model def from dict\n",
358
+ "model = pyTMD.io.model(directory=\"/var/share/tide_models/\").from_dict(custom_dict)\n",
359
+ "assert model.verify\n",
360
+ "\n",
361
+ "# Read tidal constants and interpolate to grid points\n",
362
+ "amp, ph, c = model.extract_constants(155, -32)"
363
+ ]
364
+ },
365
+ {
366
+ "cell_type": "code",
367
+ "execution_count": null,
368
+ "metadata": {},
369
+ "outputs": [],
370
+ "source": [
371
+ "model.model_file"
372
+ ]
373
+ },
374
+ {
375
+ "cell_type": "code",
376
+ "execution_count": null,
377
+ "metadata": {},
378
+ "outputs": [],
379
+ "source": [
380
+ "# Import model def from file\n",
381
+ "model = pyTMD.io.model(directory=\"/var/share/tide_models/\").from_file(\"tests/data/model_EOT20custom.json\")\n",
382
+ "assert model.verify\n",
383
+ "\n",
384
+ "# Read tidal constants and interpolate to grid points\n",
385
+ "amp, ph, c = model.extract_constants(155, -32)"
386
+ ]
387
+ },
388
+ {
389
+ "cell_type": "code",
390
+ "execution_count": null,
391
+ "metadata": {},
392
+ "outputs": [],
393
+ "source": [
394
+ "model.model_file"
395
+ ]
396
+ },
397
+ {
398
+ "cell_type": "code",
399
+ "execution_count": null,
400
+ "metadata": {},
401
+ "outputs": [],
402
+ "source": [
403
+ "model.validate_format()"
404
+ ]
405
+ },
406
+ {
407
+ "cell_type": "code",
408
+ "execution_count": null,
409
+ "metadata": {},
410
+ "outputs": [],
411
+ "source": [
412
+ "pyTMD.io.model(\"/gdata1/data/tide_models\").from_file(\"/gdata1/data/tide_models/INATIDES/model_INATIDES.json\").to_dict()"
413
+ ]
414
+ },
415
+ {
416
+ "cell_type": "code",
417
+ "execution_count": null,
418
+ "metadata": {},
419
+ "outputs": [],
420
+ "source": [
421
+ "import pyTMD\n",
422
+ "import pandas as pd\n",
423
+ "from eo_tides.utils import _custom_model_definitions, list_models\n",
424
+ "from eo_tides.model import model_tides\n"
425
+ ]
426
+ },
427
+ {
428
+ "cell_type": "code",
429
+ "execution_count": null,
430
+ "metadata": {},
431
+ "outputs": [],
432
+ "source": [
433
+ "available_models, supported_models = list_models(\n",
434
+ " directory=\"/var/share/tide_models/\",\n",
435
+ " custom_models=[custom_dict],\n",
436
+ " show_supported=False,\n",
437
+ ")"
438
+ ]
439
+ },
440
+ {
441
+ "cell_type": "code",
442
+ "execution_count": null,
443
+ "metadata": {},
444
+ "outputs": [],
445
+ "source": [
446
+ "\n",
447
+ "custom_dict = {\n",
448
+ " \"format\": \"FES-netcdf\",\n",
449
+ " \"model_file\": [\n",
450
+ " \"EOT20/ocean_tides/2N2_ocean_eot20.nc\",\n",
451
+ " \"EOT20/ocean_tides/J1_ocean_eot20.nc\",\n",
452
+ " \"EOT20/ocean_tides/K1_ocean_eot20.nc\",\n",
453
+ " \"EOT20/ocean_tides/K2_ocean_eot20.nc\",\n",
454
+ " \"EOT20/ocean_tides/M2_ocean_eot20.nc\",\n",
455
+ " \"EOT20/ocean_tides/M4_ocean_eot20.nc\",\n",
456
+ " \"EOT20/ocean_tides/MF_ocean_eot20.nc\",\n",
457
+ " \"EOT20/ocean_tides/MM_ocean_eot20.nc\",\n",
458
+ " \"EOT20/ocean_tides/N2_ocean_eot20.nc\",\n",
459
+ " \"EOT20/ocean_tides/O1_ocean_eot20.nc\",\n",
460
+ " \"EOT20/ocean_tides/P1_ocean_eot20.nc\",\n",
461
+ " \"EOT20/ocean_tides/Q1_ocean_eot20.nc\",\n",
462
+ " \"EOT20/ocean_tides/S1_ocean_eot20.nc\",\n",
463
+ " \"EOT20/ocean_tides/S2_ocean_eot20.nc\",\n",
464
+ " \"EOT20/ocean_tides/SA_ocean_eot20.nc\",\n",
465
+ " \"EOT20/ocean_tides/SSA_ocean_eot20.nc\",\n",
466
+ " \"EOT20/ocean_tides/T2_ocean_eot20.nc\"\n",
467
+ " ],\n",
468
+ " \"name\": \"EOT20_custom\",\n",
469
+ " \"reference\": \"https://doi.org/10.17882/79489\",\n",
470
+ " \"scale\": 0.01,\n",
471
+ " \"type\": \"z\",\n",
472
+ " \"variable\": \"tide_ocean\",\n",
473
+ " \"version\": \"EOT20\"\n",
474
+ "}\n",
475
+ "\n",
476
+ "\n",
477
+ "model_tides(\n",
478
+ " x=115.313154,\n",
479
+ " y=-8.668534,\n",
480
+ " time=pd.date_range(\"2022-01-01\", \"2022-01-31\", freq=\"1h\"),\n",
481
+ " model=\"EOT20_custom\",\n",
482
+ " directory=\"/var/share/tide_models/\",\n",
483
+ " custom_models=[custom_dict],\n",
484
+ ")"
485
+ ]
486
+ },
487
+ {
488
+ "cell_type": "code",
489
+ "execution_count": null,
490
+ "metadata": {},
491
+ "outputs": [],
492
+ "source": [
493
+ "df = model_tides(\n",
494
+ " x=115.313154,\n",
495
+ " y=-8.668534,\n",
496
+ " time=pd.date_range(\"2022-01-01\", \"2022-01-31\", freq=\"1h\"),\n",
497
+ " model=[\"INATIDES\", \"EOT20\", \"HAMTIDE11\"],\n",
498
+ " directory=\"/gdata1/data/tide_models\",\n",
499
+ " custom_models=[\"/gdata1/data/tide_models/INATIDES/model_INATIDES.json\"],\n",
500
+ " output_format=\"wide\",\n",
501
+ " parallel=False,\n",
502
+ ")"
503
+ ]
504
+ },
505
+ {
506
+ "cell_type": "code",
507
+ "execution_count": null,
508
+ "metadata": {},
509
+ "outputs": [],
510
+ "source": [
511
+ "# Test available tide models\n",
512
+ "def test_list_models_custom():\n",
513
+ " # Verify that custom models are added to lists of\n",
514
+ " # available and supported models\n",
515
+ " available_models, supported_models = list_models(\n",
516
+ " directory=\"./tests/data/tide_models\", \n",
517
+ " custom_models=[\"./tests/data/model_EOT20custom.json\"],\n",
518
+ " )\n",
519
+ " assert \"EOT20_custom\" in available_models\n",
520
+ " assert \"EOT20_custom\" in supported_models\n"
521
+ ]
522
+ },
301
523
  {
302
524
  "cell_type": "markdown",
303
525
  "metadata": {},
@@ -782,7 +782,7 @@ requires-dist = [
782
782
  { name = "pyogrio", specifier = ">=0.10.0" },
783
783
  { name = "pyproj", specifier = ">=3.7.0" },
784
784
  { name = "pystac-client", marker = "extra == 'notebooks'", specifier = ">=0.8.3" },
785
- { name = "pytmd", specifier = ">=2.2.2,<2.2.5" },
785
+ { name = "pytmd", specifier = ">=2.2.5" },
786
786
  { name = "scikit-learn", specifier = ">=1.4.0" },
787
787
  { name = "scipy", specifier = ">=1.14.1" },
788
788
  { name = "shapely", specifier = ">=2.0.6" },
@@ -1881,11 +1881,11 @@ wheels = [
1881
1881
 
1882
1882
  [[package]]
1883
1883
  name = "narwhals"
1884
- version = "1.43.1"
1884
+ version = "1.44.0"
1885
1885
  source = { registry = "https://pypi.org/simple" }
1886
- sdist = { url = "https://files.pythonhosted.org/packages/61/82/9f351a79260a6456db3f53d248268b4c3791f1e3228eec3c745e8816afd6/narwhals-1.43.1.tar.gz", hash = "sha256:6ff56d600da67a0a0980b83bd5577d076772fdba96474076ba4e76c920dbc1e5", size = 496655, upload-time = "2025-06-19T09:37:56.398Z" }
1886
+ sdist = { url = "https://files.pythonhosted.org/packages/56/e5/0b875d29e2a4d112c58fef6aac2ed3a73bbdd4d8d0dce722fd154357248a/narwhals-1.44.0.tar.gz", hash = "sha256:8cf0616d4f6f21225b3b56fcde96ccab6d05023561a0f162402aa9b8c33ad31d", size = 499250, upload-time = "2025-06-23T08:28:08.653Z" }
1887
1887
  wheels = [
1888
- { url = "https://files.pythonhosted.org/packages/8f/1e/b741d4eabbde95b1790e7df3c33c6b19f9b48db98a1416c6a6f06572bc66/narwhals-1.43.1-py3-none-any.whl", hash = "sha256:1ee508fa4dc0e05aa5b88717ba11613d8d9ccf0dd1e48513d4a3afb237dba9f2", size = 362737, upload-time = "2025-06-19T09:37:54.415Z" },
1888
+ { url = "https://files.pythonhosted.org/packages/ff/fb/12f4a971467aac3cb7cbccbbfca5d0f05e23722068112c1ac4a393613ebe/narwhals-1.44.0-py3-none-any.whl", hash = "sha256:a170ea0bab4cf1f323d9f8bf17f2d7042c3d73802bea321996b39bf075d57de5", size = 365240, upload-time = "2025-06-23T08:28:06.314Z" },
1889
1889
  ]
1890
1890
 
1891
1891
  [[package]]
@@ -2864,7 +2864,7 @@ wheels = [
2864
2864
 
2865
2865
  [[package]]
2866
2866
  name = "pytmd"
2867
- version = "2.2.4"
2867
+ version = "2.2.5"
2868
2868
  source = { registry = "https://pypi.org/simple" }
2869
2869
  dependencies = [
2870
2870
  { name = "lxml" },
@@ -2878,9 +2878,9 @@ dependencies = [
2878
2878
  { name = "setuptools-scm" },
2879
2879
  { name = "timescale" },
2880
2880
  ]
2881
- sdist = { url = "https://files.pythonhosted.org/packages/72/dd/4368e24136a3964437457e84f579930ed2984073cddb3ee5683ea161d983/pytmd-2.2.4.tar.gz", hash = "sha256:0b38d499b0159209b20efd89a454c2651a44eba58cec1df3097142ae37d76d72", size = 6334322, upload-time = "2025-05-07T18:31:33.588Z" }
2881
+ sdist = { url = "https://files.pythonhosted.org/packages/93/d4/b087234e49a1e9b206a7260f185ecf297fc1c60c49c16c07acc6859b117f/pytmd-2.2.5.tar.gz", hash = "sha256:4e969c693205607cc34577b1488c93d6191681e52bc1c04f897033b59f4403f3", size = 6335895, upload-time = "2025-06-23T16:40:28.904Z" }
2882
2882
  wheels = [
2883
- { url = "https://files.pythonhosted.org/packages/e5/47/b0aa85b8f883ab2d92c6404acdb305d82b667fea2537db91a55ba994ccaf/pytmd-2.2.4-py3-none-any.whl", hash = "sha256:f289d8827733f8cacbb6bc2e435c58e1bb498eb37d771df60d4bbd4baca0b81d", size = 6356538, upload-time = "2025-05-07T18:31:31.338Z" },
2883
+ { url = "https://files.pythonhosted.org/packages/cd/8c/db1e1f72ebde819e072b67a9a74b54429e5a1023d83753dd2dc9b11c7217/pytmd-2.2.5-py3-none-any.whl", hash = "sha256:2ec5ae56d98a3464bf2d05cffcef0bba2bd5f1a325068b6cbabeb90ecdbef8ec", size = 6358190, upload-time = "2025-06-23T16:40:27.054Z" },
2884
2884
  ]
2885
2885
 
2886
2886
  [[package]]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes