meerschaum 2.9.5__py3-none-any.whl → 3.0.0rc1__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 (153) hide show
  1. meerschaum/__init__.py +5 -2
  2. meerschaum/_internal/__init__.py +1 -0
  3. meerschaum/_internal/arguments/_parse_arguments.py +4 -4
  4. meerschaum/_internal/arguments/_parser.py +17 -1
  5. meerschaum/_internal/entry.py +6 -6
  6. meerschaum/_internal/shell/Shell.py +1 -1
  7. meerschaum/_internal/static.py +372 -0
  8. meerschaum/actions/api.py +12 -2
  9. meerschaum/actions/bootstrap.py +7 -7
  10. meerschaum/actions/edit.py +142 -18
  11. meerschaum/actions/register.py +137 -6
  12. meerschaum/actions/show.py +117 -29
  13. meerschaum/actions/stop.py +4 -1
  14. meerschaum/actions/sync.py +1 -1
  15. meerschaum/actions/tag.py +9 -8
  16. meerschaum/api/__init__.py +9 -2
  17. meerschaum/api/_events.py +39 -2
  18. meerschaum/api/_oauth2.py +118 -8
  19. meerschaum/api/_tokens.py +102 -0
  20. meerschaum/api/dash/__init__.py +0 -1
  21. meerschaum/api/dash/callbacks/custom.py +2 -2
  22. meerschaum/api/dash/callbacks/dashboard.py +102 -18
  23. meerschaum/api/dash/callbacks/plugins.py +0 -1
  24. meerschaum/api/dash/callbacks/register.py +1 -1
  25. meerschaum/api/dash/callbacks/settings/__init__.py +1 -0
  26. meerschaum/api/dash/callbacks/settings/password_reset.py +2 -2
  27. meerschaum/api/dash/callbacks/settings/tokens.py +388 -0
  28. meerschaum/api/dash/components.py +30 -8
  29. meerschaum/api/dash/keys.py +19 -93
  30. meerschaum/api/dash/pages/dashboard.py +1 -20
  31. meerschaum/api/dash/pages/settings/__init__.py +1 -0
  32. meerschaum/api/dash/pages/settings/password_reset.py +1 -1
  33. meerschaum/api/dash/pages/settings/tokens.py +55 -0
  34. meerschaum/api/dash/pipes.py +94 -59
  35. meerschaum/api/dash/sessions.py +12 -0
  36. meerschaum/api/dash/tokens.py +606 -0
  37. meerschaum/api/dash/websockets.py +1 -1
  38. meerschaum/api/dash/webterm.py +4 -0
  39. meerschaum/api/models/__init__.py +23 -3
  40. meerschaum/api/models/_actions.py +22 -0
  41. meerschaum/api/models/_pipes.py +85 -7
  42. meerschaum/api/models/_tokens.py +81 -0
  43. meerschaum/api/resources/templates/termpage.html +12 -0
  44. meerschaum/api/routes/__init__.py +1 -0
  45. meerschaum/api/routes/_actions.py +3 -4
  46. meerschaum/api/routes/_connectors.py +3 -7
  47. meerschaum/api/routes/_jobs.py +14 -35
  48. meerschaum/api/routes/_login.py +49 -12
  49. meerschaum/api/routes/_misc.py +5 -10
  50. meerschaum/api/routes/_pipes.py +134 -111
  51. meerschaum/api/routes/_plugins.py +38 -28
  52. meerschaum/api/routes/_tokens.py +236 -0
  53. meerschaum/api/routes/_users.py +47 -35
  54. meerschaum/api/routes/_version.py +3 -3
  55. meerschaum/config/__init__.py +43 -20
  56. meerschaum/config/_default.py +32 -5
  57. meerschaum/config/_edit.py +28 -24
  58. meerschaum/config/_environment.py +1 -1
  59. meerschaum/config/_patch.py +6 -6
  60. meerschaum/config/_paths.py +5 -1
  61. meerschaum/config/_read_config.py +65 -34
  62. meerschaum/config/_sync.py +6 -3
  63. meerschaum/config/_version.py +1 -1
  64. meerschaum/config/stack/__init__.py +24 -5
  65. meerschaum/config/static.py +18 -0
  66. meerschaum/connectors/_Connector.py +10 -4
  67. meerschaum/connectors/__init__.py +4 -20
  68. meerschaum/connectors/api/_APIConnector.py +34 -6
  69. meerschaum/connectors/api/_actions.py +2 -2
  70. meerschaum/connectors/api/_jobs.py +1 -1
  71. meerschaum/connectors/api/_login.py +33 -7
  72. meerschaum/connectors/api/_misc.py +2 -2
  73. meerschaum/connectors/api/_pipes.py +15 -14
  74. meerschaum/connectors/api/_plugins.py +2 -2
  75. meerschaum/connectors/api/_request.py +1 -1
  76. meerschaum/connectors/api/_tokens.py +146 -0
  77. meerschaum/connectors/api/_users.py +70 -58
  78. meerschaum/connectors/instance/_InstanceConnector.py +83 -0
  79. meerschaum/connectors/instance/__init__.py +10 -0
  80. meerschaum/connectors/instance/_pipes.py +442 -0
  81. meerschaum/connectors/instance/_plugins.py +151 -0
  82. meerschaum/connectors/instance/_tokens.py +296 -0
  83. meerschaum/connectors/instance/_users.py +181 -0
  84. meerschaum/connectors/parse.py +4 -1
  85. meerschaum/connectors/sql/_SQLConnector.py +8 -5
  86. meerschaum/connectors/sql/_cli.py +12 -11
  87. meerschaum/connectors/sql/_create_engine.py +6 -154
  88. meerschaum/connectors/sql/_fetch.py +2 -18
  89. meerschaum/connectors/sql/_pipes.py +42 -31
  90. meerschaum/connectors/sql/_plugins.py +29 -0
  91. meerschaum/connectors/sql/_sql.py +8 -1
  92. meerschaum/connectors/sql/_users.py +29 -2
  93. meerschaum/connectors/sql/tables/__init__.py +1 -1
  94. meerschaum/connectors/valkey/_ValkeyConnector.py +2 -4
  95. meerschaum/connectors/valkey/_pipes.py +9 -10
  96. meerschaum/connectors/valkey/_plugins.py +2 -26
  97. meerschaum/core/Pipe/__init__.py +31 -14
  98. meerschaum/core/Pipe/_attributes.py +156 -58
  99. meerschaum/core/Pipe/_bootstrap.py +54 -24
  100. meerschaum/core/Pipe/_data.py +41 -1
  101. meerschaum/core/Pipe/_dtypes.py +29 -14
  102. meerschaum/core/Pipe/_edit.py +12 -4
  103. meerschaum/core/Pipe/_show.py +5 -5
  104. meerschaum/core/Pipe/_sync.py +48 -53
  105. meerschaum/core/Pipe/_verify.py +1 -1
  106. meerschaum/{plugins → core/Plugin}/_Plugin.py +9 -11
  107. meerschaum/core/Plugin/__init__.py +1 -1
  108. meerschaum/core/Token/_Token.py +221 -0
  109. meerschaum/core/Token/__init__.py +12 -0
  110. meerschaum/core/User/_User.py +34 -8
  111. meerschaum/core/User/__init__.py +9 -1
  112. meerschaum/core/__init__.py +1 -0
  113. meerschaum/jobs/_Job.py +3 -2
  114. meerschaum/jobs/__init__.py +3 -2
  115. meerschaum/jobs/systemd.py +1 -1
  116. meerschaum/models/__init__.py +35 -0
  117. meerschaum/models/pipes.py +247 -0
  118. meerschaum/models/tokens.py +38 -0
  119. meerschaum/models/users.py +26 -0
  120. meerschaum/plugins/__init__.py +22 -7
  121. meerschaum/plugins/bootstrap.py +2 -1
  122. meerschaum/utils/_get_pipes.py +68 -27
  123. meerschaum/utils/daemon/Daemon.py +2 -1
  124. meerschaum/utils/daemon/__init__.py +30 -2
  125. meerschaum/utils/dataframe.py +95 -14
  126. meerschaum/utils/dtypes/__init__.py +91 -18
  127. meerschaum/utils/dtypes/sql.py +44 -0
  128. meerschaum/utils/formatting/__init__.py +1 -1
  129. meerschaum/utils/formatting/_pipes.py +5 -4
  130. meerschaum/utils/formatting/_shell.py +11 -9
  131. meerschaum/utils/misc.py +237 -80
  132. meerschaum/utils/packages/__init__.py +3 -6
  133. meerschaum/utils/packages/_packages.py +34 -32
  134. meerschaum/utils/pipes.py +181 -0
  135. meerschaum/utils/process.py +1 -1
  136. meerschaum/utils/prompt.py +3 -1
  137. meerschaum/utils/schedule.py +1 -0
  138. meerschaum/utils/sql.py +114 -37
  139. meerschaum/utils/typing.py +1 -4
  140. meerschaum/utils/venv/_Venv.py +2 -2
  141. meerschaum/utils/venv/__init__.py +5 -7
  142. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/METADATA +88 -80
  143. meerschaum-3.0.0rc1.dist-info/RECORD +282 -0
  144. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/WHEEL +1 -1
  145. meerschaum/api/models/_interfaces.py +0 -15
  146. meerschaum/api/models/_locations.py +0 -15
  147. meerschaum/api/models/_metrics.py +0 -15
  148. meerschaum/config/static/__init__.py +0 -186
  149. meerschaum-2.9.5.dist-info/RECORD +0 -263
  150. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/entry_points.txt +0 -0
  151. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/licenses/LICENSE +0 -0
  152. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/top_level.txt +0 -0
  153. {meerschaum-2.9.5.dist-info → meerschaum-3.0.0rc1.dist-info}/zip-safe +0 -0
