meerschaum.connectors.api
Interact with the Meerschaum API (send commands, pull data, etc.)
23class APIConnector(InstanceConnector): 24 """ 25 Connect to a Meerschaum API instance. 26 27 The requests are made by the Rust client (`meerschaum._core.ApiConnector`, one per connector 28 and process): the same routes, query parameters and bodies as v4. Nothing here imports 29 `requests` or `httpx`. 30 """ 31 32 IS_THREAD_SAFE: bool = False 33 OPTIONAL_ATTRIBUTES: List[str] = ['port', 'client_secret', 'client_id', 'api_key'] 34 35 from ._request import ( 36 make_request, 37 get, 38 post, 39 put, 40 patch, 41 delete, 42 wget, 43 ) 44 from ._actions import ( 45 get_actions, 46 do_action, 47 do_action_async, 48 do_action_legacy, 49 ) 50 from ._misc import get_mrsm_version, get_chaining_status 51 from ._metrics import get_engine_metrics, initialize_engine_metrics 52 from ._pipes import ( 53 get_pipe_instance_keys, 54 register_pipe, 55 fetch_pipes_keys, 56 edit_pipe, 57 sync_pipe, 58 delete_pipe, 59 delete_pipe_cache, 60 get_pipe_data, 61 get_pipe_id, 62 get_pipe_attributes, 63 get_sync_time, 64 pipe_exists, 65 create_metadata, 66 get_pipe_rowcount, 67 drop_pipe, 68 clear_pipe, 69 get_pipe_columns_types, 70 get_pipe_columns_indices, 71 get_pipe_index_names, 72 get_pipe_docs, 73 get_pipe_size, 74 compress_pipe, 75 decompress_pipe, 76 vacuum_pipe, 77 analyze_pipe, 78 partition_pipe, 79 ) 80 from ._fetch import fetch 81 from ._plugins import ( 82 register_plugin, 83 install_plugin, 84 delete_plugin, 85 get_plugins, 86 get_plugin_attributes, 87 get_plugin_version, 88 ) 89 from ._login import login, test_connection 90 from ._users import ( 91 register_user, 92 get_user_id, 93 get_users, 94 edit_user, 95 delete_user, 96 get_user_password_hash, 97 get_user_type, 98 get_user_attributes, 99 ) 100 from ._tokens import ( 101 register_token, 102 get_token_model, 103 get_tokens, 104 edit_token, 105 invalidate_token, 106 get_token_scopes, 107 token_exists, 108 delete_token, 109 ) 110 from ._uri import from_uri 111 from ._jobs import ( 112 get_jobs, 113 get_job, 114 get_job_metadata, 115 get_job_properties, 116 get_job_exists, 117 delete_job, 118 start_job, 119 create_job, 120 stop_job, 121 pause_job, 122 get_logs, 123 get_job_stop_time, 124 monitor_logs, 125 monitor_logs_async, 126 get_job_is_blocking_on_stdin, 127 get_job_prompt_kwargs, 128 get_job_began, 129 get_job_ended, 130 get_job_paused, 131 get_job_status, 132 ) 133 ### The access model (rc15): teams, permissions, access and locks are the server's. The 134 ### `InstanceConnector` methods reach its routes through the Rust client; these answer in 135 ### one request. 136 from ._access import ( 137 get_team_pipes_count, 138 get_team_jobs_count, 139 get_users_permissions, 140 get_user_permissions_record, 141 get_pipe_access, 142 ) 143 144 def __init__( 145 self, 146 label: Optional[str] = None, 147 wait: bool = False, 148 debug: bool = False, 149 **kw 150 ): 151 if 'uri' in kw: 152 from_uri_params = self.from_uri(kw['uri'], as_dict=True) 153 label = label or from_uri_params.get('label', None) 154 _ = from_uri_params.pop('label', None) 155 kw.update(from_uri_params) 156 157 super().__init__('api', label=label, **kw) 158 if 'protocol' not in self.__dict__: 159 self.protocol = ( 160 'https' if self.__dict__.get('uri', '').startswith('https') 161 else 'http' 162 ) 163 164 if 'uri' not in self.__dict__: 165 self.verify_attributes(required_attributes) 166 else: 167 conn_attrs = self.from_uri(self.__dict__['uri'], as_dict=True) 168 self.__dict__.update({ 169 key: val 170 for key, val in conn_attrs.items() 171 if key not in ('label', 'protocol') 172 }) 173 174 self.url = ( 175 self.protocol + '://' + 176 self.host 177 + ( 178 (':' + str(self.port)) 179 if self.__dict__.get('port', None) 180 else '' 181 ) 182 ) 183 self._rust_client_obj = None 184 self._instance_keys = self.__dict__.get('instance_keys', None) 185 186 def _rust_client(self): 187 """ 188 Return the `meerschaum._core.ApiConnector` of this connector (built once per process: 189 a forked child builds its own, which holds its own HTTP connections and token). 190 """ 191 import os 192 attributes = { 193 key: value 194 for key, value in self.__dict__.items() 195 if not str(key).startswith('_') 196 and isinstance(value, (str, int, float, bool)) 197 } 198 client = self.__dict__.get('_rust_client_obj', None) 199 if ( 200 client is not None 201 and self.__dict__.get('_rust_client_pid', None) == os.getpid() 202 and self.__dict__.get('_rust_client_attributes', None) == attributes 203 ): 204 return client 205 206 ### A new process, or credentials / address changed (`conn.password = ...`): build a client 207 ### with the current attributes (it logs in again; the native flows find it by them). 208 from meerschaum import _core 209 client = _core.ApiConnector(self.label, attributes) 210 self.__dict__['_rust_client_obj'] = client 211 self.__dict__['_rust_client_pid'] = os.getpid() 212 self.__dict__['_rust_client_attributes'] = attributes 213 return client 214 215 def __getstate__(self): 216 state = self.__dict__.copy() 217 for key in ('_rust_client_obj', '_rust_client_pid', '_rust_client_attributes', '_session'): 218 state.pop(key, None) 219 state['_rust_client_obj'] = None 220 return state 221 222 def __setstate__(self, state): 223 self.__dict__.update(state) 224 225 @property 226 def URI(self) -> str: 227 """ 228 Return the fully qualified URI. 229 """ 230 return self._rust_client().uri 231 232 @property 233 def session(self): 234 """ 235 A `requests.Session` (not used by the connector, which makes its requests in Rust). 236 It exists for plugins which still reach for it and needs `requests` installed. 237 """ 238 if self.__dict__.get('_session', None) is None: 239 from meerschaum.utils.packages import attempt_import 240 requests = attempt_import('requests', lazy=False) 241 if requests is None: 242 raise ImportError("Failed to import requests. Is requests installed?") 243 self._session = requests.Session() 244 return self._session 245 246 @property 247 def token(self): 248 """ 249 Return the API key, or the session token (logging in when it is missing or expiring). 250 """ 251 return self._rust_client().token 252 253 @property 254 def _token(self) -> Union[str, None]: 255 """ 256 The stored session token (v4's attribute): `None` before a login, and it never logs in. 257 Assign `None` to force a new login. 258 """ 259 return self._rust_client().stored_token 260 261 @_token.setter 262 def _token(self, value: Union[str, None]) -> None: 263 self._rust_client().stored_token = value 264 265 @property 266 def _expires(self): 267 """ 268 When the stored session token expires (v4's attribute, a naive `datetime`), or `None`. 269 """ 270 import datetime 271 value = self._rust_client().stored_expires 272 return None if value is None else datetime.datetime.fromisoformat(value) 273 274 @_expires.setter 275 def _expires(self, value) -> None: 276 import datetime 277 if value is not None: 278 if isinstance(value, str): 279 value = datetime.datetime.fromisoformat(value) 280 if not isinstance(value, datetime.datetime): 281 raise TypeError( 282 f"`_expires` must be a datetime, an ISO string or None, not {type(value).__name__}." 283 ) 284 ### Stored as naive UTC, like v4's: an aware value is converted, not just stripped. 285 if value.tzinfo is not None: 286 value = value.astimezone(datetime.timezone.utc).replace(tzinfo=None) 287 value = value.isoformat() 288 self._rust_client().stored_expires = value 289 290 @property 291 def instance_keys(self) -> Union[str, None]: 292 """ 293 Return the instance keys to be sent alongside pipe requests. 294 """ 295 return self._instance_keys 296 297 @property 298 def login_scheme(self) -> str: 299 """ 300 Return the login scheme to use based on the configured credentials. 301 """ 302 return self._rust_client().login_scheme
Connect to a Meerschaum API instance.
The requests are made by the Rust client (meerschaum._core.ApiConnector, one per connector
and process): the same routes, query parameters and bodies as v4. Nothing here imports
requests or httpx.
144 def __init__( 145 self, 146 label: Optional[str] = None, 147 wait: bool = False, 148 debug: bool = False, 149 **kw 150 ): 151 if 'uri' in kw: 152 from_uri_params = self.from_uri(kw['uri'], as_dict=True) 153 label = label or from_uri_params.get('label', None) 154 _ = from_uri_params.pop('label', None) 155 kw.update(from_uri_params) 156 157 super().__init__('api', label=label, **kw) 158 if 'protocol' not in self.__dict__: 159 self.protocol = ( 160 'https' if self.__dict__.get('uri', '').startswith('https') 161 else 'http' 162 ) 163 164 if 'uri' not in self.__dict__: 165 self.verify_attributes(required_attributes) 166 else: 167 conn_attrs = self.from_uri(self.__dict__['uri'], as_dict=True) 168 self.__dict__.update({ 169 key: val 170 for key, val in conn_attrs.items() 171 if key not in ('label', 'protocol') 172 }) 173 174 self.url = ( 175 self.protocol + '://' + 176 self.host 177 + ( 178 (':' + str(self.port)) 179 if self.__dict__.get('port', None) 180 else '' 181 ) 182 ) 183 self._rust_client_obj = None 184 self._instance_keys = self.__dict__.get('instance_keys', None)
225 @property 226 def URI(self) -> str: 227 """ 228 Return the fully qualified URI. 229 """ 230 return self._rust_client().uri
Return the fully qualified URI.
232 @property 233 def session(self): 234 """ 235 A `requests.Session` (not used by the connector, which makes its requests in Rust). 236 It exists for plugins which still reach for it and needs `requests` installed. 237 """ 238 if self.__dict__.get('_session', None) is None: 239 from meerschaum.utils.packages import attempt_import 240 requests = attempt_import('requests', lazy=False) 241 if requests is None: 242 raise ImportError("Failed to import requests. Is requests installed?") 243 self._session = requests.Session() 244 return self._session
A requests.Session (not used by the connector, which makes its requests in Rust).
It exists for plugins which still reach for it and needs requests installed.
246 @property 247 def token(self): 248 """ 249 Return the API key, or the session token (logging in when it is missing or expiring). 250 """ 251 return self._rust_client().token
Return the API key, or the session token (logging in when it is missing or expiring).
290 @property 291 def instance_keys(self) -> Union[str, None]: 292 """ 293 Return the instance keys to be sent alongside pipe requests. 294 """ 295 return self._instance_keys
Return the instance keys to be sent alongside pipe requests.
297 @property 298 def login_scheme(self) -> str: 299 """ 300 Return the login scheme to use based on the configured credentials. 301 """ 302 return self._rust_client().login_scheme
Return the login scheme to use based on the configured credentials.
21def make_request( 22 self, 23 method: str, 24 r_url: str, 25 headers: Optional[Dict[str, Any]] = None, 26 use_token: bool = True, 27 debug: bool = False, 28 **kwargs: Any 29) -> 'meerschaum._core.ApiResponse': 30 """ 31 Make a request to the API and return a response object 32 (`status_code`, `ok`, `text`, `content`, `headers`, `json()`, `raise_for_status()`). 33 34 Parameters 35 ---------- 36 method: str 37 The name of the request method (e.g. `'GET'`, `'POST'`). 38 39 r_url: str 40 The relative URL for the request (e.g. `'/pipes'`). 41 42 headers: Optional[Dict[str, Any]], default None 43 Headers to override the default headers. 44 45 use_token: bool, default True 46 If `True`, add the authorization token to the headers. 47 48 debug: bool, default False 49 Verbosity toggle. 50 51 kwargs: Any 52 `params` (the query), `json`, `data`, `files` and `timeout` are sent as `requests` would. 53 """ 54 if method.upper() not in METHODS: 55 raise ValueError(f"Method '{method}' is not supported.") 56 57 if debug: 58 dprint(f"[{self}] Sending a '{method.upper()}' request to {self.url}{r_url}") 59 60 return self._rust_client().make_request( 61 method, 62 r_url, 63 headers=headers, 64 use_token=use_token, 65 **kwargs 66 )
Make a request to the API and return a response object
(status_code, ok, text, content, headers, json(), raise_for_status()).
Parameters
- method (str):
The name of the request method (e.g.
'GET','POST'). - r_url (str):
The relative URL for the request (e.g.
'/pipes'). - headers (Optional[Dict[str, Any]], default None): Headers to override the default headers.
- use_token (bool, default True):
If
True, add the authorization token to the headers. - debug (bool, default False): Verbosity toggle.
- kwargs (Any):
params(the query),json,data,filesandtimeoutare sent asrequestswould.
69def get(self, r_url: str, **kwargs: Any) -> 'meerschaum._core.ApiResponse': 70 """ 71 Send a `GET` request (see `make_request()`). 72 """ 73 return self.make_request('GET', r_url, **kwargs)
Send a GET request (see make_request()).
76def post(self, r_url: str, **kwargs: Any) -> 'meerschaum._core.ApiResponse': 77 """ 78 Send a `POST` request (see `make_request()`). 79 """ 80 return self.make_request('POST', r_url, **kwargs)
Send a POST request (see make_request()).
90def put(self, r_url: str, **kwargs: Any) -> 'meerschaum._core.ApiResponse': 91 """ 92 Send a `PUT` request (see `make_request()`). 93 """ 94 return self.make_request('PUT', r_url, **kwargs)
Send a PUT request (see make_request()).
83def patch(self, r_url: str, **kwargs: Any) -> 'meerschaum._core.ApiResponse': 84 """ 85 Send a `PATCH` request (see `make_request()`). 86 """ 87 return self.make_request('PATCH', r_url, **kwargs)
Send a PATCH request (see make_request()).
97def delete(self, r_url: str, **kwargs: Any) -> 'meerschaum._core.ApiResponse': 98 """ 99 Send a `DELETE` request (see `make_request()`). 100 """ 101 return self.make_request('DELETE', r_url, **kwargs)
Send a DELETE request (see make_request()).
104def wget( 105 self, 106 r_url: str, 107 dest: Optional[Union[str, pathlib.Path]] = None, 108 headers: Optional[Dict[str, Any]] = None, 109 use_token: bool = True, 110 debug: bool = False, 111 **kw: Any 112) -> pathlib.Path: 113 """Mimic wget: download a resource of the API (with the token) to `dest`.""" 114 from meerschaum.utils.misc import wget 115 if headers is None: 116 headers = {} 117 if use_token: 118 headers.update({'Authorization': f'Bearer {self.token}'}) 119 request_url = urllib.parse.urljoin(self.url, r_url) 120 if debug: 121 dprint( 122 f"[{self}] Downloading {request_url}" 123 + (f' to {dest}' if dest is not None else '') 124 + "..." 125 ) 126 return wget(request_url, dest=dest, headers=headers, **kw)
Mimic wget: download a resource of the API (with the token) to dest.
18def get_actions(self): 19 """ 20 Get available actions from the API instance. 21 Returns the response (v4 does: `.json()` is the list of action names). 22 """ 23 from meerschaum._internal.static import STATIC_CONFIG 24 return self.get(STATIC_CONFIG['api']['endpoints']['actions'])
Get available actions from the API instance.
Returns the response (v4 does: .json() is the list of action names).
27def do_action(self, sysargs: List[str]) -> SuccessTuple: 28 """ 29 Execute a Meerschaum action remotely. 30 """ 31 return self._rust_client().do_action(sysargs)
Execute a Meerschaum action remotely.
34async def do_action_async( 35 self, 36 sysargs: List[str], 37 callback_function: Callable[[str], None] = partial(print, end=''), 38) -> SuccessTuple: 39 """ 40 Execute an action as a temporary remote job. 41 """ 42 from meerschaum.connectors.api._jobs import _LoopCallback 43 loop = asyncio.get_running_loop() 44 client = self._rust_client() 45 return await loop.run_in_executor( 46 None, 47 lambda: client.do_action(sysargs, _LoopCallback(loop, callback_function)), 48 )
Execute an action as a temporary remote job.
51def do_action_legacy( 52 self, 53 action: Optional[List[str]] = None, 54 sysargs: Optional[List[str]] = None, 55 debug: bool = False, 56 **kw 57) -> SuccessTuple: 58 """ 59 NOTE: This method is deprecated. 60 Please use `do_action()` or `do_action_async()`. 61 62 Execute a Meerschaum action remotely. 63 64 If `sysargs` are provided, parse those instead. 65 Otherwise infer everything from keyword arguments. 66 67 Examples 68 -------- 69 >>> conn = mrsm.get_connector('api:main') 70 >>> conn.do_action(['show', 'pipes']) 71 (True, "Success") 72 >>> conn.do_action(['show', 'arguments'], name='test') 73 (True, "Success") 74 """ 75 if action is None: 76 action = [] 77 78 if sysargs is not None and action and action[0] == '': 79 from meerschaum._internal.arguments import parse_arguments 80 json_dict = parse_arguments(sysargs) 81 action = list(json_dict.pop('action', None) or []) 82 kw = json_dict 83 else: 84 action = list(action) 85 if debug: 86 kw['debug'] = debug 87 88 return self._rust_client().do_action_legacy(action, kw)
NOTE: This method is deprecated.
Please use do_action() or do_action_async().
Execute a Meerschaum action remotely.
If sysargs are provided, parse those instead.
Otherwise infer everything from keyword arguments.
Examples
>>> conn = mrsm.get_connector('api:main')
>>> conn.do_action(['show', 'pipes'])
(True, "Success")
>>> conn.do_action(['show', 'arguments'], name='test')
(True, "Success")
15def get_mrsm_version(self, **kw) -> Optional[str]: 16 """ 17 Return the Meerschaum version of the API instance. 18 """ 19 return self._rust_client().get_mrsm_version()
Return the Meerschaum version of the API instance.
22def get_chaining_status(self, **kw) -> Optional[bool]: 23 """ 24 Fetch the chaining status of the API instance. 25 """ 26 return self._rust_client().get_chaining_status()
Fetch the chaining status of the API instance.
5def get_engine_metrics(self, **kwargs): 6 """Read bounded sync and Pipeline measurements visible to this credential.""" 7 from meerschaum.core.Pipeline._metrics import get_engine_metrics as read 8 return read(instance=self, **kwargs)
Read bounded sync and Pipeline measurements visible to this credential.
11def initialize_engine_metrics(self): 12 """Initialize metrics storage on the served instance (full administrator only).""" 13 from meerschaum.core.Pipeline._metrics import initialize_engine_metrics as initialize 14 return initialize(instance=self)
Initialize metrics storage on the served instance (full administrator only).
34def get_pipe_instance_keys(self, pipe: mrsm.Pipe) -> Union[str, None]: 35 """ 36 Return the configured instance keys for a pipe if set, 37 else fall back to the default `instance_keys` for this `APIConnector`. 38 """ 39 return self._rust_client().get_pipe_instance_keys(pipe)
Return the configured instance keys for a pipe if set,
else fall back to the default instance_keys for this APIConnector.
42def register_pipe( 43 self, 44 pipe: mrsm.Pipe, 45 debug: bool = False, 46) -> SuccessTuple: 47 """ 48 Submit a POST to the API to register a new Pipe object. 49 Returns a tuple of (success_bool, response_dict). 50 """ 51 return self._rust_client().register_pipe(pipe)
Submit a POST to the API to register a new Pipe object. Returns a tuple of (success_bool, response_dict).
67def fetch_pipes_keys( 68 self, 69 connector_keys: Optional[List[str]] = None, 70 metric_keys: Optional[List[str]] = None, 71 location_keys: Optional[List[str]] = None, 72 tags: Optional[List[str]] = None, 73 params: Optional[Dict[str, Any]] = None, 74 debug: bool = False 75) -> Union[ 76 Dict[Union[int, str], Tuple[str, str, Union[str, None], Dict[str, Any]]], 77 List[Tuple[str, str, Union[str, None]]], 78]: 79 """ 80 Fetch registered Pipes' keys from the API. 81 82 Parameters 83 ---------- 84 connector_keys: Optional[List[str]], default None 85 The connector keys for the query. 86 87 metric_keys: Optional[List[str]], default None 88 The metric keys for the query. 89 90 location_keys: Optional[List[str]], default None 91 The location keys for the query. 92 93 tags: Optional[List[str]], default None 94 A list of tags for the query. 95 96 params: Optional[Dict[str, Any]], default None 97 A parameters dictionary for filtering against the `pipes` table 98 (e.g. `{'connector_keys': 'plugin:foo'}`). 99 Not recommeded to be used. 100 101 Returns 102 ------- 103 A dictionary mapping pipe IDs to key tuples, or a list of key tuples for older servers. 104 """ 105 return self._rust_client().fetch_pipes_keys( 106 connector_keys, 107 metric_keys, 108 location_keys, 109 tags, 110 params, 111 )
Fetch registered Pipes' keys from the API.
Parameters
- connector_keys (Optional[List[str]], default None): The connector keys for the query.
- metric_keys (Optional[List[str]], default None): The metric keys for the query.
- location_keys (Optional[List[str]], default None): The location keys for the query.
- tags (Optional[List[str]], default None): A list of tags for the query.
- params (Optional[Dict[str, Any]], default None):
A parameters dictionary for filtering against the
pipestable (e.g.{'connector_keys': 'plugin:foo'}). Not recommeded to be used.
Returns
- A dictionary mapping pipe IDs to key tuples, or a list of key tuples for older servers.
54def edit_pipe( 55 self, 56 pipe: mrsm.Pipe, 57 patch: bool = False, 58 debug: bool = False, 59) -> SuccessTuple: 60 """ 61 Submit a PATCH to the API to edit an existing Pipe object. 62 Returns a tuple of (success_bool, response_dict). 63 """ 64 return self._rust_client().edit_pipe(pipe, patch=patch)
Submit a PATCH to the API to edit an existing Pipe object. Returns a tuple of (success_bool, response_dict).
114def sync_pipe( 115 self, 116 pipe: mrsm.Pipe, 117 df: Optional[Union['pd.DataFrame', Dict[Any, Any], str]] = None, 118 chunksize: Optional[int] = -1, 119 debug: bool = False, 120 **kw: Any 121) -> SuccessTuple: 122 """ 123 Sync a DataFrame (or documents, or a dictionary of lists) into a Pipe. 124 Keyword arguments are sent to the API as query parameters. 125 """ 126 if isinstance(df, str): 127 df = json.loads(df) 128 return self._rust_client().sync_pipe(pipe, df, chunksize=chunksize, **kw)
Sync a DataFrame (or documents, or a dictionary of lists) into a Pipe. Keyword arguments are sent to the API as query parameters.
141def delete_pipe( 142 self, 143 pipe: Optional[mrsm.Pipe] = None, 144 debug: bool = False, 145) -> SuccessTuple: 146 """Delete a Pipe and drop its table.""" 147 if pipe is None: 148 raise ValueError("Pipe cannot be None.") 149 return self._rust_client().delete_pipe(pipe)
Delete a Pipe and drop its table.
131def delete_pipe_cache( 132 self, 133 pipe: mrsm.Pipe, 134 debug: bool = False, 135 **kw: Any 136) -> SuccessTuple: 137 """Invalidate the server-side cache for a pipe.""" 138 return self._rust_client().delete_pipe_cache(pipe)
Invalidate the server-side cache for a pipe.
152def get_pipe_data( 153 self, 154 pipe: mrsm.Pipe, 155 select_columns: Optional[List[str]] = None, 156 omit_columns: Optional[List[str]] = None, 157 begin: Union[str, datetime, int, None] = None, 158 end: Union[str, datetime, int, None] = None, 159 params: Optional[Dict[str, Any]] = None, 160 as_chunks: bool = False, 161 debug: bool = False, 162 as_polars: Optional[bool] = None, 163 as_pandas: Optional[bool] = None, 164 **kw: Any 165) -> Union['pd.DataFrame', None]: 166 """ 167 Fetch data from the API, as a DataFrame of the `meerschaum:dataframe` library 168 (`as_polars=True` / `as_pandas=True` choose one). 169 """ 170 from meerschaum.utils.dataframe import frame_from_arrow, frame_library_of 171 df = self._rust_client().get_pipe_data( 172 pipe, 173 select_columns=select_columns, 174 omit_columns=omit_columns, 175 begin=begin, 176 end=end, 177 params=params, 178 as_chunks=as_chunks, 179 ) 180 if frame_library_of(df) is None: 181 return df 182 return frame_from_arrow(df, as_polars=as_polars, as_pandas=as_pandas)
Fetch data from the API, as a DataFrame of the meerschaum:dataframe library
(as_polars=True / as_pandas=True choose one).
185def get_pipe_id( 186 self, 187 pipe: mrsm.Pipe, 188 debug: bool = False, 189) -> Union[int, str, None]: 190 """Get a Pipe's ID from the API.""" 191 return self._rust_client().get_pipe_id(pipe)
Get a Pipe's ID from the API.
194def get_pipe_attributes( 195 self, 196 pipe: mrsm.Pipe, 197 debug: bool = False, 198) -> Dict[str, Any]: 199 """ 200 Get a Pipe's attributes from the API. 201 202 Parameters 203 ---------- 204 pipe: meerschaum.Pipe 205 The pipe whose attributes we are fetching. 206 207 Returns 208 ------- 209 A dictionary of a pipe's attributes. 210 If the pipe does not exist, return an empty dictionary. 211 """ 212 return self._rust_client().get_pipe_attributes(pipe)
Get a Pipe's attributes from the API.
Parameters
- pipe (meerschaum.Pipe): The pipe whose attributes we are fetching.
Returns
- A dictionary of a pipe's attributes.
- If the pipe does not exist, return an empty dictionary.
215def get_sync_time( 216 self, 217 pipe: mrsm.Pipe, 218 params: Optional[Dict[str, Any]] = None, 219 newest: bool = True, 220 debug: bool = False, 221) -> Union[datetime, int, None]: 222 """ 223 Get a Pipe's most recent datetime value from the API. 224 225 Parameters 226 ---------- 227 pipe: meerschaum.Pipe 228 The pipe to select from. 229 230 params: Optional[Dict[str, Any]], default None 231 Optional params dictionary to build the WHERE clause. 232 233 newest: bool, default True 234 If `True`, get the most recent datetime (honoring `params`). 235 If `False`, get the oldest datetime (ASC instead of DESC). 236 237 Returns 238 ------- 239 The most recent (or oldest if `newest` is `False`) datetime of a pipe, 240 rounded down to the closest minute. 241 """ 242 return self._rust_client().get_sync_time(pipe, params=params, newest=newest)
Get a Pipe's most recent datetime value from the API.
Parameters
- pipe (meerschaum.Pipe): The pipe to select from.
- params (Optional[Dict[str, Any]], default None): Optional params dictionary to build the WHERE clause.
- newest (bool, default True):
If
True, get the most recent datetime (honoringparams). IfFalse, get the oldest datetime (ASC instead of DESC).
Returns
- The most recent (or oldest if
newestisFalse) datetime of a pipe, - rounded down to the closest minute.
245def pipe_exists( 246 self, 247 pipe: mrsm.Pipe, 248 debug: bool = False 249) -> bool: 250 """ 251 Check the API to see if a Pipe exists. 252 253 Parameters 254 ---------- 255 pipe: 'meerschaum.Pipe' 256 The pipe which were are querying. 257 258 Returns 259 ------- 260 A bool indicating whether a pipe's underlying table exists. 261 """ 262 return self._rust_client().pipe_exists(pipe)
Check the API to see if a Pipe exists.
Parameters
- pipe ('meerschaum.Pipe'): The pipe which were are querying.
Returns
- A bool indicating whether a pipe's underlying table exists.
265def create_metadata( 266 self, 267 debug: bool = False 268) -> bool: 269 """ 270 Create metadata tables. 271 272 Returns 273 ------- 274 A bool indicating success. 275 """ 276 return self._rust_client().create_metadata()
Create metadata tables.
Returns
- A bool indicating success.
279def get_pipe_rowcount( 280 self, 281 pipe: mrsm.Pipe, 282 begin: Union[str, datetime, int, None] = None, 283 end: Union[str, datetime, int, None] = None, 284 params: Optional[Dict[str, Any]] = None, 285 remote: bool = False, 286 debug: bool = False, 287) -> int: 288 """ 289 Get a pipe's row count from the API. 290 291 Parameters 292 ---------- 293 pipe: 'meerschaum.Pipe': 294 The pipe whose row count we are counting. 295 296 begin: Union[str, datetime, int, None], default None 297 If provided, bound the count by this datetime. 298 299 end: Union[str, datetime, int, None], default None 300 If provided, bound the count by this datetime. 301 302 params: Optional[Dict[str, Any]], default None 303 If provided, bound the count by these parameters. 304 305 remote: bool, default False 306 If `True`, return the rowcount for the fetch definition. 307 308 Returns 309 ------- 310 The number of rows in the pipe's table, bound the given parameters. 311 If the table does not exist, return 0. 312 """ 313 return self._rust_client().get_pipe_rowcount( 314 pipe, 315 begin=begin, 316 end=end, 317 params=params, 318 remote=remote, 319 )
Get a pipe's row count from the API.
Parameters
- pipe ('meerschaum.Pipe':): The pipe whose row count we are counting.
- begin (Union[str, datetime, int, None], default None): If provided, bound the count by this datetime.
- end (Union[str, datetime, int, None], default None): If provided, bound the count by this datetime.
- params (Optional[Dict[str, Any]], default None): If provided, bound the count by these parameters.
- remote (bool, default False):
If
True, return the rowcount for the fetch definition.
Returns
- The number of rows in the pipe's table, bound the given parameters.
- If the table does not exist, return 0.
322def drop_pipe( 323 self, 324 pipe: mrsm.Pipe, 325 debug: bool = False 326) -> SuccessTuple: 327 """ 328 Drop a pipe's table but maintain its registration. 329 330 Parameters 331 ---------- 332 pipe: meerschaum.Pipe: 333 The pipe to be dropped. 334 335 Returns 336 ------- 337 A success tuple (bool, str). 338 """ 339 if pipe is None: 340 raise ValueError("Pipe cannot be None.") 341 return self._rust_client().drop_pipe(pipe)
Drop a pipe's table but maintain its registration.
Parameters
- pipe (meerschaum.Pipe:): The pipe to be dropped.
Returns
- A success tuple (bool, str).
344def clear_pipe( 345 self, 346 pipe: mrsm.Pipe, 347 begin: Union[str, datetime, int, None] = None, 348 end: Union[str, datetime, int, None] = None, 349 params: Optional[Dict[str, Any]] = None, 350 debug: bool = False, 351 **kw 352) -> SuccessTuple: 353 """ 354 Delete rows in a pipe's table. 355 356 Parameters 357 ---------- 358 pipe: meerschaum.Pipe 359 The pipe with rows to be deleted. 360 361 begin: Union[str, datetime, int, None], default None 362 Delete rows at or after this datetime. 363 364 end: Union[str, datetime, int, None], default None 365 Delete rows before this datetime. 366 367 params: Optional[Dict[str, Any]], default None 368 Delete rows matching these parameters. 369 370 Returns 371 ------- 372 A success tuple. 373 """ 374 return self._rust_client().clear_pipe(pipe, begin=begin, end=end, params=params)
Delete rows in a pipe's table.
Parameters
- pipe (meerschaum.Pipe): The pipe with rows to be deleted.
- begin (Union[str, datetime, int, None], default None): Delete rows at or after this datetime.
- end (Union[str, datetime, int, None], default None): Delete rows before this datetime.
- params (Optional[Dict[str, Any]], default None): Delete rows matching these parameters.
Returns
- A success tuple.
377def get_pipe_columns_types( 378 self, 379 pipe: mrsm.Pipe, 380 debug: bool = False, 381) -> Union[Dict[str, str], None]: 382 """ 383 Fetch the columns and types of the pipe's table. 384 385 Parameters 386 ---------- 387 pipe: meerschaum.Pipe 388 The pipe whose columns to be queried. 389 390 Returns 391 ------- 392 A dictionary mapping column names to their database types, or `None` on failure. 393 """ 394 return self._rust_client().get_pipe_columns_types(pipe)
Fetch the columns and types of the pipe's table.
Parameters
- pipe (meerschaum.Pipe): The pipe whose columns to be queried.
Returns
- A dictionary mapping column names to their database types, or
Noneon failure.
397def get_pipe_columns_indices( 398 self, 399 pipe: mrsm.Pipe, 400 debug: bool = False, 401) -> Union[Dict[str, List[Dict[str, str]]], None]: 402 """ 403 Fetch the index information for a pipe. 404 405 Parameters 406 ---------- 407 pipe: mrsm.Pipe 408 The pipe whose columns to be queried. 409 410 Returns 411 ------- 412 A dictionary mapping column names to lists of dictionaries with index `name` and `type`, 413 or `None` on failure. 414 """ 415 return self._rust_client().get_pipe_columns_indices(pipe)
Fetch the index information for a pipe.
Parameters
- pipe (mrsm.Pipe): The pipe whose columns to be queried.
Returns
- A dictionary mapping column names to lists of dictionaries with index
nameandtype, - or
Noneon failure.
509def get_pipe_index_names( 510 self, 511 pipe: mrsm.Pipe, 512 debug: bool = False, 513) -> Dict[str, str]: 514 """Return the index names of a pipe's table.""" 515 return self._rust_client().get_pipe_index_names(pipe)
Return the index names of a pipe's table.
418def get_pipe_docs( 419 self, 420 pipe: mrsm.Pipe, 421 select_columns: Optional[List[str]] = None, 422 omit_columns: Optional[List[str]] = None, 423 begin: Union[str, datetime, int, None] = None, 424 end: Union[str, datetime, int, None] = None, 425 params: Optional[Dict[str, Any]] = None, 426 order: str = 'asc', 427 limit: Optional[int] = None, 428 debug: bool = False, 429 **kw: Any 430) -> List[Dict[str, Any]]: 431 """Fetch a pipe's data as a list of documents from the API.""" 432 return self._rust_client().get_pipe_docs( 433 pipe, 434 select_columns=select_columns, 435 omit_columns=omit_columns, 436 begin=begin, 437 end=end, 438 params=params, 439 order=order, 440 limit=limit, 441 )
Fetch a pipe's data as a list of documents from the API.
444def get_pipe_size( 445 self, 446 pipe: mrsm.Pipe, 447 debug: bool = False, 448 **kw: Any 449) -> Union[int, None]: 450 """ 451 Return the size of the pipe's table in bytes, or `None` if it is not available. 452 """ 453 return self._rust_client().get_pipe_size(pipe)
Return the size of the pipe's table in bytes, or None if it is not available.
456def compress_pipe( 457 self, 458 pipe: mrsm.Pipe, 459 debug: bool = False, 460 **kw: Any 461) -> SuccessTuple: 462 """Compress a pipe's table on the API instance.""" 463 return self._rust_client().compress_pipe(pipe)
Compress a pipe's table on the API instance.
466def decompress_pipe( 467 self, 468 pipe: mrsm.Pipe, 469 no_policy: bool = False, 470 debug: bool = False, 471 **kw: Any 472) -> SuccessTuple: 473 """Decompress a pipe's table on the API instance.""" 474 return self._rust_client().decompress_pipe(pipe, no_policy=no_policy)
Decompress a pipe's table on the API instance.
477def vacuum_pipe( 478 self, 479 pipe: mrsm.Pipe, 480 full: bool = False, 481 debug: bool = False, 482 **kw: Any 483) -> SuccessTuple: 484 """Vacuum a pipe's table on the API instance.""" 485 return self._rust_client().vacuum_pipe(pipe, full=full)
Vacuum a pipe's table on the API instance.
499def analyze_pipe( 500 self, 501 pipe: mrsm.Pipe, 502 debug: bool = False, 503 **kw: Any 504) -> SuccessTuple: 505 """Analyze a pipe's table on the API instance.""" 506 return self._rust_client().analyze_pipe(pipe)
Analyze a pipe's table on the API instance.
488def partition_pipe( 489 self, 490 pipe: mrsm.Pipe, 491 chunk_minutes: Optional[int] = None, 492 debug: bool = False, 493 **kw: Any 494) -> SuccessTuple: 495 """Repartition a pipe's table on the API instance.""" 496 return self._rust_client().partition_pipe(pipe, chunk_minutes=chunk_minutes)
Repartition a pipe's table on the API instance.
19def fetch( 20 self, 21 pipe: mrsm.Pipe, 22 begin: Union[datetime, str, int] = '', 23 end: Union[datetime, int] = None, 24 params: Optional[Dict[str, Any]] = None, 25 debug: bool = False, 26 **kw: Any 27) -> Iterator['pd.DataFrame']: 28 """Get the Pipe data from the remote Pipe (`parameters['fetch']['pipe']`).""" 29 from meerschaum.config._patch import apply_patch_to_config 30 import copy 31 32 fetch_params = pipe.parameters.get('fetch', {}) 33 if not fetch_params: 34 warn(f"Missing 'fetch' parameters for {pipe}.", stack=False) 35 return None 36 37 pipe_meta = dict(fetch_params.get('pipe', {})) 38 ### Legacy: check for `connector_keys`, etc. at the root. 39 if not pipe_meta: 40 ck, mk, lk = ( 41 fetch_params.get('connector_keys', None), 42 fetch_params.get('metric_key', None), 43 fetch_params.get('location_key', None), 44 ) 45 if not ck or not mk: 46 warn(f"Missing `fetch:pipe` keys for {pipe}.", stack=False) 47 return None 48 pipe_meta.update({ 49 'connector': ck, 50 'metric': mk, 51 'location': lk, 52 }) 53 54 pipe_meta['instance'] = self 55 source_pipe = mrsm.Pipe(**pipe_meta) 56 _params = copy.deepcopy(params) if params is not None else {} 57 _params = apply_patch_to_config(_params, fetch_params.get('params', {})) 58 select_columns = fetch_params.get('select_columns', []) 59 omit_columns = fetch_params.get('omit_columns', []) 60 return source_pipe.get_data( 61 select_columns=select_columns, 62 omit_columns=omit_columns, 63 begin=begin, 64 end=end, 65 params=_params, 66 debug=debug, 67 as_iterator=True, 68 )
Get the Pipe data from the remote Pipe (parameters['fetch']['pipe']).
24def register_plugin( 25 self, 26 plugin: mrsm.core.Plugin, 27 make_archive: bool = True, 28 debug: bool = False, 29) -> SuccessTuple: 30 """Register a plugin and upload its archive.""" 31 import os 32 archive_path = plugin.make_tar(debug=debug) if make_archive else plugin.archive_path 33 try: 34 with open(archive_path, 'rb') as f: 35 archive = f.read() 36 except Exception: 37 return False, f"Failed to register plugin '{plugin}'." 38 return self._rust_client().register_plugin( 39 plugin, 40 archive, 41 os.path.basename(str(archive_path)), 42 )
Register a plugin and upload its archive.
45def install_plugin( 46 self, 47 name: str, 48 skip_deps: bool = False, 49 force: bool = False, 50 debug: bool = False 51) -> SuccessTuple: 52 """Download and attempt to install a plugin from the API.""" 53 import os 54 import pathlib 55 from meerschaum.core import Plugin 56 import meerschaum.config.paths as paths 57 58 dest = pathlib.Path(os.path.join(paths.PLUGINS_TEMP_RESOURCES_PATH, name + '.tar.gz')) 59 try: 60 archive = self._rust_client().download_plugin(name) 61 except ValueError as e: 62 return False, str(e) 63 dest.parent.mkdir(parents=True, exist_ok=True) 64 dest.write_bytes(archive) 65 plugin = Plugin(name, archive_path=dest, repo_connector=self) 66 return plugin.install(skip_deps=skip_deps, force=force, debug=debug)
Download and attempt to install a plugin from the API.
110def delete_plugin( 111 self, 112 plugin: mrsm.core.Plugin, 113 debug: bool = False 114) -> SuccessTuple: 115 """Delete a plugin from an API repository.""" 116 return self._rust_client().delete_plugin(plugin)
Delete a plugin from an API repository.
69def get_plugins( 70 self, 71 user_id: Optional[int] = None, 72 search_term: Optional[str] = None, 73 debug: bool = False 74) -> List[str]: 75 """Return a list of registered plugin names. 76 77 Parameters 78 ---------- 79 user_id: Optional[int], default None 80 If specified, return all plugins from a certain user. 81 82 search_term: Optional[str], default None 83 If specified, return plugins beginning with this string. 84 85 Returns 86 ------- 87 A list of plugin names. 88 """ 89 return self._rust_client().get_plugins(user_id=user_id, search_term=search_term)
Return a list of registered plugin names.
Parameters
- user_id (Optional[int], default None): If specified, return all plugins from a certain user.
- search_term (Optional[str], default None): If specified, return plugins beginning with this string.
Returns
- A list of plugin names.
92def get_plugin_attributes( 93 self, 94 plugin: mrsm.core.Plugin, 95 debug: bool = False 96) -> Dict[str, Any]: 97 """Return a plugin's attributes.""" 98 return self._rust_client().get_plugin_attributes(plugin)
Return a plugin's attributes.
101def get_plugin_version( 102 self, 103 plugin: mrsm.core.Plugin, 104 debug: bool = False 105) -> Union[str, None]: 106 """Return a plugin's version.""" 107 return self._rust_client().get_plugin_version(plugin)
Return a plugin's version.
15def login( 16 self, 17 debug: bool = False, 18 warn: bool = True, 19 **kw: Any 20) -> SuccessTuple: 21 """Log in and set the session token.""" 22 if warn and self.__dict__.get('_warn', None) is False: 23 warn = False 24 return self._rust_client().login(warn=warn)
Log in and set the session token.
27def test_connection( 28 self, 29 **kw: Any 30) -> Union[bool, None]: 31 """ 32 Test if a successful connection to the API may be made. 33 34 The API instance must answer `/chaining`; keyword arguments are those of `retry_connect()`: 35 `max_retries` (default 1), `retry_wait` (default 0), `warn` (default `False`), 36 `enforce_chaining` and `enforce_login` (default `False`). 37 """ 38 import time 39 from meerschaum.utils.warnings import warn as _warn 40 max_retries = kw.get('max_retries', 1) 41 retry_wait = kw.get('retry_wait', 0) 42 warn = kw.get('warn', False) 43 enforce_chaining = kw.get('enforce_chaining', False) 44 enforce_login = kw.get('enforce_login', False) 45 46 try: 47 retries = 0 48 chaining_status = None 49 while retries < max_retries: 50 connected = None 51 if not isinstance(chaining_status, bool): 52 chaining_status = self.get_chaining_status() 53 if chaining_status is False: 54 if enforce_chaining: 55 if warn: 56 _warn( 57 f"Meerschaum instance '{self}' does not allow chaining " 58 + "and cannot be used as the parent for this instance.", 59 stack=False, 60 ) 61 return False 62 chaining_status = True 63 64 if chaining_status: 65 connected = self.login(warn=warn)[0] if enforce_login else True 66 if not connected and warn: 67 _warn(f"Unable to login to '{self}'!", stack=False) 68 69 if connected: 70 return True 71 72 if warn: 73 _warn(f"Connection to '{self}' failed.", stack=False) 74 if retry_wait > 0: 75 time.sleep(retry_wait) 76 retries += 1 77 return False 78 except Exception: 79 return False
Test if a successful connection to the API may be made.
The API instance must answer /chaining; keyword arguments are those of retry_connect():
max_retries (default 1), retry_wait (default 0), warn (default False),
enforce_chaining and enforce_login (default False).
37def register_user( 38 self, 39 user: mrsm.core.User, 40 debug: bool = False, 41 **kw: Any 42) -> SuccessTuple: 43 """Register a new user.""" 44 return self._rust_client().register_user(user)
Register a new user.
47def get_user_id( 48 self, 49 user: mrsm.core.User, 50 debug: bool = False, 51 **kw: Any 52) -> Union[int, str, UUID, None]: 53 """Get a user's ID.""" 54 user_id = self._rust_client().get_user_id(user) 55 if isinstance(user_id, str): 56 try: 57 return UUID(user_id) if len(user_id) == 36 else user_id 58 except ValueError: 59 return user_id 60 return user_id
Get a user's ID.
18def get_users( 19 self, 20 debug: bool = False, 21 **kw: Any 22) -> List[str]: 23 """Return a list of registered usernames.""" 24 return self._rust_client().get_users()
Return a list of registered usernames.
27def edit_user( 28 self, 29 user: mrsm.core.User, 30 debug: bool = False, 31 **kw: Any 32) -> SuccessTuple: 33 """Edit an existing user.""" 34 return self._rust_client().edit_user(user)
Edit an existing user.
63def delete_user( 64 self, 65 user: mrsm.core.User, 66 debug: bool = False, 67 **kw: Any 68) -> SuccessTuple: 69 """Delete a user.""" 70 return self._rust_client().delete_user(user)
Delete a user.
87def get_user_password_hash( 88 self, 89 user: mrsm.core.User, 90 debug: bool = False, 91 **kw: Any 92) -> Optional[str]: 93 """If configured, get a user's password hash.""" 94 return self._rust_client().get_user_password_hash(user)
If configured, get a user's password hash.
97def get_user_type( 98 self, 99 user: mrsm.core.User, 100 debug: bool = False, 101 **kw: Any 102) -> Optional[str]: 103 """If configured, get a user's type.""" 104 return self._rust_client().get_user_type(user)
If configured, get a user's type.
73def get_user_attributes( 74 self, 75 user: mrsm.core.User, 76 debug: bool = False, 77 **kw 78) -> Any: 79 """Get a user's attributes.""" 80 return self._rust_client().get_user_attributes(user)
Get a user's attributes.
20def register_token(self, token: 'Token', debug: bool = False) -> mrsm.SuccessTuple: 21 """ 22 Register the provided token to the API. 23 """ 24 return self._rust_client().register_token(token)
Register the provided token to the API.
27def get_token_model(self, token_id: uuid.UUID, debug: bool = False) -> 'Union[TokenModel, None]': 28 """ 29 Return a token's model from the API instance. 30 """ 31 from meerschaum.models import TokenModel 32 data = self._rust_client().get_token_model(_token_id(token_id)) 33 if data is None: 34 return None 35 return TokenModel(**data)
Return a token's model from the API instance.
38def get_tokens(self, labels: Optional[List[str]] = None, debug: bool = False) -> List['Token']: 39 """ 40 Return the tokens registered to the current user. 41 """ 42 from meerschaum.core import Token 43 return [ 44 Token(instance=self, **payload) 45 for payload in self._rust_client().get_tokens(labels) 46 ]
Return the tokens registered to the current user.
49def edit_token(self, token: 'Token', debug: bool = False) -> mrsm.SuccessTuple: 50 """ 51 Persist the token's in-memory state to the API. 52 """ 53 return self._rust_client().edit_token(token)
Persist the token's in-memory state to the API.
56def invalidate_token(self, token: 'Token', debug: bool = False) -> mrsm.SuccessTuple: 57 """ 58 Invalidate the token, disabling it for future requests. 59 """ 60 return self._rust_client().invalidate_token(token)
Invalidate the token, disabling it for future requests.
63def get_token_scopes(self, token_id: Union[uuid.UUID, 'Token'], debug: bool = False) -> List[str]: 64 """ 65 Return the scopes for a token. 66 """ 67 return self._rust_client().get_token_scopes(_token_id(token_id))
Return the scopes for a token.
70def token_exists(self, token_id: Union[uuid.UUID, 'Token'], debug: bool = False) -> bool: 71 """ 72 Return `True` if a token exists. 73 """ 74 return self._rust_client().token_exists(_token_id(token_id))
Return True if a token exists.
77def delete_token(self, token: 'Token', debug: bool = False) -> mrsm.SuccessTuple: 78 """ 79 Delete the token from the API. 80 """ 81 return self._rust_client().delete_token(token)
Delete the token from the API.
13@classmethod 14def from_uri( 15 cls, 16 uri: str, 17 label: Optional[str] = None, 18 as_dict: bool = False, 19) -> Union[ 20 'meerschaum.connectors.APIConnector', 21 Dict[str, Union[str, int]], 22 ]: 23 """ 24 Create a new APIConnector from a URI string. 25 26 Parameters 27 ---------- 28 uri: str 29 The URI connection string. 30 31 label: Optional[str], default None 32 If provided, use this as the connector label. 33 Otherwise use the determined database name. 34 35 as_dict: bool, default False 36 If `True`, return a dictionary of the keyword arguments 37 necessary to create a new `APIConnector`, otherwise create a new object. 38 39 Returns 40 ------- 41 A new APIConnector object or a dictionary of attributes (if `as_dict` is `True`). 42 """ 43 from meerschaum import _core 44 params = _core.api_uri_params(uri, label) 45 return cls(**params) if not as_dict else params
Create a new APIConnector from a URI string.
Parameters
- uri (str): The URI connection string.
- label (Optional[str], default None): If provided, use this as the connector label. Otherwise use the determined database name.
- as_dict (bool, default False):
If
True, return a dictionary of the keyword arguments necessary to create a newAPIConnector, otherwise create a new object.
Returns
- A new APIConnector object or a dictionary of attributes (if
as_dictisTrue).
17def get_jobs(self, debug: bool = False) -> Dict[str, 'Job']: 18 """ 19 Return a dictionary of remote jobs. 20 """ 21 from meerschaum.jobs import Job 22 return { 23 name: Job( 24 name, 25 job_meta['sysargs'], 26 executor_keys=str(self), 27 _properties=job_meta['daemon']['properties'], 28 ) 29 for name, job_meta in self._rust_client().get_jobs_metadata().items() 30 }
Return a dictionary of remote jobs.
33def get_job(self, name: str, debug: bool = False) -> 'Job': 34 """ 35 Return a single Job object. 36 """ 37 from meerschaum.jobs import Job 38 metadata = self.get_job_metadata(name, debug=debug) 39 if not metadata: 40 raise ValueError(f"Job '{name}' does not exist.") 41 42 return Job( 43 name, 44 metadata['sysargs'], 45 executor_keys=str(self), 46 _properties=metadata['daemon']['properties'], 47 )
Return a single Job object.
50def get_job_metadata(self, name: str, debug: bool = False) -> Dict[str, Any]: 51 """ 52 Return the metadata for a single job. 53 """ 54 return self._rust_client().get_job_metadata(name)
Return the metadata for a single job.
57def get_job_properties(self, name: str, debug: bool = False) -> Dict[str, Any]: 58 """ 59 Return the daemon properties for a single job. 60 """ 61 return self._rust_client().get_job_properties(name)
Return the daemon properties for a single job.
92def get_job_exists(self, name: str, debug: bool = False) -> bool: 93 """ 94 Return whether a job exists. 95 """ 96 return self._rust_client().get_job_exists(name)
Return whether a job exists.
99def delete_job(self, name: str, debug: bool = False) -> SuccessTuple: 100 """ 101 Delete a job. 102 """ 103 return self._rust_client().delete_job(name)
Delete a job.
106def start_job(self, name: str, debug: bool = False) -> SuccessTuple: 107 """ 108 Start a job. 109 """ 110 return self._rust_client().start_job(name)
Start a job.
113def create_job( 114 self, 115 name: str, 116 sysargs: List[str], 117 properties: Optional[Dict[str, str]] = None, 118 debug: bool = False, 119) -> SuccessTuple: 120 """ 121 Create a job. 122 """ 123 return self._rust_client().create_job(name, sysargs, properties)
Create a job.
126def stop_job(self, name: str, debug: bool = False) -> SuccessTuple: 127 """ 128 Stop a job. 129 """ 130 return self._rust_client().stop_job(name)
Stop a job.
133def pause_job(self, name: str, debug: bool = False) -> SuccessTuple: 134 """ 135 Pause a job. 136 """ 137 return self._rust_client().pause_job(name)
Pause a job.
140def get_logs(self, name: str, debug: bool = False) -> str: 141 """ 142 Return the logs for a job. 143 """ 144 return self._rust_client().get_logs(name)
Return the logs for a job.
147def get_job_stop_time(self, name: str, debug: bool = False) -> Union[datetime, None]: 148 """ 149 Return the job's manual stop time. 150 """ 151 data = self._rust_client().get_job_stop_time(name) 152 if data is None: 153 return None 154 155 return datetime.fromisoformat(data)
Return the job's manual stop time.
223def monitor_logs( 224 self, 225 name: str, 226 callback_function: Callable[[Any], Any], 227 input_callback_function: Callable[[None], str], 228 stop_callback_function: Callable[[None], str], 229 stop_on_exit: bool = False, 230 strip_timestamps: bool = False, 231 accept_input: bool = True, 232 debug: bool = False, 233): 234 """ 235 Monitor a job's log files and execute a callback with the changes. 236 """ 237 return asyncio.run( 238 self.monitor_logs_async( 239 name, 240 callback_function, 241 input_callback_function=input_callback_function, 242 stop_callback_function=stop_callback_function, 243 stop_on_exit=stop_on_exit, 244 strip_timestamps=strip_timestamps, 245 accept_input=accept_input, 246 debug=debug 247 ) 248 )
Monitor a job's log files and execute a callback with the changes.
176async def monitor_logs_async( 177 self, 178 name: str, 179 callback_function: Callable[[Any], Any], 180 input_callback_function: Callable[[], str], 181 stop_callback_function: Callable[[SuccessTuple], str], 182 stop_on_exit: bool = False, 183 strip_timestamps: bool = False, 184 accept_input: bool = True, 185 debug: bool = False, 186): 187 """ 188 Monitor a job's log files and await a callback with the changes. 189 190 The stream runs in the Rust client; coroutine callbacks are awaited on this event loop. 191 Raise `meerschaum.jobs.StopMonitoringLogs` from a callback to stop monitoring. 192 """ 193 import threading 194 loop = asyncio.get_running_loop() 195 client = self._rust_client() 196 cancelled = threading.Event() 197 try: 198 await loop.run_in_executor( 199 None, 200 lambda: client.monitor_logs( 201 name, 202 _LoopCallback(loop, callback_function), 203 input_callback_function=( 204 _LoopCallback(loop, input_callback_function) 205 if input_callback_function is not None 206 else None 207 ), 208 stop_callback_function=( 209 _LoopCallback(loop, stop_callback_function) 210 if stop_callback_function is not None 211 else None 212 ), 213 stop_on_exit=stop_on_exit, 214 strip_timestamps=strip_timestamps, 215 stop_event=cancelled, 216 ), 217 ) 218 finally: 219 ### A cancelled task ends the stream (the worker thread checks every 100 ms). 220 cancelled.set()
Monitor a job's log files and await a callback with the changes.
The stream runs in the Rust client; coroutine callbacks are awaited on this event loop.
Raise meerschaum.jobs.StopMonitoringLogs from a callback to stop monitoring.
251def get_job_is_blocking_on_stdin(self, name: str, debug: bool = False) -> bool: 252 """ 253 Return whether a remote job is blocking on stdin. 254 """ 255 return self._rust_client().get_job_is_blocking_on_stdin(name)
Return whether a remote job is blocking on stdin.
258def get_job_prompt_kwargs(self, name: str, debug: bool = False) -> Dict[str, Any]: 259 """ 260 Return the kwargs to the blocking `prompt()`, if available. 261 """ 262 return self._rust_client().get_job_prompt_kwargs(name)
Return the kwargs to the blocking prompt(), if available.
71def get_job_began(self, name: str, debug: bool = False) -> Union[str, None]: 72 """ 73 Return a job's `began` timestamp, if it exists. 74 """ 75 return self._rust_client().get_job_began(name)
Return a job's began timestamp, if it exists.
78def get_job_ended(self, name: str, debug: bool = False) -> Union[str, None]: 79 """ 80 Return a job's `ended` timestamp, if it exists. 81 """ 82 return self._rust_client().get_job_ended(name)
Return a job's ended timestamp, if it exists.
85def get_job_paused(self, name: str, debug: bool = False) -> Union[str, None]: 86 """ 87 Return a job's `paused` timestamp, if it exists. 88 """ 89 return self._rust_client().get_job_paused(name)
Return a job's paused timestamp, if it exists.
64def get_job_status(self, name: str, debug: bool = False) -> str: 65 """ 66 Return the job's status. 67 """ 68 return self._rust_client().get_job_status(name)
Return the job's status.
42def get_team_pipes_count(self, name: str, debug: bool = False, **kwargs: Any) -> int: 43 """ 44 Return how many pipes (and saved Pipelines) name a team, as far as you can see them (what 45 deleting the team gives to `Everyone`): `GET /teams/{name}?counts=true`. 46 """ 47 response = self.get(f"/teams/{_segment(name)}", params={'counts': 'true'}, debug=debug) 48 return int(_body(response).get('pipes', 0) or 0)
Return how many pipes (and saved Pipelines) name a team, as far as you can see them (what
deleting the team gives to Everyone): GET /teams/{name}?counts=true.
51def get_team_jobs_count(self, name: str, debug: bool = False, **kwargs: Any) -> int: 52 """ 53 Return how many of the server's jobs belong to a team: `GET /teams/{name}?counts=true`. 54 """ 55 response = self.get(f"/teams/{_segment(name)}", params={'counts': 'true'}, debug=debug) 56 return int(_body(response).get('jobs', 0) or 0)
Return how many of the server's jobs belong to a team: GET /teams/{name}?counts=true.
59def get_users_permissions(self, debug: bool = False, **kwargs: Any) -> List[Dict[str, Any]]: 60 """ 61 Return every user as the server describes them: `username`, `user_type`, `role`, 62 `permissions`, `teams` (`[{'name', 'role'}]`), `primary_team` and `email` (`None` unless it 63 is yours, you are an administrator, or you manage a team the user is in): 64 `GET /users/permissions`. 65 """ 66 response = self.get('/users/permissions', debug=debug) 67 return list(_body(response).get('users', None) or [])
Return every user as the server describes them: username, user_type, role,
permissions, teams ([{'name', 'role'}]), primary_team and email (None unless it
is yours, you are an administrator, or you manage a team the user is in):
GET /users/permissions.
70def get_user_permissions_record( 71 self, 72 user: Any, 73 debug: bool = False, 74 **kwargs: Any 75) -> Dict[str, Any]: 76 """ 77 Return one user as `get_users_permissions()` describes them (`{}` for an unknown user): 78 `GET /users/{username}/permissions`. 79 """ 80 username = str(getattr(user, 'username', user)) 81 response = self.get(f"/users/{_segment(username)}/permissions", debug=debug) 82 if response.status_code == 404: 83 return {} 84 return dict(_body(response).get('user', None) or {})
Return one user as get_users_permissions() describes them ({} for an unknown user):
GET /users/{username}/permissions.
87def get_pipe_access(self, pipe: mrsm.Pipe, debug: bool = False, **kwargs: Any) -> Dict[str, Any]: 88 """ 89 Return a pipe's `access` (`owner`, `team`, `visibility`, `edit`), its `locks` and what you 90 `may` do with it (`edit`, `manage_access`, `lock`): `GET /pipes/{keys}/access`. 91 """ 92 from meerschaum.connectors.api._pipes import pipe_r_url 93 if pipe.connector_keys == 'mrsm' and pipe.metric_key == 'pipeline': 94 r_url = f"/pipelines/{_segment(pipe.location_key)}/access" 95 else: 96 r_url = pipe_r_url(pipe) + '/access' 97 response = self.get( 98 r_url, 99 params={'instance_keys': self.get_pipe_instance_keys(pipe)}, 100 debug=debug, 101 ) 102 body = _body(response) 103 return {key: body.get(key, None) for key in ('access', 'locks', 'may')}
Return a pipe's access (owner, team, visibility, edit), its locks and what you
may do with it (edit, manage_access, lock): GET /pipes/{keys}/access.