plash-cli 0.3.7__tar.gz → 0.3.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plash_cli
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: CLI for the Plash hosting service
5
5
  Home-page: https://github.com/AnswerDotAI/plash_cli
6
6
  Author: Jeremy Howard
@@ -0,0 +1,2 @@
1
+ __version__ = "0.3.9"
2
+ from .cli import *
@@ -12,21 +12,30 @@ d = { 'settings': { 'branch': 'main',
12
12
  'plash_cli.auth.mk_signin_url': ('auth.html#mk_signin_url', 'plash_cli/auth.py')},
13
13
  'plash_cli.cli': { 'plash_cli.cli.Path._is_dir_empty': ('cli.html#path._is_dir_empty', 'plash_cli/cli.py'),
14
14
  'plash_cli.cli.PlashError': ('cli.html#plasherror', 'plash_cli/cli.py'),
15
+ 'plash_cli.cli._app_list': ('cli.html#_app_list', 'plash_cli/cli.py'),
16
+ 'plash_cli.cli._delete': ('cli.html#_delete', 'plash_cli/cli.py'),
17
+ 'plash_cli.cli._deploy': ('cli.html#_deploy', 'plash_cli/cli.py'),
15
18
  'plash_cli.cli._deps': ('cli.html#_deps', 'plash_cli/cli.py'),
19
+ 'plash_cli.cli._download': ('cli.html#_download', 'plash_cli/cli.py'),
16
20
  'plash_cli.cli._endpoint': ('cli.html#_endpoint', 'plash_cli/cli.py'),
17
21
  'plash_cli.cli._get_app_name': ('cli.html#_get_app_name', 'plash_cli/cli.py'),
18
22
  'plash_cli.cli._get_client': ('cli.html#_get_client', 'plash_cli/cli.py'),
19
23
  'plash_cli.cli._is_included': ('cli.html#_is_included', 'plash_cli/cli.py'),
24
+ 'plash_cli.cli._logs': ('cli.html#_logs', 'plash_cli/cli.py'),
20
25
  'plash_cli.cli._mk_auth_req': ('cli.html#_mk_auth_req', 'plash_cli/cli.py'),
21
26
  'plash_cli.cli._poll_cookies': ('cli.html#_poll_cookies', 'plash_cli/cli.py'),
27
+ 'plash_cli.cli._prep': ('cli.html#_prep', 'plash_cli/cli.py'),
28
+ 'plash_cli.cli._start': ('cli.html#_start', 'plash_cli/cli.py'),
29
+ 'plash_cli.cli._stop': ('cli.html#_stop', 'plash_cli/cli.py'),
22
30
  'plash_cli.cli._validate_app': ('cli.html#_validate_app', 'plash_cli/cli.py'),
23
- 'plash_cli.cli.apps': ('cli.html#apps', 'plash_cli/cli.py'),
31
+ 'plash_cli.cli.app_list': ('cli.html#app_list', 'plash_cli/cli.py'),
24
32
  'plash_cli.cli.create_tar_archive': ('cli.html#create_tar_archive', 'plash_cli/cli.py'),
25
- 'plash_cli.cli.delete': ('cli.html#delete', 'plash_cli/cli.py'),
33
+ 'plash_cli.cli.delete_app': ('cli.html#delete_app', 'plash_cli/cli.py'),
26
34
  'plash_cli.cli.deploy': ('cli.html#deploy', 'plash_cli/cli.py'),
27
- 'plash_cli.cli.download': ('cli.html#download', 'plash_cli/cli.py'),
35
+ 'plash_cli.cli.download_app': ('cli.html#download_app', 'plash_cli/cli.py'),
28
36
  'plash_cli.cli.login': ('cli.html#login', 'plash_cli/cli.py'),
29
37
  'plash_cli.cli.logs': ('cli.html#logs', 'plash_cli/cli.py'),
30
- 'plash_cli.cli.start': ('cli.html#start', 'plash_cli/cli.py'),
31
- 'plash_cli.cli.stop': ('cli.html#stop', 'plash_cli/cli.py'),
38
+ 'plash_cli.cli.plash_tool_info': ('cli.html#plash_tool_info', 'plash_cli/cli.py'),
39
+ 'plash_cli.cli.start_app': ('cli.html#start_app', 'plash_cli/cli.py'),
40
+ 'plash_cli.cli.stop_app': ('cli.html#stop_app', 'plash_cli/cli.py'),
32
41
  'plash_cli.cli.view': ('cli.html#view', 'plash_cli/cli.py')}}}
