File: _helpers.py

package info (click to toggle)
python-click-option-group 0.5.6-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 252 kB
  • sloc: python: 1,141; makefile: 16
file content (47 lines) | stat: -rw-r--r-- 1,374 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# -*- coding: utf-8 -*-

from typing import Callable, Tuple, List, TypeVar, NoReturn

import random
import string

import click


F = TypeVar('F', bound=Callable)

FAKE_OPT_NAME_LEN = 30


def get_callback_and_params(func) -> Tuple[Callable, List[click.Option]]:
    """Returns callback function and its parameters list

    :param func: decorated function or click Command
    :return: (callback, params)
    """
    if isinstance(func, click.Command):
        params = func.params
        func = func.callback
    else:
        params = getattr(func, '__click_params__', [])

    func = resolve_wrappers(func)
    return func, params


def get_fake_option_name(name_len: int = FAKE_OPT_NAME_LEN, prefix: str = 'fake') -> str:
    return f'--{prefix}-' + ''.join(random.choices(string.ascii_lowercase, k=name_len))


def raise_mixing_decorators_error(wrong_option: click.Option, callback: Callable) -> NoReturn:
    error_hint = wrong_option.opts or [wrong_option.name]

    raise TypeError((
        "Grouped options must not be mixed with regular parameters while adding by decorator. "
        f"Check decorator position for {error_hint} option in '{callback.__name__}'."
    ))


def resolve_wrappers(f: F) -> F:
    """Get the underlying function behind any level of function wrappers."""
    return resolve_wrappers(f.__wrapped__) if hasattr(f, "__wrapped__") else f