dsw-tdk 3.22.1__py2.py3-none-any.whl → 3.24.0__py2.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.
dsw/tdk/api_client.py CHANGED
@@ -91,7 +91,7 @@ class DSWAPIClient:
91
91
  """
92
92
  self.api_url = api_url
93
93
  self.token = None
94
- self.session = session or aiohttp.ClientSession(connector=aiohttp.TCPConnector(verify_ssl=False))
94
+ self.session = session or aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False))
95
95
 
96
96
  @property
97
97
  def templates_endpoint(self):
@@ -142,6 +142,10 @@ class DSWAPIClient:
142
142
  self.token = body.get('token', None)
143
143
  return self.token
144
144
 
145
+ @handle_client_errors
146
+ async def get_current_user(self) -> dict:
147
+ return await self._get_json('/users/current')
148
+
145
149
  @handle_client_errors
146
150
  async def check_template_exists(self, remote_id: str) -> bool:
147
151
  async with self.session.get(f'{self.templates_endpoint}/{remote_id}', headers=self._headers()) as r:
dsw/tdk/build_info.py CHANGED
@@ -9,9 +9,9 @@ BuildInfo = namedtuple(
9
9
  )
10
10
 
11
11
  BUILD_INFO = BuildInfo(
12
- version='v3.22.1~f58badd',
13
- built_at='2023-04-14 12:55:45Z',
14
- sha='f58badda4c93b654651aedd46e082f1d756eb2aa',
12
+ version='v3.24.0~de1a777',
13
+ built_at='2023-05-31 09:42:09Z',
14
+ sha='de1a777fb9287f666e161e98200054ae757fa44c',
15
15
  branch='HEAD',
16
- tag='v3.22.1',
16
+ tag='v3.24.0',
17
17
  )
dsw/tdk/cli.py CHANGED
@@ -1,4 +1,6 @@
1
1
  import asyncio
2
+ import sys
3
+
2
4
  import click # type: ignore
3
5
  import datetime
4
6
  import dotenv
@@ -39,6 +41,11 @@ class ClickPrinter:
39
41
  def error(message: str, **kwargs):
40
42
  click.secho(message=message, err=True, fg='red', **kwargs)
41
43
 
44
+ @staticmethod
45
+ def warning(message: str, **kwargs):
46
+ click.secho('WARNING', fg='yellow', bold=True, nl=False)
47
+ click.echo(f': {message}')
48
+
42
49
  @staticmethod
43
50
  def success(message: str):
44
51
  click.secho('SUCCESS', fg='green', bold=True, nl=False)
@@ -171,6 +178,37 @@ class CLIContext:
171
178
  self.logger.muted = True
172
179
 
173
180
 
181
+ class APICredentials:
182
+
183
+ def __init__(self, username, password, api_key):
184
+ self.username = username
185
+ self.password = password
186
+ self.api_key = api_key
187
+
188
+ def check(self):
189
+ if self.api_key is not None:
190
+ return
191
+ if self.username is not None and self.password is not None:
192
+ ClickPrinter.warning('Using username/password credentials, '
193
+ 'consider switching to API keys.')
194
+ ClickPrinter.warning('Username/password authentication will be '
195
+ 'removed in 3.25 as deprecated.')
196
+ return False
197
+ ClickPrinter.failure('Invalid credentials entered! You need to provide '
198
+ 'either API key or username/password credentials.')
199
+ sys.exit(1)
200
+
201
+ def init_args(self):
202
+ if self.api_key is not None:
203
+ return {
204
+ 'api_key': self.api_key,
205
+ }
206
+ return {
207
+ 'username': self.username,
208
+ 'password': self.password,
209
+ }
210
+
211
+
174
212
  def interact_formats() -> Dict[str, FormatSpec]:
175
213
  add_format = click.confirm('Do you want to add a format?', default=True)
176
214
  formats = dict() # type: Dict[str, FormatSpec]
@@ -270,21 +308,25 @@ def new_template(ctx, template_dir, force):
270
308
  @click.argument('TEMPLATE-DIR', type=NEW_DIR_TYPE, default=None, required=False)
271
309
  @click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API',
272
310
  prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url)
273
- @click.option('-u', '--username', envvar='DSW_USERNAME', prompt='Username', hide_input=False,
274
- metavar='EMAIL', help='Admin username (email) for DSW instance.')
275
- @click.option('-p', '--password', envvar='DSW_PASSWORD', prompt='Email', hide_input=True,
276
- metavar='PASSWORD', help='Admin password for DSW instance.')
311
+ @click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None,
312
+ help='Admin username (email) for DSW instance.')
313
+ @click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None,
314
+ help='Admin password for DSW instance.')
315
+ @click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None,
316
+ help='API key for DSW instance.')
277
317
  @click.option('-f', '--force', is_flag=True, help='Overwrite any existing files.')
278
318
  @click.pass_context
279
- def get_template(ctx, api_server, template_id, template_dir, username, password, force):
280
- template_dir = template_dir or dir_from_id(template_id)
319
+ def get_template(ctx, api_server, template_id, template_dir, username, password, api_key, force):
320
+ template_dir = pathlib.Path(template_dir or dir_from_id(template_id))
321
+ creds = APICredentials(username=username, password=password, api_key=api_key)
322
+ creds.check()
281
323
 
282
324
  async def main_routine():
283
325
  tdk = TDKCore(logger=ctx.obj.logger)
284
326
  template_type = 'unknown'
285
327
  zip_data = None
286
328
  try:
287
- await tdk.init_client(api_url=api_server, username=username, password=password)
329
+ await tdk.init_client(api_url=api_server, **creds.init_args())
288
330
  try:
289
331
  await tdk.load_remote(template_id=template_id)
290
332
  template_type = 'draft'
@@ -295,6 +337,7 @@ def get_template(ctx, api_server, template_id, template_dir, username, password,
295
337
  except DSWCommunicationError as e:
296
338
  ClickPrinter.error('Could not get template:', bold=True)
297
339
  ClickPrinter.error(f'> {e.reason}\n> {e.message}')
340
+ await tdk.safe_client.close()
298
341
  exit(1)
299
342
  await tdk.safe_client.safe_close()
300
343
  if template_type == 'draft':
@@ -305,6 +348,7 @@ def get_template(ctx, api_server, template_id, template_dir, username, password,
305
348
  except Exception as e:
306
349
  ClickPrinter.failure('Could not store template locally')
307
350
  ClickPrinter.error(f'> {e}')
351
+ await tdk.safe_client.close()
308
352
  exit(1)
309
353
  elif template_type == 'bundle' and zip_data is not None:
310
354
  try:
@@ -313,6 +357,7 @@ def get_template(ctx, api_server, template_id, template_dir, username, password,
313
357
  except Exception as e:
314
358
  ClickPrinter.failure('Could not store template locally')
315
359
  ClickPrinter.error(f'> {e}')
360
+ await tdk.safe_client.close()
316
361
  exit(1)
317
362
  else:
318
363
  ClickPrinter.failure(f'{template_id} is not released nor draft of a document template')
@@ -326,15 +371,19 @@ def get_template(ctx, api_server, template_id, template_dir, username, password,
326
371
  @click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False)
327
372
  @click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API',
328
373
  prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url)
329
- @click.option('-u', '--username', envvar='DSW_USERNAME', prompt='Username', hide_input=False,
330
- metavar='USERNAME', help='Admin username (email address) for DSW instance.')
331
- @click.option('-p', '--password', envvar='DSW_PASSWORD', prompt='Password', hide_input=True,
332
- metavar='PASSWORD', help='Admin password for DSW instance.')
374
+ @click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None,
375
+ help='Admin username (email) for DSW instance.')
376
+ @click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None,
377
+ help='Admin password for DSW instance.')
378
+ @click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None,
379
+ help='API key for DSW instance.')
333
380
  @click.option('-f', '--force', is_flag=True, help='Delete template if already exists.')
334
381
  @click.option('-w', '--watch', is_flag=True, help='Enter watch mode to continually upload changes.')
335
382
  @click.pass_context
336
- def put_template(ctx, api_server, template_dir, username, password, force, watch):
383
+ def put_template(ctx, api_server, template_dir, username, password, api_key, force, watch):
337
384
  tdk = TDKCore(logger=ctx.obj.logger)
385
+ creds = APICredentials(username=username, password=password, api_key=api_key)
386
+ creds.check()
338
387
 
339
388
  async def watch_callback(changes):
340
389
  changes = list(changes)
@@ -350,7 +399,7 @@ def put_template(ctx, api_server, template_dir, username, password, force, watch
350
399
  async def main_routine():
351
400
  load_local(tdk, template_dir)
352
401
  try:
353
- await tdk.init_client(api_server, username, password)
402
+ await tdk.init_client(api_url=api_server, **creds.init_args())
354
403
  await tdk.store_remote(force=force)
355
404
  ClickPrinter.success(f'Template {tdk.safe_project.safe_template.id} '
356
405
  f'uploaded to {api_server}')
@@ -409,7 +458,7 @@ def extract_package(ctx, template_package, output, force: bool):
409
458
  data = pathlib.Path(template_package).read_bytes()
410
459
  tdk.extract_package(
411
460
  zip_data=data,
412
- template_dir=output,
461
+ template_dir=pathlib.Path(output),
413
462
  force=force,
414
463
  )
415
464
  except Exception as e:
@@ -422,21 +471,26 @@ def extract_package(ctx, template_package, output, force: bool):
422
471
  @main.command(help='List templates from DSW via API.', name='list')
423
472
  @click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API',
424
473
  prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url)
425
- @click.option('-u', '--username', envvar='DSW_USERNAME', prompt='Username', hide_input=False,
426
- metavar='USERNAME', help='Admin username (email address) for DSW instance.')
427
- @click.option('-p', '--password', envvar='DSW_PASSWORD', prompt='Password', hide_input=True,
428
- metavar='PASSWORD', help='Admin password for DSW instance.')
474
+ @click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None,
475
+ help='Admin username (email) for DSW instance.')
476
+ @click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None,
477
+ help='Admin password for DSW instance.')
478
+ @click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None,
479
+ help='API key for DSW instance.')
429
480
  @click.option('--output-format', default=DEFAULT_LIST_FORMAT,
430
481
  metavar='FORMAT', help='Entry format string for printing.')
431
482
  @click.option('-r', '--released-only', is_flag=True, help='List only released templates')
432
483
  @click.option('-d', '--drafts-only', is_flag=True, help='List only template drafts')
433
484
  @click.pass_context
434
- def list_templates(ctx, api_server, username, password, output_format: str,
485
+ def list_templates(ctx, api_server, username, password, api_key, output_format: str,
435
486
  released_only: bool, drafts_only: bool):
487
+ creds = APICredentials(username=username, password=password, api_key=api_key)
488
+ creds.check()
489
+
436
490
  async def main_routine():
437
491
  tdk = TDKCore(logger=ctx.obj.logger)
438
492
  try:
439
- await tdk.init_client(api_server, username, password)
493
+ await tdk.init_client(api_url=api_server, **creds.init_args())
440
494
  if released_only:
441
495
  templates = await tdk.list_remote_templates()
442
496
  for template in templates:
@@ -454,12 +508,13 @@ def list_templates(ctx, api_server, username, password, output_format: str,
454
508
  drafts = await tdk.list_remote_drafts()
455
509
  for template in drafts:
456
510
  click.echo(output_format.format(template=template))
511
+ await tdk.safe_client.safe_close()
457
512
 
458
513
  except DSWCommunicationError as e:
459
514
  ClickPrinter.failure('Failed to get list of templates')
460
515
  ClickPrinter.error(f'> {e.reason}\n> {e.message}')
516
+ await tdk.safe_client.safe_close()
461
517
  exit(1)
462
- await tdk.safe_client.safe_close()
463
518
 
464
519
  loop = asyncio.get_event_loop()
465
520
  loop.run_until_complete(main_routine())
dsw/tdk/consts.py CHANGED
@@ -3,7 +3,7 @@ import pathspec # type: ignore
3
3
  import re
4
4
 
5
5
  APP = 'dsw-tdk'
6
- VERSION = '3.22.0'
6
+ VERSION = '3.24.0'
7
7
  METAMODEL_VERSION = 11
8
8
 
9
9
  REGEX_SEMVER = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+$')
dsw/tdk/core.py CHANGED
@@ -99,12 +99,18 @@ class TDKCore:
99
99
  raise RuntimeError('No DSW API client specified')
100
100
  return self.client
101
101
 
102
- async def init_client(self, api_url: str, username: str, password: str):
102
+ async def init_client(self, api_url: str, username: Optional[str] = None,
103
+ password: Optional[str] = None, api_key: Optional[str] = None):
103
104
  self.logger.info(f'Connecting to {api_url}')
104
105
  self.client = DSWAPIClient(api_url=api_url)
105
- await self.client.login(email=username, password=password)
106
+ if api_key is not None:
107
+ self.client.token = api_key # type: ignore
108
+ if username is not None and password is not None:
109
+ await self.client.login(email=username, password=password)
106
110
  self.remote_version = await self.client.get_api_version()
107
- self.logger.info(f'Successfully authenticated as {username}')
111
+ user = await self.client.get_current_user()
112
+ self.logger.info(f'Successfully authenticated as {user["firstName"]} '
113
+ f'{user["lastName"]} ({user["email"]})')
108
114
  self.logger.debug(f'Connected to API version {self.remote_version}')
109
115
 
110
116
  def prepare_local(self, template_dir):
dsw/tdk/validation.py CHANGED
@@ -63,7 +63,7 @@ def _validate_version(field_name: str, value) -> List[ValidationError]:
63
63
 
64
64
  def _validate_natural(field_name: str, value) -> List[ValidationError]:
65
65
  if value is not None and (not isinstance(value, int) or value < 1):
66
- return [ValidationError(field_name, 'Field {field_name} must be positive integer')]
66
+ return [ValidationError(field_name, 'It must be positive integer')]
67
67
  return []
68
68
 
69
69
 
@@ -173,9 +173,7 @@ def _validate_steps(field_name: str, value: List[Step]) -> List[ValidationError]
173
173
  FormatValidator = GenericValidator({
174
174
  'uuid': [_validate_required, _validate_non_empty],
175
175
  'name': [_validate_required, _validate_non_empty],
176
- 'short_name': [_validate_required, _validate_non_empty],
177
176
  'icon': [_validate_required, _validate_non_empty],
178
- 'color': [_validate_required, _validate_non_empty],
179
177
  'steps': [_validate_required, _validate_steps],
180
178
  })
181
179
 
@@ -198,7 +196,6 @@ TemplateValidator = GenericValidator({
198
196
  'name': [_validate_required, _validate_non_empty],
199
197
  'description': [_validate_required, _validate_non_empty],
200
198
  'readme': [_validate_required, _validate_non_empty],
201
- 'recommended_package_id': [_validate_package_id],
202
199
  'license': [_validate_required, _validate_non_empty],
203
200
  'metamodel_version': [_validate_natural],
204
201
  'allowed_packages': [_validate_package_filters],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dsw-tdk
3
- Version: 3.22.1
3
+ Version: 3.24.0
4
4
  Summary: Data Stewardship Wizard Template Development Toolkit
5
5
  Author-email: Marek Suchánek <marek.suchanek@ds-wizard.org>
6
6
  License: Apache License 2.0
@@ -12,14 +12,12 @@ Classifier: Framework :: AsyncIO
12
12
  Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: Programming Language :: Python
15
- Classifier: Programming Language :: Python :: 3.7
16
- Classifier: Programming Language :: Python :: 3.8
17
15
  Classifier: Programming Language :: Python :: 3.9
18
16
  Classifier: Programming Language :: Python :: 3.10
19
17
  Classifier: Programming Language :: Python :: 3.11
20
18
  Classifier: Topic :: Internet :: WWW/HTTP
21
19
  Classifier: Topic :: Utilities
22
- Requires-Python: <4,>=3.7
20
+ Requires-Python: <4,>=3.9
23
21
  Description-Content-Type: text/markdown
24
22
  License-File: LICENSE
25
23
  Requires-Dist: aiohttp
@@ -0,0 +1,18 @@
1
+ dsw/tdk/__init__.py,sha256=zJeTybb0SqiNdGLkANjRa36hku4axi17mZL2dM3tHto,288
2
+ dsw/tdk/__main__.py,sha256=IkqeOatxravhcQCdk4l0BkbaMILkgVopB9phYCIR1uo,38
3
+ dsw/tdk/api_client.py,sha256=1Mk-OCtVNY_86JLUys72Fam0T7mGff7CMqsZDon8e0c,14205
4
+ dsw/tdk/build_info.py,sha256=4IFfjHb9Q4Q7k-W9WU72RyOB1eTM1a4KroWDgiePDFM,381
5
+ dsw/tdk/cli.py,sha256=EEvbvGrReh-R0_hKVCm9Nicc50qXCNERS_FhloW_p-w,22154
6
+ dsw/tdk/consts.py,sha256=iU8yoZLoqI5nnccQGVxBzf74JppwnU1fxtqZNJ28Bo4,635
7
+ dsw/tdk/core.py,sha256=xUbwWR7bl8K5leW8ML3Phu-XjXVejl-H8TF8RLxqVy4,25001
8
+ dsw/tdk/model.py,sha256=B9_cCmg_Z2IHabMMychKFV4dh4SFPVEentuPcb5fzlY,17235
9
+ dsw/tdk/utils.py,sha256=xt7INb2t-ChyIbR-VyQSYrPWupu2ufOlpatxN9yGrz0,4877
10
+ dsw/tdk/validation.py,sha256=hr04MRVqwBIBeKoX6v53Ix1S-vjvIQYM5dwI0SnMRsc,7827
11
+ dsw/tdk/templates/README.md.j2,sha256=FzUABeMM8To0oT48Kytoox64uAZ8F7FSAAXgpyKzqdU,247
12
+ dsw/tdk/templates/starter.j2,sha256=XjZy3T9i8aWFlq4clXL6Q4JNh455crGelR9AoHisTbw,296
13
+ dsw_tdk-3.24.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
14
+ dsw_tdk-3.24.0.dist-info/METADATA,sha256=Mp3gyrBrZyehwr8Uj2yXFIEC249E6W0SzayyFblGeIY,6149
15
+ dsw_tdk-3.24.0.dist-info/WHEEL,sha256=a-zpFRIJzOq5QfuhBzbhiA1eHTzNCJn8OdRvhdNX0Rk,110
16
+ dsw_tdk-3.24.0.dist-info/entry_points.txt,sha256=lwD5ZzRCbTFSjP1-SkhYsaJe8sEXOWWgMAMUhw0v2Hk,41
17
+ dsw_tdk-3.24.0.dist-info/top_level.txt,sha256=7SfbsHFoJ_vlAgG6C-xzETETwYO71dBrGnod8uMFnjw,4
18
+ dsw_tdk-3.24.0.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- dsw/tdk/__init__.py,sha256=zJeTybb0SqiNdGLkANjRa36hku4axi17mZL2dM3tHto,288
2
- dsw/tdk/__main__.py,sha256=IkqeOatxravhcQCdk4l0BkbaMILkgVopB9phYCIR1uo,38
3
- dsw/tdk/api_client.py,sha256=_iTJs4t4xaoQEm_4yRhUbU5xVXZXlkPd9rc6-Sl9HtM,14085
4
- dsw/tdk/build_info.py,sha256=bFisVzo1HaYqfJuTaGtWuzNAzmtiATo4bxTgS6O9YPU,381
5
- dsw/tdk/cli.py,sha256=9_A3w7N1wCWg07f8FrnD30yfpe7t_fcsbQldoCwhahk,20129
6
- dsw/tdk/consts.py,sha256=daHCLPRc35xZHgPPWItzXYpUbhuMNkQ1Xn9ydbEbP3Q,635
7
- dsw/tdk/core.py,sha256=BDRnfwI7yhAkQfzEIRF3VRPDkpX-Owmw2ATMsEyh6g8,24633
8
- dsw/tdk/model.py,sha256=B9_cCmg_Z2IHabMMychKFV4dh4SFPVEentuPcb5fzlY,17235
9
- dsw/tdk/utils.py,sha256=xt7INb2t-ChyIbR-VyQSYrPWupu2ufOlpatxN9yGrz0,4877
10
- dsw/tdk/validation.py,sha256=GuLClmYwpSr0sU4xz0TZo7jXPgDjAqRxLjgrLoHDdg0,8014
11
- dsw/tdk/templates/README.md.j2,sha256=FzUABeMM8To0oT48Kytoox64uAZ8F7FSAAXgpyKzqdU,247
12
- dsw/tdk/templates/starter.j2,sha256=XjZy3T9i8aWFlq4clXL6Q4JNh455crGelR9AoHisTbw,296
13
- dsw_tdk-3.22.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
14
- dsw_tdk-3.22.1.dist-info/METADATA,sha256=_QeXOApAsQ6tktxJiege2gPkMl4qR7AIUY3EFy4nw8Q,6249
15
- dsw_tdk-3.22.1.dist-info/WHEEL,sha256=a-zpFRIJzOq5QfuhBzbhiA1eHTzNCJn8OdRvhdNX0Rk,110
16
- dsw_tdk-3.22.1.dist-info/entry_points.txt,sha256=lwD5ZzRCbTFSjP1-SkhYsaJe8sEXOWWgMAMUhw0v2Hk,41
17
- dsw_tdk-3.22.1.dist-info/top_level.txt,sha256=7SfbsHFoJ_vlAgG6C-xzETETwYO71dBrGnod8uMFnjw,4
18
- dsw_tdk-3.22.1.dist-info/RECORD,,