pastastore 1.7.1__py3-none-any.whl → 1.8.0__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/store.py CHANGED
@@ -4,9 +4,8 @@ import json
4
4
  import logging
5
5
  import os
6
6
  import warnings
7
- from concurrent.futures import ProcessPoolExecutor
8
7
  from functools import partial
9
- from typing import Dict, List, Literal, Optional, Tuple, Union
8
+ from typing import Dict, Iterable, List, Literal, Optional, Tuple, Union
10
9
 
11
10
  import numpy as np
12
11
  import pandas as pd
@@ -14,7 +13,6 @@ import pastas as ps
14
13
  from packaging.version import parse as parse_version
15
14
  from pastas.io.pas import pastas_hook
16
15
  from tqdm.auto import tqdm
17
- from tqdm.contrib.concurrent import process_map
18
16
 
19
17
  from pastastore.base import BaseConnector
20
18
  from pastastore.connectors import DictConnector
@@ -624,8 +622,10 @@ class PastaStore:
624
622
  self,
625
623
  statistics: Union[str, List[str]],
626
624
  modelnames: Optional[List[str]] = None,
625
+ parallel: bool = False,
627
626
  progressbar: Optional[bool] = False,
628
627
  ignore_errors: Optional[bool] = False,
628
+ fancy_output: bool = True,
629
629
  **kwargs,
630
630
  ) -> FrameorSeriesUnion:
631
631
  """Get model statistics.
@@ -643,6 +643,11 @@ class PastaStore:
643
643
  ignore_errors : bool, optional
644
644
  ignore errors when True, i.e. when trying to calculate statistics
645
645
  for non-existent model in modelnames, default is False
646
+ parallel : bool, optional
647
+ use parallel processing, by default False
648
+ fancy_output : bool, optional
649
+ only read if parallel=True, if True, return as DataFrame with statistics,
650
+ otherwise return list of results
646
651
  **kwargs
647
652
  any arguments that can be passed to the methods for calculating
648
653
  statistics
@@ -657,25 +662,39 @@ class PastaStore:
657
662
  if isinstance(statistics, str):
658
663
  statistics = [statistics]
659
664
 
660
- # create dataframe for results
661
- s = pd.DataFrame(index=modelnames, columns=statistics, data=np.nan)
662
-
663
- # loop through model names
664
- desc = "Get model statistics"
665
- for mlname in tqdm(modelnames, desc=desc) if progressbar else modelnames:
666
- try:
667
- ml = self.get_models(mlname, progressbar=False)
668
- except Exception as e:
669
- if ignore_errors:
670
- continue
671
- else:
672
- raise e
673
- for stat in statistics:
674
- value = ml.stats.__getattribute__(stat)(**kwargs)
675
- s.loc[mlname, stat] = value
665
+ if parallel:
666
+ kwargs["statistics"] = statistics
667
+ if self.conn.conn_type == "pas":
668
+ kwargs["connector"] = self.conn
669
+ return self.apply(
670
+ "models",
671
+ self.conn._get_statistics,
672
+ modelnames,
673
+ kwargs=kwargs,
674
+ parallel=parallel,
675
+ progressbar=progressbar,
676
+ fancy_output=fancy_output,
677
+ ).T # transpose to match serial output
678
+ else:
679
+ # create dataframe for results
680
+ s = pd.DataFrame(index=modelnames, columns=statistics, data=np.nan)
681
+
682
+ # loop through model names
683
+ desc = "Get model statistics"
684
+ for mlname in tqdm(modelnames, desc=desc) if progressbar else modelnames:
685
+ try:
686
+ ml = self.get_models(mlname, progressbar=False)
687
+ except Exception as e:
688
+ if ignore_errors:
689
+ continue
690
+ else:
691
+ raise e
692
+ for stat in statistics:
693
+ value = getattr(ml.stats, stat)(**kwargs)
694
+ s.loc[mlname, stat] = value
676
695
 
677
- s = s.squeeze()
678
- return s.astype(float)
696
+ s = s.squeeze()
697
+ return s.astype(float)
679
698
 
680
699
  def create_model(
681
700
  self,
@@ -1235,74 +1254,58 @@ class PastaStore:
1235
1254
 
1236
1255
  modelnames = self.conn._parse_names(modelnames, libname="models")
1237
1256
 
1238
- solve_model = partial(
1239
- self._solve_model,
1240
- report=report,
1241
- ignore_solve_errors=ignore_solve_errors,
1242
- **kwargs,
1243
- )
1244
- if self.conn.conn_type != "pas":
1257
+ # prepare parallel
1258
+ if parallel and self.conn.conn_type == "dict":
1245
1259
  parallel = False
1246
1260
  logger.error(
1247
- "Parallel solving only supported for PasConnector databases."
1248
- "Setting parallel to `False`"
1261
+ "Parallel solving only supported for PasConnector and "
1262
+ "ArcticDBConnector databases. Setting parallel to `False`"
1249
1263
  )
1250
-
1251
- if parallel and progressbar:
1252
- process_map(solve_model, modelnames, max_workers=max_workers)
1253
- elif parallel and not progressbar:
1254
- with ProcessPoolExecutor(max_workers=max_workers) as executor:
1255
- executor.map(solve_model, modelnames)
1264
+ if parallel:
1265
+ if self.conn.conn_type == "arcticdb":
1266
+ solve_model = partial(
1267
+ self.conn._solve_model,
1268
+ report=report,
1269
+ ignore_solve_errors=ignore_solve_errors,
1270
+ **kwargs,
1271
+ )
1272
+ self.conn._parallel(
1273
+ solve_model,
1274
+ modelnames,
1275
+ max_workers=max_workers,
1276
+ chunksize=None,
1277
+ progressbar=progressbar,
1278
+ desc="Solving models (parallel)",
1279
+ )
1280
+ elif self.conn.conn_type == "pas":
1281
+ solve_model = partial(
1282
+ self.conn._solve_model,
1283
+ connector=self.conn,
1284
+ report=report,
1285
+ ignore_solve_errors=ignore_solve_errors,
1286
+ **kwargs,
1287
+ )
1288
+ self.conn._parallel(
1289
+ solve_model,
1290
+ modelnames,
1291
+ max_workers=max_workers,
1292
+ chunksize=None,
1293
+ progressbar=progressbar,
1294
+ desc="Solving models (parallel)",
1295
+ )
1256
1296
  else:
1297
+ solve_model = partial(
1298
+ self.conn._solve_model,
1299
+ connector=self.conn,
1300
+ report=report,
1301
+ ignore_solve_errors=ignore_solve_errors,
1302
+ **kwargs,
1303
+ )
1257
1304
  for ml_name in (
1258
1305
  tqdm(modelnames, desc="Solving models") if progressbar else modelnames
1259
1306
  ):
1260
1307
  solve_model(ml_name=ml_name)
1261
1308
 
1262
- def _solve_model(
1263
- self,
1264
- ml_name: str,
1265
- report: bool = False,
1266
- ignore_solve_errors: bool = False,
1267
- **kwargs,
1268
- ) -> None:
1269
- """Solve a model in the store (internal method).
1270
-
1271
- ml_name : list of str, optional
1272
- name of a model in the pastastore
1273
- report : boolean, optional
1274
- determines if a report is printed when the model is solved,
1275
- default is False
1276
- ignore_solve_errors : boolean, optional
1277
- if True, errors emerging from the solve method are ignored,
1278
- default is False which will raise an exception when a model
1279
- cannot be optimized
1280
- **kwargs : dictionary
1281
- arguments are passed to the solve method.
1282
- """
1283
- ml = self.conn.get_models(ml_name)
1284
- m_kwargs = {}
1285
- for key, value in kwargs.items():
1286
- if isinstance(value, pd.Series):
1287
- m_kwargs[key] = value.loc[ml.name]
1288
- else:
1289
- m_kwargs[key] = value
1290
- # Convert timestamps
1291
- for tstamp in ["tmin", "tmax"]:
1292
- if tstamp in m_kwargs:
1293
- m_kwargs[tstamp] = pd.Timestamp(m_kwargs[tstamp])
1294
-
1295
- try:
1296
- ml.solve(report=report, **m_kwargs)
1297
- except Exception as e:
1298
- if ignore_solve_errors:
1299
- warning = "Solve error ignored for '%s': %s " % (ml.name, e)
1300
- logger.warning(warning)
1301
- else:
1302
- raise e
1303
-
1304
- self.conn.add_model(ml, overwrite=True)
1305
-
1306
1309
  def model_results(
1307
1310
  self,
1308
1311
  mls: Optional[Union[ps.Model, list, str]] = None,
@@ -1443,6 +1446,7 @@ class PastaStore:
1443
1446
  conn: Optional[BaseConnector] = None,
1444
1447
  storename: Optional[str] = None,
1445
1448
  progressbar: bool = True,
1449
+ series_ext_json: bool = False,
1446
1450
  ):
1447
1451
  """Load PastaStore from zipfile.
1448
1452
 
@@ -1458,6 +1462,10 @@ class PastaStore:
1458
1462
  defaults to the name of the Connector.
1459
1463
  progressbar : bool, optional
1460
1464
  show progressbar, by default True
1465
+ series_ext_json : bool, optional
1466
+ if True, series are expected to have a .json extension, by default False,
1467
+ which assumes a .pas extension. Set this option to true for reading
1468
+ zipfiles created with older versions of pastastore <1.8.0.
1461
1469
 
1462
1470
  Returns
1463
1471
  -------
@@ -1469,9 +1477,22 @@ class PastaStore:
1469
1477
  if conn is None:
1470
1478
  conn = DictConnector("pastas_db")
1471
1479
 
1480
+ if series_ext_json:
1481
+ ext = "json"
1482
+ else:
1483
+ ext = "pas"
1484
+
1485
+ # short circuit for PasConnector when zipfile was written using pas files
1486
+ if conn.conn_type == "pas" and not series_ext_json:
1487
+ with ZipFile(fname, "r") as archive:
1488
+ archive.extractall(conn.path)
1489
+ if storename is None:
1490
+ storename = conn.name
1491
+ return cls(conn, storename)
1492
+
1472
1493
  with ZipFile(fname, "r") as archive:
1473
1494
  namelist = [
1474
- fi for fi in archive.namelist() if not fi.endswith("_meta.json")
1495
+ fi for fi in archive.namelist() if not fi.endswith(f"_meta.{ext}")
1475
1496
  ]
1476
1497
  for f in tqdm(namelist, desc="Reading zip") if progressbar else namelist:
1477
1498
  libname, fjson = os.path.split(f)
@@ -1480,7 +1501,7 @@ class PastaStore:
1480
1501
  if not isinstance(s.index, pd.DatetimeIndex):
1481
1502
  s.index = pd.to_datetime(s.index, unit="ms")
1482
1503
  s = s.sort_index()
1483
- meta = json.load(archive.open(f.replace(".json", "_meta.json")))
1504
+ meta = json.load(archive.open(f.replace(f".{ext}", f"_meta.{ext}")))
1484
1505
  conn._add_series(libname, s, fjson.split(".")[0], metadata=meta)
1485
1506
  elif libname in ["models"]:
1486
1507
  ml = json.load(archive.open(f), object_hook=pastas_hook)
@@ -1496,7 +1517,7 @@ class PastaStore:
1496
1517
  case_sensitive: bool = True,
1497
1518
  sort=True,
1498
1519
  ):
1499
- """Search for names of time series or models starting with `s`.
1520
+ """Search for names of time series or models containing string `s`.
1500
1521
 
1501
1522
  Parameters
1502
1523
  ----------
@@ -1515,30 +1536,45 @@ class PastaStore:
1515
1536
  list of names that match search result
