pastastore 1.10.0__py3-none-any.whl → 1.10.2__py3-none-any.whl

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.
pastastore/base.py CHANGED
@@ -1477,9 +1477,10 @@ class ModelAccessor:
1477
1477
  names=["oseries", "modelname"],
1478
1478
  )
1479
1479
  modeldf = pd.DataFrame(index=idx)
1480
- modeldf = modeldf.join(
1481
- self.conn.oseries, on=modeldf.index.get_level_values(0)
1482
- ).drop("key_0", axis=1)
1480
+ modeldf = modeldf.join(self.conn.oseries, on=modeldf.index.get_level_values(0))
1481
+ # drop key_0 column if it exists
1482
+ if "key_0" in modeldf.columns:
1483
+ modeldf.drop("key_0", axis=1, inplace=True)
1483
1484
  modeldf["n_stressmodels"] = 0
1484
1485
  for onam, mlnam in modeldf.index:
1485
1486
  mldict = self.conn.get_models(mlnam, return_dict=True)
pastastore/connectors.py CHANGED
@@ -608,7 +608,7 @@ class ConnectorUtil:
608
608
  s.index = pd.to_datetime(s.index, unit="ms")
609
609
  s = s.sort_index() # needed for some reason ...
610
610
  if squeeze:
611
- return s.squeeze()
611
+ return s.squeeze(axis="columns")
612
612
  return s
613
613
 
614
614
  @staticmethod
@@ -12,7 +12,7 @@ from typing import List, Optional, Union
12
12
 
13
13
  import hydropandas as hpd
14
14
  import numpy as np
15
- from hydropandas.io.knmi import _check_latest_measurement_date_de_bilt, get_stations
15
+ from hydropandas.io.knmi import _get_default_settings, download_knmi_data, get_stations
16
16
  from pandas import DataFrame, Series, Timedelta, Timestamp
17
17
  from pastas.timeseries_utils import timestep_weighted_resample
18
18
  from tqdm.auto import tqdm
@@ -25,6 +25,20 @@ logger = logging.getLogger("hydropandas_extension")
25
25
  TimeType = Optional[Union[str, Timestamp]]
26
26
 
27
27
 
28
+ def _check_latest_measurement_date_de_bilt(meteo_var: str, **kwargs):
29
+ # get measurements at de Bilt
30
+ stn_de_bilt = 550 if meteo_var == "RD" else 260
31
+ ts_de_bilt, _, _ = download_knmi_data(
32
+ stn_de_bilt,
33
+ meteo_var,
34
+ start=Timestamp.today() - Timedelta(days=60),
35
+ end=Timestamp.today(),
36
+ settings=_get_default_settings(kwargs),
37
+ stn_name="De Bilt",
38
+ )
39
+ return ts_de_bilt.index[-1] # last measurement date
40
+
41
+
28
42
  @register_pastastore_accessor("hpd")
29
43
  class HydroPandasExtension:
