meerschaum 3.0.0rc4__py3-none-any.whl → 3.0.0rc7__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 (117) hide show
  1. meerschaum/_internal/arguments/_parser.py +14 -2
  2. meerschaum/_internal/cli/__init__.py +6 -0
  3. meerschaum/_internal/cli/daemons.py +103 -0
  4. meerschaum/_internal/cli/entry.py +220 -0
  5. meerschaum/_internal/cli/workers.py +434 -0
  6. meerschaum/_internal/docs/index.py +1 -2
  7. meerschaum/_internal/entry.py +44 -8
  8. meerschaum/_internal/shell/Shell.py +113 -19
  9. meerschaum/_internal/shell/__init__.py +4 -1
  10. meerschaum/_internal/static.py +3 -1
  11. meerschaum/_internal/term/TermPageHandler.py +1 -2
  12. meerschaum/_internal/term/__init__.py +40 -6
  13. meerschaum/_internal/term/tools.py +33 -8
  14. meerschaum/actions/__init__.py +6 -4
  15. meerschaum/actions/api.py +39 -11
  16. meerschaum/actions/attach.py +1 -0
  17. meerschaum/actions/delete.py +4 -2
  18. meerschaum/actions/edit.py +27 -8
  19. meerschaum/actions/login.py +8 -8
  20. meerschaum/actions/register.py +13 -7
  21. meerschaum/actions/reload.py +22 -5
  22. meerschaum/actions/restart.py +14 -0
  23. meerschaum/actions/show.py +69 -4
  24. meerschaum/actions/start.py +135 -14
  25. meerschaum/actions/stop.py +36 -3
  26. meerschaum/actions/sync.py +6 -1
  27. meerschaum/api/__init__.py +35 -13
  28. meerschaum/api/_events.py +2 -2
  29. meerschaum/api/_oauth2.py +47 -4
  30. meerschaum/api/dash/callbacks/dashboard.py +29 -0
  31. meerschaum/api/dash/callbacks/jobs.py +3 -2
  32. meerschaum/api/dash/callbacks/login.py +10 -1
  33. meerschaum/api/dash/callbacks/register.py +9 -2
  34. meerschaum/api/dash/pages/login.py +2 -2
  35. meerschaum/api/dash/pipes.py +72 -36
  36. meerschaum/api/dash/webterm.py +14 -6
  37. meerschaum/api/models/_pipes.py +7 -1
  38. meerschaum/api/resources/static/js/terminado.js +3 -0
  39. meerschaum/api/resources/static/js/xterm-addon-unicode11.js +2 -0
  40. meerschaum/api/resources/templates/termpage.html +1 -0
  41. meerschaum/api/routes/_jobs.py +23 -11
  42. meerschaum/api/routes/_login.py +73 -5
  43. meerschaum/api/routes/_pipes.py +6 -4
  44. meerschaum/api/routes/_webterm.py +3 -3
  45. meerschaum/config/__init__.py +60 -13
  46. meerschaum/config/_default.py +89 -61
  47. meerschaum/config/_edit.py +10 -8
  48. meerschaum/config/_formatting.py +2 -0
  49. meerschaum/config/_patch.py +4 -2
  50. meerschaum/config/_paths.py +127 -12
  51. meerschaum/config/_read_config.py +20 -10
  52. meerschaum/config/_version.py +1 -1
  53. meerschaum/config/environment.py +262 -0
  54. meerschaum/config/stack/__init__.py +7 -5
  55. meerschaum/connectors/_Connector.py +1 -2
  56. meerschaum/connectors/__init__.py +37 -2
  57. meerschaum/connectors/api/_APIConnector.py +1 -1
  58. meerschaum/connectors/api/_jobs.py +11 -0
  59. meerschaum/connectors/api/_pipes.py +7 -1
  60. meerschaum/connectors/instance/_plugins.py +9 -1
  61. meerschaum/connectors/instance/_tokens.py +20 -3
  62. meerschaum/connectors/instance/_users.py +8 -1
  63. meerschaum/connectors/parse.py +1 -1
  64. meerschaum/connectors/sql/_create_engine.py +3 -0
  65. meerschaum/connectors/sql/_pipes.py +93 -79
  66. meerschaum/connectors/sql/_users.py +8 -1
  67. meerschaum/connectors/valkey/_ValkeyConnector.py +3 -3
  68. meerschaum/connectors/valkey/_pipes.py +7 -5
  69. meerschaum/core/Pipe/__init__.py +45 -71
  70. meerschaum/core/Pipe/_attributes.py +66 -90
  71. meerschaum/core/Pipe/_cache.py +555 -0
  72. meerschaum/core/Pipe/_clear.py +0 -11
  73. meerschaum/core/Pipe/_data.py +0 -50
  74. meerschaum/core/Pipe/_deduplicate.py +0 -13
  75. meerschaum/core/Pipe/_delete.py +12 -21
  76. meerschaum/core/Pipe/_drop.py +11 -23
  77. meerschaum/core/Pipe/_dtypes.py +1 -1
  78. meerschaum/core/Pipe/_index.py +8 -14
  79. meerschaum/core/Pipe/_sync.py +12 -18
  80. meerschaum/core/Plugin/_Plugin.py +7 -1
  81. meerschaum/core/Token/_Token.py +1 -1
  82. meerschaum/core/User/_User.py +1 -2
  83. meerschaum/jobs/_Executor.py +88 -4
  84. meerschaum/jobs/_Job.py +135 -35
  85. meerschaum/jobs/systemd.py +7 -2
  86. meerschaum/plugins/__init__.py +277 -81
  87. meerschaum/utils/daemon/Daemon.py +195 -41
  88. meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -1
  89. meerschaum/utils/daemon/RotatingFile.py +63 -36
  90. meerschaum/utils/daemon/StdinFile.py +53 -13
  91. meerschaum/utils/daemon/__init__.py +18 -5
  92. meerschaum/utils/daemon/_names.py +6 -3
  93. meerschaum/utils/debug.py +34 -4
  94. meerschaum/utils/dtypes/__init__.py +5 -1
  95. meerschaum/utils/formatting/__init__.py +4 -1
  96. meerschaum/utils/formatting/_jobs.py +1 -1
  97. meerschaum/utils/formatting/_pipes.py +47 -46
  98. meerschaum/utils/formatting/_shell.py +16 -6
  99. meerschaum/utils/misc.py +18 -38
  100. meerschaum/utils/packages/__init__.py +15 -13
  101. meerschaum/utils/packages/_packages.py +1 -0
  102. meerschaum/utils/pipes.py +33 -5
  103. meerschaum/utils/process.py +1 -1
  104. meerschaum/utils/prompt.py +171 -144
  105. meerschaum/utils/sql.py +12 -2
  106. meerschaum/utils/threading.py +42 -0
  107. meerschaum/utils/venv/__init__.py +2 -0
  108. meerschaum/utils/warnings.py +19 -13
  109. {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/METADATA +3 -1
  110. {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/RECORD +116 -110
  111. meerschaum/config/_environment.py +0 -145
  112. {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/WHEEL +0 -0
  113. {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/entry_points.txt +0 -0
  114. {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/licenses/LICENSE +0 -0
  115. {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/licenses/NOTICE +0 -0
  116. {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/top_level.txt +0 -0
  117. {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/zip-safe +0 -0
@@ -7,12 +7,13 @@ Functions for interacting with the Webterm via the dashboard.
7
7
  """
8
8
 
9
9
  import time
10
+ from typing import Optional, Tuple, Any
10
11
 
11
12
  import meerschaum as mrsm
12
- from meerschaum.api import CHECK_UPDATE, get_api_connector
13
+ from meerschaum.api import CHECK_UPDATE, get_api_connector, webterm_port
13
14
  from meerschaum.api.dash.sessions import is_session_authenticated, get_username_from_session
14
15
  from meerschaum.api.dash.components import alert_from_success_tuple, console_div
15
- from meerschaum.utils.typing import WebState, Tuple, Any
16
+ from meerschaum.utils.typing import WebState
16
17
  from meerschaum.utils.packages import attempt_import, import_html, import_dcc
17
18
  from meerschaum._internal.term.tools import is_webterm_running
18
19
  from meerschaum.utils.threading import Thread, RLock
@@ -22,7 +23,7 @@ dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK
22
23
 
23
24
  MAX_WEBTERM_ATTEMPTS: int = 10
24
25
  TMUX_IS_ENABLED: bool = (
25
- is_tmux_available() and mrsm.get_config('system', 'webterm', 'tmux', 'enabled')
26
+ is_tmux_available() and mrsm.get_config('api', 'webterm', 'tmux', 'enabled')
26
27
  )
27
28
 
28
29
  _locks = {'webterm_thread': RLock()}
@@ -51,7 +52,7 @@ def get_webterm(state: WebState) -> Tuple[Any, Any]:
51
52
  )
52
53
 
53
54
  for i in range(MAX_WEBTERM_ATTEMPTS):
54
- if is_webterm_running('localhost', 8765, session_id=(username or session_id)):
55
+ if is_webterm_running('localhost', webterm_port, session_id=(username or session_id)):
55
56
  return (
56
57
  [
57
58
  html.Div(
@@ -91,7 +92,7 @@ def get_webterm(state: WebState) -> Tuple[Any, Any]:
91
92
 
92
93
 
93
94
  webterm_procs = {}
94
- def start_webterm() -> None:
95
+ def start_webterm(webterm_port: Optional[int] = None) -> None:
95
96
  """
96
97
  Start the webterm thread.
97
98
  """
@@ -101,7 +102,14 @@ def start_webterm() -> None:
101
102
  conn = get_api_connector()
102
103
  _ = run_python_package(
103
104
  'meerschaum',
104
- ['start', 'webterm', '-i', str(conn)],
105
+ (
106
+ ['start', 'webterm', '-i', str(conn)]
107
+ + (
108
+ []
109
+ if not webterm_port
110
+ else ['-p', str(webterm_port)]
111
+ )
112
+ ),
105
113
  capture_output=True,
106
114
  as_proc=True,
107
115
  store_proc_dict=webterm_procs,
@@ -54,7 +54,13 @@ class PipeModel(BasePipeModel):
54
54
 
55
55
 
56
56
  class FetchPipesKeysResponseModel(
57
- RootModel[List[Tuple[ConnectorKeysModel, MetricKeyModel, LocationKeyModel]]]
57
+ RootModel[
58
+ Union[
59
+ List[Tuple[ConnectorKeysModel, MetricKeyModel, LocationKeyModel]],
60
+ List[Tuple[ConnectorKeysModel, MetricKeyModel, LocationKeyModel, Dict[str, Any]]],
61
+ List[Tuple[ConnectorKeysModel, MetricKeyModel, LocationKeyModel, List[str]]],
62
+ ]
63
+ ]
58
64
  ):
59
65
  """
60
66
  A list of tuples containing connector, metric, and location keys.
@@ -11,7 +11,10 @@ function make_terminal(element, size, ws_url) {
11
11
  useStyle: true,
12
12
  scrollback: 9999999,
13
13
  cursorBlink: true,
14
+ allowProposedApi: true
14
15
  });
16
+ term.loadAddon(new Unicode11Addon.Unicode11Addon());
17
+ term.unicode.activeVersion = '11';
15
18
  term.attachCustomKeyEventHandler(copyPasteKeyEventHandler);
16
19
  term.open(element);
17
20
 
@@ -0,0 +1,2 @@
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Unicode11Addon=t():e.Unicode11Addon=t()}(this,(()=>(()=>{"use strict";var e={433:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV11=void 0;const r=i(938),s=[[768,879],[1155,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1541],[1552,1562],[1564,1564],[1611,1631],[1648,1648],[1750,1757],[1759,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2045,2045],[2070,2073],[2075,2083],[2085,2087],[2089,2093],[2137,2139],[2259,2306],[2362,2362],[2364,2364],[2369,2376],[2381,2381],[2385,2391],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2558,2558],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2641,2641],[2672,2673],[2677,2677],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2810,2815],[2817,2817],[2876,2876],[2879,2879],[2881,2884],[2893,2893],[2902,2902],[2914,2915],[2946,2946],[3008,3008],[3021,3021],[3072,3072],[3076,3076],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3170,3171],[3201,3201],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3328,3329],[3387,3388],[3393,3396],[3405,3405],[3426,3427],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3981,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4151],[4153,4154],[4157,4158],[4184,4185],[4190,4192],[4209,4212],[4226,4226],[4229,4230],[4237,4237],[4253,4253],[4448,4607],[4957,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6158],[6277,6278],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6683,6683],[6742,6742],[6744,6750],[6752,6752],[6754,6754],[6757,6764],[6771,6780],[6783,6783],[6832,6846],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7040,7041],[7074,7077],[7080,7081],[7083,7085],[7142,7142],[7144,7145],[7149,7149],[7151,7153],[7212,7219],[7222,7223],[7376,7378],[7380,7392],[7394,7400],[7405,7405],[7412,7412],[7416,7417],[7616,7673],[7675,7679],[8203,8207],[8234,8238],[8288,8292],[8294,8303],[8400,8432],[11503,11505],[11647,11647],[11744,11775],[12330,12333],[12441,12442],[42607,42610],[42612,42621],[42654,42655],[42736,42737],[43010,43010],[43014,43014],[43019,43019],[43045,43046],[43204,43205],[43232,43249],[43263,43263],[43302,43309],[43335,43345],[43392,43394],[43443,43443],[43446,43449],[43452,43453],[43493,43493],[43561,43566],[43569,43570],[43573,43574],[43587,43587],[43596,43596],[43644,43644],[43696,43696],[43698,43700],[43703,43704],[43710,43711],[43713,43713],[43756,43757],[43766,43766],[44005,44005],[44008,44008],[44013,44013],[64286,64286],[65024,65039],[65056,65071],[65279,65279],[65529,65531]],n=[[66045,66045],[66272,66272],[66422,66426],[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[68325,68326],[68900,68903],[69446,69456],[69633,69633],[69688,69702],[69759,69761],[69811,69814],[69817,69818],[69821,69821],[69837,69837],[69888,69890],[69927,69931],[69933,69940],[70003,70003],[70016,70017],[70070,70078],[70089,70092],[70191,70193],[70196,70196],[70198,70199],[70206,70206],[70367,70367],[70371,70378],[70400,70401],[70459,70460],[70464,70464],[70502,70508],[70512,70516],[70712,70719],[70722,70724],[70726,70726],[70750,70750],[70835,70840],[70842,70842],[70847,70848],[70850,70851],[71090,71093],[71100,71101],[71103,71104],[71132,71133],[71219,71226],[71229,71229],[71231,71232],[71339,71339],[71341,71341],[71344,71349],[71351,71351],[71453,71455],[71458,71461],[71463,71467],[71727,71735],[71737,71738],[72148,72151],[72154,72155],[72160,72160],[72193,72202],[72243,72248],[72251,72254],[72263,72263],[72273,72278],[72281,72283],[72330,72342],[72344,72345],[72752,72758],[72760,72765],[72767,72767],[72850,72871],[72874,72880],[72882,72883],[72885,72886],[73009,73014],[73018,73018],[73020,73021],[73023,73029],[73031,73031],[73104,73105],[73109,73109],[73111,73111],[73459,73460],[78896,78904],[92912,92916],[92976,92982],[94031,94031],[94095,94098],[113821,113822],[113824,113827],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[121344,121398],[121403,121452],[121461,121461],[121476,121476],[121499,121503],[121505,121519],[122880,122886],[122888,122904],[122907,122913],[122915,122916],[122918,122922],[123184,123190],[123628,123631],[125136,125142],[125252,125258],[917505,917505],[917536,917631],[917760,917999]],o=[[4352,4447],[8986,8987],[9001,9002],[9193,9196],[9200,9200],[9203,9203],[9725,9726],[9748,9749],[9800,9811],[9855,9855],[9875,9875],[9889,9889],[9898,9899],[9917,9918],[9924,9925],[9934,9934],[9940,9940],[9962,9962],[9970,9971],[9973,9973],[9978,9978],[9981,9981],[9989,9989],[9994,9995],[10024,10024],[10060,10060],[10062,10062],[10067,10069],[10071,10071],[10133,10135],[10160,10160],[10175,10175],[11035,11036],[11088,11088],[11093,11093],[11904,11929],[11931,12019],[12032,12245],[12272,12283],[12288,12329],[12334,12350],[12353,12438],[12443,12543],[12549,12591],[12593,12686],[12688,12730],[12736,12771],[12784,12830],[12832,12871],[12880,19903],[19968,42124],[42128,42182],[43360,43388],[44032,55203],[63744,64255],[65040,65049],[65072,65106],[65108,65126],[65128,65131],[65281,65376],[65504,65510]],c=[[94176,94179],[94208,100343],[100352,101106],[110592,110878],[110928,110930],[110948,110951],[110960,111355],[126980,126980],[127183,127183],[127374,127374],[127377,127386],[127488,127490],[127504,127547],[127552,127560],[127568,127569],[127584,127589],[127744,127776],[127789,127797],[127799,127868],[127870,127891],[127904,127946],[127951,127955],[127968,127984],[127988,127988],[127992,128062],[128064,128064],[128066,128252],[128255,128317],[128331,128334],[128336,128359],[128378,128378],[128405,128406],[128420,128420],[128507,128591],[128640,128709],[128716,128716],[128720,128722],[128725,128725],[128747,128748],[128756,128762],[128992,129003],[129293,129393],[129395,129398],[129402,129442],[129445,129450],[129454,129482],[129485,129535],[129648,129651],[129656,129658],[129664,129666],[129680,129685],[131072,196605],[196608,262141]];let l;function d(e,t){let i,r=0,s=t.length-1;if(e<t[0][0]||e>t[s][1])return!1;for(;s>=r;)if(i=r+s>>1,e>t[i][1])r=i+1;else{if(!(e<t[i][0]))return!0;s=i-1}return!1}t.UnicodeV11=class{constructor(){if(this.version="11",!l){l=new Uint8Array(65536),l.fill(1),l[0]=0,l.fill(0,1,32),l.fill(0,127,160);for(let e=0;e<s.length;++e)l.fill(0,s[e][0],s[e][1]+1);for(let e=0;e<o.length;++e)l.fill(2,o[e][0],o[e][1]+1)}}wcwidth(e){return e<32?0:e<127?1:e<65536?l[e]:d(e,n)?0:d(e,c)?2:1}charProperties(e,t){let i=this.wcwidth(e),s=0===i&&0!==t;if(s){const e=r.UnicodeService.extractWidth(t);0===e?s=!1:e>i&&(i=e)}return r.UnicodeService.createPropertyValue(0,i,s)}}},345:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.runAndSubscribe=t.forwardEvent=t.EventEmitter=void 0,t.EventEmitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=e=>(this._listeners.push(e),{dispose:()=>{if(!this._disposed)for(let t=0;t<this._listeners.length;t++)if(this._listeners[t]===e)return void this._listeners.splice(t,1)}})),this._event}fire(e,t){const i=[];for(let e=0;e<this._listeners.length;e++)i.push(this._listeners[e]);for(let r=0;r<i.length;r++)i[r].call(void 0,e,t)}dispose(){this.clearListeners(),this._disposed=!0}clearListeners(){this._listeners&&(this._listeners.length=0)}},t.forwardEvent=function(e,t){return e((e=>t.fire(e)))},t.runAndSubscribe=function(e,t){return t(void 0),e((e=>t(e)))}},490:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV6=void 0;const r=i(938),s=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531]],n=[[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]];let o;t.UnicodeV6=class{constructor(){if(this.version="6",!o){o=new Uint8Array(65536),o.fill(1),o[0]=0,o.fill(0,1,32),o.fill(0,127,160),o.fill(2,4352,4448),o[9001]=2,o[9002]=2,o.fill(2,11904,42192),o[12351]=1,o.fill(2,44032,55204),o.fill(2,63744,64256),o.fill(2,65040,65050),o.fill(2,65072,65136),o.fill(2,65280,65377),o.fill(2,65504,65511);for(let e=0;e<s.length;++e)o.fill(0,s[e][0],s[e][1]+1)}}wcwidth(e){return e<32?0:e<127?1:e<65536?o[e]:function(e,t){let i,r=0,s=t.length-1;if(e<t[0][0]||e>t[s][1])return!1;for(;s>=r;)if(i=r+s>>1,e>t[i][1])r=i+1;else{if(!(e<t[i][0]))return!0;s=i-1}return!1}(e,n)?0:e>=131072&&e<=196605||e>=196608&&e<=262141?2:1}charProperties(e,t){let i=this.wcwidth(e),s=0===i&&0!==t;if(s){const e=r.UnicodeService.extractWidth(t);0===e?s=!1:e>i&&(i=e)}return r.UnicodeService.createPropertyValue(0,i,s)}}},938:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeService=void 0;const r=i(345),s=i(490);class n{static extractShouldJoin(e){return 0!=(1&e)}static extractWidth(e){return e>>1&3}static extractCharKind(e){return e>>3}static createPropertyValue(e,t,i=!1){return(16777215&e)<<3|(3&t)<<1|(i?1:0)}constructor(){this._providers=Object.create(null),this._active="",this._onChange=new r.EventEmitter,this.onChange=this._onChange.event;const e=new s.UnicodeV6;this.register(e),this._active=e.version,this._activeProvider=e}dispose(){this._onChange.dispose()}get versions(){return Object.keys(this._providers)}get activeVersion(){return this._active}set activeVersion(e){if(!this._providers[e])throw new Error(`unknown Unicode version "${e}"`);this._active=e,this._activeProvider=this._providers[e],this._onChange.fire(e)}register(e){this._providers[e.version]=e}wcwidth(e){return this._activeProvider.wcwidth(e)}getStringCellWidth(e){let t=0,i=0;const r=e.length;for(let s=0;s<r;++s){let o=e.charCodeAt(s);if(55296<=o&&o<=56319){if(++s>=r)return t+this.wcwidth(o);const i=e.charCodeAt(s);56320<=i&&i<=57343?o=1024*(o-55296)+i-56320+65536:t+=this.wcwidth(i)}const c=this.charProperties(o,i);let l=n.extractWidth(c);n.extractShouldJoin(c)&&(l-=n.extractWidth(i)),t+=l,i=c}return t}charProperties(e,t){return this._activeProvider.charProperties(e,t)}}t.UnicodeService=n}},t={};function i(r){var s=t[r];if(void 0!==s)return s.exports;var n=t[r]={exports:{}};return e[r](n,n.exports,i),n.exports}var r={};return(()=>{var e=r;Object.defineProperty(e,"__esModule",{value:!0}),e.Unicode11Addon=void 0;const t=i(433);e.Unicode11Addon=class{activate(e){e.unicode.register(new t.UnicodeV11)}dispose(){}}})(),r})()));
2
+ //# sourceMappingURL=addon-unicode11.js.map
@@ -9,6 +9,7 @@
9
9
  </style>
10
10
  <link rel="stylesheet" href="{{ static('css/xterm.css') }}"/>
11
11
  <script src="{{ static('js/xterm.js') }}"></script>
12
+ <script src="{{ static('js/xterm-addon-unicode11.js') }}"></script>
12
13
  <script src="{{ static('js/terminado.js') }}"></script>
13
14
  <script>
14
15
 
@@ -54,7 +54,7 @@ def _get_job(name: str, sysargs: Union[str, List[str], None] = None):
54
54
 
55
55
  @app.get(endpoints['jobs'], tags=['Jobs'])
56
56
  def get_jobs(
57
- curr_user=fastapi.Depends(ScopedAuth(['jobs:read'])),
57
+ curr_user=fastapi.Security(ScopedAuth(['jobs:read'])),
58
58
  ) -> Dict[str, Dict[str, Any]]:
59
59
  """
60
60
  Return metadata about the current jobs.
@@ -83,7 +83,7 @@ def get_jobs(
83
83
  @app.get(endpoints['jobs'] + '/{name}', tags=['Jobs'])
84
84
  def get_job(
85
85
  name: str,
86
- curr_user=fastapi.Depends(ScopedAuth(['jobs:read'])),
86
+ curr_user=fastapi.Security(ScopedAuth(['jobs:read'])),
87
87
  ) -> Dict[str, Any]:
88
88
  """
89
89
  Return metadata for a single job.
@@ -134,7 +134,7 @@ def clean_sysargs(sysargs: List[str]) -> List[str]:
134
134
  def create_job(
135
135
  name: str,
136
136
  metadata: Union[List[str], Dict[str, Any]],
137
- curr_user=fastapi.Depends(ScopedAuth(['jobs:execute', 'jobs:write'])),
137
+ curr_user=fastapi.Security(ScopedAuth(['jobs:execute', 'jobs:write'])),
138
138
  ) -> SuccessTuple:
139
139
  """
140
140
  Create and start a new job.
@@ -167,7 +167,7 @@ def create_job(
167
167
  @app.delete(endpoints['jobs'] + '/{name}', tags=['Jobs'])
168
168
  def delete_job(
169
169
  name: str,
170
- curr_user=fastapi.Depends(ScopedAuth(['jobs:delete'])),
170
+ curr_user=fastapi.Security(ScopedAuth(['jobs:delete'])),
171
171
  ) -> SuccessTuple:
172
172
  """
173
173
  Delete a job.
@@ -182,7 +182,7 @@ def delete_job(
182
182
  @app.get(endpoints['jobs'] + '/{name}/exists', tags=['Jobs'])
183
183
  def get_job_exists(
184
184
  name: str,
185
- curr_user=fastapi.Depends(ScopedAuth(['jobs:read'])),
185
+ curr_user=fastapi.Security(ScopedAuth(['jobs:read'])),
186
186
  ) -> bool:
187
187
  """
188
188
  Return whether a job exists.
@@ -194,7 +194,7 @@ def get_job_exists(
194
194
  @app.get(endpoints['logs'] + '/{name}', tags=['Jobs'])
195
195
  def get_logs(
196
196
  name: str,
197
- curr_user=fastapi.Depends(ScopedAuth(['jobs:read', 'logs:read'])),
197
+ curr_user=fastapi.Security(ScopedAuth(['jobs:read', 'logs:read'])),
198
198
  ) -> Union[str, None]:
199
199
  """
200
200
  Return a job's log text.
@@ -213,7 +213,7 @@ def get_logs(
213
213
  @app.post(endpoints['jobs'] + '/{name}/start', tags=['Jobs'])
214
214
  def start_job(
215
215
  name: str,
216
- curr_user=fastapi.Depends(ScopedAuth(['jobs:execute'])),
216
+ curr_user=fastapi.Security(ScopedAuth(['jobs:execute'])),
217
217
  ) -> SuccessTuple:
218
218
  """
219
219
  Start a job if stopped.
@@ -234,7 +234,7 @@ def start_job(
234
234
  @app.post(endpoints['jobs'] + '/{name}/stop', tags=['Jobs'])
235
235
  def stop_job(
236
236
  name: str,
237
- curr_user=fastapi.Depends(ScopedAuth(['jobs:execute', 'josb:stop'])),
237
+ curr_user=fastapi.Security(ScopedAuth(['jobs:execute', 'josb:stop'])),
238
238
  ) -> SuccessTuple:
239
239
  """
240
240
  Stop a job if running.
@@ -255,7 +255,7 @@ def stop_job(
255
255
  @app.post(endpoints['jobs'] + '/{name}/pause', tags=['Jobs'])
256
256
  def pause_job(
257
257
  name: str,
258
- curr_user=fastapi.Depends(ScopedAuth(['jobs:execute', 'jobs:pause'])),
258
+ curr_user=fastapi.Security(ScopedAuth(['jobs:execute', 'jobs:pause'])),
259
259
  ) -> SuccessTuple:
260
260
  """
261
261
  Pause a job if running.
@@ -276,7 +276,7 @@ def pause_job(
276
276
  @app.get(endpoints['jobs'] + '/{name}/stop_time', tags=['Jobs'])
277
277
  def get_stop_time(
278
278
  name: str,
279
- curr_user=fastapi.Depends(ScopedAuth(['jobs:read'])),
279
+ curr_user=fastapi.Security(ScopedAuth(['jobs:read'])),
280
280
  ) -> Union[datetime, None]:
281
281
  """
282
282
  Get the timestamp when the job was manually stopped.
@@ -288,7 +288,7 @@ def get_stop_time(
288
288
  @app.get(endpoints['jobs'] + '/{name}/is_blocking_on_stdin', tags=['Jobs'])
289
289
  def get_is_blocking_on_stdin(
290
290
  name: str,
291
- curr_user=fastapi.Depends(ScopedAuth(['jobs:read'])),
291
+ curr_user=fastapi.Security(ScopedAuth(['jobs:read'])),
292
292
  ) -> bool:
293
293
  """
294
294
  Return whether a job is blocking on stdin.
@@ -297,6 +297,18 @@ def get_is_blocking_on_stdin(
297
297
  return job.is_blocking_on_stdin()
298
298
 
299
299
 
300
+ @app.get(endpoints['jobs'] + '{name}/prompt_kwargs', tags=['Jobs'])
301
+ def get_prompt_kwargs(
302
+ name: str,
303
+ curr_user=fastapi.Security(ScopedAuth(['jobs:read'])),
304
+ ) -> Dict[str, Any]:
305
+ """
306
+ Return the kwargs for the blocking `prompt`, if available.
307
+ """
308
+ job = _get_job(name)
309
+ return job.get_prompt_kwargs()
310
+
311
+
300
312
  _job_clients = defaultdict(lambda: [])
301
313
  _job_stop_events = defaultdict(lambda: asyncio.Event())
302
314
  _job_queues = defaultdict(lambda: asyncio.Queue())
@@ -16,22 +16,69 @@ from fastapi_login.exceptions import InvalidCredentialsException
16
16
  from fastapi.exceptions import RequestValidationError
17
17
  from starlette.responses import JSONResponse
18
18
 
19
- from meerschaum.api import endpoints, get_api_connector, app, debug, manager, no_auth
19
+ import meerschaum as mrsm
20
+ from meerschaum.api import (
21
+ endpoints,
22
+ get_api_connector,
23
+ get_cache_connector,
24
+ app,
25
+ debug,
26
+ manager,
27
+ no_auth,
28
+ )
20
29
  from meerschaum.core import User
21
30
  from meerschaum._internal.static import STATIC_CONFIG
22
31
  from meerschaum.utils.typing import Dict, Any
23
- from meerschaum.utils.misc import is_uuid
32
+ from meerschaum.utils.misc import is_uuid, is_int
24
33
  from meerschaum.core.User import verify_password
25
34
  from meerschaum.utils.warnings import warn
26
35
  from meerschaum.api._oauth2 import CustomOAuth2PasswordRequestForm
27
36
 
28
37
 
38
+ USER_ID_CACHE_EXPIRES_SECONDS: int = mrsm.get_config('system', 'api', 'cache', 'session_expires_minutes') * 60
39
+ _active_user_ids = {}
40
+
41
+
29
42
  @manager.user_loader()
30
- def load_user(username: str) -> User:
43
+ def load_user_or_token_from_manager(username_or_token_id: str) -> User:
31
44
  """
32
45
  Create the `meerschaum.core.User` object from the username.
33
46
  """
34
- return User(username, instance=get_api_connector())
47
+ cache_conn = get_cache_connector()
48
+ api_conn = get_api_connector()
49
+
50
+ is_token = is_uuid(username_or_token_id)
51
+
52
+ if is_token:
53
+ return api_conn.get_token(username_or_token_id)
54
+
55
+ username = username_or_token_id
56
+
57
+ cached_user_id = (
58
+ _active_user_ids.get(username)
59
+ if cache_conn is None
60
+ else cache_conn.get(f'mrsm:users:{username}:id')
61
+ )
62
+ if isinstance(cached_user_id, str):
63
+ if is_int(cached_user_id):
64
+ cached_user_id = int(cached_user_id)
65
+ elif is_uuid(cached_user_id):
66
+ cached_user_id = uuid.UUID(cached_user_id)
67
+
68
+ user = User(username, instance=api_conn, user_id=cached_user_id)
69
+
70
+ if cached_user_id is not None:
71
+ return user
72
+
73
+ user_id = api_conn.get_user_id(user)
74
+ if user_id is not None:
75
+ user._user_id = user_id
76
+ if cache_conn is not None:
77
+ cache_conn.set(f'mrsm:users:{username}:id', str(user_id), ex=USER_ID_CACHE_EXPIRES_SECONDS)
78
+ else:
79
+ _active_user_ids[username] = user_id
80
+ return user
81
+
35
82
 
36
83
 
37
84
  @app.post(endpoints['login'], tags=['Users'])
@@ -63,7 +110,10 @@ def login(
63
110
  else 'client_credentials'
64
111
  )
65
112
 
113
+ allowed_scopes = []
114
+ type_ = None
66
115
  expires_dt: Union[datetime, None] = None
116
+ sub_id = None
67
117
  if grant_type == 'password':
68
118
  user = User(str(username), str(password), instance=get_api_connector())
69
119
  correct_password = no_auth or verify_password(
@@ -73,6 +123,10 @@ def login(
73
123
  if not correct_password:
74
124
  raise InvalidCredentialsException
75
125
 
126
+ allowed_scopes = user.get_scopes(debug=debug)
127
+ type_ = get_api_connector().get_user_type(user, debug=debug)
128
+ sub_id = username
129
+
76
130
  elif grant_type == 'client_credentials':
77
131
  if not is_uuid(str(client_id)):
78
132
  raise InvalidCredentialsException
@@ -83,15 +137,29 @@ def login(
83
137
  )
84
138
  if not correct_password:
85
139
  raise InvalidCredentialsException
140
+
141
+ allowed_scopes = get_api_connector().get_token_scopes(token_id, debug=debug)
142
+ sub_id = client_id
143
+
86
144
  else:
87
145
  raise InvalidCredentialsException
88
146
 
147
+ requested_scopes = data.scope.split()
148
+ if '*' in allowed_scopes:
149
+ final_scopes = requested_scopes or ['*']
150
+ else:
151
+ final_scopes = [
152
+ s for s in requested_scopes if s in allowed_scopes
153
+ ] if requested_scopes else allowed_scopes
154
+
89
155
  expires_minutes = STATIC_CONFIG['api']['oauth']['token_expires_minutes']
90
156
  expires_delta = timedelta(minutes=expires_minutes)
91
157
  expires_dt = datetime.now(timezone.utc).replace(tzinfo=None) + expires_delta
92
158
  access_token = manager.create_access_token(
93
159
  data={
94
- 'sub': (username if grant_type == 'password' else client_id),
160
+ 'sub': sub_id,
161
+ 'scopes': final_scopes,
162
+ 'type': type_,
95
163
  },
96
164
  expires=expires_delta
97
165
  )
@@ -25,6 +25,7 @@ from meerschaum.api import (
25
25
  _get_pipes,
26
26
  debug,
27
27
  ScopedAuth,
28
+ manager,
28
29
  )
29
30
  from meerschaum.models import (
30
31
  ConnectorKeysModel,
@@ -148,7 +149,7 @@ def delete_pipe(
148
149
  location_key: str,
149
150
  instance_keys: Optional[str] = None,
150
151
  curr_user = fastapi.Security(ScopedAuth(['pipes:delete'])),
151
- ) -> SuccessTuple:
152
+ ) -> mrsm.SuccessTuple:
152
153
  """
153
154
  Delete a Pipe (without dropping its table).
154
155
  """
@@ -187,7 +188,10 @@ async def fetch_pipes_keys(
187
188
  tags=json.loads(tags),
188
189
  params=json.loads(params),
189
190
  )
190
- return keys
191
+ return [
192
+ (keys_tuple[0], keys_tuple[1], keys_tuple[2])
193
+ for keys_tuple in keys
194
+ ]
191
195
 
192
196
 
193
197
  @app.get(pipes_endpoint, tags=['Pipes: Attributes'])
@@ -197,7 +201,6 @@ async def get_pipes(
197
201
  location_keys: str = "",
198
202
  instance_keys: str = "",
199
203
  curr_user=fastapi.Security(ScopedAuth(['pipes:read'])),
200
- debug: bool = False,
201
204
  ) -> PipesWithParametersDictModel:
202
205
  """
203
206
  Get all registered Pipes with metadata, excluding parameters.
@@ -384,7 +387,6 @@ async def sync_pipe(
384
387
  workers: Optional[int] = None,
385
388
  columns: Optional[str] = None,
386
389
  curr_user = fastapi.Security(ScopedAuth(['pipes:write'])),
387
- debug: bool = False,
388
390
  ) -> mrsm.SuccessTuple:
389
391
  """
390
392
  Add data to an existing Pipe.
@@ -8,7 +8,7 @@ Routes to the Webterm proxy.
8
8
 
9
9
  import asyncio
10
10
  from meerschaum.utils.typing import Optional
11
- from meerschaum.api import app, endpoints
11
+ from meerschaum.api import app, endpoints, webterm_port
12
12
  from meerschaum.utils.packages import attempt_import
13
13
  from meerschaum.api.dash.sessions import is_session_authenticated, get_username_from_session
14
14
  fastapi, fastapi_responses = attempt_import('fastapi', 'fastapi.responses')
@@ -71,7 +71,7 @@ async def get_webterm(
71
71
 
72
72
  username = get_username_from_session(session_id)
73
73
  async with httpx.AsyncClient() as client:
74
- webterm_url = f"http://localhost:8765/webterm/{username or session_id}"
74
+ webterm_url = f"http://localhost:{webterm_port}/webterm/{username or session_id}"
75
75
  response = await client.get(webterm_url)
76
76
  text = response.text
77
77
  if request.url.scheme == 'https':
@@ -100,7 +100,7 @@ async def webterm_websocket(websocket: WebSocket, session_id: str):
100
100
 
101
101
  username = get_username_from_session(session_id)
102
102
 
103
- ws_url = f"ws://localhost:8765/websocket/{username or session_id}"
103
+ ws_url = f"ws://localhost:{webterm_port}/websocket/{username or session_id}"
104
104
  async with websockets.connect(ws_url) as ws:
105
105
  async def forward_messages():
106
106
  try:
@@ -13,8 +13,9 @@ import os
13
13
  import shutil
14
14
  import sys
15
15
  import copy
16
+ import contextlib
16
17
 
17
- from meerschaum.utils.typing import Any, Dict, Optional
18
+ from meerschaum.utils.typing import Any, Dict, Optional, Union
18
19
  from meerschaum.utils.threading import RLock
19
20
 
20
21
  from meerschaum.config._version import __version__
@@ -43,6 +44,7 @@ __all__ = (
43
44
  'write_config',
44
45
  'edit_config',
45
46
  'set_config',
47
+ 'replace_config',
46
48
  'search_and_substitute_config',
47
49
  'revert_symlinks_config',
48
50
  'get_possible_keys',
@@ -57,17 +59,23 @@ _locks = {'config': RLock()}
57
59
 
58
60
  ### apply config preprocessing (e.g. main to meta)
59
61
  config = {}
62
+ _backup_config = None
63
+ _allow_write_missing: bool = True
64
+
65
+
60
66
  def _config(
61
67
  *keys: str,
62
68
  reload: bool = False,
63
69
  substitute: bool = True,
64
70
  sync_files: bool = True,
71
+ allow_replaced: bool = True,
65
72
  write_missing: bool = True,
66
73
  ) -> Dict[str, Any]:
67
74
  """
68
75
  Read and process the configuration file.
69
76
  """
70
- global config
77
+ global config, _backup_config
78
+
71
79
  if config is None or reload:
72
80
  with _locks['config']:
73
81
  config = {}
@@ -77,12 +85,16 @@ def _config(
77
85
  key_config = read_config(
78
86
  keys = [keys[0]],
79
87
  substitute = substitute,
80
- write_missing = write_missing,
88
+ write_missing = write_missing and _allow_write_missing,
81
89
  )
82
90
  if keys[0] in key_config:
83
91
  config[keys[0]] = key_config[keys[0]]
84
- if sync_files:
92
+ if sync_files and _allow_write_missing:
85
93
  _sync_files(keys=[keys[0] if keys else None])
94
+
95
+ if not allow_replaced:
96
+ return _backup_config if _backup_config is not None else config
97
+
86
98
  return config
87
99
 
88
100
 
@@ -158,7 +170,11 @@ def get_config(
158
170
  dprint(f"Indexing keys: {keys}", color=False)
159
171
 
160
172
  if len(keys) == 0:
161
- _rc = _config(substitute=substitute, sync_files=sync_files, write_missing=write_missing)
173
+ _rc = _config(
174
+ substitute=substitute,
175
+ sync_files=sync_files,
176
+ write_missing=(write_missing and _allow_write_missing),
177
+ )
162
178
  if as_tuple:
163
179
  return True, _rc
164
180
  return _rc
@@ -177,15 +193,15 @@ def get_config(
177
193
  except Exception:
178
194
  import traceback
179
195
  traceback.print_exc()
196
+ _subbed = {keys[0]: config[keys[0]]}
197
+
180
198
  config[keys[0]] = _subbed[keys[0]]
181
199
  if symlinks_key in _subbed:
182
200
  if symlinks_key not in config:
183
201
  config[symlinks_key] = {}
184
- if keys[0] not in config[symlinks_key]:
185
- config[symlinks_key][keys[0]] = {}
186
- config[symlinks_key][keys[0]] = apply_patch_to_config(
187
- _subbed,
188
- {symlinks_key: config[symlinks_key][keys[0]]}
202
+ config[symlinks_key] = apply_patch_to_config(
203
+ _subbed.get(symlinks_key, {}),
204
+ config.get(symlinks_key, {}),
189
205
  )
190
206
 
191
207
  from meerschaum.config._sync import sync_files as _sync_files
@@ -312,13 +328,44 @@ def write_plugin_config(
312
328
  return write_config(cf, **kw)
313
329
 
314
330
 
331
+ @contextlib.contextmanager
332
+ def replace_config(config_: Union[Dict[str, Any], None]):
333
+ """
334
+ Temporarily override the Meerschaum config dictionary.
335
+
336
+ Parameters
337
+ ----------
338
+ config_: Dict[str, Any]
339
+ The new config dictionary to temporarily replace the canonical `config`.
340
+ """
341
+ if config_ is None:
342
+ try:
343
+ yield
344
+ finally:
345
+ return
346
+
347
+ global _backup_config, _allow_write_missing
348
+
349
+ _backup_config = _config()
350
+ _allow_write_missing = False
351
+ set_config(config_)
352
+
353
+ try:
354
+ yield
355
+ finally:
356
+ set_config(_backup_config)
357
+ _allow_write_missing = True
358
+
315
359
  ### This need to be below get_config to avoid a circular import.
316
360
  from meerschaum.config._read_config import read_config
317
361
 
318
362
  ### If environment variable MRSM_CONFIG or MRSM_PATCH is set, patch config before anything else.
319
- from meerschaum.config._environment import apply_environment_patches, apply_environment_uris
320
- apply_environment_uris()
321
- apply_environment_patches()
363
+ from meerschaum.config.environment import (
364
+ apply_environment_patches as _apply_environment_patches,
365
+ apply_environment_uris as _apply_environment_uris,
366
+ )
367
+ _apply_environment_uris()
368
+ _apply_environment_patches()
322
369
 
323
370
 
324
371
  from meerschaum.config._paths import PATCH_DIR_PATH, PERMANENT_PATCH_DIR_PATH