@@ -0,0 +1,221 @@
1
+ #! /usr/bin/env python3
2
+ # vim:fenc=utf-8
3
+
4
+ """
5
+ Define the properties of a long-lived access token.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import base64
11
+ import uuid
12
+ from random import randint
13
+ from typing import Optional, Union, List, Tuple
14
+ from datetime import datetime, timedelta, timezone
15
+
16
+ import meerschaum as mrsm
17
+ from meerschaum.models import TokenModel
18
+
19
+ _PLACEHOLDER_EXPIRATION = datetime(2000, 1, 1)
20
+
21
+ class Token:
22
+ """
23
+ Tokens (long lived access tokens) may be registered and revoked to provide easier authentication (e.g. IoT devices).
24
+ Tokens must be tied to a Meerschaum user account.
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ label: Optional[str] = None,
30
+ creation: Optional[datetime] = None,
31
+ expiration: Optional[datetime] = _PLACEHOLDER_EXPIRATION,
32
+ instance: Optional[str] = None,
33
+ user: Optional[mrsm.core.User] = None,
34
+ user_id: Union[int, str, uuid.UUID, None] = None,
35
+ scopes: Optional[List[str]] = None,
36
+ is_valid: bool = True,
37
+ id: Optional[uuid.UUID] = None,
38
+ secret: Optional[str] = None,
39
+ secret_hash: Optional[str] = None,
40
+ ):
41
+ from meerschaum.utils.dtypes import coerce_timezone
42
+ from meerschaum.utils.daemon import get_new_daemon_name
43
+ from meerschaum.utils.misc import round_time
44
+ from meerschaum._internal.static import STATIC_CONFIG
45
+ now = datetime.now(timezone.utc)
46
+ default_expiration_days = mrsm.get_config(
47
+ 'system', 'api', 'tokens', 'default_expiration_days',
48
+ ) or 366
49
+ default_expiration = round_time(
50
+ now + timedelta(days=default_expiration_days),
51
+ timedelta(days=1),
52
+ )
53
+ if expiration == _PLACEHOLDER_EXPIRATION:
54
+ expiration = default_expiration
55
+ self.creation = coerce_timezone(creation) if creation is not None else None
56
+ self.expiration = coerce_timezone(expiration) if expiration is not None else None
57
+ self._instance_keys = str(instance) if instance is not None else None
58
+ self.label = label or get_new_daemon_name()
59
+ self._user = user
60
+ self._user_id = user_id
61
+ self.scopes = scopes or list(STATIC_CONFIG['tokens']['scopes'])
62
+ self.is_valid = is_valid
63
+ self.id = id
64
+ self.secret = secret
65
+ self.secret_hash = secret_hash
66
+
67
+ def generate_credentials(self) -> Tuple[uuid.UUID, str]:
68
+ """
69
+ Generate and return the client ID and secret values for this token.
70
+ """
71
+ if self.id and self.secret:
72
+ return self.id, self.secret
73
+
74
+ from meerschaum.utils.misc import generate_password
75
+ from meerschaum._internal.static import STATIC_CONFIG
76
+ min_len = STATIC_CONFIG['tokens']['minimum_length']
77
+ max_len = STATIC_CONFIG['tokens']['maximum_length']
78
+
79
+ secret_len = randint(min_len, max_len + 1)
80
+ self.secret = generate_password(secret_len)
81
+ self.id = uuid.uuid4()
82
+ return self.id, self.secret
83
+
84
+ def get_api_key(self) -> str:
85
+ """
86
+ Return the API key to be sent in the `Authorization` header.
87
+ """
88
+ return 'mrsm-key:' + base64.b64encode(f"{self.id}:{self.secret}".encode('utf-8')).decode('utf-8')
89
+
90
+ @property
91
+ def instance_connector(self) -> mrsm.connectors.InstanceConnector:
92
+ """
93
+ Return the instance connector to use for this token.
94
+ """
95
+ from meerschaum.connectors.parse import parse_instance_keys
96
+ return parse_instance_keys(self._instance_keys)
97
+
98
+ @property
99
+ def user(self) -> Union[mrsm.core.User, None]:
100
+ """
101
+ Return the `User` for this token.
102
+ """
103
+ if self._user is not None:
104
+ return self._user
105
+
106
+ if self._user_id is not None:
107
+ username = self.instance_connector.get_username(self._user_id)
108
+ if not username:
109
+ return None
110
+ _user = mrsm.core.User(
111
+ username,
112
+ user_id=self._user_id,
113
+ instance=str(self.instance_connector),
114
+ )
115
+ self._user = _user
116
+ return _user
117
+
118
+ return None
119
+
120
+ def register(self, debug: bool = False) -> mrsm.SuccessTuple:
121
+ """
122
+ Register the new token to the configured instance.
123
+ """
124
+ if self.user is None:
125
+ raise ValueError("Cannot register a token with a user.")
126
+
127
+ return self.instance_connector.register_token(self, debug=debug)
128
+
129
+ def edit(self, debug: bool = False) -> mrsm.SuccessTuple:
130
+ """
131
+ Edit some of the token's attributes (expiration, scopes).
132
+ """
133
+ return self.instance_connector.edit_token(self, debug=debug)
134
+
135
+ def invalidate(self, debug: bool = False) -> mrsm.SuccessTuple:
136
+ """
137
+ Set `is_valid` to False for this token.
138
+ """
139
+ self.is_valid = False
140
+ return self.instance_connector.invalidate_token(self, debug=debug)
141
+
142
+ def delete(self, debug: bool = False) -> mrsm.SuccessTuple:
143
+ """
144
+ Delete this token from the instance connector.
145
+ """
146
+ return self.instance_connector.delete_token(self, debug=debug)
147
+
148
+ def exists(self, debug: bool = False) -> bool:
149
+ """
150
+ Return `True` if a token's ID exists in the tokens pipe.
151
+ """
152
+ if not self.id:
153
+ return False
154
+ return self.instance_connector.token_exists(self.id, debug=debug)
155
+
156
+ def to_model(self, refresh: bool = False, debug: bool = False) -> TokenModel:
157
+ """
158
+ Export the current state to a `TokenModel`.
159
+ """
160
+ in_memory_doc = {
161
+ 'id': self.id,
162
+ 'label': self.label,
163
+ 'creation': self.creation,
164
+ 'expiration': self.expiration,
165
+ 'is_valid': self.is_valid,
166
+ 'user_id': self._user_id,
167
+ 'scopes': self.scopes,
168
+ }
169
+ if not refresh:
170
+ return TokenModel(**in_memory_doc)
171
+
172
+ if not self.id:
173
+ raise ValueError(f"ID is not set for {self}.")
174
+
175
+ token_model = self.instance_connector.get_token_model(self.id, debug=debug)
176
+ if token_model is None:
177
+ raise ValueError(f"{self} does not exist on instance '{self.instance_connector}'.")
178
+
179
+ return token_model
180
+
181
+ def get_scopes(self, refresh: bool = False, debug: bool = False) -> List[str]:
182
+ """
183
+ Return the scopes for this `Token`.
184
+ """
185
+ if not refresh:
186
+ return self.scopes
187
+
188
+ self.scopes = self.instance_connector.get_token_scopes(self, debug=debug)
189
+ return self.scopes
190
+
191
+ def get_expiration_status(self, debug: bool = False) -> bool:
192
+ """
193
+ Check the token's expiration against the current timestamp.
194
+ If it's expired, invalidate the token.
195
+
196
+ Returns
197
+ -------
198
+ A bool to indication whether the token has expired.
199
+ A value of `True` means the token is invalid,
200
+ and `False` indicates a valid token.
201
+ """
202
+ expiration = self.expiration
203
+ if expiration is None:
204
+ return False
205
+
206
+ now = datetime.now(timezone.utc)
207
+ is_expired = expiration <= now
208
+ if is_expired:
209
+ self.is_valid = False
210
+ invalidate_success, invalidate_msg = self.invalidate(debug=debug)
211
+ if not invalidate_success:
212
+ from meerschaum.utils.warnings import warn
213
+ warn(f"Failed to invalidate {self}:\n{invalidate_msg}")
214
+
215
+ return is_expired
216
+
217
+ def __str__(self):
218
+ return self.label
219
+
220
+ def __repr__(self):
221
+ return self.to_model(refresh=False).__repr__().replace('TokenModel(', 'Token(')
@@ -0,0 +1,12 @@
1
+ #! /usr/bin/env python3
2
+ # vim:fenc=utf-8
3
+
4
+ """
5
+ Define the components of long-lived access tokens.
6
+ """
7
+
8
+ from meerschaum.core.Token._Token import Token
9
+
10
+ __all__ = (
11
+ 'Token',
12
+ )
@@ -7,14 +7,15 @@ User class definition
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
+
10
11
  import os