30
44
  """HydroPandas extension for PastaStore.
@@ -171,7 +185,7 @@ class HydroPandasExtension:
171
185
  metadata.pop("name", None)
172
186
  metadata.pop("meta", None)
173
187
  unit = metadata.get("unit", None)
174
- if unit == "m" and np.allclose(unit_multiplier, 1e-3):
188
+ if unit == "m" and np.allclose(unit_multiplier, 1e3):
175
189
  metadata["unit"] = "mm"
176
190
  elif unit_multiplier != 1.0:
177
191
  metadata["unit"] = f"{unit_multiplier:.1e}*{unit}"
@@ -681,10 +695,18 @@ class HydroPandasExtension:
681
695
  continue
682
696
  stn = stns.loc[mask].index[0]
683
697
 
684
- if unit == "mm":
698
+ if unit == "m":
699
+ unit_multiplier = 1.0
700
+ elif unit == "mm":
685
701
  unit_multiplier = 1e3
702
+ elif unit.count("m") == 1 and unit.endswith("m"):
703
+ unit_multiplier = float(unit.replace("m", ""))
686
704
  else:
687
705
  unit_multiplier = 1.0
706
+ logger.warning(
707
+ "Unit '%s' not recognized, using unit_multiplier=%.1e."
708
+ % (unit, unit_multiplier)
709
+ )
688
710
 
689
711
  logger.debug("Updating KNMI %s from %s to %s" % (name, itmin, itmax))
690
712
  knmi = hpd.read_knmi(
pastastore/store.py CHANGED
@@ -5,6 +5,7 @@ import logging
5
5
  import os
6
6
  import warnings
7
7
  from functools import partial
8
+ from pathlib import Path
8
9
  from typing import Dict, Iterable, List, Literal, Optional, Tuple, Union
9
10
 
10
11
  import numpy as np
@@ -80,15 +81,39 @@ class PastaStore:
80
81
  self.yaml = PastastoreYAML(self)
81
82
 
82
83
  @classmethod
83
- def from_pastastore_config_file(cls, fname):
84
- """Create a PastaStore from a pastastore config file."""
84
+ def from_pastastore_config_file(cls, fname, update_path: bool = True):
85
+ """Create a PastaStore from a pastastore config file.
86
+
87
+ Parameters
88
+ ----------
89
+ fname : str
90
+ path to the pastastore config file
91
+ update_path : bool, optional
92
+ when True, use path derived from location of the config file instead of
93
+ the stored path in the config file. If a PastaStore is moved, the path
94
+ in the config file will probably still refer to the old location. Set to
95
+ False to read the file from the path listed in the config file. In that
96
+ case config files do not need to be stored within the correct directory.
97
+
98
+ Returns
99
+ -------
100
+ PastaStore
101
+ PastaStore
102
+ """
85
103
  with open(fname, "r") as f:
86
104
  cfg = json.load(f)
87
-
88
105
  conn_type = cfg.pop("connector_type")
89
106
  if conn_type == "pas":
107
+ # allow loading of pas files from config file that was moved
108
+ if update_path:
109
+ # update path to the config file
110
+ cfg["path"] = Path(fname).parent.parent
90
111
  conn = PasConnector(**cfg)
91
112
  elif conn_type == "arcticdb":
113
+ if update_path:
114
+ prefix, _ = cfg["uri"].split("://")
115
+ if prefix.lower() == "lmbd":
116
+ cfg["uri"] = prefix + "://" + str(Path(fname).parent)
92
117
  conn = ArcticDBConnector(**cfg)
93
118
  else:
94
119
  raise ValueError(
@@ -1533,7 +1558,7 @@ class PastaStore:
1533
1558
  else:
1534
1559
  ext = "pas"
1535
1560
 
1536
- # short circuit for PasConnector when zipfile was written using pas files
1561
+ # short-circuit for PasConnector when zipfile was written using pas files
1537
1562
  if conn.conn_type == "pas" and not series_ext_json:
1538
1563
  with ZipFile(fname, "r") as archive:
1539
1564
  archive.extractall(conn.path)
@@ -1543,10 +1568,20 @@ class PastaStore:
1543
1568
 
1544
1569
  with ZipFile(fname, "r") as archive:
1545
1570
  namelist = [
1546
- fi for fi in archive.namelist() if not fi.endswith(f"_meta.{ext}")
1571
+ fi
1572
+ for fi in archive.namelist()
1573
+ if not fi.endswith(f"_meta.{ext}") and not fi.endswith(os.sep)
1547
1574
  ]
1548
1575
  for f in tqdm(namelist, desc="Reading zip") if progressbar else namelist:
1576
+ if f.endswith("_meta.json"):
1577
+ raise (
1578
+ ValueError(
1579
+ "The zipfile was created using pastastore <1.8.0."
1580
+ " Please pass `series_ext_json=True` to `from_zip()`"
1581
+ )
1582
+ )
1549
1583
  libname, fjson = os.path.split(f)
1584
+ libname = os.path.split(libname)[-1] # in case zip is one level deeper
1550
1585
  if libname in ["stresses", "oseries"]:
1551
1586
  s = pd.read_json(archive.open(f), dtype=float, orient="columns")
1552
1587
  if not isinstance(s.index, pd.DatetimeIndex):
pastastore/version.py CHANGED
@@ -9,7 +9,7 @@ PASTAS_VERSION = parse_version(ps.__version__)
9
9
  PASTAS_LEQ_022 = PASTAS_VERSION <= parse_version("0.22.0")
10
10
  PASTAS_GEQ_150 = PASTAS_VERSION >= parse_version("1.5.0")
11
11
 
12
- __version__ = "1.10.0"
12
+ __version__ = "1.10.2"
13
13
 
14
14
 
15
15
  def show_versions(optional=False) -> None:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pastastore
3
- Version: 1.10.0
3
+ Version: 1.10.2
4
4
  Summary: Tools for managing Pastas time series models.
5
5
  Author: D.A. Brakenhoff
6
6
  Maintainer-email: "D.A. Brakenhoff" <d.brakenhoff@artesia-water.nl>, "R. Calje" <r.calje@artesia-water.nl>, "M.A. Vonk" <m.vonk@artesia-water.nl>
@@ -63,6 +63,7 @@ Requires-Dist: pyproj; extra == "optional"
63
63
  Requires-Dist: adjustText; extra == "optional"
64
64
  Provides-Extra: arcticdb
65
65
  Requires-Dist: arcticdb; extra == "arcticdb"
66
+ Requires-Dist: protobuf<6,>=3.5.0.post1; extra == "arcticdb"
66
67
  Provides-Extra: lint
67
68
  Requires-Dist: ruff; extra == "lint"
68
69
  Provides-Extra: pytest
@@ -83,6 +84,7 @@ Requires-Dist: Ipython; extra == "docs"
83
84
  Requires-Dist: ipykernel; extra == "docs"
84
85
  Requires-Dist: nbsphinx; extra == "docs"
85
86
  Requires-Dist: nbsphinx_link; extra == "docs"
87
+ Dynamic: license-file
86
88
 
87
89
  ![pastastore](https://github.com/pastas/pastastore/workflows/pastastore/badge.svg)
88
90
  [![Documentation Status](https://readthedocs.org/projects/pastastore/badge/?version=latest)](https://pastastore.readthedocs.io/en/latest/?badge=latest)
@@ -1,28 +1,28 @@
1
1
  docs/conf.py,sha256=XcZUTmn9fGDhhu8k3mpaLu435SpIRNpABADCCTJJuag,6291
2
2
  pastastore/__init__.py,sha256=cWwG9-YeiI4aOU0CDBGKbQgmKmmkcPd64YwPq2rRGt0,416
3
- pastastore/base.py,sha256=B7sPe1eEpXFSeQsgrPXc5Mvp8Xkbhe_TxML6Zlp19Lk,48172
4
- pastastore/connectors.py,sha256=6D2j1AUMQhHZNUhCD0tKoxf77FlQM5fTdH2m_c8KAnY,50183
3
+ pastastore/base.py,sha256=ng64KGuKo2iMLjL0H7qG3NVNvXPwMGJBf3oLtQbt6DQ,48264
4
+ pastastore/connectors.py,sha256=hum8KkPi28B3XBsKL_RghRCsZndf-jeFlb4baTvyDG4,50197
5
5
  pastastore/datasets.py,sha256=FHVfmKqb8beEs9NONsWrCoJY37BmlvFLSEQ1VAFmE8A,6415
6
6
  pastastore/plotting.py,sha256=ygKXdi42sPLaehze4EjU8kRE2Dk46wVxSkB9RJ2Re84,54535
7
- pastastore/store.py,sha256=KOs0L4AICRFRaQRdnnq2o-oadmX1CDkcg_kDtC8Tal0,67703
7
+ pastastore/store.py,sha256=Fs_WCEGqafOKm3whLUR54tqXL1dL3FdzwxNI1DSZ2KI,69272
8
8
  pastastore/styling.py,sha256=0IEp_r-SpcaslShAZvZV6iuEhTG_YzNq-ad8krib3U0,2304
9
9
  pastastore/util.py,sha256=31dzHaK6xdFHGDkYh49qGBq1dGel2m9r7i797S3WUpQ,28505
10
- pastastore/version.py,sha256=EyZTJILqRXkQwkj1Pipjq7kjKw-VsZMCFcFt78vCEK0,1206
10
+ pastastore/version.py,sha256=2Y6_CKnmHYQTxRyvvUEW2519LmIeszWd-0NYpCRyV6M,1206
11
11
  pastastore/yaml_interface.py,sha256=n6zjQ7ENrUvxszb6zE-jPLa-XVsoEOTJHQmRV1_fFt0,30818
12
12
  pastastore/extensions/__init__.py,sha256=lCN9xfX1qefUzUbE2FQ12c6NjLbf5HoNo-D8cGb5CTw,461
13
13
  pastastore/extensions/accessor.py,sha256=kftQM6dqMDoySbyTKcvmkjC5gJRp465KA18G4NVXUO0,367
14
- pastastore/extensions/hpd.py,sha256=VHMhGZaSIHTZNDYuyxGqWtDqlCSbucq44oT8sZRsu0E,27749
14
+ pastastore/extensions/hpd.py,sha256=i9Ty9GyRyrtY0uqjMpWheH33oYDQM8WMmygaDEPx-w4,28581
15
+ pastastore-1.10.2.dist-info/licenses/LICENSE,sha256=MB_6p4kXDCUsYNjslcMByBu6i7wMNRKPC36JnhzpN4o,1087
15
16
  tests/conftest.py,sha256=TB0ZUH1m45gvQd_EZO7iudvhFw4JA-8rTJ71GT6Nf1w,5061
16
17
  tests/test_001_import.py,sha256=g8AaJzWZ088A4B30_w-MrDfAVeeg8m78l--j7Onsklc,208
17
- tests/test_002_connectors.py,sha256=k9etSRuSFVOrSEtZyxqsCF9GwIg0T7VdDJ2SjSe6i_s,7742
18
+ tests/test_002_connectors.py,sha256=X7IbxZZXBYd2UT8B5gu0_Jw--3Twe7KHjSBbmMwNnRk,8193
18
19
  tests/test_003_pastastore.py,sha256=nhcUJHC2KiF9KREP_2uj_T2skKooUk13T1EVtkbwQnM,10051
19
20
  tests/test_004_yaml.py,sha256=3hMNjb9s0S2rbmpyEjW6FDRAxfUZS_U1qoPl4wB-cCo,4440
20
21
  tests/test_005_maps_plots.py,sha256=L0ppGf-cudsrdxteWy3qsV4We96DW4bCBE7c6jEm6aM,1866
21
22
  tests/test_006_benchmark.py,sha256=VZG0bY7uz8DkfIZTgRCzkEDG8rguBEt_-mdGSMQLN2w,4930
22
23
  tests/test_007_hpdextension.py,sha256=1QNUahq3hzqxjKbzsjofi9Yuyqe_oDGL0vWp6iouYe4,3004
23
24
  tests/test_008_stressmodels.py,sha256=733fyCvuzjKcaLjvSMt5dTTLp-T4alzNJAToSxTIUug,4003
24
- pastastore-1.10.0.dist-info/LICENSE,sha256=MB_6p4kXDCUsYNjslcMByBu6i7wMNRKPC36JnhzpN4o,1087
25
- pastastore-1.10.0.dist-info/METADATA,sha256=xfHn3JQgATCb34Bfn3xImDDhEFGCo5x6SnK6xDQwTbQ,7579
26
- pastastore-1.10.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
27
- pastastore-1.10.0.dist-info/top_level.txt,sha256=1bgyMk1p23f04RK83Jju2_YAQBwyoQD_fInxoPB4YRw,22
28
- pastastore-1.10.0.dist-info/RECORD,,
25
+ pastastore-1.10.2.dist-info/METADATA,sha256=8oLyVDQ95wA9wzSxBR29fMg2s81HjlvXGenukFxx2NA,7662
26
+ pastastore-1.10.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ pastastore-1.10.2.dist-info/top_level.txt,sha256=1bgyMk1p23f04RK83Jju2_YAQBwyoQD_fInxoPB4YRw,22
28
+ pastastore-1.10.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -34,6 +34,19 @@ def test_add_get_series(request, conn):
34
34
  conn.del_oseries("test_series")
35
35
 
36
36
 
37
+ def test_add_get_single_value_series(request, conn):
38
+ o1 = pd.Series({pd.Timestamp(2025, 1, 1): 5.0})
39
+ o1.name = "test_single_value_series"
40
+ conn.add_oseries(o1, "test_single_value_series", metadata=None)
41
+ o2 = conn.get_oseries("test_single_value_series")
42
+ try:
43
+ assert isinstance(o2, pd.Series)
44
+ assert o1.equals(o2)
45
+ assert o1.dtype == o2.dtype
46
+ finally:
47
+ conn.del_oseries("test_single_value_series")
48
+
49
+
37
50
  def test_add_get_series_wnans(request, conn):
38
51
  o1 = pd.Series(
39
52
  index=pd.date_range("2000", periods=10, freq="D"),