plash-cli 0.3.12__tar.gz → 0.3.14__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,43 +1,29 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plash_cli
3
- Version: 0.3.12
3
+ Version: 0.3.14
4
4
  Summary: CLI for the Plash hosting service
5
- Home-page: https://github.com/AnswerDotAI/plash_cli
6
- Author: Jeremy Howard
7
- Author-email: info@fast.ai
8
- License: Apache Software License 2.0
9
- Keywords: nbdev jupyter notebook python
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Intended Audience :: Developers
5
+ Author-email: Jeremy Howard <info@fast.ai>
6
+ License: Apache-2.0
7
+ Project-URL: Repository, https://github.com/AnswerDotAI/plash_cli
8
+ Project-URL: Documentation, https://AnswerDotAI.github.io/plash_cli
9
+ Keywords: nbdev,jupyter,notebook,python
12
10
  Classifier: Natural Language :: English
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
17
15
  Requires-Python: >=3.10
18
16
  Description-Content-Type: text/markdown
19
17
  License-File: LICENSE
20
- Requires-Dist: fastcore
18
+ Requires-Dist: fastcore>=1.12.27
21
19
  Requires-Dist: httpx>=0.28.1
22
20
  Requires-Dist: python-dotenv
23
21
  Requires-Dist: pyjwt
24
22
  Requires-Dist: cryptography
25
23
  Provides-Extra: dev
26
24
  Requires-Dist: bash_kernel; extra == "dev"
27
- Requires-Dist: nbdev; extra == "dev"
28
- Dynamic: author
29
- Dynamic: author-email
30
- Dynamic: classifier
31
- Dynamic: description
32
- Dynamic: description-content-type
33
- Dynamic: home-page
34
- Dynamic: keywords
35
- Dynamic: license
25
+ Requires-Dist: nbdev>=3; extra == "dev"
36
26
  Dynamic: license-file
37
- Dynamic: provides-extra
38
- Dynamic: requires-dist
39
- Dynamic: requires-python
40
- Dynamic: summary
41
27
 
42
28
  # Plash
43
29
 
@@ -0,0 +1,2 @@
1
+ __version__ = "0.3.14"
2
+ from .cli import *
@@ -1,21 +1,23 @@
1
- """Client side logic to add Plash Auth to your app"""
1
+ """Client side logic to add Plash Auth to your app
2
+
3
+ Docs: https://AnswerDotAI.github.io/plash_cli/auth.html.md"""
2
4
 
3
5
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_auth.ipynb.
4
6
 
5
- # %% auto 0
7
+ # %% auto #0
6
8
  __all__ = ['signin_completed_rt', 'mk_signin_url', 'PlashAuthError', 'goog_id_from_signin_reply']
7
9
 
8
- # %% ../nbs/01_auth.ipynb 4
10
+ # %% ../nbs/01_auth.ipynb #c6aa552a
9
11
  import httpx,os,jwt
10
12
  from pathlib import Path
11
13
  from warnings import warn
12
14
 
13
15
  from . import __version__
14
16
 
15
- # %% ../nbs/01_auth.ipynb 5
17
+ # %% ../nbs/01_auth.ipynb #d3504f51
16
18
  _in_prod = os.getenv('PLASH_PRODUCTION', '') == '1'
17
19
 
18
- # %% ../nbs/01_auth.ipynb 6
20
+ # %% ../nbs/01_auth.ipynb #e6590075
19
21
  def _signin_url(email_re: str=None, hd_re: str=None):
20
22
  res = httpx.post(os.environ['PLASH_AUTH_URL'], json=dict(email_re=email_re, hd_re=hd_re),
21
23
  auth=(os.environ['PLASH_APP_ID'], os.environ['PLASH_APP_SECRET']),
@@ -23,20 +25,22 @@ def _signin_url(email_re: str=None, hd_re: str=None):
23
25
  if "warning" in res: warn(res.pop('warning'))
24
26
  return res
25
27
 
26
- # %% ../nbs/01_auth.ipynb 8
28
+ # %% ../nbs/01_auth.ipynb #4b15411c
27
29
  signin_completed_rt = "/signin_completed"
28
30
 
29
- # %% ../nbs/01_auth.ipynb 10
30
- def mk_signin_url(session: dict, # Session dictionary
31
- email_re: str=None, # Regex filter for allowed email addresses
32
- hd_re: str=None): # Regex filter for allowed Google hosted domains
31
+ # %% ../nbs/01_auth.ipynb #74a0a24d
32
+ def mk_signin_url(
33
+ session: dict, # Session dictionary
34
+ email_re: str=None, # Regex filter for allowed email addresses
35
+ hd_re: str=None # Regex filter for allowed Google hosted domains
36
+ ):
33
37
  "Generate a Google Sign-In URL for Plash authentication."
34
38
  if not _in_prod: return f"{signin_completed_rt}?signin_reply=mock-sign-in-reply"
35
39
  res = _signin_url(email_re, hd_re)
36
40
  session['req_id'] = res['req_id']
37
41
  return res['plash_signin_url']
38
42
 
39
- # %% ../nbs/01_auth.ipynb 12
43
+ # %% ../nbs/01_auth.ipynb #8e66bb6e
40
44
  def _parse_jwt(reply: str) -> dict:
41
45
  "Parse JWT reply and return decoded claims or error info"
42
46
  try: decoded = jwt.decode(reply, key=open(Path(__file__).parent / "assets" / "es256_public_key.pem","rb").read(), algorithms=["ES256"],
@@ -44,14 +48,16 @@ def _parse_jwt(reply: str) -> dict:
44
48
  except Exception as e: return dict(req_id=None, sub=None, err=f'JWT validation failed: {e}')
45
49
  return dict(req_id=decoded.get('req_id'), sub=decoded.get('sub'), err=decoded.get('err'))
46
50
 
47
- # %% ../nbs/01_auth.ipynb 14
51
+ # %% ../nbs/01_auth.ipynb #0e61fbdd
48
52
  class PlashAuthError(Exception):
49
53
  """Raised when Plash authentication fails"""
50
54
  pass
51
55
 
52
- # %% ../nbs/01_auth.ipynb 16
53
- def goog_id_from_signin_reply(session: dict, # Session dictionary containing 'req_id'
54
- reply: str): # The JWT reply string from Plash after Google authentication
56
+ # %% ../nbs/01_auth.ipynb #a311ce9a
57
+ def goog_id_from_signin_reply(
58
+ session: dict, # Session dictionary containing 'req_id'
59
+ reply: str # The JWT reply string from Plash after Google authentication
60
+ ):
55
61
  "Validate Google sign-in reply and returns Google user ID if valid."
56
62
  if not _in_prod: return '424242424242424242424'
57
63
  parsed = _parse_jwt(reply)
@@ -1,12 +1,14 @@
1
- """The Plash CLI tool"""
1
+ """The Plash CLI tool
2
+
3
+ Docs: https://AnswerDotAI.github.io/plash_cli/cli.html.md"""
2
4
 
3
5
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_cli.ipynb.
4
6
 
5
- # %% auto 0
7
+ # %% auto #0
6
8
  __all__ = ['PLASH_CONFIG_HOME', 'PLASH_DOMAIN', 'pat', 'log_modes', 'PlashError', 'login', 'create_tar_archive', 'deploy', 'view',
7
9
  'delete_app', 'start_app', 'stop_app', 'logs', 'download_app', 'app_list', 'plash_tool_info']
8
10
 
9
- # %% ../nbs/00_cli.ipynb 3
11
+ # %% ../nbs/00_cli.ipynb #702c219c
10
12
  from fastcore.all import *
11
13
  from fastcore.xdg import *
12
14
  import secrets, webbrowser, httpx, io, tarfile, random, string
@@ -17,11 +19,11 @@ import io, os, re, tarfile
17
19
 
18
20
  from . import __version__
19
21
 
20
- # %% ../nbs/00_cli.ipynb 6
22
+ # %% ../nbs/00_cli.ipynb #2fc99aa4
21
23
  PLASH_CONFIG_HOME = xdg_config_home() / 'plash_config.json'
22
24
  PLASH_DOMAIN = os.getenv("PLASH_DOMAIN","pla.sh") # pla.sh plash-dev.answer.ai localhost:5002
23
25
 
24
- # %% ../nbs/00_cli.ipynb 7
26
+ # %% ../nbs/00_cli.ipynb #1de1e2b3
25
27
  def _get_client(cfg=PLASH_CONFIG_HOME):
26
28
  client = httpx.Client()
27
29
  if tok := os.getenv("PLASH_TOKEN"): cookies = {"session_": tok}
@@ -31,13 +33,14 @@ def _get_client(cfg=PLASH_CONFIG_HOME):
31
33
  client.headers.update({'X-PLASH': 'true', 'User-Agent': f'plash_cli/{__version__}'})
32
34
  return client
33
35
 
34
- # %% ../nbs/00_cli.ipynb 8
36
+ # %% ../nbs/00_cli.ipynb #47d01e47
35
37
  def _mk_auth_req(url:str, method:str='get', timeout=300., **kwargs):
36
38
  r = getattr(_get_client(), method)(url, timeout=timeout, **kwargs)
37
39
  if r.status_code == 200: return r
38
- else: print(f'Failure: {r.headers["X-Plash-Error"]}')
40
+ msg = r.headers.get('X-Plash-Error') or r.text.strip() or f'HTTP {r.status_code}'
41
+ raise PlashError(msg)
39
42
 
40
- # %% ../nbs/00_cli.ipynb 9
43
+ # %% ../nbs/00_cli.ipynb #7edae5c8
41
44
  def _get_app_name(path:Path):
42
45
  plash_app = Path(path) / '.plash'
43
46
  if not plash_app.exists(): raise FileNotFoundError(f"File not found: {plash_app=}")
@@ -49,15 +52,15 @@ def _get_app_name(path:Path):
49
52
  raise RuntimeError(f"{plash_app=} did not have a PLASH_APP_NAME")
50
53
 
51
54
 
52
- # %% ../nbs/00_cli.ipynb 10
55
+ # %% ../nbs/00_cli.ipynb #b607f7a9
53
56
  def _prep(path,name): return name if name else _get_app_name(Path(path))
54
57
 
55
- # %% ../nbs/00_cli.ipynb 11
58
+ # %% ../nbs/00_cli.ipynb #acaf42cf
56
59
  def _endpoint(sub='', rt=''):
57
60
  p = "http" if "localhost" in PLASH_DOMAIN else "https"
58
61
  return f"{p}://{sub}{'.' if sub else ''}{PLASH_DOMAIN}{rt}"
59
62
 
60
- # %% ../nbs/00_cli.ipynb 12
63
+ # %% ../nbs/00_cli.ipynb #d1638ced
61
64
  def _is_included(path):
62
65
  "Returns True if path should be included in deployment"
63
66
  if path.name.startswith('.'): return False
@@ -67,10 +70,10 @@ def _is_included(path):
67
70
  '.vscode', '.idea', '.sesskey'}
68
71
  return not any(p in excludes for p in path.parts)
69
72
 
70
- # %% ../nbs/00_cli.ipynb 13
73
+ # %% ../nbs/00_cli.ipynb #a20045ed
71
74
  class PlashError(Exception): pass
72
75
 
73
- # %% ../nbs/00_cli.ipynb 14
76
+ # %% ../nbs/00_cli.ipynb #b7d4028e
74
77
  def _poll_cookies(paircode, interval=1, timeout=180):
75
78
  "Poll server for token until received or timeout"
76
79
  start = time()
@@ -81,7 +84,7 @@ def _poll_cookies(paircode, interval=1, timeout=180):
81
84
  if resp.text.strip(): return dict(client.cookies)
82
85
  sleep(interval)
83
86
 
84
- # %% ../nbs/00_cli.ipynb 15
87
+ # %% ../nbs/00_cli.ipynb #eadaa5df
85
88
  @call_parse
86
89
  def login(
87
90
  token:str=None, # Token to save directly to config
@@ -105,7 +108,7 @@ def login(
105
108
  print(f"Authentication successful! Config saved to {PLASH_CONFIG_HOME}")
106
109
  else: print("Authentication timed out.")
107
110
 
108
- # %% ../nbs/00_cli.ipynb 18
111
+ # %% ../nbs/00_cli.ipynb #d52c060e
109
112
  pat = r'(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\s(?P<content>(^#(| .*)$\s)+)^# ///$'
110
113
 
111
114
  def _deps(script: bytes | str):
@@ -121,7 +124,7 @@ def _deps(script: bytes | str):
121
124
  return '\n'.join(tomllib.loads(content)['dependencies'])
122
125
  else: return None
123
126
 
124
- # %% ../nbs/00_cli.ipynb 20
127
+ # %% ../nbs/00_cli.ipynb #3747912c
125
128
  def _validate_app(path):
126
129
  "Validates directory `path` is a deployable Plash app"
127
130
  if not (path / 'main.py').exists():
@@ -130,7 +133,7 @@ def _validate_app(path):
130
133
  if deps and (path/"requirements.txt").exists():
131
134
  raise PlashError('A Plash app should not contain both a requirements.txt file and inline dependencies (see PEP723).')
132
135
 
133
- # %% ../nbs/00_cli.ipynb 23
136
+ # %% ../nbs/00_cli.ipynb #ee0a7f14
134
137
  def create_tar_archive(path:Path, force_data:bool=False) -> tuple[io.BytesIO, int]:
135
138
  "Creates a tar archive of a directory, excluding files based on is_included"
136
139
  tarz = io.BytesIO()
@@ -145,11 +148,12 @@ def create_tar_archive(path:Path, force_data:bool=False) -> tuple[io.BytesIO, in
145
148
  tarz.seek(0)
146
149
  return tarz, len(files)
147
150
 
148
- # %% ../nbs/00_cli.ipynb 24
151
+ # %% ../nbs/00_cli.ipynb #2f2a6e00
149
152
  def deploy(
150
153
  path:Path='.', # Path to project
151
154
  name:str=None, # Overrides the .plash file in project root if provided
152
- _force_data:bool=False): # Overwrite data/ directory during deployment
155
+ _force_data:bool=False # Overwrite data/ directory during deployment
156
+ ):
153
157
  """
154
158
  Deploys app to production. By default, this command erases all files in your app which are not in data/.
155
159
  Then uploads all files and folders, except paths starting with `.` and except the local data/ directory.
@@ -169,17 +173,16 @@ def deploy(
169
173
  plash_app.write_text(f'export PLASH_APP_NAME={name}')
170
174
 
171
175
  tarz, _ = create_tar_archive(path, _force_data)
172
- r = _mk_auth_req(_endpoint(rt="/upload"), "post", files={'file': tarz},
173
- data={'name': name, 'force_data': _force_data})
174
- if not r: raise PlashError('Unknown failure')
176
+ _mk_auth_req(_endpoint(rt="/upload"), "post", files={'file': tarz}, data={'name': name, 'force_data': _force_data})
175
177
  return name if "." in name else _endpoint(sub=name)
176
178
 
177
- # %% ../nbs/00_cli.ipynb 25
179
+ # %% ../nbs/00_cli.ipynb #59d06b03
178
180
  @call_parse
179
181
  def _deploy(
180
182
  path:Path='.', # Path to project
181
183
  name:str=None, # Overrides the .plash file in project root if provided
182
- force_data:bool=False): # Overwrite data/ directory during deployment
184
+ force_data:bool=False # Overwrite data/ directory during deployment
185
+ ):
183
186
  print('Initializing deployment...')
184
187
  try: res = deploy(path=path, name=name, _force_data=force_data)
185
188
  except PlashError as e: return str(e)
@@ -187,7 +190,7 @@ def _deploy(
187
190
  f'It will be live at {res}')
188
191
  _deploy.__doc__ = deploy.__doc__
189
192
 
190
- # %% ../nbs/00_cli.ipynb 28
193
+ # %% ../nbs/00_cli.ipynb #75f7d1ab
191
194
  @call_parse
192
195
  def view(
193
196
  path:Path='.', # Path to project directory
@@ -199,20 +202,22 @@ def view(
199
202
  print(f"Opening browser to view app :\n{url}\n")
200
203
  webbrowser.open(url)
201
204
 
202
- # %% ../nbs/00_cli.ipynb 31
205
+ # %% ../nbs/00_cli.ipynb #43535aef
203
206
  def delete_app(
204
207
  path:Path='.', # Path to project
205
- name:str=None): # Overrides the .plash file in project root if provided
208
+ name:str=None # Overrides the .plash file in project root if provided
209
+ ):
206
210
  'Delete your deployed app'
207
211
  name = _prep(path, name)
208
- r = _mk_auth_req(_endpoint(rt=f"/delete?name={name}"), "delete")
209
- if not r: raise PlashError('Failed to delete app')
212
+ _mk_auth_req(_endpoint(rt=f"/delete?name={name}"), "delete")
210
213
  return f"App '{name}' deleted successfully"
211
214
 
212
215
  @call_parse
213
216
  @delegates(delete_app)
214
- def _delete(force:bool=False, # Skip confirmation prompt
215
- **kwargs):
217
+ def _delete(
218
+ force:bool=False, # Skip confirmation prompt
219
+ **kwargs
220
+ ):
216
221
  'Delete your deployed app'
217
222
  if not force:
218
223
  confirm = input("Are you sure you want to delete the app? [y/N]: ")
@@ -221,14 +226,14 @@ def _delete(force:bool=False, # Skip confirmation prompt
221
226
  except PlashError as e: return str(e)
222
227
  _delete.__doc__ = delete_app.__doc__
223
228
 
224
- # %% ../nbs/00_cli.ipynb 34
229
+ # %% ../nbs/00_cli.ipynb #d72ccd37
225
230
  def start_app(
226
231
  path:Path='.', # Path to project
227
- name:str=None): # Overrides the .plash file in project root if provided
232
+ name:str=None # Overrides the .plash file in project root if provided
233
+ ):
228
234
  'Start your deployed app'
229
235
  name = _prep(path, name)
230
- r = _mk_auth_req(_endpoint(rt=f"/start?name={name}"))
231
- if not r: raise PlashError('Failed to start app')
236
+ _mk_auth_req(_endpoint(rt=f"/start?name={name}"))
232
237
  return f"App '{name}' started"
233
238
 
234
239
  @call_parse
@@ -238,14 +243,14 @@ def _start(**kwargs):
238
243
  except PlashError as e: return str(e)
239
244
  _start.__doc__ = start_app.__doc__
240
245
 
241
- # %% ../nbs/00_cli.ipynb 37
246
+ # %% ../nbs/00_cli.ipynb #ace91510
242
247
  def stop_app(
243
248
  path:Path='.', # Path to project
244
- name:str=None): # Overrides the .plash file in project root if provided
249
+ name:str=None # Overrides the .plash file in project root if provided
250
+ ):
245
251
  'Stop your deployed app'
246
252
  name = _prep(path, name)
247
- r = _mk_auth_req(_endpoint(rt=f"/stop?name={name}"))
248
- if not r: raise PlashError('Failed to stop app')
253
+ _mk_auth_req(_endpoint(rt=f"/stop?name={name}"))
249
254
  return f"App '{name}' stopped"
250
255
 
251
256
  @call_parse
@@ -255,24 +260,26 @@ def _stop(**kwargs):
255
260
  except PlashError as e: return str(e)
256
261
  _stop.__doc__ = stop_app.__doc__
257
262
 
258
- # %% ../nbs/00_cli.ipynb 40
263
+ # %% ../nbs/00_cli.ipynb #24e62f1f
259
264
  log_modes = str_enum('log_modes', 'build', 'app')
260
265
 
261
- # %% ../nbs/00_cli.ipynb 41
266
+ # %% ../nbs/00_cli.ipynb #4c1597b9
262
267
  def logs(
263
268
  path:Path='.', # Path to project
264
269
  name:str=None, # Overrides the .plash file in project root if provided
265
- mode:log_modes='build'): # Choose between build or app logs
270
+ mode:log_modes='build' # Choose between build or app logs
271
+ ):
266
272
  'Get logs for your deployed app'
267
273
  name = _prep(path, name)
268
274
  r = _mk_auth_req(_endpoint(rt=f"/logs?name={name}&mode={mode}"))
269
- if not r: raise PlashError('Failed to retrieve logs')
270
275
  return r.text
271
276
 
272
277
  @call_parse
273
278
  @delegates(logs)
274
- def _logs(tail:bool=False, # Tail the logs
275
- **kwargs):
279
+ def _logs(
280
+ tail:bool=False, # Tail the logs
281
+ **kwargs
282
+ ):
276
283
  try:
277
284
  if not tail: return print(logs(**kwargs))
278
285
  text = ''
@@ -287,22 +294,22 @@ def _logs(tail:bool=False, # Tail the logs
287
294
  except PlashError as e: return str(e)
288
295
  _logs.__doc__ = logs.__doc__
289
296
 
290
- # %% ../nbs/00_cli.ipynb 44
297
+ # %% ../nbs/00_cli.ipynb #f8441125
291
298
  @patch
292
299
  def _is_dir_empty(self:Path): return next(self.iterdir(), None) is None
293
300
 
294
- # %% ../nbs/00_cli.ipynb 48
301
+ # %% ../nbs/00_cli.ipynb #1c057f57
295
302
  def download_app(
296
303
  path:Path='.', # Path to project
297
304
  name:str=None, # Overrides the .plash file in project root if provided
298
- save_path:Path="./download/"): # Save path (optional)
305
+ save_path:Path="./download/" # Save path (optional)
306
+ ):
299
307
  "Download deployed app to save_path."
300
308
  name = _prep(path, name)
301
309
  save_path = Path(save_path)
302
310
  save_path.mkdir(exist_ok=True)
303
311
  if not save_path._is_dir_empty(): raise PlashError(f'Save path ({save_path}) is not empty.')
304
312
  r = _mk_auth_req(_endpoint(rt=f'/download?name={name}'))
305
- if not r: raise PlashError('Download request failed')
306
313
  with tarfile.open(fileobj=io.BytesIO(r.content), mode="r:gz") as tar:
307
314
  tar.extractall(path=save_path, filter='data')
308
315
  return save_path
@@ -314,11 +321,10 @@ def _download(**kwargs):
314
321
  except PlashError as e: return str(e)
315
322
  _download.__doc__ = download_app.__doc__
316
323
 
317
- # %% ../nbs/00_cli.ipynb 51
324
+ # %% ../nbs/00_cli.ipynb #8378e31d
318
325
  def app_list():
319
326
  "List your deployed apps"
320
327
  r = _mk_auth_req(_endpoint(rt="/user_apps"))
321
- if not r: raise PlashError('Failed to retrieve')
322
328
  return r.json()
323
329
 
324
330
  @call_parse
@@ -329,7 +335,7 @@ def _app_list(verbose:bool=False): # Whether to show running status as well as n
329
335
  for a in res: print(f"{a['running']} {a['name']}" if verbose else a['name'])
330
336
  _app_list.__doc__ = app_list.__doc__
331
337
 
332
- # %% ../nbs/00_cli.ipynb 54
338
+ # %% ../nbs/00_cli.ipynb #6ff07c8d
333
339
  def plash_tool_info():
334
340
  from dialoghelper import add_msg
335
341
  add_msg('Plash tools: &`[login, deploy, start_app, stop_app, logs, download_app, app_list]`')
@@ -1,43 +1,29 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plash_cli
3
- Version: 0.3.12
3
+ Version: 0.3.14
4
4
  Summary: CLI for the Plash hosting service
5
- Home-page: https://github.com/AnswerDotAI/plash_cli
6
- Author: Jeremy Howard
7
- Author-email: info@fast.ai
8
- License: Apache Software License 2.0
9
- Keywords: nbdev jupyter notebook python
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Intended Audience :: Developers
5
+ Author-email: Jeremy Howard <info@fast.ai>
6
+ License: Apache-2.0
7
+ Project-URL: Repository, https://github.com/AnswerDotAI/plash_cli
8
+ Project-URL: Documentation, https://AnswerDotAI.github.io/plash_cli
9
+ Keywords: nbdev,jupyter,notebook,python
12
10
  Classifier: Natural Language :: English
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
17
15
  Requires-Python: >=3.10
18
16
  Description-Content-Type: text/markdown
19
17
  License-File: LICENSE
20
- Requires-Dist: fastcore
18
+ Requires-Dist: fastcore>=1.12.27
21
19
  Requires-Dist: httpx>=0.28.1
22
20
  Requires-Dist: python-dotenv
23
21
  Requires-Dist: pyjwt
24
22
  Requires-Dist: cryptography
25
23
  Provides-Extra: dev
26
24
  Requires-Dist: bash_kernel; extra == "dev"
27
- Requires-Dist: nbdev; extra == "dev"
28
- Dynamic: author
29
- Dynamic: author-email
30
- Dynamic: classifier
31
- Dynamic: description
32
- Dynamic: description-content-type
33
- Dynamic: home-page
34
- Dynamic: keywords
35
- Dynamic: license
25
+ Requires-Dist: nbdev>=3; extra == "dev"
36
26
  Dynamic: license-file
37
- Dynamic: provides-extra
38
- Dynamic: requires-dist
39
- Dynamic: requires-python
40
- Dynamic: summary
41
27
 
42
28
  # Plash
43
29
 
@@ -2,8 +2,6 @@ LICENSE
2
2
  MANIFEST.in
3
3
  README.md
4
4
  pyproject.toml
5
- settings.ini
6
- setup.py
7
5
  plash_cli/__init__.py
8
6
  plash_cli/_bash_magic.py
9
7
  plash_cli/_modidx.py
@@ -13,7 +11,6 @@ plash_cli.egg-info/PKG-INFO
13
11
  plash_cli.egg-info/SOURCES.txt
14
12
  plash_cli.egg-info/dependency_links.txt
15
13
  plash_cli.egg-info/entry_points.txt
16
- plash_cli.egg-info/not-zip-safe
17
14
  plash_cli.egg-info/requires.txt
18
15
  plash_cli.egg-info/top_level.txt
19
16
  plash_cli/assets/es256_public_key.pem
@@ -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
@@ -1,4 +1,4 @@
1
- fastcore
1
+ fastcore>=1.12.27
2
2
  httpx>=0.28.1
3
3
  python-dotenv
4
4
  pyjwt
@@ -6,4 +6,4 @@ cryptography
6
6
 
7
7
  [dev]
8
8
  bash_kernel
9
- nbdev
9
+ nbdev>=3
@@ -0,0 +1,51 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "plash_cli"
7
+ dynamic = ["version"]
8
+ description = "CLI for the Plash hosting service"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "Apache-2.0"}
12
+ authors = [{name = "Jeremy Howard", email = "info@fast.ai"}]
13
+ keywords = ['nbdev', 'jupyter', 'notebook', 'python']
14
+ classifiers = ["Natural Language :: English", "Intended Audience :: Developers", "Development Status :: 3 - Alpha", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only"]
15
+ dependencies = ['fastcore>=1.12.27', 'httpx>=0.28.1', 'python-dotenv', 'pyjwt', 'cryptography']
16
+
17
+ [project.urls]
18
+ Repository = "https://github.com/AnswerDotAI/plash_cli"
19
+ Documentation = "https://AnswerDotAI.github.io/plash_cli"
20
+
21
+ [project.entry-points.nbdev]
22
+ plash_cli = "plash_cli._modidx:d"
23
+
24
+ [project.optional-dependencies]
25
+ dev = ['bash_kernel', 'nbdev>=3']
26
+
27
+
28
+ [project.scripts]
29
+ plash-deploy = "plash_cli.cli:_deploy"
30
+ plash-login = "plash_cli.cli:login"
31
+ plash-view = "plash_cli.cli:view"
32
+ plash-logs = "plash_cli.cli:_logs"
33
+ plash-delete = "plash_cli.cli:_delete"
34
+ plash-stop = "plash_cli.cli:_stop"
35
+ plash-start = "plash_cli.cli:_start"
36
+ plash-download = "plash_cli.cli:_download"
37
+ plash-apps = "plash_cli.cli:_app_list"
38
+
39
+ [tool.setuptools.dynamic]
40
+ version = {attr = "plash_cli.__version__"}
41
+
42
+ [tool.setuptools.packages.find]
43
+ include = ["plash_cli"]
44
+
45
+ [tool.nbdev]
46
+ allowed_metadata_keys = ['solveit']
47
+ allowed_cell_metadata_keys = ['solveit_ai']
48
+ custom_sidebar = false
49
+
50
+ [tool.chkstyle]
51
+ skip_paths = ["_modidx.py"]
@@ -1,2 +0,0 @@
1
- __version__ = "0.3.12"
2
- from .cli import *
@@ -1,13 +0,0 @@
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
@@ -1,11 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=64.0"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name="plash_cli"
7
- requires-python=">=3.10"
8
- dynamic = [ "keywords", "description", "version", "dependencies", "optional-dependencies", "readme", "license", "authors", "classifiers", "entry-points", "scripts", "urls"]
9
-
10
- [tool.uv]
11
- cache-keys = [{ file = "pyproject.toml" }, { file = "settings.ini" }, { file = "setup.py" }]
@@ -1,49 +0,0 @@
1
- [DEFAULT]
2
- jupyter_hooks = False
3
- repo = plash_cli
4
- lib_name = plash_cli
5
- version = 0.3.12
6
- min_python = 3.10
7
- license = apache2
8
- black_formatting = False
9
- doc_path = _docs
10
- lib_path = plash_cli
11
- nbs_path = nbs
12
- recursive = True
13
- tst_flags = notest
14
- put_version_in_init = True
15
- branch = main
16
- custom_sidebar = False
17
- doc_host = https://AnswerDotAI.github.io
18
- doc_baseurl = /plash_cli
19
- git_url = https://github.com/AnswerDotAI/plash_cli
20
- title = plash_cli
21
- audience = Developers
22
- author = Jeremy Howard
23
- author_email = info@fast.ai
24
- copyright = 2025 onwards, Jeremy Howard
25
- description = CLI for the Plash hosting service
26
- keywords = nbdev jupyter notebook python
27
- language = English
28
- status = 3
29
- user = AnswerDotAI
30
- requirements = fastcore httpx>=0.28.1 python-dotenv pyjwt cryptography
31
- dev_requirements = bash_kernel nbdev
32
- console_scripts = plash_deploy=plash_cli.cli:_deploy
33
- plash_login=plash_cli.cli:login
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:_app_list
41
- readme_nb = index.ipynb
42
- allowed_metadata_keys =
43
- allowed_cell_metadata_keys =
44
- clean_ids = True
45
- clear_all = False
46
- cell_number = True
47
- skip_procs =
48
- update_pyproject = True
49
-
plash_cli-0.3.12/setup.py DELETED
@@ -1,64 +0,0 @@
1
- from pkg_resources import parse_version
2
- from configparser import ConfigParser
3
- import setuptools, shlex
4
- assert parse_version(setuptools.__version__)>=parse_version('36.2')
5
-
6
- # note: all settings are in settings.ini; edit there, not here
7
- config = ConfigParser(delimiters=['='])
8
- config.read('settings.ini', encoding='utf-8')
9
- cfg = config['DEFAULT']
10
-
11
- cfg_keys = 'version description keywords author author_email'.split()
12
- expected = cfg_keys + "lib_name user branch license status min_python audience language".split()
13
- for o in expected: assert o in cfg, "missing expected setting: {}".format(o)
14
- setup_cfg = {o:cfg[o] for o in cfg_keys}
15
-
16
- licenses = {
17
- 'apache2': ('Apache Software License 2.0','OSI Approved :: Apache Software License'),
18
- 'mit': ('MIT License', 'OSI Approved :: MIT License'),
19
- 'gpl2': ('GNU General Public License v2', 'OSI Approved :: GNU General Public License v2 (GPLv2)'),
20
- 'gpl3': ('GNU General Public License v3', 'OSI Approved :: GNU General Public License v3 (GPLv3)'),
21
- 'bsd3': ('BSD License', 'OSI Approved :: BSD License'),
22
- }
23
- statuses = [ '1 - Planning', '2 - Pre-Alpha', '3 - Alpha',
24
- '4 - Beta', '5 - Production/Stable', '6 - Mature', '7 - Inactive' ]
25
- py_versions = '3.6 3.7 3.8 3.9 3.10 3.11 3.12'.split()
26
-
27
- requirements = shlex.split(cfg.get('requirements', ''))
28
- if cfg.get('pip_requirements'): requirements += shlex.split(cfg.get('pip_requirements', ''))
29
- min_python = cfg['min_python']
30
- lic = licenses.get(cfg['license'].lower(), (cfg['license'], None))
31
- dev_requirements = (cfg.get('dev_requirements') or '').split()
32
-
33
- package_data = dict()
34
- pkg_data = cfg.get('package_data', None)
35
- if pkg_data:
36
- package_data[cfg['lib_name']] = pkg_data.split() # split as multiple files might be listed
37
- # Add package data to setup_cfg for setuptools.setup(..., **setup_cfg)
38
- setup_cfg['package_data'] = package_data
39
-
40
- setuptools.setup(
41
- name = cfg['lib_name'],
42
- license = lic[0],
43
- classifiers = [
44
- 'Development Status :: ' + statuses[int(cfg['status'])],
45
- 'Intended Audience :: ' + cfg['audience'].title(),
46
- 'Natural Language :: ' + cfg['language'].title(),
47
- ] + ['Programming Language :: Python :: '+o for o in py_versions[py_versions.index(min_python):]] + (['License :: ' + lic[1] ] if lic[1] else []),
48
- url = cfg['git_url'],
49
- packages = setuptools.find_packages(),
50
- include_package_data = True,
51
- install_requires = requirements,
52
- extras_require={ 'dev': dev_requirements },
53
- dependency_links = cfg.get('dep_links','').split(),
54
- python_requires = '>=' + cfg['min_python'],
55
- long_description = open('README.md', encoding='utf-8').read(),
56
- long_description_content_type = 'text/markdown',
57
- zip_safe = False,
58
- entry_points = {
59
- 'console_scripts': cfg.get('console_scripts','').split(),
60
- 'nbdev': [f'{cfg.get("lib_path")}={cfg.get("lib_path")}._modidx:d']
61
- },
62
- **setup_cfg)
63
-
64
-
File without changes
File without changes
File without changes
File without changes