1516
1537
  """
1517
1538
  if libname == "models":
1518
- lib_names = self.model_names
1539
+ lib_names = {"models": self.model_names}
1519
1540
  elif libname == "stresses":
1520
- lib_names = self.stresses_names
1541
+ lib_names = {"stresses": self.stresses_names}
1521
1542
  elif libname == "oseries":
1522
- lib_names = self.oseries_names
1543
+ lib_names = {"oseries": self.oseries_names}
1544
+ elif libname is None:
1545
+ lib_names = {
1546
+ "oseries": self.oseries_names,
1547
+ "stresses": self.stresses_names,
1548
+ "models": self.model_names,
1549
+ }
1523
1550
  else:
1524
1551
  raise ValueError("Provide valid libname: 'models', 'stresses' or 'oseries'")
1525
1552
 
1526
- if isinstance(s, str):
1527
- if case_sensitive:
1528
- matches = [n for n in lib_names if s in n]
1529
- else:
1530
- matches = [n for n in lib_names if s.lower() in n.lower()]
1531
- if isinstance(s, list):
1532
- m = np.array([])
1533
- for sub in s:
1553
+ result = {}
1554
+ for lib, names in lib_names.items():
1555
+ if isinstance(s, str):
1534
1556
  if case_sensitive:
1535
- m = np.append(m, [n for n in lib_names if sub in n])
1557
+ matches = [n for n in names if s in n]
1536
1558
  else:
1537
- m = np.append(m, [n for n in lib_names if sub.lower() in n.lower()])
1538
- matches = list(np.unique(m))
1539
- if sort:
1540
- matches.sort()
1541
- return matches
1559
+ matches = [n for n in names if s.lower() in n.lower()]
1560
+ elif isinstance(s, list):
1561
+ m = np.array([])
1562
+ for sub in s:
1563
+ if case_sensitive:
1564
+ m = np.append(m, [n for n in names if sub in n])
1565
+ else:
1566
+ m = np.append(m, [n for n in names if sub.lower() in n.lower()])
1567
+ matches = list(np.unique(m))
1568
+ else:
1569
+ raise TypeError("s must be str or list of str!")
1570
+ if sort:
1571
+ matches.sort()
1572
+ result[lib] = matches
1573
+
1574
+ if len(result) == 1:
1575
+ return result[lib]
1576
+ else:
1577
+ return result
1542
1578
 
1543
1579
  def get_model_timeseries_names(
1544
1580
  self,
@@ -1603,7 +1639,17 @@ class PastaStore:
1603
1639
  else:
1604
1640
  return structure
1605
1641
 
1606
- def apply(self, libname, func, names=None, progressbar=True):
1642
+ def apply(
1643
+ self,
1644
+ libname: str,
1645
+ func: callable,
1646
+ names: Optional[Union[str, List[str]]] = None,
1647
+ kwargs: Optional[dict] = None,
1648
+ progressbar: bool = True,
1649
+ parallel: bool = False,
1650
+ max_workers: Optional[int] = None,
1651
+ fancy_output: bool = True,
1652
+ ) -> Union[dict, pd.Series, pd.DataFrame]:
1607
1653
  """Apply function to items in library.
1608
1654
 
1609
1655
  Supported libraries are oseries, stresses, and models.
@@ -1613,32 +1659,114 @@ class PastaStore:
1613
1659
  libname : str
1614
1660
  library name, supports "oseries", "stresses" and "models"
1615
1661
  func : callable
1616
- function that accepts items from one of the supported libraries as input
1662
+ function that accepts a string corresponding to the name of an item in
1663
+ the library as its first argument. Additional keyword arguments can be
1664
+ specified. The function can return any result, or update an item in the
1665
+ database without returning anything.
1617
1666
  names : str, list of str, optional
1618
1667
  apply function to these names, by default None which loops over all stored
1619
1668
  items in library
1669
+ kwargs : dict, optional
1670
+ keyword arguments to pass to func, by default None
1620
1671
  progressbar : bool, optional
1621
1672
  show progressbar, by default True
1673
+ parallel : bool, optional
1674
+ run apply in parallel, default is False.
1675
+ max_workers : int, optional
1676
+ max no. of workers, only used if parallel is True
1677
+ fancy_output : bool, optional
1678
+ if True, try returning result as pandas Series or DataFrame, by default
1679
+ False
1622
1680
 
1623
1681
  Returns
1624
1682
  -------
1625
1683
  dict
1626
1684
  dict of results of func, with names as keys and results as values
1685
+
1686
+ Notes
1687
+ -----
1688
+ Users should be aware that parallel solving is platform dependent
1689
+ and may not always work. The current implementation works well for Linux users.
1690
+ For Windows users, parallel solving does not work when called directly from
1691
+ Jupyter Notebooks or IPython. To use parallel solving on Windows, the following
1692
+ code should be used in a Python file::
1693
+
1694
+ from multiprocessing import freeze_support
1695
+
1696
+ if __name__ == "__main__":
1697
+ freeze_support()
1698
+ pstore.apply("models", some_func, parallel=True)
1627
1699
  """
1628
1700
  names = self.conn._parse_names(names, libname)
1629
- result = {}
1701
+ if kwargs is None:
1702
+ kwargs = {}
1630
1703
  if libname not in ("oseries", "stresses", "models"):
1631
1704
  raise ValueError(
1632
1705
  "'libname' must be one of ['oseries', 'stresses', 'models']!"
1633
1706
  )
1634
- getter = getattr(self.conn, f"get_{libname}")
1635
- for n in (
1636
- tqdm(names, desc=f"Applying {func.__name__}") if progressbar else names
1637
- ):
1638
- result[n] = func(getter(n))
1639
- return result
1707
+ if parallel:
1708
+ result = self.conn._parallel(
1709
+ func,
1710
+ kwargs=kwargs,
1711
+ names=names,
1712
+ progressbar=progressbar,
1713
+ max_workers=max_workers,
1714
+ chunksize=None,
1715
+ desc=f"Applying {func.__name__} (parallel)",
1716
+ )
1717
+ else:
1718
+ result = []
1719
+ for n in tqdm(
1720
+ names, desc=f"Applying {func.__name__}", disable=not progressbar
1721
+ ):
1722
+ result.append(func(n, **kwargs))
1723
+ if fancy_output:
1724
+ return PastaStore._fancy_output(result, names, func.__name__)
1725
+ else:
1726
+ return result
1727
+
1728
+ @staticmethod
1729
+ def _fancy_output(
1730
+ result: Iterable,
1731
+ names: List[str],
1732
+ label: Optional[str] = None,
1733
+ ) -> Union[pd.Series, pd.DataFrame, dict]:
1734
+ """Convert apply result to pandas Series, DataFrame or dict.
1640
1735
 
1641
- def within(self, extent, names=None, libname="oseries"):
1736
+ Parameters
1737
+ ----------
1738
+ result : Iterable
1739
+ result of apply function
1740
+ names : list
1741
+ list of names
1742
+ label : str, optional
1743
+ label for columns, by default None
1744
+
1745
+ Returns
1746
+ -------
1747
+ pd.Series, pd.DataFrame, dict
1748
+ Series, DataFrame or dict with results
1749
+ """
1750
+ if not isinstance(result, list):
1751
+ result = list(result)
1752
+ if isinstance(result[0], (float, int, np.integer)):
1753
+ return pd.Series(result, index=names)
1754
+ elif isinstance(result[0], (pd.Series, pd.DataFrame)):
1755
+ df = pd.concat(dict(zip(names, result, strict=True)), axis=1)
1756
+ if label is not None:
1757
+ df.columns.name = label
1758
+ return df
1759
+ elif result[0] is None:
1760
+ return None # return None if first result is None?
1761
+ else:
1762
+ return dict(zip(names, result, strict=True))
1763
+
1764
+ def within(
1765
+ self,
1766
+ extent: list,
1767
+ names: Optional[list[str]] = None,
1768
+ libname: str = "oseries",
1769
+ ):
1642
1770
  """Get names of items within extent.
1643
1771
 
1644
1772
  Parameters
pastastore/util.py CHANGED
@@ -385,7 +385,7 @@ def copy_database(
385
385
  conn2,
386
386
  libraries: Optional[List[str]] = None,
387
387
  overwrite: bool = False,
388
- progressbar: bool = False,
388
+ progressbar: bool = True,
389
389
  ) -> None:
390
390
  """Copy libraries from one database to another.
391
391
 
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.7.1"
12
+ __version__ = "1.8.0"
13
13
 
14
14
 
15
15
  def show_versions(optional=False) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pastastore
3
- Version: 1.7.1
3
+ Version: 1.8.0
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>
@@ -49,48 +49,49 @@ Classifier: Topic :: Scientific/Engineering :: Hydrology
49
49
  Requires-Python: >=3.7
50
50
  Description-Content-Type: text/markdown
51
51
  License-File: LICENSE
52
- Requires-Dist: pastas >=0.13
53
- Requires-Dist: tqdm >=4.36
52
+ Requires-Dist: pastas>=0.13
53
+ Requires-Dist: tqdm>=4.36
54
54
  Requires-Dist: pyyaml
55
- Provides-Extra: arcticdb
56
- Requires-Dist: arcticdb ; extra == 'arcticdb'
57
- Provides-Extra: docs
58
- Requires-Dist: pastastore[optional] ; extra == 'docs'
59
- Requires-Dist: sphinx-rtd-theme ; extra == 'docs'
60
- Requires-Dist: Ipython ; extra == 'docs'
61
- Requires-Dist: ipykernel ; extra == 'docs'
62
- Requires-Dist: nbsphinx ; extra == 'docs'
63
- Requires-Dist: nbsphinx-link ; extra == 'docs'
64
- Provides-Extra: extensions
65
- Requires-Dist: hydropandas ; extra == 'extensions'
66
55
  Provides-Extra: full
67
- Requires-Dist: pastastore[arcticdb,optional] ; extra == 'full'
68
- Provides-Extra: lint
69
- Requires-Dist: ruff ; extra == 'lint'
56
+ Requires-Dist: pastastore[arcticdb,optional]; extra == "full"
57
+ Requires-Dist: hydropandas; extra == "full"
58
+ Provides-Extra: extensions
59
+ Requires-Dist: hydropandas; extra == "extensions"
70
60
  Provides-Extra: optional
71
- Requires-Dist: contextily ; extra == 'optional'
72
- Requires-Dist: pyproj ; extra == 'optional'
73
- Requires-Dist: adjustText ; extra == 'optional'
61
+ Requires-Dist: contextily; extra == "optional"
62
+ Requires-Dist: pyproj; extra == "optional"
63
+ Requires-Dist: adjustText; extra == "optional"
64
+ Provides-Extra: arcticdb
65
+ Requires-Dist: arcticdb; extra == "arcticdb"
66
+ Provides-Extra: lint
67
+ Requires-Dist: ruff; extra == "lint"
74
68
  Provides-Extra: test
75
- Requires-Dist: pastastore[arcticdb,lint,optional] ; extra == 'test'
76
- Requires-Dist: hydropandas[full] ; extra == 'test'
77
- Requires-Dist: coverage ; extra == 'test'
78
- Requires-Dist: codecov ; extra == 'test'
79
- Requires-Dist: pytest ; extra == 'test'
80
- Requires-Dist: pytest-cov ; extra == 'test'
81
- Requires-Dist: pytest-dependency ; extra == 'test'
82
- Requires-Dist: pytest-benchmark ; extra == 'test'
83
- Requires-Dist: codacy-coverage ; extra == 'test'
84
- Provides-Extra: test_py312
85
- Requires-Dist: pastastore[lint,optional] ; extra == 'test_py312'
86
- Requires-Dist: hydropandas[full] ; extra == 'test_py312'
87
- Requires-Dist: coverage ; extra == 'test_py312'
88
- Requires-Dist: codecov ; extra == 'test_py312'
89
- Requires-Dist: pytest ; extra == 'test_py312'
90
- Requires-Dist: pytest-cov ; extra == 'test_py312'
91
- Requires-Dist: pytest-dependency ; extra == 'test_py312'
92
- Requires-Dist: pytest-benchmark ; extra == 'test_py312'
93
- Requires-Dist: codacy-coverage ; extra == 'test_py312'
69
+ Requires-Dist: pastastore[arcticdb,lint,optional]; extra == "test"
70
+ Requires-Dist: hydropandas[full]; extra == "test"
71
+ Requires-Dist: coverage; extra == "test"
72
+ Requires-Dist: codecov; extra == "test"
73
+ Requires-Dist: pytest; extra == "test"
74
+ Requires-Dist: pytest-cov; extra == "test"
75
+ Requires-Dist: pytest-dependency; extra == "test"
76
+ Requires-Dist: pytest-benchmark; extra == "test"
77
+ Requires-Dist: codacy-coverage; extra == "test"
78
+ Provides-Extra: test-py312
79
+ Requires-Dist: pastastore[lint,optional]; extra == "test-py312"
80
+ Requires-Dist: hydropandas[full]; extra == "test-py312"
81
+ Requires-Dist: coverage; extra == "test-py312"
82
+ Requires-Dist: codecov; extra == "test-py312"
83
+ Requires-Dist: pytest; extra == "test-py312"
84
+ Requires-Dist: pytest-cov; extra == "test-py312"
85
+ Requires-Dist: pytest-dependency; extra == "test-py312"
86
+ Requires-Dist: pytest-benchmark; extra == "test-py312"
87
+ Requires-Dist: codacy-coverage; extra == "test-py312"
88
+ Provides-Extra: docs
89
+ Requires-Dist: pastastore[optional]; extra == "docs"
90
+ Requires-Dist: sphinx_rtd_theme; extra == "docs"
91
+ Requires-Dist: Ipython; extra == "docs"
92
+ Requires-Dist: ipykernel; extra == "docs"
93
+ Requires-Dist: nbsphinx; extra == "docs"
94
+ Requires-Dist: nbsphinx_link; extra == "docs"
94
95
 
95
96
  ![pastastore](https://github.com/pastas/pastastore/workflows/pastastore/badge.svg)
96
97
  [![Documentation Status](https://readthedocs.org/projects/pastastore/badge/?version=latest)](https://pastastore.readthedocs.io/en/latest/?badge=latest)
@@ -0,0 +1,28 @@
1
+ docs/conf.py,sha256=XcZUTmn9fGDhhu8k3mpaLu435SpIRNpABADCCTJJuag,6291
2
+ pastastore/__init__.py,sha256=cWwG9-YeiI4aOU0CDBGKbQgmKmmkcPd64YwPq2rRGt0,416
3
+ pastastore/base.py,sha256=hOvkgACew4fpLWumLfHA6PrxLDH1EvqdWjEvFbmxJR0,46436
4
+ pastastore/connectors.py,sha256=QlaFcVEM_ZtOgLd3M2yZfgogcw0zNM08pVbnyRS3Mr8,48454
5
+ pastastore/datasets.py,sha256=FHVfmKqb8beEs9NONsWrCoJY37BmlvFLSEQ1VAFmE8A,6415
6
+ pastastore/plotting.py,sha256=t6gEeHVGzrwvM6q1l8V3OkklpU75O2Y4h6nKEHRWdjo,46416
7
+ pastastore/store.py,sha256=HZtof9gIFSW2nQpc5FHMPb1RTjgo-QzIJxueywd4jDA,65840
8
+ pastastore/styling.py,sha256=4xAY0FmhKrvmAGIuoMM7Uucww_X4KAxTpEoHlsxMldc,2280
9
+ pastastore/util.py,sha256=KCUFV4GkocWaRpG57CdxzfkTXyTEpPjnxsKehYPVN7U,28249
10
+ pastastore/version.py,sha256=vuqYDMX5ua14OQP04vqXH_0A_Ra2XErriiNPxgZEc5w,1205
11
+ pastastore/yaml_interface.py,sha256=MddELxWe8_aqJRMUydOCbjoU1-ZodzxFKYnAaqJ5SqA,29947
12
+ pastastore/extensions/__init__.py,sha256=lCN9xfX1qefUzUbE2FQ12c6NjLbf5HoNo-D8cGb5CTw,461
13
+ pastastore/extensions/accessor.py,sha256=kftQM6dqMDoySbyTKcvmkjC5gJRp465KA18G4NVXUO0,367
14
+ pastastore/extensions/hpd.py,sha256=fcXWb3BlWlogCbg7a2Gmha8P_eCh6zSGTyRlYp3mjXA,27466
15
+ tests/conftest.py,sha256=u097z7LGAnviuzXPzvER9oPjsZWqdij1CJLnW_sPY8E,5258
16
+ tests/test_001_import.py,sha256=g8AaJzWZ088A4B30_w-MrDfAVeeg8m78l--j7Onsklc,208
17
+ tests/test_002_connectors.py,sha256=k9etSRuSFVOrSEtZyxqsCF9GwIg0T7VdDJ2SjSe6i_s,7742
18
+ tests/test_003_pastastore.py,sha256=2nC0pU478iRbYKnVVSjh5F6PA_7SvFROwD6SABL2YSE,9370
19
+ tests/test_004_yaml.py,sha256=3hMNjb9s0S2rbmpyEjW6FDRAxfUZS_U1qoPl4wB-cCo,4440
20
+ tests/test_005_maps_plots.py,sha256=L0ppGf-cudsrdxteWy3qsV4We96DW4bCBE7c6jEm6aM,1866
21
+ tests/test_006_benchmark.py,sha256=yuExF35qqxhw04uYMH3OIOlGr71c4AJSJDMjGD8GefY,4983
22
+ tests/test_007_hpdextension.py,sha256=1QNUahq3hzqxjKbzsjofi9Yuyqe_oDGL0vWp6iouYe4,3004
23
+ tests/test_008_stressmodels.py,sha256=733fyCvuzjKcaLjvSMt5dTTLp-T4alzNJAToSxTIUug,4003
24
+ pastastore-1.8.0.dist-info/LICENSE,sha256=DtHftfUEm99KzgwLr3rQUTg8H3kAS0Z-p5WWJgLf_OY,1082
25
+ pastastore-1.8.0.dist-info/METADATA,sha256=nWFELMkHg9yfp76Ib1xlnPdrp7RZh-9KyhW3CO3rOVY,8032
26
+ pastastore-1.8.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
27
+ pastastore-1.8.0.dist-info/top_level.txt,sha256=1bgyMk1p23f04RK83Jju2_YAQBwyoQD_fInxoPB4YRw,22
28
+ pastastore-1.8.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1 +1,3 @@
1
+ docs
1
2
  pastastore
3
+ tests