meerschaum 2.2.5.dev2__py3-none-any.whl → 2.2.6__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.
Files changed (54) hide show
  1. meerschaum/__init__.py +4 -1
  2. meerschaum/_internal/arguments/_parser.py +13 -3
  3. meerschaum/_internal/docs/index.py +513 -110
  4. meerschaum/_internal/term/__init__.py +2 -2
  5. meerschaum/actions/bootstrap.py +13 -14
  6. meerschaum/actions/python.py +11 -8
  7. meerschaum/actions/register.py +130 -32
  8. meerschaum/actions/show.py +92 -75
  9. meerschaum/actions/stack.py +12 -12
  10. meerschaum/actions/stop.py +11 -11
  11. meerschaum/api/__init__.py +0 -1
  12. meerschaum/api/dash/__init__.py +0 -1
  13. meerschaum/api/dash/callbacks/custom.py +1 -1
  14. meerschaum/api/dash/callbacks/login.py +21 -13
  15. meerschaum/api/dash/pages/login.py +2 -2
  16. meerschaum/api/dash/plugins.py +5 -6
  17. meerschaum/api/routes/_login.py +5 -5
  18. meerschaum/config/__init__.py +8 -1
  19. meerschaum/config/_paths.py +20 -2
  20. meerschaum/config/_version.py +1 -1
  21. meerschaum/config/paths.py +21 -2
  22. meerschaum/config/static/__init__.py +1 -0
  23. meerschaum/connectors/Connector.py +7 -2
  24. meerschaum/connectors/__init__.py +7 -5
  25. meerschaum/connectors/api/APIConnector.py +7 -2
  26. meerschaum/connectors/api/_actions.py +23 -31
  27. meerschaum/connectors/api/_uri.py +5 -5
  28. meerschaum/core/Pipe/__init__.py +7 -3
  29. meerschaum/core/Pipe/_data.py +23 -15
  30. meerschaum/core/Pipe/_deduplicate.py +1 -1
  31. meerschaum/core/Pipe/_dtypes.py +5 -0
  32. meerschaum/core/Pipe/_fetch.py +18 -16
  33. meerschaum/core/Pipe/_sync.py +20 -15
  34. meerschaum/plugins/_Plugin.py +6 -6
  35. meerschaum/plugins/__init__.py +1 -1
  36. meerschaum/utils/daemon/RotatingFile.py +15 -16
  37. meerschaum/utils/dataframe.py +12 -4
  38. meerschaum/utils/debug.py +9 -15
  39. meerschaum/utils/formatting/__init__.py +13 -12
  40. meerschaum/utils/misc.py +117 -11
  41. meerschaum/utils/packages/__init__.py +7 -1
  42. meerschaum/utils/typing.py +1 -0
  43. meerschaum/utils/venv/__init__.py +5 -1
  44. meerschaum/utils/warnings.py +9 -1
  45. meerschaum/utils/yaml.py +2 -2
  46. {meerschaum-2.2.5.dev2.dist-info → meerschaum-2.2.6.dist-info}/METADATA +1 -1
  47. {meerschaum-2.2.5.dev2.dist-info → meerschaum-2.2.6.dist-info}/RECORD +53 -54
  48. {meerschaum-2.2.5.dev2.dist-info → meerschaum-2.2.6.dist-info}/WHEEL +1 -1
  49. meerschaum/actions/backup.py +0 -43
  50. {meerschaum-2.2.5.dev2.dist-info → meerschaum-2.2.6.dist-info}/LICENSE +0 -0
  51. {meerschaum-2.2.5.dev2.dist-info → meerschaum-2.2.6.dist-info}/NOTICE +0 -0
  52. {meerschaum-2.2.5.dev2.dist-info → meerschaum-2.2.6.dist-info}/entry_points.txt +0 -0
  53. {meerschaum-2.2.5.dev2.dist-info → meerschaum-2.2.6.dist-info}/top_level.txt +0 -0
  54. {meerschaum-2.2.5.dev2.dist-info → meerschaum-2.2.6.dist-info}/zip-safe +0 -0