@@ -4,7 +4,7 @@
4
4
 
5
5
  # %% auto 0
6
6
  __all__ = ['PLASH_CONFIG_HOME', 'PLASH_DOMAIN', 'pat', 'log_modes', 'PlashError', 'login', 'create_tar_archive', 'deploy', 'view',
7
- 'delete', 'start', 'stop', 'logs', 'download', 'apps']
7
+ 'delete_app', 'start_app', 'stop_app', 'logs', 'download_app', 'app_list', 'plash_tool_info']
8
8
 
9
9
  # %% ../nbs/00_cli.ipynb 3
10
10
  from fastcore.all import *
@@ -50,11 +50,14 @@ def _get_app_name(path:Path):
50
50
 
51
51
 
52
52
  # %% ../nbs/00_cli.ipynb 10
53
+ def _prep(path,name): return name if name else _get_app_name(Path(path))
54
+
55
+ # %% ../nbs/00_cli.ipynb 11
53
56
  def _endpoint(sub='', rt=''):
54
57
  p = "http" if "localhost" in PLASH_DOMAIN else "https"
55
58
  return f"{p}://{sub}{'.' if sub else ''}{PLASH_DOMAIN}{rt}"
56
59
 
57
- # %% ../nbs/00_cli.ipynb 11
60
+ # %% ../nbs/00_cli.ipynb 12
58
61
  def _is_included(path):
59
62
  "Returns True if path should be included in deployment"
60
63
  if path.name.startswith('.'): return False
@@ -64,10 +67,10 @@ def _is_included(path):
64
67
  '.vscode', '.idea', '.sesskey'}
65
68
  return not any(p in excludes for p in path.parts)
66
69
 
67
- # %% ../nbs/00_cli.ipynb 12
70
+ # %% ../nbs/00_cli.ipynb 13
68
71
  class PlashError(Exception): pass
69
72
 
70
- # %% ../nbs/00_cli.ipynb 13
73
+ # %% ../nbs/00_cli.ipynb 14
71
74
  def _poll_cookies(paircode, interval=1, timeout=180):
72
75
  "Poll server for token until received or timeout"
73
76
  start = time()
@@ -78,7 +81,7 @@ def _poll_cookies(paircode, interval=1, timeout=180):
78
81
  if resp.text.strip(): return dict(client.cookies)
79
82
  sleep(interval)
80
83
 
81
- # %% ../nbs/00_cli.ipynb 14
84
+ # %% ../nbs/00_cli.ipynb 15
82
85
  @call_parse
