hydrobot 0.2.2__tar.gz → 0.3.0__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 (45) hide show
  1. {hydrobot-0.2.2 → hydrobot-0.3.0}/CONTRIBUTING.rst +55 -8
  2. {hydrobot-0.2.2 → hydrobot-0.3.0}/HISTORY.rst +5 -0
  3. {hydrobot-0.2.2 → hydrobot-0.3.0}/PKG-INFO +7 -2
  4. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/installation.rst +20 -0
  5. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot/__init__.py +1 -1
  6. hydrobot-0.3.0/hydrobot/config/TwoLevelMeasurement_QC_config.csv +1 -0
  7. hydrobot-0.3.0/hydrobot/config/measurement_QC_config.csv +2 -0
  8. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot/data_acquisition.py +1 -0
  9. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot/data_sources.py +4 -1
  10. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot/evaluator.py +3 -3
  11. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot/filters.py +33 -6
  12. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot/plotter.py +1 -0
  13. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot/processor.py +55 -19
  14. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot.egg-info/PKG-INFO +7 -2
  15. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot.egg-info/SOURCES.txt +2 -0
  16. {hydrobot-0.2.2 → hydrobot-0.3.0}/setup.cfg +1 -1
  17. {hydrobot-0.2.2 → hydrobot-0.3.0}/setup.py +9 -3
  18. {hydrobot-0.2.2 → hydrobot-0.3.0}/tests/test_filters.py +16 -4
  19. {hydrobot-0.2.2 → hydrobot-0.3.0}/tests/test_processor.py +11 -9
  20. {hydrobot-0.2.2 → hydrobot-0.3.0}/AUTHORS.rst +0 -0
  21. {hydrobot-0.2.2 → hydrobot-0.3.0}/LICENSE +0 -0
  22. {hydrobot-0.2.2 → hydrobot-0.3.0}/MANIFEST.in +0 -0
  23. {hydrobot-0.2.2 → hydrobot-0.3.0}/README.rst +0 -0
  24. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/Makefile +0 -0
  25. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/_build/_static/file.png +0 -0
  26. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/_build/_static/minus.png +0 -0
  27. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/_build/_static/plus.png +0 -0
  28. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/authors.rst +0 -0
  29. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/conf.py +0 -0
  30. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/contributing.rst +0 -0
  31. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/history.rst +0 -0
  32. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/hydrobot.rst +0 -0
  33. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/index.rst +0 -0
  34. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/make.bat +0 -0
  35. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/modules.rst +0 -0
  36. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/readme.rst +0 -0
  37. {hydrobot-0.2.2 → hydrobot-0.3.0}/docs/usage.rst +0 -0
  38. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot.egg-info/dependency_links.txt +0 -0
  39. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot.egg-info/not-zip-safe +0 -0
  40. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot.egg-info/requires.txt +0 -0
  41. {hydrobot-0.2.2 → hydrobot-0.3.0}/hydrobot.egg-info/top_level.txt +0 -0
  42. {hydrobot-0.2.2 → hydrobot-0.3.0}/tests/__init__.py +0 -0
  43. {hydrobot-0.2.2 → hydrobot-0.3.0}/tests/site_list_response.xml +0 -0
  44. {hydrobot-0.2.2 → hydrobot-0.3.0}/tests/test_data_sources.py +0 -0
  45. {hydrobot-0.2.2 → hydrobot-0.3.0}/tests/test_evaluator.py +0 -0
@@ -141,7 +141,6 @@ Before you submit a pull request, check that it meets these guidelines:
141
141
  2. If the pull request adds functionality, the docs should be updated. Put
142
142
  your new functionality into a function with a docstring, and add the
143
143
  feature to the appropriate location in the documentation.
144
- 3. The pull request should work for Python 3.5, 3.6, 3.7 and 3.8, and for PyPy. [*NOTE: This is a matter of trust for now, but I will figure out how to enforce this with "tox" at some point*]
145
144
 
146
145
  Tips
147
146
  ----
@@ -151,13 +150,61 @@ To run a subset of tests::
151
150
  $ pytest tests.test_hydrobot
152
151
 
153
152
 
154
- Deploying
155
- ---------
153
+ Releasing to PyPI
154
+ ------------------
156
155
 
157
156
  A reminder for the maintainers on how to deploy.
158
- Make sure all your changes are committed (including an entry in HISTORY.rst).
159
- Then run::
160
157
 
161
- $ bump2version patch # possible: major / minor / patch
162
- $ git push
163
- $ git push --tags
158
+ 1. Make sure all your changes are committed (including an entry in HISTORY.rst, documentation, etc.).
159
+
160
+ 2. Then run `bump2version` to increment the release tags in the appropriate places. Consider running `bump2version --dry-run` to make sure there are no errors first::
161
+
162
+ $ bump2version --dry-run --verbose patch # Optional, just to test if it runs without errors
163
+ $ bump2version patch # For real this time. Possible values: major / minor / patch
164
+
165
+ 3. Install the local development version of the package (make sure you're in the package root directory where setup.py is). You should see the package install with the correct version number.::
166
+
167
+ $ pip install -e .
168
+
169
+ 4. Run the tests to see that they still work with this local install::
170
+
171
+ $ pytest
172
+
173
+ 5. Push the commit::
174
+
175
+ $ git push
176
+
177
+ 6. Push the tags to GitHub. (Note that we don't actually release on GitHub though. We want to keep the releases to PyPI so there's less ambiguity about how to install it.)::
178
+
179
+ $ git push --tags
180
+
181
+ 7. Do the release.
182
+
183
+ * If using the Makefile (i.e. you have `make` installed and can run `make help` without errors) you can simply run::
184
+
185
+ $ make release
186
+
187
+ * Otherwise, you would have to do the release manually.
188
+
189
+ a. Clean up all the artifact files::
190
+
191
+ $ rm -fr build/
192
+ $ rm -fr dist/
193
+ $ rm -fr .eggs/
194
+ $ find . -name '*.egg-info' -exec rm -fr {} +
195
+ $ find . -name '*.egg' -exec rm -f {} +
196
+ $ find . -name '*.pyc' -exec rm -f {} +
197
+ $ find . -name '*.pyo' -exec rm -f {} +
198
+ $ find . -name '*~' -exec rm -f {} +
199
+ $ find . -name '__pycache__' -exec rm -fr {} +
200
+ $ rm -fr .pytest_cache
201
+
202
+ b. Build the source and wheel packages::
203
+
204
+ $ python setup.py sdist
205
+ $ python setup.py bdist_wheel
206
+ $ ls -l dist
207
+
208
+ c. Use twine to release to PyPI. You'll be asked for authentication. Use the username `__token__`, along with the API key I gave you.::
209
+
210
+ $ twine upload dist/*
@@ -21,3 +21,8 @@ History
21
21
  ------------------
22
22
 
23
23
  * Ok, actually including the config files (promise, but my fingers are crossed behind my back)
24
+
25
+ 0.2.3 (2023-11-30)
26
+ ------------------
27
+
28
+ * Fixed some tests and hopefully fixed the config file issue this time.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hydrobot
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Python Package providing a suite of processing tools and utilities for Hilltop hydrological data.
5
5
  Home-page: https://github.com/nicmostert/hydrobot
6
6
  Author: Nic Mostert
@@ -12,7 +12,7 @@ Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
13
13
  Classifier: Natural Language :: English
14
14
  Classifier: Programming Language :: Python :: 3.11
15
- Requires-Python: ==3.11
15
+ Requires-Python: ==3.11.6
16
16
  License-File: LICENSE
17
17
  License-File: AUTHORS.rst
18
18
 
@@ -80,3 +80,8 @@ History
80
80
  ------------------
81
81
 
82
82
  * Ok, actually including the config files (promise, but my fingers are crossed behind my back)
83
+
84
+ 0.2.3 (2023-11-30)
85
+ ------------------
86
+
87
+ * Fixed some tests and hopefully fixed the config file issue this time.
@@ -49,3 +49,23 @@ Once you have a copy of the source, you can install it with:
49
49
 
50
50
  .. _Github repo: https://github.com/nicmostert/hydrobot
51
51
  .. _tarball: https://github.com/nicmostert/hydrobot/tarball/master
52
+
53
+
54
+ Usage
55
+ -----
56
+
57
+ For purposes of auditing data changes, you may want to track what changes to
58
+ the data are made, and what version of hydrobot (and it's dependencies) are
59
+ used.
60
+
61
+ Windows
62
+
63
+ In Powershell:
64
+
65
+ .. code-block:: console
66
+
67
+ cd path/to/Hydrobot_install
68
+ python -m venv /path/to/Hydrobot_install/venv
69
+ path/to/Hydrobot_install/venv/Scripts/Activate.ps1
70
+ pip install hydrobot
71
+ pip freeze > requirements.txt
@@ -2,4 +2,4 @@
2
2
 
3
3
  __author__ = """Nic Mostert"""
4
4
  __email__ = "nicolas.mostert@horizons.govt.nz"
5
- __version__ = "0.2.2"
5
+ __version__ = "0.3.0"
@@ -0,0 +1 @@
1
+ Water level statistics: Point Sample,10,3,0.5,0.2,2000
@@ -0,0 +1,2 @@
1
+ Atmospheric Pressure,5,2.5
2
+ Water Temperature [Dissolved Oxygen sensor],1.2,0.8
@@ -103,4 +103,5 @@ def get_series(
103
103
  data = pd.Series(data["Value"].values, data["Time"])
104
104
  data.index.name = "Time"
105
105
  data.name = "Value"
106
+ data.index = pd.to_datetime(data.index)
106
107
  return data
@@ -196,7 +196,10 @@ def get_measurement(measurement_name):
196
196
  if measurement_name in m_dict:
197
197
  return m_dict[measurement_name]
198
198
  else:
199
- raise Exception("Measurement not found in the config file")
199
+ raise Exception(
200
+ f"Measurement {measurement_name} not found in the config file. "
201
+ f"Available measurements are {list(m_dict.keys())}."
202
+ )
200
203
 
201
204
 
202
205
  def series_export_to_csv(
@@ -311,10 +311,10 @@ def diagnose_data(base_series, check_series, qc_series, frequency):
311
311
  split_data = splitter(base_series, qc_series, frequency)
312
312
  for qc in split_data:
313
313
  print(
314
- f"Data that is QC{qc} makes up {len(split_data[qc].dropna()) / len(base_series.dropna()) * 100}% of the "
315
- f"workable data and {len(split_data[qc].dropna()) / len(base_series) * 100}% of the time period"
314
+ f"Data that is QC{qc} makes up {len(split_data[qc].dropna()) / len(base_series.dropna()) * 100:.2f}% of "
315
+ f"the "
316
+ f"workable data and {len(split_data[qc].dropna()) / len(base_series) * 100:.2f}% of the time period"
316
317
  )
317
- print("Now it's your job to figure out if that's good enough")
318
318
 
319
319
 
320
320
  def splitter(base_series, qc_series, frequency):
@@ -23,7 +23,8 @@ def clip(unclipped, low_clip: float, high_clip: float):
23
23
  Returns
24
24
  -------
25
25
  pandas.Series
26
- A Series containing the clipped values with the same index as the input Series.
26
+ A Series containing the clipped values with the same index as the
27
+ input Series.
27
28
  """
28
29
  unclipped_arr = unclipped.values
29
30
 
@@ -33,11 +34,11 @@ def clip(unclipped, low_clip: float, high_clip: float):
33
34
  # Use pandas' where function to clip values to NaN where the condition is
34
35
  # True
35
36
  clipped_series = unclipped.where(~clip_cond, np.nan)
36
- clipped_series = unclipped.where(~clip_cond, np.nan)
37
37
 
38
38
  return clipped_series
39
39
 
40
40
 
41
+ # noinspection SpellCheckingInspection
41
42
  def fbewma(input_data, span: int):
42
43
  """
43
44
  Calculate the Forward-Backward Exponentially Weighted Moving Average (FBEWMA) of a pandas Series.
@@ -52,7 +53,8 @@ def fbewma(input_data, span: int):
52
53
  Returns
53
54
  -------
54
55
  pandas.Series
55
- A Series containing the FBEWMA values with the same index as the input Series.
56
+ A Series containing the FBEWMA values with the same index as the
57
+ input Series.
56
58
  """
57
59
  # Calculate the Forward EWMA.
58
60
  fwd = input_data.ewm(span=span).mean()
@@ -74,14 +76,14 @@ def remove_outliers(input_data, span: int, delta: float):
74
76
  Remove outliers.
75
77
 
76
78
  Remove outliers from a time series by comparing it to the
77
- Forward-Backward Exponentially Weighted Moving Average (FB-EWMA).
79
+ Forward-Backward Exponentially Weighted Moving Average (FBEWMA).
78
80
 
79
81
  Parameters
80
82
  ----------
81
83
  input_data : pandas.Series
82
84
  Input time series data.
83
85
  span : int
84
- Span parameter for exponential weighting used in the FB-EWMA.
86
+ Span parameter for exponential weighting used in the FBEWMA.
85
87
  delta : float
86
88
  Threshold for identifying outliers. Values greater than this
87
89
  threshold will be set to NaN.
@@ -92,7 +94,7 @@ def remove_outliers(input_data, span: int, delta: float):
92
94
  A Series containing the time series with outliers removed with
93
95
  the same index as the input Series.
94
96
  """
95
- # Calculate the FB-EWMA of the time series
97
+ # Calculate the FBEWMA of the time series
96
98
  fbewma_series = fbewma(input_data, span)
97
99
 
98
100
  # Create a condition to identify outliers based on the absolute difference
@@ -143,3 +145,28 @@ def remove_spikes(
143
145
  # interp_series = gaps_series.interpolate()
144
146
 
145
147
  return gaps_series
148
+
149
+
150
+ def remove_range(input_series: pd.Series, from_date, to_date):
151
+ """
152
+ Remove data from series in given range.
153
+
154
+ Returns the input series without data between from_date and to_date
155
+ inclusive
156
+
157
+ Parameters
158
+ ----------
159
+ input_series : pd.Series
160
+ The series to have a section removed
161
+ from_date : str
162
+ Start of removed section
163
+ to_date : str
164
+ End of removed section
165
+
166
+ Returns
167
+ -------
168
+ pd.Series
169
+ The series with relevant slice removed
170
+ """
171
+ slice_to_remove = input_series.loc[from_date:to_date]
172
+ return input_series.drop(slice_to_remove.index)
@@ -165,6 +165,7 @@ def qc_plotter(base_series, check_series, qc_series, frequency, show=True):
165
165
  color="black",
166
166
  linestyle="None",
167
167
  )
168
+ plt.xticks(rotation=45, ha="right")
168
169
 
169
170
  plt.legend()
170
171
  if show:
@@ -16,14 +16,16 @@ def stale_warning(method):
16
16
  Decorate dangerous functions.
17
17
 
18
18
  Check whether the data is stale, and warn user if so.
19
- Warning will then take input form user to determine whether to proceed or cancel.
20
- Cancelling will return a null function, which returns None with no side effects no matter what the input
19
+ Warning will then take input form user to determine whether to proceed
20
+ or cancel.
21
+ Cancelling will return a null function, which returns None with no side
22
+ effects no matter what the input
21
23
 
22
24
  Parameters
23
25
  ----------
24
26
  method : function
25
- A function that might have some problems if the parameters have been changed but the data hasn't been
26
- updated
27
+ A function that might have some problems if the parameters have been
28
+ changed but the data hasn't been updated
27
29
 
28
30
  Returns
29
31
  -------
@@ -35,7 +37,8 @@ def stale_warning(method):
35
37
  def _impl(self, *method_args, **method_kwargs):
36
38
  if self._stale:
37
39
  warnings.warn(
38
- "Warning: a key parameter of the data has changed but the data itself has not been reloaded."
40
+ "Warning: a key parameter of the data has changed but the "
41
+ "data itself has not been reloaded."
39
42
  )
40
43
  while True:
41
44
  user_input = input("Do you want to continue? y/n: ")
@@ -71,7 +74,7 @@ class Processor:
71
74
  to_date: str | None = None,
72
75
  check_hts: str | None = None,
73
76
  check_measurement: str | None = None,
74
- defaults: dict = {},
77
+ defaults: dict | None = None,
75
78
  **kwargs,
76
79
  ):
77
80
  """Initialize a Processor instance."""
@@ -90,27 +93,30 @@ class Processor:
90
93
  else:
91
94
  raise ValueError(
92
95
  f"Site '{site}' not found for both base_url and hts combos."
93
- f"Available sites in standard_hts are {[s for s in standard_hilltop.available_sites]}"
94
- f"Available sites in check_hts are {[s for s in check_hilltop.available_sites]}"
96
+ f"Available sites in standard_hts are: "
97
+ f"{[s for s in standard_hilltop.available_sites]}"
98
+ f"Available sites in check_hts are: "
99
+ f"{[s for s in check_hilltop.available_sites]}"
95
100
  )
96
101
 
97
- self._standard_measurement_list = standard_hilltop.get_measurement_list(site)
98
- if standard_measurement in self._standard_measurement_list.values:
102
+ standard_measurement_list = standard_hilltop.get_measurement_list(site)
103
+ if standard_measurement in list(standard_measurement_list.MeasurementName):
99
104
  self._standard_measurement = standard_measurement
100
105
  else:
101
106
  raise ValueError(
102
- f"Standard measurement '{standard_measurement}' not found at site '{site}'. "
107
+ f"Standard measurement '{standard_measurement}' not found at "
108
+ f"site '{site}'. "
103
109
  "Available measurements are "
104
- f"{[str(m[0]) for m in self._standard_measurement_list.values]}"
110
+ f"{list(standard_measurement_list.MeasurementName)}"
105
111
  )
106
- self._check_measurement_list = check_hilltop.get_measurement_list(site)
107
- if check_measurement in self._check_measurement_list.values:
112
+ check_measurement_list = check_hilltop.get_measurement_list(site)
113
+ if check_measurement in list(check_measurement_list.MeasurementName):
108
114
  self._check_measurement = check_measurement
109
115
  else:
110
116
  raise ValueError(
111
117
  f"Check measurement '{check_measurement}' not found at site '{site}'. "
112
118
  "Available measurements are "
113
- f"{[str(m[0]) for m in self._check_measurement_list.values]}"
119
+ f"{list(check_measurement_list.MeasurementName)}"
114
120
  )
115
121
 
116
122
  self._base_url = base_url
@@ -281,10 +287,9 @@ class Processor:
281
287
  tstype="Standard",
282
288
  )
283
289
  insert_series = insert_series.asfreq(self.frequency)
284
- slice_to_remove = self.standard_series.loc[
285
- insert_series.index[0] : insert_series.index[-1]
286
- ]
287
- cleaned_series = self.standard_series.drop(slice_to_remove.index)
290
+ cleaned_series = filters.remove_range(
291
+ self.standard_series, insert_series.index[0], insert_series.index[-1]
292
+ )
288
293
  self.standard_series = pd.concat(
289
294
  [cleaned_series, insert_series]
290
295
  ).sort_index()
@@ -328,6 +333,9 @@ class Processor:
328
333
  quality: bool = False,
329
334
  ):
330
335
  """Import data using class parameter range."""
336
+ self.standard_series = pd.Series({})
337
+ self.check_series = pd.Series({})
338
+ self.quality_series = pd.Series({})
331
339
  self.import_range(self._from_date, self._to_date, standard, check, quality)
332
340
  self._stale = False
333
341
 
@@ -410,6 +418,34 @@ class Processor:
410
418
  self._standard_series, span, low_clip, high_clip, delta
411
419
  )
412
420
 
421
+ @ClassLogger
422
+ def delete_range(
423
+ self,
424
+ from_date,
425
+ to_date,
426
+ tstype_standard=True,
427
+ tstype_check=False,
428
+ tstype_quality=False,
429
+ ):
430
+ """Delete range of data a la remove_range."""
431
+ if tstype_standard:
432
+ self.standard_series = filters.remove_range(
433
+ self.standard_series, from_date, to_date
434
+ )
435
+ if tstype_check:
436
+ self.standard_series = filters.remove_range(
437
+ self.standard_series, from_date, to_date
438
+ )
439
+ if tstype_quality:
440
+ self.standard_series = filters.remove_range(
441
+ self.standard_series, from_date, to_date
442
+ )
443
+
444
+ @ClassLogger
445
+ def insert_missing_nans(self):
446
+ """Set the data to the correct frequency, filled with NaNs as appropriate."""
447
+ self.standard_series = self.standard_series.asfreq(self.frequency)
448
+
413
449
  @ClassLogger
414
450
  def data_exporter(self, file_location):
415
451
  """Export data to csv."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hydrobot
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Python Package providing a suite of processing tools and utilities for Hilltop hydrological data.
5
5
  Home-page: https://github.com/nicmostert/hydrobot
6
6
  Author: Nic Mostert
@@ -12,7 +12,7 @@ Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
13
13
  Classifier: Natural Language :: English
14
14
  Classifier: Programming Language :: Python :: 3.11
15
- Requires-Python: ==3.11
15
+ Requires-Python: ==3.11.6
16
16
  License-File: LICENSE
17
17
  License-File: AUTHORS.rst
18
18
 
@@ -80,3 +80,8 @@ History
80
80
  ------------------
81
81
 
82
82
  * Ok, actually including the config files (promise, but my fingers are crossed behind my back)
83
+
84
+ 0.2.3 (2023-11-30)
85
+ ------------------
86
+
87
+ * Fixed some tests and hopefully fixed the config file issue this time.
@@ -34,6 +34,8 @@ hydrobot.egg-info/dependency_links.txt
34
34
  hydrobot.egg-info/not-zip-safe
35
35
  hydrobot.egg-info/requires.txt
36
36
  hydrobot.egg-info/top_level.txt
37
+ hydrobot/config/TwoLevelMeasurement_QC_config.csv
38
+ hydrobot/config/measurement_QC_config.csv
37
39
  tests/__init__.py
38
40
  tests/site_list_response.xml
39
41
  tests/test_data_sources.py
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.2.2
2
+ current_version = 0.3.0
3
3
  commit = True
4
4
  tag = True
5
5
 
@@ -12,12 +12,17 @@ with open("HISTORY.rst") as history_file:
12
12
 
13
13
  requirements: list = ["hilltop-py>=2.3.1", "data-annalist>=0.3.6", "matplotlib>=3.8.0"]
14
14
 
15
- test_requirements = ["pytest>=3", "data-annalist>=0.3.6"]
15
+ test_requirements = [
16
+ "pytest>=3",
17
+ "data-annalist>=0.3.6",
18
+ "pytest-mock>=3.12.0",
19
+ "pytest-dependency>=0.5.1",
20
+ ]
16
21
 
17
22
  setup(
18
23
  author="Nic Mostert",
19
24
  author_email="nicolas.mostert@horizons.govt.nz",
20
- python_requires="==3.11",
25
+ python_requires="==3.11.6",
21
26
  classifiers=[
22
27
  "Development Status :: 2 - Pre-Alpha",
23
28
  "Intended Audience :: Developers",
@@ -42,6 +47,7 @@ setup(
42
47
  test_suite="tests",
43
48
  tests_require=test_requirements,
44
49
  url="https://github.com/nicmostert/hydrobot",
45
- version="0.2.2",
50
+ version="0.3.0",
46
51
  zip_safe=False,
52
+ package_data={"hydrobot": ["config/*"]},
47
53
  )
@@ -36,9 +36,10 @@ def raw_data():
36
36
 
37
37
 
38
38
  def insert_raw_data_gaps(gaps):
39
+ gap_data_dict = dict(raw_data_dict)
39
40
  for gap in gaps:
40
- raw_data_dict[gap] = np.nan
41
- data_series = pd.Series(raw_data_dict)
41
+ gap_data_dict[gap] = np.nan
42
+ data_series = pd.Series(gap_data_dict)
42
43
  return data_series
43
44
 
44
45
 
@@ -81,10 +82,10 @@ def test_fbewma(raw_data, fbewma_data):
81
82
  span = 3
82
83
 
83
84
  # Testing
84
- fbewmadf = filters.fbewma(raw_data, span)
85
+ fbewma_df = filters.fbewma(raw_data, span)
85
86
 
86
87
  # pytest.approx accounts for floating point errors and such
87
- assert fbewmadf.values == pytest.approx(fbewma_data.values), "FBEWMA failed!"
88
+ assert fbewma_df.values == pytest.approx(fbewma_data.values), "FBEWMA failed!"
88
89
 
89
90
 
90
91
  def test_remove_outliers(raw_data, fbewma_data, mocker, span=2, delta=2):
@@ -127,3 +128,14 @@ def test_remove_spike(raw_data, fbewma_data, mocker):
127
128
 
128
129
  spike_removed = filters.remove_spikes(raw_data, span, high_clip, low_clip, delta)
129
130
  assert math.isnan(spike_removed["2021-01-01 00:10"]), "Spike not removed!"
131
+
132
+
133
+ def test_remove_range(raw_data):
134
+ a = filters.remove_range(raw_data, "2021-01-01 00:05", "2021-01-01 00:10")
135
+ assert len(a) == 3, "Incorrect number of values removed"
136
+ assert a["2021-01-01 00:00"] == 1.0, "first value compromised"
137
+ assert a["2021-01-01 00:15"] == 4.0, "after value compromised"
138
+ assert a["2021-01-01 00:20"] == 5.0, "end value compromised"
139
+
140
+ b = filters.remove_range(raw_data, "2021-01-01 00:03", "2021-01-01 00:14")
141
+ assert b.equals(a), "time rounding error"
@@ -1,4 +1,3 @@
1
- '''
2
1
  import random
3
2
  from datetime import datetime, timedelta
4
3
 
@@ -20,6 +19,7 @@ SITES = [
20
19
 
21
20
  MEASUREMENTS = [
22
21
  "General Nastiness (out of 10)",
22
+ "Atmospheric Pressure",
23
23
  "Number of Actual Whole Turds Floating By (t/s)",
24
24
  "Dead Cow Concentration (ppm)",
25
25
  ]
@@ -27,14 +27,13 @@ MEASUREMENTS = [
27
27
 
28
28
  @pytest.fixture(autouse=True)
29
29
  def no_requests(monkeypatch):
30
- """Don't allow requests to make requests"""
30
+ """Don't allow requests to make requests."""
31
31
  monkeypatch.delattr("requests.sessions.Session.request")
32
32
 
33
33
 
34
34
  @pytest.fixture
35
35
  def mock_site_list():
36
- """Mock response from SiteList server call method"""
37
-
36
+ """Mock response from SiteList server call method."""
38
37
  data = {
39
38
  "SiteName": SITES,
40
39
  }
@@ -45,8 +44,7 @@ def mock_site_list():
45
44
 
46
45
  @pytest.fixture
47
46
  def mock_measurement_list():
48
- """Mock response from MeasurementList server call method"""
49
-
47
+ """Mock response from MeasurementList server call method."""
50
48
  data = {
51
49
  "MeasurementName": MEASUREMENTS,
52
50
  }
@@ -78,8 +76,9 @@ def mock_dataset():
78
76
  return df
79
77
 
80
78
 
81
-
82
79
  def test_processor(monkeypatch, mock_site_list, mock_measurement_list, mock_dataset):
80
+ """Test the processor function."""
81
+
83
82
  def get_mock_site_list(*args, **kwargs):
84
83
  return mock_site_list
85
84
 
@@ -95,8 +94,11 @@ def test_processor(monkeypatch, mock_site_list, mock_measurement_list, mock_data
95
94
 
96
95
  pr = processor.Processor(
97
96
  "https://greenwashed.and.pleasant/",
98
- "GreenPasturesAreNaturalAndEcoFriendlyISwear.hts",
99
97
  SITES[1],
98
+ "GreenPasturesAreNaturalAndEcoFriendlyISwear.hts",
100
99
  MEASUREMENTS[1],
100
+ "5T",
101
101
  )
102
- assert pr.dataset.loc[0].Time == "2020-10-01 08:00:00"'''
102
+ pr.import_data()
103
+ print(pr.standard_series)
104
+ assert pr.standard_series.loc["2020-10-01 08:00:00"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes