tfv-get-tools 0.2.0__tar.gz → 0.2.2__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 (75) hide show
  1. tfv_get_tools-0.2.2/LICENSE +21 -0
  2. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/PKG-INFO +8 -7
  3. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/README.md +5 -6
  4. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/pyproject.toml +1 -1
  5. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/_merger.py +9 -16
  6. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/era5.py +13 -7
  7. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools.egg-info/PKG-INFO +8 -7
  8. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools.egg-info/SOURCES.txt +1 -0
  9. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/tests/test_all_downloaders.py +41 -28
  10. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/tests/test_mergers.py +36 -1
  11. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/setup.cfg +0 -0
  12. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/__init__.py +0 -0
  13. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/_standard_attrs.py +0 -0
  14. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/atmos.py +0 -0
  15. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/cli/_cli_base.py +0 -0
  16. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/cli/atmos_cli.py +0 -0
  17. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/cli/ocean_cli.py +0 -0
  18. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/cli/tide_cli.py +0 -0
  19. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/cli/wave_cli.py +0 -0
  20. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/fvc/__init__.py +0 -0
  21. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/fvc/_atmos.py +0 -0
  22. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/fvc/_fvc.py +0 -0
  23. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/fvc/_ocean.py +0 -0
  24. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/fvc/_tide.py +0 -0
  25. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/ocean.py +0 -0
  26. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/__init__.py +0 -0
  27. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/_custom_conversions.py +0 -0
  28. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/_downloader.py +0 -0
  29. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/_utilities.py +0 -0
  30. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/barra2.py +0 -0
  31. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/cfgs/barra2_c2.yaml +0 -0
  32. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/cfgs/barra2_r2.yaml +0 -0
  33. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/cfgs/barra2_re2.yaml +0 -0
  34. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/cfgs/cfsr.yaml +0 -0
  35. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/cfgs/era5.yaml +0 -0
  36. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/cfgs/era5_gcp.yaml +0 -0
  37. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/cfsr.py +0 -0
  38. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/era5.py +0 -0
  39. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/atmos/era5_gcp.py +0 -0
  40. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/ocean/cfgs/copernicus_blk.yaml +0 -0
  41. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/ocean/cfgs/copernicus_glo.yaml +0 -0
  42. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/ocean/cfgs/copernicus_nws.yaml +0 -0
  43. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/ocean/cfgs/hycom.yaml +0 -0
  44. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/ocean/copernicus_ocean.py +0 -0
  45. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/ocean/hycom.py +0 -0
  46. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cawcr.py +0 -0
  47. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/cawcr_aus_10m.yaml +0 -0
  48. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/cawcr_aus_4m.yaml +0 -0
  49. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/cawcr_glob_24m.yaml +0 -0
  50. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/cawcr_pac_10m.yaml +0 -0
  51. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/cawcr_pac_4m.yaml +0 -0
  52. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/copernicus_glo.yaml +0 -0
  53. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/copernicus_nws.yaml +0 -0
  54. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/era5.yaml +0 -0
  55. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/cfgs/era5_gcp.yaml +0 -0
  56. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/copernicus_wave.py +0 -0
  57. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/providers/wave/era5_gcp.py +0 -0
  58. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/tide/__init__.py +0 -0
  59. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/tide/_nodestring.py +0 -0
  60. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/tide/_tidal_base.py +0 -0
  61. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/utilities/_tfv_bc.py +0 -0
  62. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/utilities/horizontal_padding.py +0 -0
  63. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/utilities/land_masking.py +0 -0
  64. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/utilities/parsers.py +0 -0
  65. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/utilities/warnings.py +0 -0
  66. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools/wave.py +0 -0
  67. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools.egg-info/dependency_links.txt +0 -0
  68. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools.egg-info/entry_points.txt +0 -0
  69. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools.egg-info/requires.txt +0 -0
  70. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/src/tfv_get_tools.egg-info/top_level.txt +0 -0
  71. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/tests/test_cli_get_atmos.py +0 -0
  72. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/tests/test_downloader.py +0 -0
  73. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/tests/test_era5_merger.py +0 -0
  74. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/tests/test_frontend_python_api.py +0 -0
  75. {tfv_get_tools-0.2.0 → tfv_get_tools-0.2.2}/tests/test_tide_extraction.py +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 BMT
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tfv_get_tools
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Tool for downloading and processing data for TUFLOW FV modelling
5
5
  Author-email: Alex Waterhouse <alex.waterhouse@apac.bmt.org>, Mitchell Smith <mitchell.smith@apac.bmt.org>, TUFLOW Support <support@tuflow.com>
6
6
  License: MIT
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Programming Language :: Python :: 3.13
19
19
  Requires-Python: <3.14,>=3.9
20
20
  Description-Content-Type: text/markdown
21
+ License-File: LICENSE
21
22
  Requires-Dist: netCDF4>=1.6.2
22
23
  Requires-Dist: tqdm>=4.65.0
23
24
  Requires-Dist: xarray>=2023.1.0
@@ -41,6 +42,7 @@ Requires-Dist: sphinx>=7.3.7; extra == "dev"
41
42
  Requires-Dist: recommonmark>=0.7.1; extra == "dev"
42
43
  Requires-Dist: sphinx-markdown-builder>=0.6.6; extra == "dev"
43
44
  Requires-Dist: pyprojroot; extra == "dev"
45
+ Dynamic: license-file
44
46
 
45
47
  # TFV Get Tools
46
48
 
@@ -58,22 +60,22 @@ TFV Get Tools is a Python package that simplifies the process of downloading and
58
60
  ### Supported Data Sources
59
61
 
60
62
  **Atmospheric Data:**
61
- - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (Default - registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
63
+ - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (*Atmos Default* - registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
62
64
  - [NOAA CFSR](https://www.ncei.noaa.gov/data/climate-forecast-system/) (Climate Forecast System Reanalysis)
63
65
  - [BARRA2](http://www.bom.gov.au/research/projects/reanalysis/) (Australian Bureau of Meteorology)
64
66
 
65
67
  **Ocean Data:**
66
- - [HYCOM](https://www.hycom.org/) (Naval Research Laboratory - Global Ocean Forecast System)
68
+ - [HYCOM](https://www.hycom.org/) (*Ocean Default* Naval Research Laboratory - Global Ocean Forecast System)
67
69
  - [Copernicus Marine](https://marine.copernicus.eu/) Global and NWS (registration required, see [Copernicus Marine Service](https://marine.copernicus.eu/))
68
70
 
69
71
  **Wave Data:**
70
- - [CSIRO CAWCR](https://data.csiro.au/collection/csiro:39819) (glob_24m, aus_10m, aus_4m, pac_10m, pac_4m)
72
+ - [CSIRO CAWCR](https://data.csiro.au/collection/csiro:39819) (*Wave Default* glob_24m, aus_10m, aus_4m, pac_10m, pac_4m)
71
73
  - [Copernicus Marine](https://marine.copernicus.eu/) Global and NWS
72
74
  - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
73
75
 
74
76
  **Tidal Data:**
75
77
  - [FES2014](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (AVISO+ Finite Element Solution 2014)
76
- - [FES2022](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (AVISO+ Finite Element Solution 2022)
78
+ - [FES2022](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (*Tide Default* AVISO+ Finite Element Solution 2022)
77
79
 
78
80
  ## Installation
79
81
 
@@ -255,7 +257,6 @@ This package utilises data from multiple authoritative sources. Please ensure ap
255
257
  For questions, bug reports, or feature requests:
256
258
  - 📧 **Email**: support@tuflow.com
257
259
  - 🐛 **Issues**: Submit via the project repository
258
- - 📖 **Documentation**: [Link to documentation] (if available)
259
260
 
260
261
  ## Contributing
261
262
 
@@ -275,7 +276,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
275
276
 
276
277
  ## Authors
277
278
 
278
- Developed by [BMT](https://www.bmt.org/), 2025
279
+ Developed by [TUFLOW](https://www.tuflow.com/), 2025
279
280
 
280
281
  ## Project Status
281
282
 
@@ -14,22 +14,22 @@ TFV Get Tools is a Python package that simplifies the process of downloading and
14
14
  ### Supported Data Sources
15
15
 
16
16
  **Atmospheric Data:**
17
- - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (Default - registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
17
+ - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (*Atmos Default* - registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
18
18
  - [NOAA CFSR](https://www.ncei.noaa.gov/data/climate-forecast-system/) (Climate Forecast System Reanalysis)
19
19
  - [BARRA2](http://www.bom.gov.au/research/projects/reanalysis/) (Australian Bureau of Meteorology)
20
20
 
21
21
  **Ocean Data:**
22
- - [HYCOM](https://www.hycom.org/) (Naval Research Laboratory - Global Ocean Forecast System)
22
+ - [HYCOM](https://www.hycom.org/) (*Ocean Default* Naval Research Laboratory - Global Ocean Forecast System)
23
23
  - [Copernicus Marine](https://marine.copernicus.eu/) Global and NWS (registration required, see [Copernicus Marine Service](https://marine.copernicus.eu/))
24
24
 
25
25
  **Wave Data:**
26
- - [CSIRO CAWCR](https://data.csiro.au/collection/csiro:39819) (glob_24m, aus_10m, aus_4m, pac_10m, pac_4m)
26
+ - [CSIRO CAWCR](https://data.csiro.au/collection/csiro:39819) (*Wave Default* glob_24m, aus_10m, aus_4m, pac_10m, pac_4m)
27
27
  - [Copernicus Marine](https://marine.copernicus.eu/) Global and NWS
28
28
  - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
29
29
 
30
30
  **Tidal Data:**
31
31
  - [FES2014](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (AVISO+ Finite Element Solution 2014)
32
- - [FES2022](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (AVISO+ Finite Element Solution 2022)
32
+ - [FES2022](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (*Tide Default* AVISO+ Finite Element Solution 2022)
33
33
 
34
34
  ## Installation
35
35
 
@@ -211,7 +211,6 @@ This package utilises data from multiple authoritative sources. Please ensure ap
211
211
  For questions, bug reports, or feature requests:
212
212
  - 📧 **Email**: support@tuflow.com
213
213
  - 🐛 **Issues**: Submit via the project repository
214
- - 📖 **Documentation**: [Link to documentation] (if available)
215
214
 
216
215
  ## Contributing
217
216
 
@@ -231,7 +230,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
231
230
 
232
231
  ## Authors
233
232
 
234
- Developed by [BMT](https://www.bmt.org/), 2025
233
+ Developed by [TUFLOW](https://www.tuflow.com/), 2025
235
234
 
236
235
  ## Project Status
237
236
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tfv_get_tools"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "Tool for downloading and processing data for TUFLOW FV modelling"
5
5
  authors = [
6
6
  { name = "Alex Waterhouse", email = "alex.waterhouse@apac.bmt.org" },
@@ -208,30 +208,23 @@ class BaseMerger(ABC):
208
208
  download_interval = self.cfg.get("_DOWNLOAD_INTERVAL", "monthly")
209
209
 
210
210
  if download_interval == "monthly":
211
- start_time_strings = [x.stem.split("_")[-2] for x in file_list]
212
- end_time_strings = [x.stem.split("_")[-1] for x in file_list]
211
+ time_stings = [re.search(r'_(\d{8})_(\d{8})', x.stem) for x in file_list]
212
+ start_time_strings = [x.group(1) for x in time_stings]
213
+ end_time_strings = [x.group(2) for x in time_stings]
214
+
213
215
  start_times = pd.DatetimeIndex(
214
- [pd.Timestamp(x, unit="h") for x in start_time_strings]
216
+ [pd.to_datetime(x, format="%Y%m%d") for x in start_time_strings]
215
217
  )
216
218
  end_times = pd.DatetimeIndex(
217
- [pd.Timestamp(x, unit="h") for x in end_time_strings]
219
+ [pd.to_datetime(x, format="%Y%m%d") for x in end_time_strings]
218
220
  )
219
221
 
220
222
  elif download_interval == "daily":
221
- start_time_strings = [x.stem.split("_")[-1] for x in file_list]
222
-
223
- # Handle legacy HYCOM files
224
- if start_time_strings and start_time_strings[0] == "0000":
225
- if self.verbose:
226
- print("WARNING: Detected legacy HYCOM files with time suffixes")
227
- start_time_strings = [
228
- x.name.split(".")[0].split("_")[-2] for x in file_list
229
- ]
230
-
223
+ start_time_strings = [re.search(r'_(\d{8})_', x.stem).group(1) for x in file_list]
231
224
  start_times = pd.DatetimeIndex(
232
- [pd.Timestamp(x, unit="h") for x in start_time_strings]
225
+ [pd.to_datetime(x, format="%Y%m%d") for x in start_time_strings]
233
226
  )
234
- end_times = start_times + pd.Timedelta("23.9h")
227
+ end_times = start_times + pd.Timedelta("23.99h")
235
228
  else:
236
229
  raise ValueError(f"Unknown download interval: {download_interval}")
237
230
 
@@ -99,13 +99,19 @@ class DownloadERA5Wave(BaseDownloader):
99
99
  print("You can find your key at: https://cds.climate.copernicus.eu/user/")
100
100
  print("="*60)
101
101
 
102
+ elif "cds-beta.climate.copernicus.eu" in error_msg:
103
+ print("\n" + "="*60)
104
+ print("CDS API AUTHENTICATION ERROR")
105
+ print("="*60)
106
+ print("Your CDS API key appears to be invalid.")
107
+ print("This is likely due to an update by the Copernicus Climate Data Store.")
108
+ print("Please check your .cdsapirc file and ensure your API key is correct.")
109
+ print("You can find your key at: https://cds.climate.copernicus.eu/user/")
110
+ print("="*60)
111
+
102
112
  else:
103
- # For any other errors, show the original message if verbose
104
- if self.verbose:
105
- print(f"Failed to download via CDS API: {e}")
106
- else:
107
- # Always show some info for unhandled errors
108
- print(f"\nCDS API Error: {e}")
113
+ print(f"Failed to download via CDS API: {e}")
114
+
109
115
 
110
116
  return False
111
117
 
@@ -229,4 +235,4 @@ class MergeERA5Wave(BaseMerger):
229
235
  if 'latitude' in merged.coords:
230
236
  merged = merged.sortby("latitude")
231
237
 
232
- return merged, skipped_files
238
+ return merged, skipped_files
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tfv_get_tools
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Tool for downloading and processing data for TUFLOW FV modelling
5
5
  Author-email: Alex Waterhouse <alex.waterhouse@apac.bmt.org>, Mitchell Smith <mitchell.smith@apac.bmt.org>, TUFLOW Support <support@tuflow.com>
6
6
  License: MIT
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Programming Language :: Python :: 3.13
19
19
  Requires-Python: <3.14,>=3.9
20
20
  Description-Content-Type: text/markdown
21
+ License-File: LICENSE
21
22
  Requires-Dist: netCDF4>=1.6.2
22
23
  Requires-Dist: tqdm>=4.65.0
23
24
  Requires-Dist: xarray>=2023.1.0
@@ -41,6 +42,7 @@ Requires-Dist: sphinx>=7.3.7; extra == "dev"
41
42
  Requires-Dist: recommonmark>=0.7.1; extra == "dev"
42
43
  Requires-Dist: sphinx-markdown-builder>=0.6.6; extra == "dev"
43
44
  Requires-Dist: pyprojroot; extra == "dev"
45
+ Dynamic: license-file
44
46
 
45
47
  # TFV Get Tools
46
48
 
@@ -58,22 +60,22 @@ TFV Get Tools is a Python package that simplifies the process of downloading and
58
60
  ### Supported Data Sources
59
61
 
60
62
  **Atmospheric Data:**
61
- - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (Default - registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
63
+ - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (*Atmos Default* - registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
62
64
  - [NOAA CFSR](https://www.ncei.noaa.gov/data/climate-forecast-system/) (Climate Forecast System Reanalysis)
63
65
  - [BARRA2](http://www.bom.gov.au/research/projects/reanalysis/) (Australian Bureau of Meteorology)
64
66
 
65
67
  **Ocean Data:**
66
- - [HYCOM](https://www.hycom.org/) (Naval Research Laboratory - Global Ocean Forecast System)
68
+ - [HYCOM](https://www.hycom.org/) (*Ocean Default* Naval Research Laboratory - Global Ocean Forecast System)
67
69
  - [Copernicus Marine](https://marine.copernicus.eu/) Global and NWS (registration required, see [Copernicus Marine Service](https://marine.copernicus.eu/))
68
70
 
69
71
  **Wave Data:**
70
- - [CSIRO CAWCR](https://data.csiro.au/collection/csiro:39819) (glob_24m, aus_10m, aus_4m, pac_10m, pac_4m)
72
+ - [CSIRO CAWCR](https://data.csiro.au/collection/csiro:39819) (*Wave Default* glob_24m, aus_10m, aus_4m, pac_10m, pac_4m)
71
73
  - [Copernicus Marine](https://marine.copernicus.eu/) Global and NWS
72
74
  - [ECMWF ERA5](https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5) (registration required, see [CDS API](https://cds.climate.copernicus.eu/api-how-to))
73
75
 
74
76
  **Tidal Data:**
75
77
  - [FES2014](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (AVISO+ Finite Element Solution 2014)
76
- - [FES2022](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (AVISO+ Finite Element Solution 2022)
78
+ - [FES2022](https://www.aviso.altimetry.fr/en/data/products/auxiliary-products/global-tide-fes.html) (*Tide Default* AVISO+ Finite Element Solution 2022)
77
79
 
78
80
  ## Installation
79
81
 
@@ -255,7 +257,6 @@ This package utilises data from multiple authoritative sources. Please ensure ap
255
257
  For questions, bug reports, or feature requests:
256
258
  - 📧 **Email**: support@tuflow.com
257
259
  - 🐛 **Issues**: Submit via the project repository
258
- - 📖 **Documentation**: [Link to documentation] (if available)
259
260
 
260
261
  ## Contributing
261
262
 
@@ -275,7 +276,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
275
276
 
276
277
  ## Authors
277
278
 
278
- Developed by [BMT](https://www.bmt.org/), 2025
279
+ Developed by [TUFLOW](https://www.tuflow.com/), 2025
279
280
 
280
281
  ## Project Status
281
282
 
@@ -1,3 +1,4 @@
1
+ LICENSE
1
2
  README.md
2
3
  pyproject.toml
3
4
  src/tfv_get_tools/__init__.py
@@ -9,11 +9,16 @@ from tfv_get_tools import DownloadAtmos, DownloadOcean, DownloadWave
9
9
 
10
10
 
11
11
  # Loopy test :) Add new sources here
12
+ # Turned off Copernicus because of login checks
13
+ # We could mock this properly but I think it
14
+ # is low value...
15
+ # There is a test for login failure low which will only trigger
16
+ # if it asks for stdin user/password, which means it is working
12
17
  @pytest.mark.parametrize(
13
18
  "source,downloader_class,model",
14
19
  [
15
- ("COPERNICUS", DownloadOcean, "GLO"),
16
- ("COPERNICUS", DownloadWave, "GLO"),
20
+ # ("COPERNICUS", DownloadOcean, "GLO"),
21
+ # ("COPERNICUS", DownloadWave, "GLO"),
17
22
  ("HYCOM", DownloadOcean, None),
18
23
  ("CAWCR", DownloadWave, "glob_24m"),
19
24
  ("CAWCR", DownloadWave, "aus_10m"),
@@ -59,36 +64,44 @@ class TestDownloaderIntegration:
59
64
  skip_check = True
60
65
 
61
66
  def test_copernicus_ocean_glo(self):
62
- """Test COPERNICUS ocean downloader with GLO model."""
67
+ """Test COPERNICUS ocean downloader with GLO model.
68
+ These could be better - I am testing that copernicus kicks off ok
69
+ and that it triggers a manual user login via terminal"""
63
70
  with tempfile.TemporaryDirectory() as temp_dir:
64
- result = DownloadOcean(
65
- start_date=self.start_date,
66
- end_date=self.end_date,
67
- xlims=self.xlims,
68
- ylims=self.ylims,
69
- source="COPERNICUS",
70
- model="GLO",
71
- out_path=temp_dir,
72
- TEST_MODE=self.test_mode,
73
- skip_check=self.skip_check,
74
- )
75
- assert result is not None
71
+
72
+ with pytest.raises(OSError,
73
+ match="reading from stdin"):
74
+ result = DownloadOcean(
75
+ start_date=self.start_date,
76
+ end_date=self.end_date,
77
+ xlims=self.xlims,
78
+ ylims=self.ylims,
79
+ source="COPERNICUS",
80
+ model="GLO",
81
+ out_path=temp_dir,
82
+ TEST_MODE=self.test_mode,
83
+ skip_check=self.skip_check,
84
+ )
85
+
76
86
 
77
87
  def test_copernicus_wave_glo(self):
78
- """Test COPERNICUS wave downloader with GLO model."""
88
+ """Test COPERNICUS wave downloader with GLO model.
89
+ These could be better - I am testing that copernicus kicks off ok
90
+ and that it triggers a manual user login via terminal"""
79
91
  with tempfile.TemporaryDirectory() as temp_dir:
80
- result = DownloadWave(
81
- start_date=self.start_date,
82
- end_date=self.end_date,
83
- xlims=self.xlims,
84
- ylims=self.ylims,
85
- source="COPERNICUS",
86
- model="GLO",
87
- out_path=temp_dir,
88
- TEST_MODE=self.test_mode,
89
- skip_check=self.skip_check,
90
- )
91
- assert result is not None
92
+ with pytest.raises(OSError,
93
+ match="reading from stdin"):
94
+ result = DownloadWave(
95
+ start_date=self.start_date,
96
+ end_date=self.end_date,
97
+ xlims=self.xlims,
98
+ ylims=self.ylims,
99
+ source="COPERNICUS",
100
+ model="GLO",
101
+ out_path=temp_dir,
102
+ TEST_MODE=self.test_mode,
103
+ skip_check=self.skip_check,
104
+ )
92
105
 
93
106
  def test_hycom_ocean(self):
94
107
  """Test HYCOM ocean downloader."""
@@ -378,7 +378,7 @@ class TestFileHandling:
378
378
  assert "RANDOM_FILE.nc" not in era5_files
379
379
  assert "ERA5_WAVE_20220101_20220131.nc" not in era5_files
380
380
 
381
- def test_time_filtering(self):
381
+ def test_time_filtering_simple_ERA5(self):
382
382
  """Test filtering files by time range."""
383
383
  # Create files with different dates
384
384
  test_files = [
@@ -408,6 +408,41 @@ class TestFileHandling:
408
408
  assert "ERA5_ATMOS_20220201_20220228.nc" in filtered_files
409
409
  # Should exclude March file
410
410
  assert "ERA5_ATMOS_20220301_20220331.nc" not in filtered_files
411
+
412
+ def test_time_filtering_painful_HYCOM(self):
413
+ """Test filtering files by time range."""
414
+ # Create files with different dates
415
+ test_files = [
416
+ "HYCOM_OCEAN_20220101_03h.nc",
417
+ "HYCOM_OCEAN_20220102_03h_somedbase.nc",
418
+ "A_LONG_PREFIX_BOUND_TO_GET_YA_HYCOM_OCEAN_20220103_03h_somedbase.nc",
419
+ "KEEP_ME_HYCOM_OCEAN_20210101_03h.nc",
420
+ "EXCLUDE_ME_HYCOM_OCEAN_20230101_03h.nc",
421
+ "WHY_DID_I_EVER_ALLOW_SUCH_FLEXIBILITY_HYCOM_OCEAN_20220301_03h.nc",
422
+ ]
423
+
424
+ for filename in test_files:
425
+ (self.in_path / filename).touch()
426
+
427
+ # Test filtering with time constraints
428
+ merger = MergeHYCOM(
429
+ in_path=self.in_path,
430
+ out_path=self.out_path,
431
+ time_start="2021-01-01", # Keep em all except the EXCLUDE_ME one
432
+ time_end="2022-09-01",
433
+ execute=False,
434
+ verbose=False
435
+ )
436
+
437
+ files = merger.get_file_list()
438
+ filtered_files = [f.name for f in files]
439
+
440
+ # Should include Jan and Feb files
441
+ assert "KEEP_ME_HYCOM_OCEAN_20210101_03h.nc" in filtered_files
442
+
443
+ # Should exclude March file
444
+ assert "EXCLUDE_ME_HYCOM_OCEAN_20230101_03h.nc" not in filtered_files
445
+
411
446
 
412
447
  def test_no_files_found_error(self):
413
448
  """Test error handling when no files match pattern."""
File without changes