11
12
  import hashlib
12
13
  import hmac
14
+ import uuid
13
15
  from binascii import b2a_base64, a2b_base64, Error as _BinAsciiError
14
16
 
15
17
  import meerschaum as mrsm
16
- from meerschaum.utils.typing import Optional, Dict, Any, Union
17
- from meerschaum.config.static import STATIC_CONFIG
18
+ from meerschaum.utils.typing import Optional, Dict, Any, Union, List
18
19
  from meerschaum.utils.warnings import warn
19
20
 
20
21
 
@@ -40,7 +41,7 @@ def hash_password(
40
41
 
41
42
  rounds: Optional[int], default None
42
43
  If provided, use this number of rounds to generate the hash.
43
- Defaults to 3,000,000.
44
+ Defaults to 1,000,000.
44
45
 
45
46
  Returns
46
47
  -------
@@ -48,6 +49,7 @@ def hash_password(
48
49
  See the `passlib` documentation on the string format:
49
50
  https://passlib.readthedocs.io/en/stable/lib/passlib.hash.pbkdf2_digest.html#format-algorithm
50
51
  """
52
+ from meerschaum._internal.static import STATIC_CONFIG
51
53
  hash_config = STATIC_CONFIG['users']['password_hash']
52
54
  if password is None:
53
55
  password = ''
@@ -64,7 +66,7 @@ def hash_password(
64
66
  )
65
67
  return (
66
68
  f"$pbkdf2-{hash_config['algorithm_name']}"
67
- + f"${hash_config['pbkdf2_sha256__default_rounds']}"
69
+ + f"${rounds}"
68
70
  + '$' + ab64_encode(salt).decode('utf-8')
69
71
  + '$' + ab64_encode(pw_hash).decode('utf-8')
70
72
  )
@@ -89,6 +91,7 @@ def verify_password(
89
91
  -------
90
92
  A `bool` indicating whether `password` matches `password_hash`.
91
93
  """
94
+ from meerschaum._internal.static import STATIC_CONFIG
92
95
  if password is None or password_hash is None:
93
96
  return False
94
97
  hash_config = STATIC_CONFIG['users']['password_hash']
@@ -177,7 +180,7 @@ class User:
177
180
  type: Optional[str] = None,
178
181
  email: Optional[str] = None,
179
182
  attributes: Optional[Dict[str, Any]] = None,
180
- user_id: Optional[int] = None,
183
+ user_id: Union[int, str, uuid.UUID, None] = None,
181
184
  instance: Optional[str] = None
182
185
  ):
183
186
  if password is None:
@@ -188,7 +191,7 @@ class User:
188
191
  self.type = type
189
192
  self._attributes = attributes
190
193
  self._user_id = user_id
191
- self._instance_keys = str(instance)
194
+ self._instance_keys = str(instance) if instance is not None else None
192
195
 
193
196
  def __repr__(self):
194
197
  return str(self)
@@ -203,14 +206,14 @@ class User:
203
206
  return self._attributes
204
207
 
205
208
  @property
206
- def instance_connector(self) -> 'mrsm.connectors.Connector':
209
+ def instance_connector(self) -> mrsm.connectors.InstanceConnector:
207
210
  from meerschaum.connectors.parse import parse_instance_keys
208
211
  if '_instance_connector' not in self.__dict__:
209
212
  self._instance_connector = parse_instance_keys(self._instance_keys)
210
213
  return self._instance_connector
211
214
 
212
215
  @property
213
- def user_id(self) -> Union[int, str, None]:
216
+ def user_id(self) -> Union[int, str, uuid.UUID, None]:
214
217
  """NOTE: This causes recursion with the API,
215
218
  so don't try to get fancy with read-only attributes.
216
219
  """
@@ -231,3 +234,26 @@ class User:
231
234
 
232
235
  self._password_hash = hash_password(self.password)
233
236
  return self._password_hash
237
+
238
+ def get_attributes(self, refresh: bool = False, debug: bool = False) -> Dict[str, Any]:
239
+ """
240
+ Return the user's attributes.
241
+ """
242
+ if not refresh:
243
+ return self.attributes
244
+ self._attributes = self.instance_connector.get_user_attributes(self, debug=debug) or {}
245
+ return self._attributes
246
+
247
+ def get_scopes(self, refresh: bool = False, debug: bool = False) -> List[str]:
248
+ """
249
+ Return the scopes for this user.
250
+ """
251
+ from meerschaum._internal.static import STATIC_CONFIG
252
+ _attributes = self.get_attributes(refresh=refresh, debug=debug)
253
+ return _attributes.get('scopes', None) or list(STATIC_CONFIG['tokens']['scopes'])
254
+
255
+ def register(self, debug: bool = False, **kwargs: Any) -> mrsm.SuccessTuple:
256
+ """
257
+ Register a user to the instance connector.
258
+ """
259
+ return self.instance_connector.register_user(self, debug=debug, **kwargs)
@@ -9,7 +9,15 @@ Manager users' metadata via the User class
9
9
  from typing import Optional
10
10
 
11
11
  import meerschaum as mrsm
12
- from meerschaum.core.User._User import User
12
+ from meerschaum.core.User._User import User, hash_password, verify_password
13
+
14
+
15
+ __all__ = (
16
+ 'User',
17
+ 'hash_password',
18
+ 'verify_password',
19
+ 'is_user_allowed_to_execute',
20
+ )
13
21
 
14
22
 
15
23
  def is_user_allowed_to_execute(
@@ -9,3 +9,4 @@ Import the core class definitions into the parent module.
9
9
  from meerschaum.core.Pipe import Pipe
10
10
  from meerschaum.core.Plugin import Plugin
11
11
  from meerschaum.core.User import User
12
+ from meerschaum.core.Token import Token
meerschaum/jobs/_Job.py CHANGED
@@ -24,7 +24,7 @@ from meerschaum._internal.entry import entry
24
24
  from meerschaum.utils.warnings import warn
25
25
  from meerschaum.config.paths import LOGS_RESOURCES_PATH
26
26
  from meerschaum.config import get_config
27
- from meerschaum.config.static import STATIC_CONFIG
27
+ from meerschaum._internal.static import STATIC_CONFIG
28
28
 
29
29
  if TYPE_CHECKING:
30
30
  from meerschaum.jobs._Executor import Executor
@@ -702,7 +702,8 @@ class Job:
702
702
 
703
703
  _result = self.daemon.properties.get('result', None)
704
704
  if _result is None:
705
- return False, "No result available."
705
+ from meerschaum.utils.daemon.Daemon import _results
706
+ return _results.get(self.daemon.daemon_id, (False, "No result available."))
706
707
 
707
708
  return tuple(_result)
708
709
 
@@ -79,7 +79,8 @@ def get_jobs(
79
79
  }
80
80
 
81
81
  def _get_systemd_jobs():
82
- conn = mrsm.get_connector('systemd')
82
+ from meerschaum.jobs.systemd import SystemdExecutor
83
+ conn = SystemdExecutor('systemd')
83
84
  jobs = conn.get_jobs(debug=debug)
84
85
  return {
85
86
  name: job
@@ -369,7 +370,7 @@ def start_check_jobs_thread():
369
370
  import atexit
370
371
  from functools import partial
371
372
  from meerschaum.utils.threading import RepeatTimer
372
- from meerschaum.config.static import STATIC_CONFIG
373
+ from meerschaum._internal.static import STATIC_CONFIG
373
374
 
374
375
  global _check_loop_stop_thread
375
376
  sleep_seconds = STATIC_CONFIG['jobs']['check_restart_seconds']
@@ -21,7 +21,7 @@ import meerschaum as mrsm
21
21
  from meerschaum.jobs import Job, Executor, make_executor
22
22
  from meerschaum.utils.typing import Dict, Any, List, SuccessTuple, Union, Optional, Callable
23
23
  from meerschaum.config import get_config
24
- from meerschaum.config.static import STATIC_CONFIG
24
+ from meerschaum._internal.static import STATIC_CONFIG
25
25
  from meerschaum.utils.warnings import warn, dprint
26
26
  from meerschaum._internal.arguments._parse_arguments import parse_arguments
27
27
 
@@ -0,0 +1,35 @@
1
+ #! /usr/bin/env python3
2
+ # vim:fenc=utf-8
3
+
4
+ """
5
+ Define fundamental Pydantic models (to be built upon for API response models).
6
+ """
7
+
8
+ import meerschaum as mrsm
9
+
10
+ annotated_types = mrsm.attempt_import('annotated_types', lazy=False)
11
+ pydantic = mrsm.attempt_import('pydantic', lazy=False)
12
+
13
+ from meerschaum.models.pipes import (
14
+ PipeModel,
15
+ PipeWithParametersModel,
16
+ PipesWithParametersDictModel,
17
+ ConnectorKeysModel,
18
+ MetricKeyModel,
19
+ LocationKeyModel,
20
+ InstanceKeysModel,
21
+ )
22
+ from meerschaum.models.users import UserModel
23
+ from meerschaum.models.tokens import TokenModel
24
+
25
+ __all__ = (
26
+ 'PipeModel',
27
+ 'PipeWithParametersModel',
28
+ 'PipesWithParametersDictModel',
29
+ 'ConnectorKeysModel',
30
+ 'MetricKeyModel',
31
+ 'LocationKeyModel',
32
+ 'InstanceKeysModel',
33
+ 'UserModel',
34
+ 'TokenModel',
35
+ )