opentf-toolkit-nightly 0.62.0.dev1286__py3-none-any.whl → 0.62.0.dev1291__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.
@@ -465,8 +465,9 @@ def get_context_parameter(
465
465
  - `{app.name.upper()}_{name.upper()}` environment variable
466
466
  - `{name.upper()}` environment variable (if spec is shared)
467
467
  - `name` in configuration context
468
- - `spec['default']` if spec defines a default value
468
+ - for each deprecated name, in order, repeat the three steps above
469
469
  - `default` if not None
470
+ - `spec['default']` if spec defines a default value
470
471
 
471
472
  # Required parameters
472
473
 
@@ -482,9 +483,29 @@ def get_context_parameter(
482
483
 
483
484
  An integer if the parameter has a specification and is expected to
484
485
  be of type int. The actual parameter type otherwise.
486
+
487
+ # Spec format
488
+
489
+ (Optional, in `spec.contextParameters` in the service descriptor.)
490
+
491
+ ```yaml
492
+ - name: parameter_name
493
+ deprecatedNames: [alternative_parameter_names]
494
+ descriptiveName: parameter description
495
+ shared: true
496
+ type: int
497
+ default: 66
498
+ minValue: 10
499
+ maxValue: 100
500
+ ```
501
+
502
+ If `minValue` and/or `maxValue` are defined, the parameter must be
503
+ within the range.
504
+
505
+ If `type` is defined, the parameter must be of the specified type.
485
506
  """
486
507
 
487
- def _maybe_validate(v) -> int:
508
+ def _maybe_validate(v):
488
509
  newv, reason = validator(name, v) if validator else (v, None)
489
510
  lhs = f' {spec["descriptiveName"]} ({name}):' if spec else f' {name}:'
490
511
  if newv != v:
@@ -493,36 +514,46 @@ def get_context_parameter(
493
514
  app.logger.info(f'{lhs} {newv}')
494
515
  return newv
495
516
 
496
- def _fatal(*msg) -> NoReturn:
497
- app.logger.error(*msg)
517
+ def _fatal(msg: str) -> NoReturn:
518
+ app.logger.error(msg)
498
519
  sys.exit(2)
499
520
 
500
521
  spec = _get_contextparameter_spec(app, name)
501
- val = os.environ.get(name.upper()) if spec and spec.get('shared') else None
502
- val = os.environ.get(f'{app.name.upper()}_{name.upper()}', val)
503
- if val is None and name not in app.config['CONTEXT']:
504
- if spec and 'default' in spec:
505
- return _maybe_validate(spec['default'])
506
- if default is not None:
507
- return _maybe_validate(default)
522
+ shared = spec and spec.get('shared')
523
+ deprecateds: List[str] = spec.get('deprecatedNames', []) if spec else []
524
+
525
+ for alternative in [name] + deprecateds:
526
+ val = os.environ.get(alternative.upper()) if shared else None
527
+ val = os.environ.get(f'{app.name.upper()}_{alternative.upper()}', val)
528
+ val = val if val is not None else app.config['CONTEXT'].get(alternative)
529
+ if val is not None:
530
+ if alternative != name:
531
+ app.logger.warning(
532
+ f' "{alternative}" is deprecated. Consider using "{name}" instead.'
533
+ )
534
+ break
535
+ else:
536
+ val = default
537
+
538
+ if val is None and spec:
539
+ val = spec.get('default')
540
+ if val is None:
508
541
  _fatal(
509
- 'Context parameter %s not in current context and no default value specified.',
510
- name,
542
+ f'Context parameter "{name}" not in current context and no default value specified.'
511
543
  )
512
544
 
513
- val = val if val is not None else app.config['CONTEXT'][name]
514
- if not spec:
515
- return _maybe_validate(val)
516
- if spec.get('type') == 'int':
517
- try:
518
- val = int(val)
519
- except ValueError as err:
520
- _fatal('Context parameter %s not an integer: %s.', name, str(err))
521
- desc = spec['descriptiveName'][0].upper() + spec['descriptiveName'][1:]
522
- if 'minValue' in spec and val < spec['minValue']:
523
- _fatal(f'{desc} must be greater than {spec["minValue"]-1}.')
524
- if 'maxValue' in spec and val > spec['maxValue']:
525
- _fatal(f'{desc} must be less that {spec["maxValue"]+1}.')
545
+ if spec:
546
+ if spec.get('type') == 'int':
547
+ try:
548
+ val = int(val)
549
+ except ValueError as err:
550
+ _fatal(f'Context parameter "{name}" not an integer: {err}.')
551
+ desc = spec['descriptiveName'][0].upper() + spec['descriptiveName'][1:]
552
+ if 'minValue' in spec and val < spec['minValue']:
553
+ _fatal(f'{desc} must be greater than {spec["minValue"]-1}.')
554
+ if 'maxValue' in spec and val > spec['maxValue']:
555
+ _fatal(f'{desc} must be less that {spec["maxValue"]+1}.')
556
+
526
557
  return _maybe_validate(val)
527
558
 
528
559
 
@@ -23,7 +23,7 @@ import sys
23
23
  from collections import defaultdict
24
24
  from time import sleep
25
25
 
26
- from flask import request, g
26
+ from flask import Flask, request, g
27
27
 
28
28
  import yaml
29
29
 
@@ -121,7 +121,7 @@ def _maybe_get_item(cache: Dict[Any, Any], labels: Dict[str, str]) -> Optional[A
121
121
 
122
122
 
123
123
  def _ensure_inputs_match(
124
- plugin, labels: Dict[str, str], inputs: Dict[str, Any]
124
+ plugin: Flask, labels: Dict[str, str], inputs: Dict[str, Any]
125
125
  ) -> None:
126
126
  """Check inputs.
127
127
 
@@ -207,7 +207,7 @@ INVALID_HOOKS_DEFINITION_TEMPLATE = {
207
207
  }
208
208
 
209
209
 
210
- def _maybe_add_hook_watcher(plugin, schema: str) -> None:
210
+ def _maybe_add_hook_watcher(plugin: Flask, schema: str) -> None:
211
211
  if plugin.config['CONTEXT'][KIND_KEY] == EXECUTIONCOMMAND:
212
212
  type_ = 'CHANNEL'
213
213
  else:
@@ -235,7 +235,7 @@ def _maybe_add_hook_watcher(plugin, schema: str) -> None:
235
235
 
236
236
 
237
237
  def _read_hooks_definition(
238
- plugin, hooksfile: str, schema: str, invalid: Dict[str, Any]
238
+ plugin: Flask, hooksfile: str, schema: str, invalid: Dict[str, Any]
239
239
  ) -> None:
240
240
  """Read hooks definition file.
241
241
 
@@ -285,7 +285,9 @@ def _read_hooks_definition(
285
285
  # Dispatchers
286
286
 
287
287
 
288
- def _dispatch_providercommand(plugin, handler: Handler, body: Dict[str, Any]) -> None:
288
+ def _dispatch_providercommand(
289
+ plugin: Flask, handler: Handler, body: Dict[str, Any]
290
+ ) -> None:
289
291
  """Provider plugin dispatcher.
290
292
 
291
293
  `handler` is expected to return either a list of steps or raise a
@@ -308,7 +310,7 @@ def _dispatch_providercommand(plugin, handler: Handler, body: Dict[str, Any]) ->
308
310
  core.publish_error(f'Unexpected execution error: {err}.')
309
311
 
310
312
 
311
- def _dispatch_executioncommand(_, handler: Handler, body: Dict[str, Any]):
313
+ def _dispatch_executioncommand(_, handler: Handler, body: Dict[str, Any]) -> None:
312
314
  """Channel plugin dispatcher."""
313
315
  try:
314
316
  handler(body)
@@ -316,7 +318,9 @@ def _dispatch_executioncommand(_, handler: Handler, body: Dict[str, Any]):
316
318
  core.publish_error(f'Unexpected execution error: {err}.')
317
319
 
318
320
 
319
- def _dispatch_generatorcommand(plugin, handler: Handler, body: Dict[str, Any]):
321
+ def _dispatch_generatorcommand(
322
+ plugin: Flask, handler: Handler, body: Dict[str, Any]
323
+ ) -> None:
320
324
  """Generator plugin dispatcher."""
321
325
  try:
322
326
  labels = body['metadata'].get('labels', {})
@@ -339,7 +343,7 @@ def _dispatch_generatorcommand(plugin, handler: Handler, body: Dict[str, Any]):
339
343
  # Watchdog
340
344
 
341
345
 
342
- def _run_handlers(plugin, file, handlers):
346
+ def _run_handlers(plugin: Flask, file, handlers) -> None:
343
347
  """Run file handlers."""
344
348
  for handler, args, kwargs in handlers:
345
349
  try:
@@ -350,7 +354,7 @@ def _run_handlers(plugin, file, handlers):
350
354
  )
351
355
 
352
356
 
353
- def _watchdog(plugin, polling_delay):
357
+ def _watchdog(plugin: Flask, polling_delay: int) -> None:
354
358
  """Watch changes and call handlers when appropriate."""
355
359
  files_stat = defaultdict(float)
356
360
  files_handlers = plugin.config[WATCHEDFILES_KEY]
@@ -373,7 +377,7 @@ def _watchdog(plugin, polling_delay):
373
377
  plugin.config[WATCHEDFILES_EVENT_KEY].clear()
374
378
 
375
379
 
376
- def _start_watchdog(plugin) -> None:
380
+ def _start_watchdog(plugin: Flask) -> None:
377
381
  """Set up a watchdog that monitors specified files for changes."""
378
382
  polling_delay = max(
379
383
  WATCHDOG_POLLING_DELAY_SECONDS,
@@ -386,7 +390,7 @@ def _start_watchdog(plugin) -> None:
386
390
  ).start()
387
391
 
388
392
 
389
- def watch_file(plugin, path: str, handler, *args, **kwargs) -> None:
393
+ def watch_file(plugin: Flask, path: str, handler, *args, **kwargs) -> None:
390
394
  """Watch file changes.
391
395
 
392
396
  There can be more than one handler watching a given file. A handler
@@ -420,12 +424,18 @@ def watch_file(plugin, path: str, handler, *args, **kwargs) -> None:
420
424
  plugin.config[WATCHEDFILES_EVENT_KEY].set()
421
425
 
422
426
 
423
- def _watchnotifier(plugin, polling_delay, check, items, notify):
427
+ def _watchnotifier(
428
+ plugin: Flask,
429
+ polling_delay: int,
430
+ check: Callable[..., bool],
431
+ items,
432
+ notify: Callable[[], None],
433
+ ):
424
434
  reference = {}
425
435
  while True:
426
436
  sleep(polling_delay)
427
437
  try:
428
- statuses = {item: check(item) for item in items.copy()}
438
+ statuses = {item: check(item) for item in list(items)}
429
439
  if statuses != reference:
430
440
  notify()
431
441
  reference = statuses
@@ -435,7 +445,9 @@ def _watchnotifier(plugin, polling_delay, check, items, notify):
435
445
  )
436
446
 
437
447
 
438
- def watch_and_notify(plugin, status, items, notify):
448
+ def watch_and_notify(
449
+ plugin: Flask, status: Callable[..., Any], items, notify: Callable[[], None]
450
+ ) -> None:
439
451
  """Watch statuses changes in items.
440
452
 
441
453
  Check item status change at regular interval, call notify if
@@ -444,11 +456,11 @@ def watch_and_notify(plugin, status, items, notify):
444
456
  # Required parameters
445
457
 
446
458
  - plugin: a Flask application
447
- - status: a function taking an item and returning a boolean
459
+ - status: a function taking an item and returning a value
448
460
  - items: an iterable
449
461
  - notify: a function of no arguments
450
462
  """
451
- polling_delay = get_context_parameter(plugin, 'availability_check_delay')
463
+ polling_delay = get_context_parameter(plugin, 'availability_check_delay_seconds')
452
464
 
453
465
  plugin.logger.debug('Starting watch notifier thread.')
454
466
  threading.Thread(
@@ -459,7 +471,7 @@ def watch_and_notify(plugin, status, items, notify):
459
471
 
460
472
 
461
473
  def _subscribe(
462
- plugin,
474
+ plugin: Flask,
463
475
  cat_prefix: Optional[str],
464
476
  cat: Optional[str],
465
477
  cat_version: Optional[str],
@@ -499,7 +511,7 @@ def _subscribe(
499
511
  return subscribe(kind=kind, target='inbox', app=plugin, labels=labels)
500
512
 
501
513
 
502
- def run_plugin(plugin):
514
+ def run_plugin(plugin: Flask) -> None:
503
515
  """Start and run plugin.
504
516
 
505
517
  Subscribe to the relevant events before startup and tries to
@@ -553,7 +565,7 @@ def make_plugin(
553
565
  schema=None,
554
566
  configfile=None,
555
567
  args: Optional[Any] = None,
556
- ):
568
+ ) -> Flask:
557
569
  """Create and return a new plugin service.
558
570
 
559
571
  One and only one of `channel`, `generator`, `provider`, `providers`,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: opentf-toolkit-nightly
3
- Version: 0.62.0.dev1286
3
+ Version: 0.62.0.dev1291
4
4
  Summary: OpenTestFactory Orchestrator Toolkit
5
5
  Home-page: https://gitlab.com/henixdevelopment/open-source/opentestfactory/python-toolkit
6
6
  Author: Martin Lafaix
@@ -1,4 +1,4 @@
1
- opentf/commons/__init__.py,sha256=thcqhAp--rYDw-JIBIkgpaLu1kEk3pyPJz8brx7f7vU,22599
1
+ opentf/commons/__init__.py,sha256=_LTxZRG9KKhmx6T5Tn19un_FBE2WH_1ZV_cG43MYAcI,23441
2
2
  opentf/commons/auth.py,sha256=gXRp_0Tf3bfd65F4QiQmh6C6vR9y3ugag_0DSvozJFk,15898
3
3
  opentf/commons/config.py,sha256=RVSSdQhMle4oCo_z_AR2EQ4U6sUjSxw-qVBtjKuJVfo,10219
4
4
  opentf/commons/exceptions.py,sha256=7dhUXO8iyAbqVwlUKxZhgRzGqVcb7LkG39hFlm-VxIA,2407
@@ -55,11 +55,11 @@ opentf/schemas/opentestfactory.org/v1beta1/Workflow.json,sha256=QZ8mM9PhzsI9gTmw
55
55
  opentf/schemas/opentestfactory.org/v1beta2/ServiceConfig.json,sha256=rEvK2YWL5lG94_qYgR_GnLWNsaQhaQ-2kuZdWJr5NnY,3517
56
56
  opentf/scripts/launch_java_service.sh,sha256=S0jAaCuv2sZy0Gf2NGBuPX-eD531rcM-b0fNyhmzSjw,2423
57
57
  opentf/scripts/startup.py,sha256=vOGxl7xBcp1-_LsAKiOmeOqFl2iT81A2XRrXBLUrNi4,22785
58
- opentf/toolkit/__init__.py,sha256=mYeJPZ92ulbTBItqEsZgF4nnuRh6G19QPY3Jxc92ifc,23028
58
+ opentf/toolkit/__init__.py,sha256=_I003tfzaNTpMxS_CgqMIrgud66Rofz4pfFk0Jbjwls,23320
59
59
  opentf/toolkit/channels.py,sha256=whLfPVT5PksVlprmoeb2ktaZ3KEhqyryUCVWBJq7PeY,24308
60
60
  opentf/toolkit/core.py,sha256=fqnGgaYnuVcd4fyeNIwpc0QtyUo7jsKeVgdkBfY3iqo,9443
61
- opentf_toolkit_nightly-0.62.0.dev1286.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
62
- opentf_toolkit_nightly-0.62.0.dev1286.dist-info/METADATA,sha256=_LVp3XnOgkbwM-JnwBA7EiqniPxVpA6bfZGfhdBZW_o,2192
63
- opentf_toolkit_nightly-0.62.0.dev1286.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
64
- opentf_toolkit_nightly-0.62.0.dev1286.dist-info/top_level.txt,sha256=_gPuE6GTT6UNXy1DjtmQSfCcZb_qYA2vWmjg7a30AGk,7
65
- opentf_toolkit_nightly-0.62.0.dev1286.dist-info/RECORD,,
61
+ opentf_toolkit_nightly-0.62.0.dev1291.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
62
+ opentf_toolkit_nightly-0.62.0.dev1291.dist-info/METADATA,sha256=jitqIOoKF4yrCa7b44WWH6WzZUdHPKOOpauF1rESCLc,2192
63
+ opentf_toolkit_nightly-0.62.0.dev1291.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
64
+ opentf_toolkit_nightly-0.62.0.dev1291.dist-info/top_level.txt,sha256=_gPuE6GTT6UNXy1DjtmQSfCcZb_qYA2vWmjg7a30AGk,7
65
+ opentf_toolkit_nightly-0.62.0.dev1291.dist-info/RECORD,,