83
86
  def login(
84
87
  token:str=None, # Token to save directly to config
@@ -102,7 +105,7 @@ def login(
102
105
  print(f"Authentication successful! Config saved to {PLASH_CONFIG_HOME}")
103
106
  else: print("Authentication timed out.")
104
107
 
105
- # %% ../nbs/00_cli.ipynb 17
108
+ # %% ../nbs/00_cli.ipynb 18
106
109
  pat = r'(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\s(?P<content>(^#(| .*)$\s)+)^# ///$'
107
110
 
108
111
  def _deps(script: bytes | str):
@@ -117,7 +120,7 @@ def _deps(script: bytes | str):
117
120
  return '\n'.join(tomllib.loads(content)['dependencies'])
118
121
  else: return None
119
122
 
120
- # %% ../nbs/00_cli.ipynb 19
123
+ # %% ../nbs/00_cli.ipynb 20
121
124
  def _validate_app(path):
122
125
  "Validates directory `path` is a deployable Plash app"
123
126
  if not (path / 'main.py').exists():
@@ -126,7 +129,7 @@ def _validate_app(path):
126
129
  if deps and (path/"requirements.txt").exists():
127
130
  raise PlashError('A Plash app should not contain both a requirements.txt file and inline dependencies (see PEP723).')
128
131
 
129
- # %% ../nbs/00_cli.ipynb 22
132
+ # %% ../nbs/00_cli.ipynb 23
130
133
  def create_tar_archive(path:Path, force_data:bool=False) -> tuple[io.BytesIO, int]:
131
134
  "Creates a tar archive of a directory, excluding files based on is_included"
132
135
  tarz = io.BytesIO()
@@ -141,23 +144,21 @@ def create_tar_archive(path:Path, force_data:bool=False) -> tuple[io.BytesIO, in
141
144
  tarz.seek(0)
142
145
  return tarz, len(files)
143
146
 
144
- # %% ../nbs/00_cli.ipynb 23
145
- @call_parse
147
+ # %% ../nbs/00_cli.ipynb 24
146
148
  def deploy(
147
- path:Path=Path('.'), # Path to project
149
+ path:Path='.', # Path to project
148
150
  name:str=None, # Overrides the .plash file in project root if provided
149
- force_data:bool=False): # Overwrite data/ directory during deployment
151
+ _force_data:bool=False): # Overwrite data/ directory during deployment
150
152
  """
151
153
  Deploys app to production. By default, this command erases all files in your app which are not in data/.
152
154
  Then uploads all files and folders, except paths starting with `.` and except the local data/ directory.
153
- If `--force_data` is used, then it erases all files in production. Then it uploads all files and folders,
155
+ If `force_data` is used, then it erases all files in production. Then it uploads all files and folders,
154
156
  including `data/`, except paths starting with `.`.
155
157
  """
156
- print('Initializing deployment...')
157
- if name == '': print('Error: App name cannot be an empty string'); return
158
- if not path.is_dir(): print("Error: Path should point to the project directory"); return
159
- try: _validate_app(path)
160
- except PlashError as e: print(f"Error: {str(e)}\nInvalid path: {path}"); return
158
+ path = Path(path)
159
+ if name == '': raise PlashError('App name cannot be an empty string')
160
+ if not path.is_dir(): raise PlashError("Path should point to the project directory")
161
+ _validate_app(path)
161
162
 
162
163
  try:
163
164
  if not name: name = _get_app_name(path)
@@ -169,103 +170,165 @@ def deploy(
169
170
  tarz, _ = create_tar_archive(path, force_data)
170
171
  r = _mk_auth_req(_endpoint(rt="/upload"), "post", files={'file': tarz},
171
172
  data={'name': name, 'force_data': force_data})
172
- if r:
173
- print('✅ Upload complete! Your app is currently being built.\n' +
174
- f'It will be live at {name if "." in name else _endpoint(sub=name)}')
175
- else: return 'Unknown failure'
173
+ if not r: raise PlashError('Unknown failure')
174
+ return name if "." in name else _endpoint(sub=name)
175
+
176
+ # %% ../nbs/00_cli.ipynb 25
177
+ @call_parse
178
+ def _deploy(
179
+ path:Path='.', # Path to project
180
+ name:str=None, # Overrides the .plash file in project root if provided
181
+ force_data:bool=False): # Overwrite data/ directory during deployment
182
+ print('Initializing deployment...')
183
+ try: res = deploy(path=path, name=name, _force_data=force_data)
184
+ except PlashError as e: return str(e)
185
+ print('✅ Upload complete! Your app is currently being built.\n' +
186
+ f'It will be live at {res}')
187
+ _deploy.__doc__ = deploy.__doc__
176
188
 
177
- # %% ../nbs/00_cli.ipynb 26
189
+ # %% ../nbs/00_cli.ipynb 28
178
190
  @call_parse
179
191
  def view(
180
- path:Path=Path('.'), # Path to project directory
192
+ path:Path='.', # Path to project directory
181
193
  name:str=None, # Overrides the .plash file in project root if provided
182
194
  ):
183
195
  "Open your app in the browser"
184
- if not name: name = _get_app_name(path)
196
+ name = _prep(path, name)
185
197
  url = name if '.' in name else _endpoint(sub=name)
186
198
  print(f"Opening browser to view app :\n{url}\n")
187
199
  webbrowser.open(url)
188
200
 
189
- # %% ../nbs/00_cli.ipynb 29
201
+ # %% ../nbs/00_cli.ipynb 31
202
+ def delete_app(
203
+ path:Path='.', # Path to project
204
+ name:str=None): # Overrides the .plash file in project root if provided
205
+ 'Delete your deployed app'
206
+ name = _prep(path, name)
207
+ r = _mk_auth_req(_endpoint(rt=f"/delete?name={name}"), "delete")
208
+ if not r: raise PlashError('Failed to delete app')
209
+ return f"App '{name}' deleted successfully"
210
+
190
211
  @call_parse
191
- def delete(
192
- path:Path=Path('.'), # Path to project
193
- name:str=None, # Overrides the .plash file in project root if provided
194
- force:bool=False): # Skip confirmation prompt
212
+ @delegates(delete_app)
213
+ def _delete(force:bool=False, # Skip confirmation prompt
214
+ **kwargs):
195
215
  'Delete your deployed app'
196
- if not name: name = _get_app_name(path)
197
216
  if not force:
198
- confirm = input(f"Are you sure you want to delete app '{name}'? This action cannot be undone. [y/N]: ")
199
- if confirm.lower() not in ['y', 'yes']:
200
- print("Deletion cancelled.")
201
- return
202
-
203
- print(f"Deleting app '{name}'...")
204
- if r := _mk_auth_req(_endpoint(rt=f"/delete?name={name}"), "delete"): return r.text
217
+ confirm = input("Are you sure you want to delete the app? [y/N]: ")
218
+ if confirm.lower() not in ['y', 'yes']: return print("Deletion cancelled.")
219
+ try: print(delete_app(**kwargs))
220
+ except PlashError as e: return str(e)
221
+ _delete.__doc__ = delete_app.__doc__
222
+
223
+ # %% ../nbs/00_cli.ipynb 34
224
+ def start_app(
225
+ path:Path='.', # Path to project
226
+ name:str=None): # Overrides the .plash file in project root if provided
227
+ 'Start your deployed app'
228
+ name = _prep(path, name)
229
+ r = _mk_auth_req(_endpoint(rt=f"/start?name={name}"))
230
+ if not r: raise PlashError('Failed to start app')
231
+ return f"App '{name}' started"
205
232
 
206
- # %% ../nbs/00_cli.ipynb 32
207
233
  @call_parse
208
- def start(path:Path=Path('.'), name:str=None):
209
- "Start your deployed app"
210
- if not name: name = _get_app_name(path)
211
- if r := _mk_auth_req(_endpoint(rt=f"/start?name={name}")): return r.text
212
-
213
- # %% ../nbs/00_cli.ipynb 35
214
- @call_parse
215
- def stop(path:Path=Path('.'), name:str=None):
216
- "Stop your deployed app"
217
- if not name: name = _get_app_name(path)
218
- if r := _mk_auth_req(_endpoint(rt=f"/stop?name={name}")): return r.text
219
-
220
- # %% ../nbs/00_cli.ipynb 38
221
- log_modes = str_enum('log_modes', 'build', 'app')
234
+ @delegates(start_app)
235
+ def _start(**kwargs):
236
+ try: print(start_app(**kwargs))
237
+ except PlashError as e: return str(e)
238
+ _start.__doc__ = start_app.__doc__
239
+
240
+ # %% ../nbs/00_cli.ipynb 37
241
+ def stop_app(
242
+ path:Path='.', # Path to project
243
+ name:str=None): # Overrides the .plash file in project root if provided
244
+ 'Stop your deployed app'
245
+ name = _prep(path, name)
246
+ r = _mk_auth_req(_endpoint(rt=f"/stop?name={name}"))
247
+ if not r: raise PlashError('Failed to stop app')
248
+ return f"App '{name}' stopped"
222
249
 
223
- # %% ../nbs/00_cli.ipynb 39
224
250
  @call_parse
251
+ @delegates(stop_app)
252
+ def _stop(**kwargs):
253
+ try: print(stop_app(**kwargs))
254
+ except PlashError as e: return str(e)
255
+ _stop.__doc__ = stop_app.__doc__
256
+
257
+ # %% ../nbs/00_cli.ipynb 40
258
+ log_modes = str_enum('log_modes', 'build', 'app')
259
+
260
+ # %% ../nbs/00_cli.ipynb 41
225
261
  def logs(
226
- path:Path=Path('.'), # Path to project
262
+ path:Path='.', # Path to project
227
263
  name:str=None, # Overrides the .plash file in project root if provided
228
- mode:log_modes='build', # Choose between build or app logs
229
- tail:bool=False): # Tail the logs
230
- 'Prints the logs for your deployed app'
231
- if not name: name = _get_app_name(path)
232
- if tail:
264
+ mode:log_modes='build'): # Choose between build or app logs
265
+ 'Get logs for your deployed app'
266
+ name = _prep(path, name)
267
+ r = _mk_auth_req(_endpoint(rt=f"/logs?name={name}&mode={mode}"))
268
+ if not r: raise PlashError('Failed to retrieve logs')
269
+ return r.text
270
+
271
+ @call_parse
272
+ @delegates(logs)
273
+ def _logs(tail:bool=False, # Tail the logs
274
+ **kwargs):
275
+ try:
276
+ if not tail: return print(logs(**kwargs))
233
277
  text = ''
234
278
  while True:
235
279
  try:
236
- r = _mk_auth_req(_endpoint(rt=f"/logs?name={name}&mode={mode}"))
237
- print(r.text[len(text):], end='') # Only print updates
238
- text = r.text
239
- if mode == 'build' and 'Build End Time:' in r.text: return
280
+ new_text = logs(**kwargs)
281
+ print(new_text[len(text):], end='')
282
+ text = new_text
283
+ if kwargs.get('mode','build') == 'build' and 'Build End Time:' in new_text: return
240
284
  sleep(1)
241
- except KeyboardInterrupt: return "\nExiting"
242
- if r := _mk_auth_req(_endpoint(rt=f"/logs?name={name}&mode={mode}")): return r.text
285
+ except KeyboardInterrupt: print("\nExiting"); return
286
+ except PlashError as e: return str(e)
287
+ _logs.__doc__ = logs.__doc__
243
288
 
244
- # %% ../nbs/00_cli.ipynb 42
289
+ # %% ../nbs/00_cli.ipynb 44
245
290
  @patch
246
291
  def _is_dir_empty(self:Path): return next(self.iterdir(), None) is None
247
292
 
248
- # %% ../nbs/00_cli.ipynb 46
249
- @call_parse
250
- def download(
251
- path:Path=Path('.'), # Path to project
252
- name:str=None, # Overrides the .plash file in project root if provided
253
- save_path:Path=Path("./download/")): # Save path (optional)
254
- 'Download your deployed app'
255
- if not name: name = _get_app_name(path)
293
+ # %% ../nbs/00_cli.ipynb 48
294
+ def download_app(
295
+ path:Path='.', # Path to project
296
+ name:str=None, # Overrides the .plash file in project root if provided
297
+ save_path:Path="./download/"): # Save path (optional)
298
+ "Download deployed app to save_path."
299
+ name = _prep(path, name)
300
+ save_path = Path(save_path)
256
301
  save_path.mkdir(exist_ok=True)
257
- if not save_path._is_dir_empty(): return print(f'ERROR: Save path ({save_path}) is not empty.')
258
- if r := _mk_auth_req(_endpoint(rt=f'/download?name={name}')):
259
- with tarfile.open(fileobj=io.BytesIO(r.content), mode="r:gz") as tar: tar.extractall(path=save_path, filter='data')
260
- print(f"Downloaded your app to: {save_path}")
302
+ if not save_path._is_dir_empty(): raise PlashError(f'Save path ({save_path}) is not empty.')
303
+ r = _mk_auth_req(_endpoint(rt=f'/download?name={name}'))
304
+ if not r: raise PlashError('Download request failed')
305
+ with tarfile.open(fileobj=io.BytesIO(r.content), mode="r:gz") as tar:
306
+ tar.extractall(path=save_path, filter='data')
307
+ return save_path
261
308
 
262
- # %% ../nbs/00_cli.ipynb 49
263
309
  @call_parse
264
- def apps(verbose:bool=False):
265
- "List your deployed apps (verbose shows status table: 1=running, 0=stopped)"
310
+ @delegates(download_app)
311
+ def _download(**kwargs):
312
+ try: print(f"Downloaded your app to: {download_app(**kwargs)}")
313
+ except PlashError as e: return str(e)
314
+ _download.__doc__ = download_app.__doc__
315
+
316
+ # %% ../nbs/00_cli.ipynb 51
317
+ def app_list():
318
+ "List your deployed apps"
266
319
  r = _mk_auth_req(_endpoint(rt="/user_apps"))
267
- if r:
268
- apps = r.json()
269
- if not apps: return "You don't have any deployed Plash apps."
270
- if verbose: return [print(f"{a['running']} {a['name']}") for a in apps]
271
- else: return [print(a['name']) for a in apps]
320
+ if not r: raise PlashError('Failed to retrieve')
321
+ return r.json()
322
+
323
+ @call_parse
324
+ def _app_list(verbose:bool=False): # Whether to show running status as well as name: 1=running, 0=stopped
325
+ try: res = app_list()
326
+ except PlashError as e: return str(e)
327
+ if not res: print("You don't have any deployed Plash apps.")
328
+ for a in res: print(f"{a['running']} {a['name']}" if verbose else a['name'])
329
+ _app_list.__doc__ = app_list.__doc__
330
+
331
+ # %% ../nbs/00_cli.ipynb 54
332
+ def plash_tool_info():
333
+ from dialoghelper import add_msg
334
+ add_msg('Plash tools: &`[login, deploy, start_app, stop_app, logs, download_app, app_list]`')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plash_cli
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: CLI for the Plash hosting service
5
5
  Home-page: https://github.com/AnswerDotAI/plash_cli
6
6
  Author: Jeremy Howard
@@ -0,0 +1,13 @@
1
+ [console_scripts]
2
+ plash_apps = plash_cli.cli:_app_list
3
+ plash_delete = plash_cli.cli:_delete
4
+ plash_deploy = plash_cli.cli:_deploy
5
+ plash_download = plash_cli.cli:_download
6
+ plash_login = plash_cli.cli:login
7
+ plash_logs = plash_cli.cli:_logs
8
+ plash_start = plash_cli.cli:_start
9
+ plash_stop = plash_cli.cli:_stop
10
+ plash_view = plash_cli.cli:view
11
+
12
+ [nbdev]
13
+ plash_cli = plash_cli._modidx:d
@@ -2,7 +2,7 @@
2
2
  jupyter_hooks = False
3
3
  repo = plash_cli
4
4
  lib_name = plash_cli
5
- version = 0.3.7
5
+ version = 0.3.9
6
6
  min_python = 3.11
7
7
  license = apache2
8
8
  black_formatting = False
@@ -29,15 +29,15 @@ status = 3
29
29
  user = AnswerDotAI
30
30
  requirements = fastcore httpx>=0.28.1 python-dotenv pyjwt cryptography
31
31
  dev_requirements = bash_kernel nbdev
32
- console_scripts = plash_deploy=plash_cli.cli:deploy
32
+ console_scripts = plash_deploy=plash_cli.cli:_deploy
33
33
  plash_login=plash_cli.cli:login
34
34
  plash_view=plash_cli.cli:view
35
- plash_logs=plash_cli.cli:logs
36
- plash_delete=plash_cli.cli:delete
37
- plash_stop=plash_cli.cli:stop
38
- plash_start=plash_cli.cli:start
39
- plash_download=plash_cli.cli:download
40
- plash_apps=plash_cli.cli:apps
35
+ plash_logs=plash_cli.cli:_logs
36
+ plash_delete=plash_cli.cli:_delete
37
+ plash_stop=plash_cli.cli:_stop
38
+ plash_start=plash_cli.cli:_start
39
+ plash_download=plash_cli.cli:_download
40
+ plash_apps=plash_cli.cli:_app_list
41
41
  readme_nb = index.ipynb
42
42
  allowed_metadata_keys =
43
43
  allowed_cell_metadata_keys =
@@ -1,2 +0,0 @@
1
- __version__ = "0.3.7"
2
- from .cli import *
@@ -1,13 +0,0 @@
1
- [console_scripts]
2
- plash_apps = plash_cli.cli:apps
3
- plash_delete = plash_cli.cli:delete
4
- plash_deploy = plash_cli.cli:deploy
5
- plash_download = plash_cli.cli:download
6
- plash_login = plash_cli.cli:login
7
- plash_logs = plash_cli.cli:logs
8
- plash_start = plash_cli.cli:start
9
- plash_stop = plash_cli.cli:stop
10
- plash_view = plash_cli.cli:view
11
-
12
- [nbdev]
13
- plash_cli = plash_cli._modidx:d
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes