dsw-tdk 4.13.0__tar.gz → 4.15.0__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.
Files changed (39) hide show
  1. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/CHANGELOG.md +15 -0
  2. {dsw_tdk-4.13.0/dsw_tdk.egg-info → dsw_tdk-4.15.0}/PKG-INFO +4 -4
  3. dsw_tdk-4.15.0/dsw/tdk/__main__.py +4 -0
  4. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/api_client.py +58 -30
  5. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/build_info.py +4 -4
  6. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/cli.py +62 -48
  7. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/consts.py +4 -3
  8. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/core.py +127 -99
  9. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/model.py +77 -67
  10. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/templates/starter.j2 +1 -2
  11. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/utils.py +8 -9
  12. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/validation.py +72 -18
  13. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0/dsw_tdk.egg-info}/PKG-INFO +4 -4
  14. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/pyproject.toml +3 -3
  15. dsw_tdk-4.13.0/dsw/tdk/__main__.py +0 -3
  16. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/LICENSE +0 -0
  17. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/MANIFEST.in +0 -0
  18. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/README.md +0 -0
  19. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/__init__.py +0 -0
  20. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/templates/LICENSE.j2 +0 -0
  21. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/templates/README.md.j2 +0 -0
  22. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw/tdk/templates/env.j2 +0 -0
  23. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw_tdk.egg-info/SOURCES.txt +0 -0
  24. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw_tdk.egg-info/dependency_links.txt +0 -0
  25. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw_tdk.egg-info/entry_points.txt +0 -0
  26. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw_tdk.egg-info/not-zip-safe +0 -0
  27. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw_tdk.egg-info/requires.txt +0 -0
  28. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/dsw_tdk.egg-info/top_level.txt +0 -0
  29. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/setup.cfg +0 -0
  30. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/setup.py +0 -0
  31. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_basic.py +0 -0
  32. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_cmd_dot-env.py +0 -0
  33. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_cmd_get.py +0 -0
  34. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_cmd_list.py +0 -0
  35. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_cmd_new.py +0 -0
  36. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_cmd_package.py +0 -0
  37. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_cmd_put.py +0 -0
  38. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_cmd_unpackage.py +0 -0
  39. {dsw_tdk-4.13.0 → dsw_tdk-4.15.0}/tests/test_cmd_verify.py +0 -0
@@ -8,6 +8,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  ## [Unreleased]
9
9
 
10
10
 
11
+ ## [4.15.0]
12
+
13
+ ### Fixed
14
+
15
+ - Fixed broken variables in logs
16
+
17
+ ## [4.14.0]
18
+
19
+ ### Changed
20
+
21
+ - Improved hidden file handling
22
+ - Updated initial Jinja file for new projects
23
+
11
24
  ## [4.13.0]
12
25
 
13
26
  ### Changed
@@ -509,3 +522,5 @@ Initial DSW Template Development Kit (versioned as part of the [DSW platform](ht
509
522
  [4.11.0]: /../../tree/v4.11.0
510
523
  [4.12.0]: /../../tree/v4.12.0
511
524
  [4.13.0]: /../../tree/v4.13.0
525
+ [4.14.0]: /../../tree/v4.14.0
526
+ [4.15.0]: /../../tree/v4.15.0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dsw-tdk
3
- Version: 4.13.0
3
+ Version: 4.15.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,12 +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.9
16
15
  Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Topic :: Internet :: WWW/HTTP
19
19
  Classifier: Topic :: Utilities
20
- Requires-Python: <4,>=3.9
20
+ Requires-Python: <4,>=3.10
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  Requires-Dist: aiohttp
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ # pylint: disable-next=no-value-for-parameter
4
+ main(ctx=None)
@@ -1,10 +1,9 @@
1
- import aiohttp
2
- import aiohttp.client_exceptions
3
1
  import functools
4
2
  import pathlib
5
3
  import urllib.parse
6
4
 
7
- from typing import List, Optional
5
+ import aiohttp
6
+ import aiohttp.client_exceptions
8
7
 
9
8
  from .consts import DEFAULT_ENCODING, APP, VERSION
10
9
  from .model import Template, TemplateFile, TemplateFileType
@@ -36,30 +35,31 @@ def handle_client_errors(func):
36
35
  raise DSWCommunicationError(
37
36
  reason='Unexpected response type',
38
37
  message=e.message
39
- )
38
+ ) from e
40
39
  except aiohttp.client_exceptions.ClientResponseError as e:
41
40
  raise DSWCommunicationError(
42
41
  reason='Error response status',
43
42
  message=f'Server responded with error HTTP status {e.status}: {e.message}'
44
- )
43
+ ) from e
45
44
  except aiohttp.client_exceptions.InvalidURL as e:
46
45
  raise DSWCommunicationError(
47
46
  reason='Invalid URL',
48
47
  message=f'Provided API URL seems invalid: {e.url}'
49
- )
48
+ ) from e
50
49
  except aiohttp.client_exceptions.ClientConnectorError as e:
51
50
  raise DSWCommunicationError(
52
51
  reason='Server unreachable',
53
52
  message=f'Desired server is not reachable (errno {e.os_error.errno})'
54
- )
53
+ ) from e
55
54
  except Exception as e:
56
55
  raise DSWCommunicationError(
57
56
  reason='Communication error',
58
57
  message=f'Communication with server failed ({e})'
59
- )
58
+ ) from e
60
59
  return handled_client_call
61
60
 
62
61
 
62
+ # pylint: disable-next=too-many-public-methods
63
63
  class DSWAPIClient:
64
64
 
65
65
  def _headers(self, extra=None):
@@ -91,7 +91,9 @@ class DSWAPIClient:
91
91
  """
92
92
  self.api_url = api_url
93
93
  self.token = api_key
94
- self.session = session or aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False))
94
+ self.session = session or aiohttp.ClientSession(
95
+ connector=aiohttp.TCPConnector(ssl=False),
96
+ )
95
97
 
96
98
  @property
97
99
  def templates_endpoint(self):
@@ -112,31 +114,48 @@ class DSWAPIClient:
112
114
  return False
113
115
 
114
116
  async def _post_json(self, endpoint, json) -> dict:
115
- async with self.session.post(f'{self.api_url}{endpoint}', json=json, headers=self._headers()) as r:
117
+ async with self.session.post(
118
+ url=f'{self.api_url}{endpoint}',
119
+ json=json,
120
+ headers=self._headers(),
121
+ ) as r:
116
122
  self._check_status(r, expected_status=201)
117
123
  return await r.json()
118
124
 
119
125
  async def _put_json(self, endpoint, json) -> dict:
120
- async with self.session.put(f'{self.api_url}{endpoint}', json=json, headers=self._headers()) as r:
126
+ async with self.session.put(
127
+ url=f'{self.api_url}{endpoint}',
128
+ json=json,
129
+ headers=self._headers(),
130
+ ) as r:
121
131
  self._check_status(r, expected_status=200)
122
132
  return await r.json()
123
133
 
124
134
  async def _get_json(self, endpoint) -> dict:
125
- async with self.session.get(f'{self.api_url}{endpoint}', headers=self._headers()) as r:
135
+ async with self.session.get(
136
+ url=f'{self.api_url}{endpoint}',
137
+ headers=self._headers(),
138
+ ) as r:
126
139
  self._check_status(r, expected_status=200)
127
140
  return await r.json()
128
141
 
129
142
  async def _get_bytes(self, endpoint) -> bytes:
130
- async with self.session.get(f'{self.api_url}{endpoint}', headers=self._headers()) as r:
143
+ async with self.session.get(
144
+ url=f'{self.api_url}{endpoint}',
145
+ headers=self._headers(),
146
+ ) as r:
131
147
  self._check_status(r, expected_status=200)
132
148
  return await r.read()
133
149
 
134
150
  async def _delete(self, endpoint) -> bool:
135
- async with self.session.delete(f'{self.api_url}{endpoint}', headers=self._headers()) as r:
151
+ async with self.session.delete(
152
+ url=f'{self.api_url}{endpoint}',
153
+ headers=self._headers(),
154
+ ) as r:
136
155
  return r.status == 204
137
156
 
138
157
  @handle_client_errors
139
- async def login(self, email: str, password: str) -> Optional[str]:
158
+ async def login(self, email: str, password: str) -> str | None:
140
159
  req = {'email': email, 'password': password}
141
160
  body = await self._post_json('/tokens', json=req)
142
161
  self.token = body.get('token', None)
@@ -148,7 +167,10 @@ class DSWAPIClient:
148
167
 
149
168
  @handle_client_errors
150
169
  async def check_template_exists(self, remote_id: str) -> bool:
151
- async with self.session.get(f'{self.templates_endpoint}/{remote_id}', headers=self._headers()) as r:
170
+ async with self.session.get(
171
+ url=f'{self.templates_endpoint}/{remote_id}',
172
+ headers=self._headers(),
173
+ ) as r:
152
174
  if r.status == 404:
153
175
  return False
154
176
  self._check_status(r, expected_status=200)
@@ -156,20 +178,22 @@ class DSWAPIClient:
156
178
 
157
179
  @handle_client_errors
158
180
  async def check_draft_exists(self, remote_id: str) -> bool:
159
- async with self.session.get(f'{self.drafts_endpoint}/{remote_id}', headers=self._headers()) as r:
181
+ async with self.session.get(
182
+ url=f'{self.drafts_endpoint}/{remote_id}',
183
+ headers=self._headers(),
184
+ ) as r:
160
185
  if r.status == 404:
161
186
  return False
162
187
  self._check_status(r, expected_status=200)
163
188
  return True
164
189
 
165
190
  @handle_client_errors
166
- async def get_templates(self) -> List[Template]:
191
+ async def get_templates(self) -> list[Template]:
167
192
  body = await self._get_json('/document-templates/all')
168
193
  return list(map(_load_remote_template, body))
169
194
 
170
195
  @handle_client_errors
171
- async def get_drafts(self) -> List[Template]:
172
- # TODO: better paging
196
+ async def get_drafts(self) -> list[Template]:
173
197
  body = await self._get_json('/document-template-drafts?size=10000')
174
198
  drafts = body.get('_embedded', {}).get('documentTemplateDrafts', [])
175
199
  return list(map(_load_remote_template, drafts))
@@ -191,7 +215,7 @@ class DSWAPIClient:
191
215
  return _load_remote_template(body)
192
216
 
193
217
  @handle_client_errors
194
- async def get_template_draft_files(self, remote_id: str) -> List[TemplateFile]:
218
+ async def get_template_draft_files(self, remote_id: str) -> list[TemplateFile]:
195
219
  body = await self._get_json(f'/document-template-drafts/{remote_id}/files')
196
220
  result = []
197
221
  for file_body in body:
@@ -206,7 +230,7 @@ class DSWAPIClient:
206
230
  return _load_remote_file(body)
207
231
 
208
232
  @handle_client_errors
209
- async def get_template_draft_assets(self, remote_id: str) -> List[TemplateFile]:
233
+ async def get_template_draft_assets(self, remote_id: str) -> list[TemplateFile]:
210
234
  body = await self._get_json(f'/document-template-drafts/{remote_id}/assets')
211
235
  result = []
212
236
  for file_body in body:
@@ -217,8 +241,10 @@ class DSWAPIClient:
217
241
 
218
242
  @handle_client_errors
219
243
  async def get_template_draft_asset(self, remote_id: str, asset_id: str) -> TemplateFile:
220
- body = await self._get_json(f'/document-template-drafts/{remote_id}/assets/{asset_id}')
221
- content = await self._get_bytes(f'/document-template-drafts/{remote_id}/assets/{asset_id}/content')
244
+ body = await self._get_json(f'/document-template-drafts/{remote_id}'
245
+ f'/assets/{asset_id}')
246
+ content = await self._get_bytes(f'/document-template-drafts/{remote_id}'
247
+ f'/assets/{asset_id}/content')
222
248
  return _load_remote_asset(body, content)
223
249
 
224
250
  @handle_client_errors
@@ -258,7 +284,8 @@ class DSWAPIClient:
258
284
  async def put_template_draft_file_content(self, remote_id: str, tfile: TemplateFile):
259
285
  self.session.headers.update(self._headers())
260
286
  async with self.session.put(
261
- f'{self.api_url}/document-template-drafts/{remote_id}/files/{tfile.remote_id}/content',
287
+ f'{self.api_url}/document-template-drafts/{remote_id}'
288
+ f'/files/{tfile.remote_id}/content',
262
289
  data=tfile.content,
263
290
  headers={'Content-Type': 'text/plain;charset=UTF-8'},
264
291
  ) as r:
@@ -302,7 +329,8 @@ class DSWAPIClient:
302
329
  value=tfile.filename.as_posix(),
303
330
  )
304
331
  async with self.session.put(
305
- f'{self.api_url}/document-template-drafts/{remote_id}/assets/{tfile.remote_id}/content',
332
+ f'{self.api_url}/document-template-drafts/{remote_id}'
333
+ f'/assets/{tfile.remote_id}/content',
306
334
  data=data,
307
335
  headers=self._headers()
308
336
  ) as r:
@@ -338,11 +366,11 @@ class DSWAPIClient:
338
366
 
339
367
 
340
368
  def _load_remote_file(data: dict) -> TemplateFile:
341
- content = data.get('content', None) # type: str
342
- filename = str(data.get('fileName', '')) # type: str
369
+ content: str = data.get('content', '')
370
+ filename: str = str(data.get('fileName', ''))
343
371
  template_file = TemplateFile(
344
372
  remote_id=data.get('uuid', None),
345
- remote_type=TemplateFileType.file,
373
+ remote_type=TemplateFileType.FILE,
346
374
  filename=pathlib.Path(urllib.parse.unquote(filename)),
347
375
  content=content.encode(encoding=DEFAULT_ENCODING),
348
376
  )
@@ -353,7 +381,7 @@ def _load_remote_asset(data: dict, content: bytes) -> TemplateFile:
353
381
  filename = str(data.get('fileName', ''))
354
382
  template_file = TemplateFile(
355
383
  remote_id=data.get('uuid', None),
356
- remote_type=TemplateFileType.asset,
384
+ remote_type=TemplateFileType.ASSET,
357
385
  filename=pathlib.Path(urllib.parse.unquote(filename)),
358
386
  content_type=data.get('contentType', None),
359
387
  content=content,
@@ -9,9 +9,9 @@ BuildInfo = namedtuple(
9
9
  )
10
10
 
11
11
  BUILD_INFO = BuildInfo(
12
- version='v4.13.0~c8e1cb3',
13
- built_at='2024-12-05 08:07:57Z',
14
- sha='c8e1cb3b7e0cc93bdf509eef715cd0a926d907c3',
12
+ version='v4.15.0~0624f1a',
13
+ built_at='2025-02-04 15:03:55Z',
14
+ sha='0624f1af3f4ccd0fa38ec76a640b17ef405ab153',
15
15
  branch='HEAD',
16
- tag='v4.13.0',
16
+ tag='v4.15.0',
17
17
  )
@@ -1,17 +1,17 @@
1
+ # pylint: disable=too-many-positional-arguments
1
2
  import asyncio
2
- import signal
3
-
4
- import click # type: ignore
5
3
  import datetime
6
- import dotenv
7
- import humanize # type: ignore
8
4
  import logging
9
5
  import mimetypes
10
6
  import pathlib
11
- import slugify
12
- import watchfiles # type: ignore
7
+ import signal
8
+ import sys
13
9
 
14
- from typing import Dict
10
+ import click
11
+ import dotenv
12
+ import humanize
13
+ import slugify
14
+ import watchfiles
15
15
 
16
16
  from .api_client import DSWCommunicationError
17
17
  from .core import TDKCore, TDKProcessingError
@@ -43,7 +43,7 @@ class ClickPrinter:
43
43
 
44
44
  @staticmethod
45
45
  def warning(message: str, **kwargs):
46
- click.secho('WARNING', fg='yellow', bold=True, nl=False)
46
+ click.secho('WARNING', fg='yellow', bold=True, nl=False, **kwargs)
47
47
  click.echo(f': {message}')
48
48
 
49
49
  @staticmethod
@@ -62,7 +62,8 @@ class ClickPrinter:
62
62
  click.echo(f': {message}')
63
63
 
64
64
  @classmethod
65
- def watch_change(cls, change_type: watchfiles.Change, filepath: pathlib.Path, root: pathlib.Path):
65
+ def watch_change(cls, change_type: watchfiles.Change, filepath: pathlib.Path,
66
+ root: pathlib.Path):
66
67
  timestamp = datetime.datetime.now().isoformat(timespec='milliseconds')
67
68
  sign = cls.CHANGE_SIGNS[change_type]
68
69
  click.secho('WATCH', fg='blue', bold=True, nl=False)
@@ -93,10 +94,12 @@ def print_template_info(template: Template):
93
94
  click.echo(f' - {tfile.filename.as_posix()} [{filesize}]')
94
95
 
95
96
 
97
+ # pylint: disable-next=unused-argument
96
98
  def rectify_url(ctx, param, value) -> str:
97
99
  return value.rstrip('/')
98
100
 
99
101
 
102
+ # pylint: disable-next=unused-argument
100
103
  def rectify_key(ctx, param, value) -> str:
101
104
  return value.strip()
102
105
 
@@ -130,7 +133,7 @@ class ClickLogger(logging.Logger):
130
133
  name = logging.getLevelName(level) # type: str
131
134
  if justify:
132
135
  name = name.ljust(8, ' ')
133
- if self.colors and level in self.LEVEL_STYLES.keys():
136
+ if self.colors and level in self.LEVEL_STYLES:
134
137
  name = self.LEVEL_STYLES[level](name)
135
138
  return name
136
139
 
@@ -143,10 +146,10 @@ class ClickLogger(logging.Logger):
143
146
  click.echo(self._format_level(level, justify=self.show_timestamp) + sep, nl=False)
144
147
  click.echo(message)
145
148
 
146
- def _log(self, level, msg, *args, **kwargs):
147
- if not self.muted:
148
- # super()._log(level, msg, args, exc_info, extra, stack_info, stacklevel)
149
- self._print_message(level, msg)
149
+ # pylint: disable-next=unused-argument
150
+ def _log(self, level, msg, args, *other, **kwargs):
151
+ if not self.muted and isinstance(msg, str):
152
+ self._print_message(level, msg % args)
150
153
 
151
154
  @staticmethod
152
155
  def default():
@@ -165,9 +168,9 @@ class AliasedGroup(click.Group):
165
168
  if x.startswith(cmd_name)]
166
169
  if not matches:
167
170
  return None
168
- elif len(matches) == 1:
171
+ if len(matches) == 1:
169
172
  return click.Group.get_command(self, ctx, matches[0])
170
- ctx.fail('Too many matches: %s' % ', '.join(sorted(matches)))
173
+ return ctx.fail(f'Too many matches: {", ".join(sorted(matches))}')
171
174
 
172
175
 
173
176
  class CLIContext:
@@ -184,21 +187,26 @@ class CLIContext:
184
187
  self.logger.muted = True
185
188
 
186
189
 
187
- def interact_formats() -> Dict[str, FormatSpec]:
190
+ def interact_formats() -> dict[str, FormatSpec]:
188
191
  add_format = click.confirm('Do you want to add a format?', default=True)
189
- formats = dict() # type: Dict[str, FormatSpec]
192
+ formats: dict[str, FormatSpec] = {}
190
193
  while add_format:
191
194
  format_spec = FormatSpec()
192
195
  prompt_fill('Format name', obj=format_spec, attr='name', default='HTML')
193
- if format_spec.name not in formats.keys() or click.confirm(
196
+ if format_spec.name not in formats or click.confirm(
194
197
  'There is already a format with this name. Do you want to change it?'
195
198
  ):
196
199
  prompt_fill('File extension', obj=format_spec, attr='file_extension',
197
200
  default=format_spec.name.lower() if ' ' not in format_spec.name else None)
198
201
  prompt_fill('Content type', obj=format_spec, attr='content_type',
199
202
  default=mimetypes.types_map.get(f'.{format_spec.file_extension}', None))
200
- default_filename = str(pathlib.Path('src') / f'template.{format_spec.file_extension}.j2')
201
- prompt_fill('Jinja2 filename', obj=format_spec, attr='filename', default=default_filename)
203
+ t_path = pathlib.Path('src') / f'template.{format_spec.file_extension}.j2'
204
+ prompt_fill(
205
+ text='Jinja2 filename',
206
+ obj=format_spec,
207
+ attr='filename',
208
+ default=str(t_path),
209
+ )
202
210
  formats[format_spec.name] = format_spec
203
211
  click.echo('=' * 60)
204
212
  add_format = click.confirm('Do you want to add yet another format?', default=False)
@@ -208,10 +216,14 @@ def interact_formats() -> Dict[str, FormatSpec]:
208
216
  def interact_builder(builder: TemplateBuilder):
209
217
  prompt_fill('Template name', obj=builder, attr='name')
210
218
  prompt_fill('Organization ID', obj=builder, attr='organization_id')
211
- prompt_fill('Template ID', obj=builder, attr='template_id', default=slugify.slugify(builder.name))
212
- prompt_fill('Version', obj=builder, attr='version', default='0.1.0')
213
- prompt_fill('Description', obj=builder, attr='description', default='My custom template')
214
- prompt_fill('License', obj=builder, attr='license', default='CC0')
219
+ prompt_fill('Template ID', obj=builder, attr='template_id',
220
+ default=slugify.slugify(builder.name))
221
+ prompt_fill('Version', obj=builder, attr='version',
222
+ default='0.1.0')
223
+ prompt_fill('Description', obj=builder, attr='description',
224
+ default='My custom template')
225
+ prompt_fill('License', obj=builder, attr='license',
226
+ default='CC0')
215
227
  click.echo('=' * 60)
216
228
  formats = interact_formats()
217
229
  for format_spec in formats.values():
@@ -224,19 +236,16 @@ def load_local(tdk: TDKCore, template_dir: pathlib.Path):
224
236
  except Exception as e:
225
237
  ClickPrinter.failure('Could not load local template')
226
238
  ClickPrinter.error(f'> {e}')
227
- exit(1)
239
+ sys.exit(1)
228
240
 
229
241
 
230
242
  def dir_from_id(template_id: str) -> pathlib.Path:
231
243
  return pathlib.Path.cwd() / template_id.replace(':', '_')
232
244
 
233
245
 
234
- #############################################################################################################
235
-
236
-
237
246
  @click.group(cls=AliasedGroup)
238
- @click.option('-e', '--dot-env', default='.env', required=False, show_default=True,
239
- type=click.Path(file_okay=True, dir_okay=False),
247
+ @click.option('-e', '--dot-env', default='.env', required=False,
248
+ show_default=True, type=click.Path(file_okay=True, dir_okay=False),
240
249
  help='Provide file with environment variables.')
241
250
  @click.option('-q', '--quiet', is_flag=True,
242
251
  help='Hide additional information logs.')
@@ -266,7 +275,7 @@ def new_template(ctx, template_dir, force):
266
275
  except Exception:
267
276
  click.echo('')
268
277
  ClickPrinter.failure('Exited...')
269
- exit(1)
278
+ sys.exit(1)
270
279
  tdk = TDKCore(template=builder.build(), logger=ctx.obj.logger)
271
280
  template_dir = template_dir or dir_from_id(tdk.safe_template.id)
272
281
  tdk.prepare_local(template_dir=template_dir)
@@ -276,7 +285,7 @@ def new_template(ctx, template_dir, force):
276
285
  except Exception as e:
277
286
  ClickPrinter.failure('Could not create new template project')
278
287
  ClickPrinter.error(f'> {e}')
279
- exit(1)
288
+ sys.exit(1)
280
289
 
281
290
 
282
291
  @main.command(help='Download template from Wizard.', name='get')
@@ -309,30 +318,32 @@ def get_template(ctx, api_url, template_id, template_dir, api_key, force):
309
318
  ClickPrinter.error('Could not get template:', bold=True)
310
319
  ClickPrinter.error(f'> {e.reason}\n> {e.message}')
311
320
  await tdk.safe_client.close()
312
- exit(1)
321
+ sys.exit(1)
313
322
  await tdk.safe_client.safe_close()
314
323
  if template_type == 'draft':
315
324
  tdk.prepare_local(template_dir=template_dir)
316
325
  try:
317
326
  tdk.store_local(force=force)
318
- ClickPrinter.success(f'Template draft {template_id} downloaded to {template_dir}')
327
+ ClickPrinter.success(f'Template draft {template_id} '
328
+ f'downloaded to {template_dir}')
319
329
  except Exception as e:
320
330
  ClickPrinter.failure('Could not store template locally')
321
331
  ClickPrinter.error(f'> {e}')
322
332
  await tdk.safe_client.close()
323
- exit(1)
333
+ sys.exit(1)
324
334
  elif template_type == 'bundle' and zip_data is not None:
325
335
  try:
326
336
  tdk.extract_package(zip_data=zip_data, template_dir=template_dir, force=force)
327
- ClickPrinter.success(f'Template {template_id} (released) downloaded to {template_dir}')
337
+ ClickPrinter.success(f'Template {template_id} (released) '
338
+ f'downloaded to {template_dir}')
328
339
  except Exception as e:
329
340
  ClickPrinter.failure('Could not store template locally')
330
341
  ClickPrinter.error(f'> {e}')
331
342
  await tdk.safe_client.close()
332
- exit(1)
343
+ sys.exit(1)
333
344
  else:
334
345
  ClickPrinter.failure(f'{template_id} is not released nor draft of a document template')
335
- exit(1)
346
+ sys.exit(1)
336
347
 
337
348
  loop = asyncio.get_event_loop()
338
349
  loop.run_until_complete(main_routine())
@@ -345,8 +356,10 @@ def get_template(ctx, api_url, template_id, template_dir, api_key, force):
345
356
  @click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY',
346
357
  prompt='API Key', help='API key for Wizard instance.', callback=rectify_key,
347
358
  hide_input=True)
348
- @click.option('-f', '--force', is_flag=True, help='Delete template if already exists.')
349
- @click.option('-w', '--watch', is_flag=True, help='Enter watch mode to continually upload changes.')
359
+ @click.option('-f', '--force', is_flag=True,
360
+ help='Delete template if already exists.')
361
+ @click.option('-w', '--watch', is_flag=True,
362
+ help='Enter watch mode to continually upload changes.')
350
363
  @click.pass_context
351
364
  def put_template(ctx, api_url, template_dir, api_key, force, watch):
352
365
  tdk = TDKCore(logger=ctx.obj.logger)
@@ -380,7 +393,7 @@ def put_template(ctx, api_url, template_dir, api_key, force, watch):
380
393
  ClickPrinter.failure('Could not upload template')
381
394
  ClickPrinter.error(f'> {e.message}\n> {e.hint}')
382
395
  await tdk.safe_client.safe_close()
383
- exit(1)
396
+ sys.exit(1)
384
397
  except DSWCommunicationError as e:
385
398
  ClickPrinter.failure('Could not upload template')
386
399
  ClickPrinter.error(f'> {e.reason}\n> {e.message}')
@@ -388,8 +401,9 @@ def put_template(ctx, api_url, template_dir, api_key, force, watch):
388
401
  'or template already exists...')
389
402
  ClickPrinter.error('> Check if you are using the matching version')
390
403
  await tdk.safe_client.safe_close()
391
- exit(1)
404
+ sys.exit(1)
392
405
 
406
+ # pylint: disable-next=unused-argument
393
407
  def set_stop_event(signum, frame):
394
408
  signame = signal.Signals(signum).name
395
409
  ClickPrinter.warning(f'Got {signame}, finishing... Bye!')
@@ -417,7 +431,7 @@ def create_package(ctx, template_dir, output, force: bool):
417
431
  except Exception as e:
418
432
  ClickPrinter.failure('Failed to create the package')
419
433
  ClickPrinter.error(f'> {e}')
420
- exit(1)
434
+ sys.exit(1)
421
435
  filename = click.style(output, bold=True)
422
436
  ClickPrinter.success(f'Package {filename} created')
423
437
 
@@ -440,7 +454,7 @@ def extract_package(ctx, template_package, output, force: bool):
440
454
  except Exception as e:
441
455
  ClickPrinter.failure('Failed to extract the package')
442
456
  ClickPrinter.error(f'> {e}')
443
- exit(1)
457
+ sys.exit(1)
444
458
  ClickPrinter.success(f'Package {template_package} extracted')
445
459
 
446
460
 
@@ -484,7 +498,7 @@ def list_templates(ctx, api_url, api_key, output_format: str,
484
498
  ClickPrinter.failure('Failed to get list of templates')
485
499
  ClickPrinter.error(f'> {e.reason}\n> {e.message}')
486
500
  await tdk.safe_client.safe_close()
487
- exit(1)
501
+ sys.exit(1)
488
502
 
489
503
  loop = asyncio.get_event_loop()
490
504
  loop.run_until_complete(main_routine())
@@ -529,4 +543,4 @@ def create_dot_env(ctx, template_dir, api_url, api_key, force):
529
543
  except Exception as e:
530
544
  ClickPrinter.failure('Failed to create dot-env file')
531
545
  ClickPrinter.error(f'> {e}')
532
- exit(1)
546
+ sys.exit(1)
@@ -1,9 +1,10 @@
1
1
  import pathlib
2
- import pathspec # type: ignore
3
2
  import re
4
3
 
4
+ import pathspec
5
+
5
6
  APP = 'dsw-tdk'
6
- VERSION = '4.13.0'
7
+ VERSION = '4.15.0'
7
8
  METAMODEL_VERSION = 16
8
9
 
9
10
  REGEX_SEMVER = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+$')
@@ -17,4 +18,4 @@ DEFAULT_ENCODING = 'utf-8'
17
18
  DEFAULT_README = pathlib.Path('README.md')
18
19
 
19
20
  TEMPLATE_FILE = 'template.json'
20
- PATHSPEC_FACTORY = pathspec.patterns.GitWildMatchPattern
21
+ PathspecFactory = pathspec.patterns.GitWildMatchPattern