@@ -14,7 +14,9 @@ import threading
14
14
  import multiprocessing
15
15
  import functools
16
16
  from datetime import datetime, timedelta
17
+ from typing import TYPE_CHECKING
17
18
 
19
+ import meerschaum as mrsm
18
20
  from meerschaum.utils.typing import (
19
21
  Union,
20
22
  Optional,
@@ -26,13 +28,16 @@ from meerschaum.utils.typing import (
26
28
  List,
27
29
  Iterable,
28
30
  Generator,
29
- Iterator,
30
31
  )
31
32
  from meerschaum.utils.warnings import warn, error
32
33
 
34
+ if TYPE_CHECKING:
35
+ pd = mrsm.attempt_import('pandas')
36
+
33
37
  class InferFetch:
34
38
  MRSM_INFER_FETCH: bool = True
35
39
 
40
+
36
41
  def sync(
37
42
  self,
38
43
  df: Union[
@@ -125,7 +130,7 @@ def sync(
125
130
  from meerschaum.utils.formatting import get_console
126
131
  from meerschaum.utils.venv import Venv
127
132
  from meerschaum.connectors import get_connector_plugin
128
- from meerschaum.utils.misc import df_is_chunk_generator, filter_keywords
133
+ from meerschaum.utils.misc import df_is_chunk_generator, filter_keywords, filter_arguments
129
134
  from meerschaum.utils.pool import get_pool
130
135
  from meerschaum.config import get_config
131
136
 
@@ -210,28 +215,28 @@ def sync(
210
215
  ):
211
216
  with Venv(get_connector_plugin(self.instance_connector)):
212
217
  p._exists = None
213
- return self.instance_connector.sync_pipe_inplace(
218
+ _args, _kwargs = filter_arguments(
219
+ p.instance_connector.sync_pipe_inplace,
214
220
  p,
215
- **filter_keywords(
216
- p.instance_connector.sync_pipe_inplace,
217
- debug=debug,
218
- **kw
219
- )
221
+ debug=debug,
222
+ **kw
223
+ )
224
+ return self.instance_connector.sync_pipe_inplace(
225
+ *_args,
226
+ **_kwargs
220
227
  )
221
-
222
228
 
223
229
  ### Activate and invoke `sync(pipe)` for plugin connectors with `sync` methods.
224
230
  try:
225
231
  if getattr(p.connector, 'sync', None) is not None:
226
232
  with Venv(get_connector_plugin(p.connector), debug=debug):
227
- return_tuple = p.connector.sync(
233
+ _args, _kwargs = filter_arguments(
234
+ p.connector.sync,
228
235
  p,
229
- **filter_keywords(
230
- p.connector.sync,
231
- debug=debug,
232
- **kw
233
- )
236
+ debug=debug,
237
+ **kw
234
238
  )
239
+ return_tuple = p.connector.sync(*_args, **_kwargs)
235
240
  p._exists = None
236
241
  if not isinstance(return_tuple, tuple):
237
242
  return_tuple = (
@@ -654,17 +654,18 @@ class Plugin:
654
654
  import ast, re
655
655
  ### NOTE: This technically would break
656
656
  ### if `required` was the very first line of the file.
657
- req_start_match = re.search(r'\nrequired(\s?)=', text)
657
+ req_start_match = re.search(r'required(:\s*)?.*=', text)
658
658
  if not req_start_match:
659
659
  return []
660
660
  req_start = req_start_match.start()
661
+ equals_sign = req_start + text[req_start:].find('=')
661
662
 
662
663
  ### Dependencies may have brackets within the strings, so push back the index.
663
- first_opening_brace = req_start + 1 + text[req_start:].find('[')
664
+ first_opening_brace = equals_sign + 1 + text[equals_sign:].find('[')
664
665
  if first_opening_brace == -1:
665
666
  return []
666
667
 
667
- next_closing_brace = req_start + 1 + text[req_start:].find(']')
668
+ next_closing_brace = equals_sign + 1 + text[equals_sign:].find(']')
668
669
  if next_closing_brace == -1:
669
670
  return []
670
671
 
@@ -681,12 +682,11 @@ class Plugin:
681
682
 
682
683
  req_end = end_ix + 1
683
684
  req_text = (
684
- text[req_start:req_end]
685
- .lstrip()
686
- .replace('required', '', 1)
685
+ text[(first_opening_brace-1):req_end]
687
686
  .lstrip()
688
687
  .replace('=', '', 1)
689
688
  .lstrip()
689
+ .rstrip()
690
690
  )
691
691
  try:
692
692
  required = ast.literal_eval(req_text)
@@ -27,7 +27,7 @@ _locks = {
27
27
  'PLUGINS_INTERNAL_LOCK_PATH': RLock(),
28
28
  }
29
29
  __all__ = (
30
- "Plugin", "make_action", "api_plugin", "import_plugins",
30
+ "Plugin", "make_action", "api_plugin", "dash_plugin", "import_plugins",
31
31
  "reload_plugins", "get_plugins", "get_data_plugins", "add_plugin_argument",
32
32
  "pre_sync_hook", "post_sync_hook",
33
33
  )
@@ -32,14 +32,14 @@ class RotatingFile(io.IOBase):
32
32
  SEEK_BACK_ATTEMPTS: int = 5
33
33
 
34
34
  def __init__(
35
- self,
36
- file_path: pathlib.Path,
37
- num_files_to_keep: Optional[int] = None,
38
- max_file_size: Optional[int] = None,
39
- redirect_streams: bool = False,
40
- write_timestamps: bool = False,
41
- timestamp_format: str = '%Y-%m-%d %H:%M',
42
- ):
35
+ self,
36
+ file_path: pathlib.Path,
37
+ num_files_to_keep: Optional[int] = None,
38
+ max_file_size: Optional[int] = None,
39
+ redirect_streams: bool = False,
40
+ write_timestamps: bool = False,
41
+ timestamp_format: str = '%Y-%m-%d %H:%M',
42
+ ):
43
43
  """
44
44
  Create a file-like object which manages other files.
45
45
 
@@ -79,11 +79,7 @@ class RotatingFile(io.IOBase):
79
79
  self.redirect_streams = redirect_streams
80
80
  self.write_timestamps = write_timestamps
81
81
  self.timestamp_format = timestamp_format
82
- self.subfile_regex_pattern = re.compile(
83
- r'^'
84
- + self.file_path.name
85
- + r'(?:\.\d+)?$'
86
- )
82
+ self.subfile_regex_pattern = re.compile(r'(.*)\.log(?:\.\d+)?$')
87
83
 
88
84
  ### When subfiles are opened, map from their index to the file objects.
89
85
  self.subfile_objects = {}
@@ -173,7 +169,7 @@ class RotatingFile(io.IOBase):
173
169
  latest_index = (
174
170
  self.get_index_from_subfile_name(existing_subfile_paths[-1].name)
175
171
  if existing_subfile_paths
176
- else -1
172
+ else 0
177
173
  )
178
174
  return latest_index
179
175
 
@@ -222,9 +218,12 @@ class RotatingFile(io.IOBase):
222
218
  [
223
219
  (file_name, self.get_index_from_subfile_name(file_name))
224
220
  for file_name in os.listdir(self.file_path.parent)
225
- if re.match(self.subfile_regex_pattern, file_name)
221
+ if (
222
+ file_name.startswith(self.file_path.name)
223
+ and re.match(self.subfile_regex_pattern, file_name)
224
+ )
226
225
  ],
227
- key = lambda x: x[1],
226
+ key=lambda x: x[1],
228
227
  )
229
228
  return [
230
229
  (self.file_path.parent / file_name)
@@ -8,13 +8,21 @@ Utility functions for working with DataFrames.
8
8
 
9
9
  from __future__ import annotations
10
10
  from datetime import datetime
11
+
12
+ import meerschaum as mrsm
11
13
  from meerschaum.utils.typing import (
12
14
  Optional, Dict, Any, List, Hashable, Generator,
13
- Iterator, Iterable, Union, Tuple,
15
+ Iterator, Iterable, Union, TYPE_CHECKING,
14
16
  )
15
17
 
18
+ if TYPE_CHECKING:
19
+ pd, dask = mrsm.attempt_import('pandas', 'dask')
20
+
16
21
 
17
- def add_missing_cols_to_df(df: 'pd.DataFrame', dtypes: Dict[str, Any]) -> pd.DataFrame:
22
+ def add_missing_cols_to_df(
23
+ df: 'pd.DataFrame',
24
+ dtypes: Dict[str, Any],
25
+ ) -> 'pd.DataFrame':
18
26
  """
19
27
  Add columns from the dtypes dictionary as null columns to a new DataFrame.
20
28
 
@@ -723,7 +731,7 @@ def get_datetime_bound_from_df(
723
731
  df: Union['pd.DataFrame', dict, list],
724
732
  datetime_column: str,
725
733
  minimum: bool = True,
726
- ) -> Union[int, 'datetime.datetime', None]:
734
+ ) -> Union[int, datetime, None]:
727
735
  """
728
736
  Return the minimum or maximum datetime (or integer) from a DataFrame.
729
737
 
@@ -818,7 +826,7 @@ def chunksize_to_npartitions(chunksize: Optional[int]) -> int:
818
826
 
819
827
 
820
828
  def df_from_literal(
821
- pipe: Optional['meerschaum.Pipe'] = None,
829
+ pipe: Optional[mrsm.Pipe] = None,
822
830
  literal: str = None,
823
831
  debug: bool = False
824
832
  ) -> 'pd.DataFrame':
meerschaum/utils/debug.py CHANGED
@@ -93,22 +93,16 @@ def _checkpoint(
93
93
  ) -> None:
94
94
  """If the `_progress` and `_task` objects are provided, increment the task by one step.
95
95
  If `_total` is provided, update the total instead.
96
-
97
- Parameters
98
- ----------
99
- _progress: Optional['rich.progress.Progress'] :
100
- (Default value = None)
101
- _task: Optional[int] :
102
- (Default value = None)
103
- _total: Optional[int] :
104
- (Default value = None)
105
- **kw :
106
-
107
-
108
- Returns
109
- -------
110
-
111
96
  """
112
97
  if _progress is not None and _task is not None:
113
98
  _kw = {'total': _total} if _total is not None else {'advance': 1}
114
99
  _progress.update(_task, **_kw)
100
+
101
+
102
+ def trace(browser: bool = True):
103
+ """
104
+ Open a web-based debugger to trace the execution of the program.
105
+ """
106
+ from meerschaum.utils.packages import attempt_import
107
+ heartrate = attempt_import('heartrate')
108
+ heartrate.trace(files=heartrate.files.all, browser=browser)
@@ -291,16 +291,16 @@ def print_tuple(
291
291
 
292
292
 
293
293
  def print_options(
294
- options: Optional[Dict[str, Any]] = None,
295
- nopretty: bool = False,
296
- no_rich: bool = False,
297
- name: str = 'options',
298
- header: Optional[str] = None,
299
- num_cols: Optional[int] = None,
300
- adjust_cols: bool = True,
301
- sort_options: bool = False,
302
- **kw
303
- ) -> None:
294
+ options: Optional[Dict[str, Any]] = None,
295
+ nopretty: bool = False,
296
+ no_rich: bool = False,
297
+ name: str = 'options',
298
+ header: Optional[str] = None,
299
+ num_cols: Optional[int] = None,
300
+ adjust_cols: bool = True,
301
+ sort_options: bool = False,
302
+ **kw
303
+ ) -> None:
304
304
  """
305
305
  Print items in an iterable as a fancy table.
306
306
 
@@ -342,7 +342,7 @@ def print_options(
342
342
  _options.append(str(o))
343
343
  if sort_options:
344
344
  _options = sorted(_options)
345
- _header = f"Available {name}" if header is None else header
345
+ _header = f"\nAvailable {name}" if header is None else header
346
346
 
347
347
  if num_cols is None:
348
348
  num_cols = 8
@@ -388,7 +388,7 @@ def print_options(
388
388
 
389
389
  if _header is not None:
390
390
  table = Table(
391
- title = ('\n' + _header) if header else header,
391
+ title = _header,
392
392
  box = box.SIMPLE,
393
393
  show_header = False,
394
394
  show_footer = False,
@@ -467,6 +467,7 @@ def fill_ansi(string: str, style: str = '') -> str:
467
467
 
468
468
  return rich_text_to_str(msg)
469
469
 
470
+
470
471
  def __getattr__(name: str) -> str:
471
472
  """
472
473
  Lazily load module-level variables.
meerschaum/utils/misc.py CHANGED
@@ -6,6 +6,7 @@ Miscellaneous functions go here
6
6
  """
7
7
 
8
8
  from __future__ import annotations
9
+ import sys
9
10
  from datetime import timedelta, datetime, timezone
10
11
  from meerschaum.utils.typing import (
11
12
  Union,
@@ -22,8 +23,11 @@ from meerschaum.utils.typing import (
22
23
  Hashable,
23
24
  Generator,
24
25
  Iterator,
26
+ TYPE_CHECKING,
25
27
  )
26
28
  import meerschaum as mrsm
29
+ if TYPE_CHECKING:
30
+ import collections
27
31
 
28
32
  __pdoc__: Dict[str, bool] = {
29
33
  'to_pandas_dtype': False,
@@ -208,6 +212,7 @@ def parse_config_substitution(
208
212
 
209
213
  return leading_key[len(leading_key):][len():-1].split(delimeter)
210
214
 
215
+
211
216
  def edit_file(
212
217
  path: Union[pathlib.Path, str],
213
218
  default_editor: str = 'pyvim',
@@ -233,7 +238,6 @@ def edit_file(
233
238
  Returns
234
239
  -------
235
240
  A bool indicating the file was successfully edited.
236
-
237
241
  """
238
242
  import os
239
243
  from subprocess import call
@@ -254,7 +258,7 @@ def edit_file(
254
258
 
255
259
 
256
260
  def is_pipe_registered(
257
- pipe: 'meerschaum.Pipe',
261
+ pipe: mrsm.Pipe,
258
262
  pipes: PipesDict,
259
263
  debug: bool = False
260
264
  ) -> bool:
@@ -726,25 +730,53 @@ def replace_password(d: Dict[str, Any], replace_with: str = '*') -> Dict[str, An
726
730
  return _d
727
731
 
728
732
 
733
+ def filter_arguments(
734
+ func: Callable[[Any], Any],
735
+ *args: Any,
736
+ **kwargs: Any
737
+ ) -> Tuple[Tuple[Any], Dict[str, Any]]:
738
+ """
739
+ Filter out unsupported positional and keyword arguments.
740
+
741
+ Parameters
742
+ ----------
743
+ func: Callable[[Any], Any]
744
+ The function to inspect.
745
+
746
+ *args: Any
747
+ Positional arguments to filter and pass to `func`.
748
+
749
+ **kwargs
750
+ Keyword arguments to filter and pass to `func`.
751
+
752
+ Returns
753
+ -------
754
+ The `args` and `kwargs` accepted by `func`.
755
+ """
756
+ args = filter_positionals(func, *args)
757
+ kwargs = filter_keywords(func, **kwargs)
758
+ return args, kwargs
759
+
760
+
729
761
  def filter_keywords(
730
- func: Callable[[Any], Any],
731
- **kw: Any
732
- ) -> Dict[str, Any]:
762
+ func: Callable[[Any], Any],
763
+ **kw: Any
764
+ ) -> Dict[str, Any]:
733
765
  """
734
- Filter out unsupported keywords.
766
+ Filter out unsupported keyword arguments.
735
767
 
736
768
  Parameters
737
769
  ----------
738
770
  func: Callable[[Any], Any]
739
771
  The function to inspect.
740
-
772
+
741
773
  **kw: Any
742
774
  The arguments to be filtered and passed into `func`.
743
775
 
744
776
  Returns
745
777
  -------
746
778
  A dictionary of keyword arguments accepted by `func`.
747
-
779
+
748
780
  Examples
749
781
  --------
750
782
  ```python
@@ -766,6 +798,69 @@ def filter_keywords(
766
798
  return {k: v for k, v in kw.items() if k in func_params}
767
799
 
768
800
 
801
+ def filter_positionals(
802
+ func: Callable[[Any], Any],
803
+ *args: Any
804
+ ) -> Tuple[Any]:
805
+ """
806
+ Filter out unsupported positional arguments.
807
+
808
+ Parameters
809
+ ----------
810
+ func: Callable[[Any], Any]
811
+ The function to inspect.
812
+
813
+ *args: Any
814
+ The arguments to be filtered and passed into `func`.
815
+ NOTE: If the function signature expects more arguments than provided,
816
+ the missing slots will be filled with `None`.
817
+
818
+ Returns
819
+ -------
820
+ A tuple of positional arguments accepted by `func`.
821
+
822
+ Examples
823
+ --------
824
+ ```python
825
+ >>> def foo(a, b):
826
+ ... return a * b
827
+ >>> filter_positionals(foo, 2, 4, 6)
828
+ (2, 4)
829
+ >>> foo(*filter_positionals(foo, 2, 4, 6))
830
+ 8
831
+ ```
832
+
833
+ """
834
+ import inspect
835
+ from meerschaum.utils.warnings import warn
836
+ func_params = inspect.signature(func).parameters
837
+ acceptable_args: List[Any] = []
838
+
839
+ def _warn_invalids(_num_invalid):
840
+ if _num_invalid > 0:
841
+ warn(
842
+ "Too few arguments were provided. "
843
+ + f"{_num_invalid} argument"
844
+ + ('s have ' if _num_invalid != 1 else " has ")
845
+ + " been filled with `None`.",
846
+ )
847
+
848
+ num_invalid: int = 0
849
+ for i, (param, val) in enumerate(func_params.items()):
850
+ if '=' in str(val) or '*' in str(val):
851
+ _warn_invalids(num_invalid)
852
+ return tuple(acceptable_args)
853
+
854
+ try:
855
+ acceptable_args.append(args[i])
856
+ except IndexError:
857
+ acceptable_args.append(None)
858
+ num_invalid += 1
859
+
860
+ _warn_invalids(num_invalid)
861
+ return tuple(acceptable_args)
862
+
863
+
769
864
  def dict_from_od(od: collections.OrderedDict) -> Dict[Any, Any]:
770
865
  """
771
866
  Convert an ordered dict to a dict.
@@ -974,10 +1069,11 @@ def async_wrap(func):
974
1069
  def debug_trace(browser: bool = True):
975
1070
  """
976
1071
  Open a web-based debugger to trace the execution of the program.
1072
+
1073
+ This is an alias import for `meerschaum.utils.debug.debug_trace`.
977
1074
  """
978
- from meerschaum.utils.packages import attempt_import
979
- heartrate = attempt_import('heartrate')
980
- heartrate.trace(files=heartrate.files.all, browser=browser)
1075
+ from meerschaum.utils.debug import trace
1076
+ trace(browser=browser)
981
1077
 
982
1078
 
983
1079
  def items_str(
@@ -1554,3 +1650,13 @@ def _get_subaction_names(*args, **kwargs) -> Any:
1554
1650
  """
1555
1651
  from meerschaum.actions import _get_subaction_names as real_function
1556
1652
  return real_function(*args, **kwargs)
1653
+
1654
+
1655
+ _current_module = sys.modules[__name__]
1656
+ __all__ = tuple(
1657
+ name
1658
+ for name, obj in globals().items()
1659
+ if callable(obj)
1660
+ and name not in __pdoc__
1661
+ and getattr(obj, '__module__', None) == _current_module.__name__
1662
+ )
@@ -1849,10 +1849,16 @@ def _get_pip_os_env(color: bool = True):
1849
1849
  Return the environment variables context in which `pip` should be run.
1850
1850
  See PEP 668 for why we are overriding the environment.
1851
1851
  """
1852
- import os
1852
+ import os, sys, platform
1853
+ python_bin_path = pathlib.Path(sys.executable)
1853
1854
  pip_os_env = os.environ.copy()
1855
+ path_str = pip_os_env.get('PATH', '') or ''
1856
+ path_sep = ':' if platform.system() != 'Windows' else ';'
1854
1857
  pip_os_env.update({
1855
1858
  'PIP_BREAK_SYSTEM_PACKAGES': 'true',
1856
1859
  ('FORCE_COLOR' if color else 'NO_COLOR'): '1',
1857
1860
  })
1861
+ if str(python_bin_path) not in path_str:
1862
+ pip_os_env['PATH'] = str(python_bin_path.parent) + path_sep + path_str
1863
+
1858
1864
  return pip_os_env
@@ -14,6 +14,7 @@ try:
14
14
  Hashable,
15
15
  Generator,
16
16
  Iterator,
17
+ TYPE_CHECKING,
17
18
  )
18
19
  except Exception as e:
19
20
  import urllib.request, sys, pathlib, os
@@ -616,7 +616,11 @@ def venv_target_path(
616
616
  return site_packages_path
617
617
 
618
618
  if not inside_venv():
619
- site_path = pathlib.Path(site.getusersitepackages())
619
+ user_site_packages = site.getusersitepackages()
620
+ if user_site_packages is None:
621
+ raise EnvironmentError("Could not determine user site packages.")
622
+
623
+ site_path = pathlib.Path(user_site_packages)
620
624
  if not site_path.exists():
621
625
 
622
626
  ### Windows does not have `os.geteuid()`.
@@ -3,15 +3,23 @@
3
3
  # vim:fenc=utf-8
4
4
 
5
5
  """
6
- Handle all things warnings and errors here
6
+ Handle all things warnings and errors.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
10
  from meerschaum.utils.typing import Any, Union
11
+ from meerschaum.utils.debug import dprint
11
12
 
12
13
  import sys
13
14
  import warnings
14
15
 
16
+ __all__ = (
17
+ 'warn',
18
+ 'info',
19
+ 'error',
20
+ 'dprint',
21
+ )
22
+
15
23
  warnings.filterwarnings(
16
24
  "always",
17
25
  category = UserWarning
meerschaum/utils/yaml.py CHANGED
@@ -10,7 +10,7 @@ This is so switching between PyYAML and ruamel.yaml is smoother.
10
10
 
11
11
  from meerschaum.utils.misc import filter_keywords
12
12
  from meerschaum.utils.packages import attempt_import, all_packages, _import_module
13
- from meerschaum.utils.warnings import error, warn
13
+ from meerschaum.utils.warnings import error
14
14
  from meerschaum.utils.threading import Lock
15
15
 
16
16
  _lib = None
@@ -49,7 +49,7 @@ class yaml:
49
49
  """
50
50
  global _yaml, _lib, _dumper
51
51
  if _import_name is None:
52
- error(f"No YAML library declared.")
52
+ error("No YAML library declared.")
53
53
  with _locks['_lib']:
54
54
  try:
55
55
  _lib = _import_module(_import_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.2.5.dev2
3
+ Version: 2.2.6
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares