cave-utils 2.0.1__tar.gz → 2.0.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 (33) hide show
  1. {cave_utils-2.0.1 → cave_utils-2.0.2}/PKG-INFO +2 -3
  2. {cave_utils-2.0.1 → cave_utils-2.0.2}/README.md +1 -2
  3. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/appBar.py +1 -1
  4. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/groupedOutputs.py +73 -36
  5. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/maps.py +9 -2
  6. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api_utils/general.py +45 -12
  7. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api_utils/validator_utils.py +12 -10
  8. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils.egg-info/PKG-INFO +2 -3
  9. {cave_utils-2.0.1 → cave_utils-2.0.2}/pyproject.toml +1 -1
  10. {cave_utils-2.0.1 → cave_utils-2.0.2}/setup.cfg +1 -1
  11. {cave_utils-2.0.1 → cave_utils-2.0.2}/LICENSE +0 -0
  12. {cave_utils-2.0.1 → cave_utils-2.0.2}/NOTICE.md +0 -0
  13. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/__init__.py +0 -0
  14. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/__init__.py +0 -0
  15. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/extraKwargs.py +0 -0
  16. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/globalOutputs.py +0 -0
  17. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/mapFeatures.py +0 -0
  18. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/pages.py +0 -0
  19. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/panes.py +0 -0
  20. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api/settings.py +0 -0
  21. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api_utils/__init__.py +0 -0
  22. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/api_utils/validator.py +0 -0
  23. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/arguments.py +0 -0
  24. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/log.py +0 -0
  25. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils/socket.py +0 -0
  26. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils.egg-info/SOURCES.txt +0 -0
  27. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils.egg-info/dependency_links.txt +0 -0
  28. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils.egg-info/requires.txt +0 -0
  29. {cave_utils-2.0.1 → cave_utils-2.0.2}/cave_utils.egg-info/top_level.txt +0 -0
  30. {cave_utils-2.0.1 → cave_utils-2.0.2}/test/test_arguments.py +0 -0
  31. {cave_utils-2.0.1 → cave_utils-2.0.2}/test/test_import.py +0 -0
  32. {cave_utils-2.0.1 → cave_utils-2.0.2}/test/test_log.py +0 -0
  33. {cave_utils-2.0.1 → cave_utils-2.0.2}/test/test_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cave_utils
3
- Version: 2.0.1
3
+ Version: 2.0.2
4
4
  Summary: Python wrapper for api use in the cave_app
5
5
  Author-email: Connor Makowski <conmak@mit.edu>
6
6
  Project-URL: Homepage, https://github.com/mit-cave/cave_utils
@@ -80,9 +80,8 @@ pip install cave_utils
80
80
 
81
81
  2. Remove `cave_utils` from the root `requirements.txt` file
82
82
 
83
- 3. In your cave_app, set `LIVE_API_VALIDATION=True` in the `.env` file
83
+ 3. In your cave_app, set `LIVE_API_VALIDATION_PRINT=True` in the `.env` file
84
84
  - This will validate your data every time an API command is called for each session
85
- - Outputs will be stored in `logs/validation/{session_name}.log`
86
85
 
87
86
  4. Use the following command to run your cave_app:
88
87
  `cave run --docker-args "--volume {local_path_to_cave_utils}/cave_utils:/cave_utils"`
@@ -64,9 +64,8 @@ pip install cave_utils
64
64
 
65
65
  2. Remove `cave_utils` from the root `requirements.txt` file
66
66
 
67
- 3. In your cave_app, set `LIVE_API_VALIDATION=True` in the `.env` file
67
+ 3. In your cave_app, set `LIVE_API_VALIDATION_PRINT=True` in the `.env` file
68
68
  - This will validate your data every time an API command is called for each session
69
- - Outputs will be stored in `logs/validation/{session_name}.log`
70
69
 
71
70
  4. Use the following command to run your cave_app:
72
71
  `cave run --docker-args "--volume {local_path_to_cave_utils}/cave_utils:/cave_utils"`
@@ -78,7 +78,7 @@ class appBar_data_star(ApiValidator):
78
78
  * `"lowerRight"`: Lower section of the right-side bar
79
79
  * **`variant`**: `[str]` = `None` &rarr; The variant of the button.
80
80
  * **Accepted Values**:
81
- * When **`type`** == `"pane"` | `"page"`:
81
+ * When **`type`** == `"pane"`:
82
82
  * `"modal"`: A [modal pane][]
83
83
  * `"wall"`: A [wall pane][]
84
84
  * Otherwise:
@@ -60,9 +60,10 @@ class groupedOutputs_data_star(ApiValidator):
60
60
  * **`stats`**: `[dict]` &rarr; A dictionary of stats that are available for the data.
61
61
  * **See**: `cave_utils.api.groupedOutputs.groupedOutputs_data_star_stats`
62
62
  **`valueLists`**: `[dict]` &rarr; A dictionary of lists that make up the stats for the data.
63
+ * **See**: `cave_utils.api.groupedOutputs.groupedOutputs_data_star_valueLists`
64
+ * **Note**: Each key must also be a key in `groupedOutputs.data.*.stats`.
63
65
  **`groupLists`**: `[dict]` &rarr; A dictionary of lists that make up the groupings for the data.
64
66
  """
65
- # TODO: Flesh out valueLists and groupLists
66
67
  return {"kwargs": kwargs, "accepted_values": {}}
67
68
 
68
69
  def __extend_spec__(self, **kwargs):
@@ -74,45 +75,37 @@ class groupedOutputs_data_star(ApiValidator):
74
75
  validator=groupedOutputs_data_star_stats,
75
76
  **kwargs,
76
77
  )
77
- list_lengths = []
78
- pass_list_lengths = True
79
78
  # Ensure Valid Value Lists
80
79
  valueLists_data = self.data.get("valueLists", {})
81
- for key, value in valueLists_data.items():
82
- if not self.__check_type__(
83
- value=value, check_type=(list,), prepend_path=["valueLists", key]
84
- ):
85
- pass_list_lengths = False
86
- continue
87
- list_lengths.append(len(value))
88
- self.__check_type_list__(
89
- data=value, types=(int, float), prepend_path=["valueLists", key]
90
- )
80
+ groupedOutputs_data_star_valueLists(
81
+ data=valueLists_data,
82
+ log=self.log,
83
+ prepend_path=["valueLists"],
84
+ acceptable_data_keys=list(stats_data.keys()),
85
+ **kwargs,
86
+ )
91
87
  # Ensure Valid Group Lists
92
- available_groups = kwargs.get("available_groups", {})
93
88
  groupLists_data = self.data.get("groupLists", {})
94
- self.__check_subset_valid__(
95
- subset=list(groupLists_data.keys()),
96
- valid_values=list(available_groups.keys()),
89
+ groupedOutputs_data_star_groupLists(
90
+ data=groupLists_data,
91
+ log=self.log,
97
92
  prepend_path=["groupLists"],
93
+ **kwargs,
98
94
  )
99
- for key, value in groupLists_data.items():
100
- if not self.__check_type__(
101
- value=value, check_type=(list,), prepend_path=["groupLists", key]
102
- ):
103
- pass_list_lengths = False
104
- continue
105
- list_lengths.append(len(value))
106
- valid_values = available_groups.get(key, [])
107
- if not self.__check_type_list__(
108
- data=valid_values, types=(str,), prepend_path=["groupLists", key]
95
+
96
+ # Ensure that all lists are the same length
97
+ try:
98
+ if (
99
+ len(
100
+ set(
101
+ [len(v) for v in valueLists_data.values()]
102
+ + [len(v) for v in groupLists_data.values()]
103
+ )
104
+ )
105
+ != 1
109
106
  ):
110
- continue
111
- self.__check_subset_valid__(
112
- subset=value, valid_values=valid_values, prepend_path=["groupLists", key]
113
- )
114
- # Ensure all lists are the same length
115
- if not pass_list_lengths or len(set(list_lengths)) != 1:
107
+ raise Exception
108
+ except:
116
109
  self.__error__(
117
110
  msg="All values in groupedOutputs.data.*.groupLists and groupedOutputs.data.*.valueLists must be lists of the same length.",
118
111
  )
@@ -180,14 +173,58 @@ class groupedOutputs_data_star_valueLists(ApiValidator):
180
173
  @staticmethod
181
174
  def spec(**kwargs):
182
175
  """
183
- Accepts any key value pairs as a dictionary structure for the data.
184
- Each value must be a list of integers or floats.
176
+ Arguments:
177
+
178
+ - **`yourCustomKeyHere`**: `[list]` &rarr;
179
+ - * **Note**: Each custom key passed must also be a key in `groupedOutputs.data.*.stats`.
180
+ - * **Note**: Each value must be a list of integers or floats.
185
181
  """
186
182
  return {"kwargs": {}, "accepted_values": {}}
187
183
 
188
184
  def __extend_spec__(self, **kwargs):
185
+ if not self.__check_subset_valid__(
186
+ subset=list(self.data.keys()),
187
+ valid_values=kwargs.get("acceptable_data_keys", []),
188
+ prepend_path=[],
189
+ ):
190
+ return
189
191
  for key, value in self.data.items():
190
- self.__check_type_list__(data=value, types=(int, float), prepend_path=[key])
192
+ if self.__check_type__(value=value, check_type=(list,), prepend_path=[key]):
193
+ self.__check_type_list__(data=value, types=(int, float), prepend_path=[key])
194
+
195
+
196
+ @type_enforced.Enforcer
197
+ class groupedOutputs_data_star_groupLists(ApiValidator):
198
+ """
199
+ The group lists are located under the path **`groupedOutputs.data.*.groupLists`**.
200
+ """
201
+
202
+ @staticmethod
203
+ def spec(**kwargs):
204
+ """
205
+ Arguments:
206
+
207
+ - **`yourCustomKeyHere`**: `[list]` &rarr;
208
+ - * **Note**: Each value must be a list of strings
209
+ - * **Note**: Each item in the passed value must also be found in `groupedOutputs.groupings.{yourCustomKeyHere}.data.id`.
210
+ """
211
+ return {"kwargs": {}, "accepted_values": {}}
212
+
213
+ def __extend_spec__(self, **kwargs):
214
+ available_groups = kwargs.get("available_groups", {})
215
+ if self.__check_subset_valid__(
216
+ subset=list(self.data.keys()),
217
+ valid_values=list(available_groups.keys()),
218
+ prepend_path=[],
219
+ ):
220
+ for key, value in self.data.items():
221
+ if self.__check_type__(value=value, check_type=(list,), prepend_path=[key]):
222
+ self.__check_type_list__(data=value, types=(str,), prepend_path=[key])
223
+ self.__check_subset_valid__(
224
+ subset=value,
225
+ valid_values=available_groups.get(key, []),
226
+ prepend_path=[key],
227
+ )
191
228
 
192
229
 
193
230
  @type_enforced.Enforcer
@@ -365,6 +365,7 @@ class maps_data_star_legendGroups_star_data_star(ApiValidator):
365
365
  * **Notes**:
366
366
  * If `None`, the data layer will not be colored.
367
367
  * Does not apply to shape layers
368
+ * Only props of type `"num"`, `"toggle"`, and `"selector"` can be colored.
368
369
  * **Example**:
369
370
  ```py
370
371
  "colorByOptions": {
@@ -386,6 +387,7 @@ class maps_data_star_legendGroups_star_data_star(ApiValidator):
386
387
  * **Notes**:
387
388
  * If `None`, the data layer will not be sized.
388
389
  * Does not apply to shape layers
390
+ * Only props of type `"num"` can be sized.
389
391
  * **Example**:
390
392
  ```py
391
393
  "sizeByOptions": {
@@ -447,7 +449,7 @@ class maps_data_star_legendGroups_star_data_star(ApiValidator):
447
449
  colorBy_availableProps = {
448
450
  k: v
449
451
  for k, v in available_props.items()
450
- if v.get("type") in ["num", "toggle", "selector"]
452
+ if v.get("type") in ["num", "toggle", "selector", "text"]
451
453
  }
452
454
  sizeBy_availableProps = {
453
455
  k: v for k, v in available_props.items() if v.get("type") in ["num"]
@@ -591,8 +593,13 @@ class colorByOptions(ApiValidator):
591
593
  ):
592
594
  return
593
595
  self.__check_rgba_string_valid__(rgba_string=value, prepend_path=[key])
596
+ elif prop_type == "text":
597
+ for key, value in self.data.items():
598
+ self.__check_rgba_string_valid__(rgba_string=value, prepend_path=[key])
594
599
  else:
595
- self.__error__(msg=f"Invalid prop type ({prop_type}) for colorByOptions")
600
+ self.__error__(
601
+ msg=f"Invalid prop type ({prop_type}) for colorByOptions. Allowed props are `num`, `toggle`, `selector`, and `text`"
602
+ )
596
603
 
597
604
 
598
605
  @type_enforced.Enforcer
@@ -40,6 +40,7 @@ class props(ApiValidator):
40
40
  unitPlacement: [str, None] = None,
41
41
  locale: [str, None] = None,
42
42
  fallbackValue: [str, None] = None,
43
+ allowNone: [bool, None] = None,
43
44
  **kwargs,
44
45
  ):
45
46
  """
@@ -88,11 +89,14 @@ class props(ApiValidator):
88
89
  * `"picture"`: Show a PNG or JPG image
89
90
  * `"video"`: Display a YouTube, Vimeo, or Dailymotion video clip
90
91
  * **`enabled`**: `[bool]` = `True` &rarr; Whether or not the prop will be enabled.
92
+ * **Note**: This attribute is applicable to all props except `"head"` props.
91
93
  * **`apiCommand`**: `[str]` = `None` &rarr; The name of the API command to trigger.
92
94
  * **Note**: If `None`, no `apiCommand` is triggered.
95
+ * **Note**: This attribute is applicable to all props except `"head"` props.
93
96
  * **`apiCommandKeys`**: `[list]` = `None` &rarr;
94
97
  * The root API keys to pass to your `execute_command` function if an `apiCommand` is provided.
95
98
  * **Note**: If `None`, all API keys are passed to your `execute_command`.
99
+ * **Note**: This attribute is applicable to all props except `"head"` props.
96
100
  * **`icon`**: `[str]` = `None` &rarr; The icon to use for the prop.
97
101
  * **Notes**:
98
102
  * It must be a valid icon name from the [react-icons][] bundle, preceded by the abbreviated name of the icon library source.
@@ -146,8 +150,10 @@ class props(ApiValidator):
146
150
  * This attribute is applicable exclusively to `"num"` props.
147
151
  * **`fallbackValue`**: [str] = `None` &rarr; A value to show when the value is missing or invalid.
148
152
  * **Notes**:
153
+ * This is only for display purposes as related to number formatting. It does not affect the actual value or any computations.
154
+ * For example, if the value passed is `None`, the fallback value will be displayed instead.
149
155
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.fallbackValue`.
150
- * This attribute only applies to `"num"` props.
156
+ * This attribute is applicable exclusively to `"num"` props.
151
157
  * **`unit`**: `[str]` = `None` &rarr; The unit to use for the prop.
152
158
  * **Notes**:
153
159
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.unit`.
@@ -229,6 +235,17 @@ class props(ApiValidator):
229
235
  * Takes precedence over other formatting, except when used in a node cluster and the `cave_utils.api.maps.group` attribute is `True`. In this case, the max value within the node cluster is displayed.
230
236
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.legendMaxLabel`.
231
237
  * This attribute is applicable exclusively to `"num"` props.
238
+ * **`allowNone`**: `[bool]` = `False` &rarr;
239
+ * Whether or not to allow `None` as a valid value for the prop. This is primarily used to help when validating `values` and `valueLists`.
240
+ * **Notes**:
241
+ * If `True`, `None` will be a valid value for the prop.
242
+ * `None` values will be treated differently in the front end
243
+ * For map display purposes: `None` values will be shown as a different color or ignored.
244
+ * See `nullColor` in: `/cave_utils/cave_utils/api/maps.html#colorByOptions`
245
+ * For prop purposes: `None` values will be left blank.
246
+ * If `False`, `None` will not be a valid value for the prop.
247
+ * This attribute is applicable to all props except `"head"` props.
248
+
232
249
 
233
250
  [metric prefix]: https://en.wikipedia.org/wiki/Metric_prefix
234
251
  [Scientific notation]: https://en.wikipedia.org/wiki/Scientific_notation
@@ -236,9 +253,9 @@ class props(ApiValidator):
236
253
  """
237
254
  passed_values = {k: v for k, v in locals().items() if (v is not None) and k != "kwargs"}
238
255
  required_fields = ["name", "type"]
239
- optional_fields = ["help", "variant", "enabled"]
256
+ optional_fields = ["help", "variant"]
240
257
  if type != "head":
241
- optional_fields += ["apiCommand", "apiCommandKeys"]
258
+ optional_fields += ["enabled", "apiCommand", "apiCommandKeys", "allowNone"]
242
259
  if type == "head":
243
260
  if variant == "icon":
244
261
  required_fields += ["icon"]
@@ -458,8 +475,12 @@ class values(ApiValidator):
458
475
  )
459
476
  continue
460
477
  prop_type = prop_spec.get("type", None)
478
+ if prop_type == "head":
479
+ self.__error__(
480
+ msg=f"`{prop_key}` with the prop type of `{prop_type}` can not have an associated value."
481
+ )
482
+ continue
461
483
  acceptable_types = {
462
- "head": (str,),
463
484
  "num": (int, float),
464
485
  "toggle": (bool,),
465
486
  "button": (str,),
@@ -467,9 +488,16 @@ class values(ApiValidator):
467
488
  "selector": (list,),
468
489
  "date": (str,),
469
490
  "media": (str,),
470
- }.get(prop_type, None)
491
+ }.get(prop_type, tuple())
492
+ # Add None to acceptable types if allowed
493
+ if prop_spec.get("allowNone", False):
494
+ acceptable_types += (type(None),)
495
+ # Validate types and continue if invalid
471
496
  if not self.__check_type__(prop_value, acceptable_types, prepend_path=[prop_key]):
472
497
  continue
498
+ # Continue if the value is None
499
+ if prop_value is None:
500
+ continue
473
501
  if prop_type == "num":
474
502
  min_value = prop_spec.get("minValue", float("-inf"))
475
503
  max_value = prop_spec.get("maxValue", float("inf"))
@@ -480,10 +508,6 @@ class values(ApiValidator):
480
508
  elif prop_type == "selector":
481
509
  options = list(prop_spec.get("options", {}).keys())
482
510
  self.__check_subset_valid__(prop_value, options, prepend_path=[prop_key])
483
- elif prop_type == "head":
484
- self.__error__(
485
- msg=f"`{prop_key}` with the prop type of `{prop_type}` can not have an associated value."
486
- )
487
511
  elif prop_type == "date":
488
512
  pass
489
513
  # TODO: Validate date string
@@ -498,7 +522,7 @@ class valueLists(ApiValidator):
498
522
  """
499
523
  Accepts all arbitrary values depending on what you have in your props as part of the API spec.
500
524
 
501
- The valueLists you pass will be validated against the props in your API spec.
525
+ The valueLists you pass will be validated against the `props` from your API spec.
502
526
  """
503
527
  return {
504
528
  "kwargs": {},
@@ -520,8 +544,12 @@ class valueLists(ApiValidator):
520
544
  )
521
545
  continue
522
546
  prop_type = prop_spec.get("type", None)
547
+ if prop_type == "head":
548
+ self.__error__(
549
+ msg=f"`{prop_key}` with the prop type of `{prop_type}` can not have an associated value."
550
+ )
551
+ continue
523
552
  acceptable_types = {
524
- "head": (str,),
525
553
  "num": (int, float),
526
554
  "toggle": (bool,),
527
555
  "button": (str,),
@@ -529,11 +557,16 @@ class valueLists(ApiValidator):
529
557
  "selector": (list,),
530
558
  "date": (str,),
531
559
  "media": (str,),
532
- }.get(prop_type, None)
560
+ }.get(prop_type, tuple())
561
+ # Add None to acceptable types if allowed
562
+ if prop_spec.get("allowNone", False):
563
+ acceptable_types += (type(None),)
533
564
  if not self.__check_type_list__(
534
565
  data=prop_value_list, types=acceptable_types, prepend_path=[prop_key]
535
566
  ):
536
567
  continue
568
+ if prop_spec.get("allowNone", False):
569
+ prop_value_list = [v for v in prop_value_list if v is not None]
537
570
  if prop_type == "num":
538
571
  # Validate minimum is met
539
572
  min_value = prop_spec.get("minValue")
@@ -93,40 +93,42 @@ class ApiValidator:
93
93
  """
94
94
  Validate an rgba string and if an issue is present, log an error
95
95
  """
96
+ msg = "Invalid RGBA string. Must be in the format 'rgba(0, 0, 0, 0)' where each value is an integer between 0 and 255."
96
97
  try:
97
98
  if "rgba(" != rgba_string[:5]:
98
- self.__error__(path=prepend_path, msg="Invalid RGBA string")
99
+ self.__error__(path=prepend_path, msg=msg)
99
100
  return
100
101
  if ")" != rgba_string[-1]:
101
- self.__error__(path=prepend_path, msg="Invalid RGBA string")
102
+ self.__error__(path=prepend_path, msg=msg)
102
103
  return
103
104
  rgba_list = rgba_string[5:-1].replace(" ", "").split(",")
104
105
  for rgba in rgba_list:
105
106
  if not rgba.isdigit():
106
- self.__error__(path=prepend_path, msg="Invalid RGBA string")
107
+ self.__error__(path=prepend_path, msg=msg)
107
108
  return
108
109
  if int(rgba) < 0 or int(rgba) > 255:
109
- self.__error__(path=prepend_path, msg="Invalid RGBA string")
110
+ self.__error__(path=prepend_path, msg=msg)
110
111
  return
111
112
  except:
112
- self.__error__(path=prepend_path, msg="Invalid RGBA string")
113
+ self.__error__(path=prepend_path, msg=msg)
113
114
 
114
115
  def __check_pixel_string_valid__(self, pixel_string: str, prepend_path: list = list()):
115
116
  """
116
117
  Validate a pixel string and if an issue is present, log an error
117
118
  """
119
+ msg = "Invalid pixel string. Must be in the format '5px' where the value portion is a whole number."
118
120
  try:
119
121
  if "px" != pixel_string[-2:]:
120
- self.__error__(path=prepend_path, msg="Invalid pixel string")
122
+ self.__error__(path=prepend_path, msg=msg)
121
123
  return
122
- if int(pixel_string[:-2]) <= 0:
123
- self.__error__(path=prepend_path, msg="Invalid pixel string")
124
+ if int(pixel_string[:-2]) < 0:
125
+ self.__error__(path=prepend_path, msg=msg)
124
126
  except:
125
- self.__error__(path=prepend_path, msg="Invalid pixel string")
127
+ self.__error__(path=prepend_path, msg=msg)
126
128
 
127
129
  def __check_url_valid__(self, url: str, prepend_path: list = list()):
128
130
  """
129
- Validate a url and if an issue is present, log an error
131
+ Validate a url and if an issue is present, log an error.
130
132
  """
131
133
  # Use Django regex for URL validation
132
134
  # See https://stackoverflow.com/a/7160778/12014156
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cave-utils
3
- Version: 2.0.1
3
+ Version: 2.0.2
4
4
  Summary: Python wrapper for api use in the cave_app
5
5
  Author-email: Connor Makowski <conmak@mit.edu>
6
6
  Project-URL: Homepage, https://github.com/mit-cave/cave_utils
@@ -80,9 +80,8 @@ pip install cave_utils
80
80
 
81
81
  2. Remove `cave_utils` from the root `requirements.txt` file
82
82
 
83
- 3. In your cave_app, set `LIVE_API_VALIDATION=True` in the `.env` file
83
+ 3. In your cave_app, set `LIVE_API_VALIDATION_PRINT=True` in the `.env` file
84
84
  - This will validate your data every time an API command is called for each session
85
- - Outputs will be stored in `logs/validation/{session_name}.log`
86
85
 
87
86
  4. Use the following command to run your cave_app:
88
87
  `cave run --docker-args "--volume {local_path_to_cave_utils}/cave_utils:/cave_utils"`
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
12
12
 
13
13
  [project]
14
14
  name = "cave_utils"
15
- version = "2.0.1"
15
+ version = "2.0.2"
16
16
  description = "Python wrapper for api use in the cave_app"
17
17
  authors = [
18
18
  {name="Connor Makowski", email="conmak@mit.edu"}
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = cave_utils
3
- version = 2.0.1
3
+ version = 2.0.2
4
4
  description_file = README.md
5
5
 
6
6
  [options]
File without changes
File without changes
File without changes
File without changes