Exemple #1
0
def validate_invoke(invoke):
    """
    Validates the given invoker.
    
    Parameters
    ----------
    invoke : `callable`
        The invoker to validate.
    
    Raises
    ------
    TypeError
        If `invoke` is not async callable or accepts not 1 parameter.
    """
    if invoke is None:
        raise TypeError(f'`invoke` function cannot be `None`.')

    analyzer = CallableAnalyzer(invoke, as_method=True)
    if not analyzer.is_async():
        raise TypeError(
            f'`invoke` can be `CoroutineFunction`, got {invoke!r}.')

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if min_ > 1:
        raise TypeError(
            f'`invoke` should accept `1` parameter, meanwhile the given one expects at '
            f'least `{min_!r}`, got {invoke!r}.')

    if min_ != 1:
        if max_ < 1:
            if not analyzer.accepts_args():
                raise TypeError(
                    f'`invoke` should accept `1` parameters, meanwhile the given one expects '
                    f'up to `{max_!r}`, got {invoke!r}.')
Exemple #2
0
def _validate_random_error_message_getter(random_error_message_getter):
    """
    Validates the given `random_error_message_getter`. It should accept no parameters and return a string.
    
    Parameters
    ----------
    random_error_message_getter : `callable`
        The random message getter to validate.
    
    Raises
    ------
    TypeError
        - If `random_error_message_getter` is not callable.
        - If `random_error_message_getter` is not async.
        - If `random_error_message_getter` excepts not `0` parameters.
    """
    analyzer = CallableAnalyzer(random_error_message_getter)
    if analyzer.is_async():
        raise TypeError(
            f'`random_error_message_getter` cannot be async, got {random_error_message_getter!r}.'
        )

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if (min_ > 0):
        raise TypeError(
            f'A `random_error_message_getter` should accept `0` parameters, meanwhile '
            f'{random_error_message_getter!r} accepts between `{min_}` and `{max_}`.'
        )
Exemple #3
0
def validate_initial_invoke(initial_invoke):
    """
    Validates the given default content getter.
    
    Parameters
    ----------
    initial_invoke : `callable`
        The default content getter to validate.
    
    Raises
    ------
    TypeError
        If `initial_invoke` is not async callable or accepts any parameters.
    """
    if initial_invoke is None:
        raise TypeError(f'`initial_invoke` function cannot be `None`.')

    analyzer = CallableAnalyzer(initial_invoke, as_method=True)
    if not analyzer.is_async():
        raise TypeError(
            f'`initial_invoke` should have be `async` function, got {initial_invoke!r}.'
        )

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if min_ > 0:
        raise TypeError(
            f'`initial_invoke` should accept `0` parameters, meanwhile the given one expects at '
            f'least `{min_!r}`, got {initial_invoke!r}.')

    if min_ != 0:
        if max_ < 0:
            if not analyzer.accepts_args():
                raise TypeError(
                    f'`initial_invoke` should accept `0` parameters, meanwhile the given one '
                    f'expects up to `{max_!r}`, got {initial_invoke!r}.')
Exemple #4
0
def validate_close(close):
    """
    Validates the given closer.
    
    Parameters
    ----------
    close : `callable`
        The closer to validate.
    
    Raises
    ------
    TypeError
        If `close` is not async callable or accepts not 1 parameter.
    """
    if close is None:
        raise TypeError(f'`close` function cannot be `None`.')

    analyzer = CallableAnalyzer(close, as_method=True)
    if not analyzer.is_async():
        raise TypeError(
            f'`close` should have be `async` function, got {close!r}.')

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if min_ > 1:
        raise TypeError(
            f'`close` should accept `1` parameters, meanwhile the given one expects at '
            f'least `{min_!r}`, got {close!r}.')

    if min_ != 1:
        if max_ < 1:
            if not analyzer.accepts_args():
                raise TypeError(
                    f'`close` should accept `1` parameters, meanwhile the given one expects '
                    f'up to `{max_!r}`, got {close!r}.')
Exemple #5
0
def validate_check(check):
    """
    Validates the given check.
    
    Parameters
    ----------
    check : `None` of `callable`
        The check to validate.
    
    Raises
    ------
    TypeError
        If `check` is not `None` neither a non-async function accepting 1 parameter.
    """
    if check is None:
        return

    analyzer = CallableAnalyzer(check, as_method=True)
    if analyzer.is_async():
        raise TypeError(
            f'`check` should have NOT be be `async` function, got {check!r}.')

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if min_ > 1:
        raise TypeError(
            f'`check` should accept `1` parameters, meanwhile the given one expects at '
            f'least `{min_!r}`, got {check!r}.')

    if min_ != 1:
        if max_ < 1:
            if not analyzer.accepts_args():
                raise TypeError(
                    f'`check` should accept `1` parameters, meanwhile the given one expects '
                    f'up to `{max_!r}`, got `{check!r}`.')
Exemple #6
0
def test_exception_handler(exception_handler):
    """
    Tests whether the given exception handler accepts the expected amount of parameters.
    
    Parameters
    ----------
    exception_handler : `CoroutineFunction`
        A function, which handles an exception and returns whether handled it.
        
        The following parameters are passed to it:
        
        +-------------------+-------------------------------------------------------------------------------+
        | Name              | Type                                                                          |
        +===================+===============================================================================+
        | client            | ``Client``                                                                    |
        +-------------------+-------------------------------------------------------------------------------+
        | interaction_event | ``InteractionEvent``                                                          |
        +-------------------+-------------------------------------------------------------------------------+
        | command           | ``ComponentCommand``, ``SlasherApplicationCommand``,                          |
        |                   | ``SlasherApplicationCommandFunction``, ``SlasherApplicationCommandCategory``, |
        |                   | ``SlasherApplicationCommandParameterAutoCompleter``                           |
        +-------------------+-------------------------------------------------------------------------------+
        | exception         | `BaseException`                                                               |
        +-------------------+-------------------------------------------------------------------------------+
        
        Should return the following parameters:
        
        +-------------------+-----------+
        | Name              | Type      |
        +===================+===========+
        | handled           | `bool`    |
        +-------------------+-----------+
    
    Raises
    ------
    TypeError
        - If `exception_handler` accepts bad amount of parameters.
        - If `exception_handler` is not a coroutine function.
    """
    analyzer = CallableAnalyzer(exception_handler)
    if not analyzer.is_async():
        raise TypeError(
            f'`exception_handler` can be `async` function, got {exception_handler!r}.'
        )

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if min_ > 4:
        raise TypeError(
            f'`exception_handler` should accept `4` parameters, meanwhile the given callable expects at '
            f'least `{min_!r}`, got {exception_handler!r}.')

    if min_ != 4:
        if max_ < 4:
            if not analyzer.accepts_args():
                raise TypeError(
                    f'`exception_handler` should accept `4` parameters, meanwhile the given callable '
                    f'expects up to `{max_!r}`, got {exception_handler!r}.')
Exemple #7
0
    def __new__(cls, prefix=None, embed_postprocessor=None):
        """
        Creates a new ``SubterraneanHelpCommand``.
        
        Parameters
        ----------
        prefix : `None`, `str` = `None`, Optional
            Prefix inserted before commands's display name.
        
        embed_postprocessor : `None`, `callable` = `None`, Optional
            An embed post-processor, what is called with the autogenerated embeds.
            
            The following `2` parameters are passed to it:
            
            +-----------------------+-------------------------------+
            | Respective name       | Type                          |
            +=======================+===============================+
            | command_context       | ``CommandContext``            |
            +-----------------------+-------------------------------+
            | command_context       | ``Command``, ``Category``     |
            +-----------------------+-------------------------------+
        
        Raises
        ------
        TypeError
            If `embed_postprocessor` is given, but not as a `non-async` `callable` accepting `2` parameters.
        """
        if (embed_postprocessor is not None):
            analyzer = CallableAnalyzer(embed_postprocessor)
            min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
            if min_ > 3:
                raise TypeError(
                    f'`embed_postprocessor` should accept `3` parameters: `command_context, '
                    f'command_context`, meanwhile the given one expects at least `{min_!r}`, got '
                    f'{embed_postprocessor!r}.')

            if (min_ != 2) and (max_ < 2) and (not analyzer.accepts_args()):
                raise TypeError(
                    f'`embed_postprocessor` should accept `2` parameters: `command_context, '
                    f'command_context`, meanwhile the given one expects up to `{max_!r}`, got '
                    f'{embed_postprocessor!r}.')

            if analyzer.is_async():
                raise TypeError(
                    f'`embed_postprocessor` cannot be async, got {embed_postprocessor!r}.'
                )

        if prefix is None:
            prefix = DEFAULT_PREFIX
        else:
            prefix = preconvert_str(prefix, 'prefix', 1, 32)

        self = object.__new__(cls)
        self.embed_postprocessor = embed_postprocessor
        self.prefix = prefix
        return self
Exemple #8
0
def test_precheck(precheck):
    """
    Tests whether the given precheck accepts the expected amount of parameters.
    
    Parameters
    ----------
    precheck : `callable`
        A function, which decides whether a received message should be processed.
        
        The following parameters are passed to it:
        
        +-----------+---------------+
        | Name      | Type          |
        +===========+===============+
        | client    | ``Client``    |
        +-----------+---------------+
        | message   | ``Message``   |
        +-----------+---------------+
        
        Should return the following parameters:
        
        +-------------------+-----------+
        | Name              | Type      |
        +===================+===========+
        | should_process    | `bool`    |
        +-------------------+-----------+
    
    Raises
    ------
    TypeError
        - If `precheck` accepts bad amount of parameters.
        - If `precheck` is async.
    """
    analyzer = CallableAnalyzer(precheck)
    if analyzer.is_async():
        raise TypeError(
            f'`precheck` should not be given as `async` function, got {precheck!r}.'
        )

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if min_ > 2:
        raise TypeError(
            f'`precheck` should accept `2` parameters, meanwhile the given callable expects at '
            f'least `{min_!r}`, got {precheck!r}.')

    if min_ != 2:
        if max_ < 2:
            if not analyzer.accepts_args():
                raise TypeError(
                    f'`precheck` should accept `2` parameters, meanwhile the given callable expects '
                    f'up to `{max_!r}`, got {precheck!r}.')
Exemple #9
0
def test_error_handler(error_handler):
    """
    Tests whether the given error handler accepts the expected amount of parameters.
    
    Parameters
    ----------
    error_handler : `callable`
        A function, which handles an error and returns whether handled it.
        
        The following parameters are passed to it:
        
        +-------------------+-----------------------+
        | Name              | Type                  |
        +===================+=======================+
        | command_context   | ``CommandContext``    |
        +-------------------+-----------------------+
        | exception         | `BaseException`       |
        +-------------------+-----------------------+
        
        Should return the following parameters:
        
        +-------------------+-----------+
        | Name              | Type      |
        +===================+===========+
        | handled           | `bool`    |
        +-------------------+-----------+
    
    Raises
    ------
    TypeError
        - If `error_handler` accepts bad amount of parameters.
        - If `error_handler` is not async.
    """
    analyzer = CallableAnalyzer(error_handler)
    if not analyzer.is_async():
        raise TypeError(
            f'`error_handler` can be `async` function, got {error_handler!r}')

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if min_ > 2:
        raise TypeError(
            f'`error_handler` should accept `2` parameters, meanwhile the given callable expects at '
            f'least `{min_!r}`, got {error_handler!r}')

    if min_ != 2:
        if max_ < 2:
            if not analyzer.accepts_args():
                raise TypeError(
                    f'`error_handler` should accept `2` parameters, meanwhile the given callable expects '
                    f'up to `{max_!r}`, got {error_handler!r}.')
Exemple #10
0
def test_unknown_command(unknown_command):
    """
    Tests whether the given unknown command handler accepts the expected amount of parameters.
    
    Parameters
    ----------
    unknown_command : `callable`
        A function, which is called when no command is found.
        
        The following parameters are passed to it:
        
        +---------------+---------------+
        | Name          | Type          |
        +===============+===============+
        | client        | ``Client``    |
        +---------------+---------------+
        | message       | ``Message``   |
        +---------------+---------------+
        | command_name  | `str`         |
        +---------------+---------------+
    
    Raises
    ------
    TypeError
        - If `unknown_command` accepts bad amount of parameters.
        - If `unknown_command` is not async.
    """
    analyzer = CallableAnalyzer(unknown_command)
    if not analyzer.is_async():
        raise TypeError(
            f'`unknown_command` can be `async` function, got {unknown_command!r}.'
        )

    min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
    if min_ > 3:
        raise TypeError(
            f'`unknown_command` should accept `2` parameters, meanwhile the given callable expects at '
            f'least `{min_!r}`, got {unknown_command!r}.')

    if min_ != 3:
        if max_ < 3:
            if not analyzer.accepts_args():
                raise TypeError(
                    f'`unknown_command` should accept `2` parameters, meanwhile the given callable expects '
                    f'up to `{max_!r}`, got {unknown_command!r}.')
Exemple #11
0
    def __new__(cls, color):
        """
        Creates a new ``ColorGetter`` with the given parameter.
        
        Attributes
        ----------
        color : `None`, `color `, `callable`
            A color for the generated embeds by the respective help command.
        
        Raises
        ------
        TypeError
            If `color` was not given as `None`, `int`, neither as a `callable` accepting `3` parameters.
        ValueError
            If the `color` was given as `int`, but it's value is less than `0` or is over than `0xffffff`.
        """
        if color is None:
            getter = None
            type_ = COLOR_GETTER_TYPE_STATIC
        elif callable(color):
            analyzer = CallableAnalyzer(color)
            min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
            if min_ > 3:
                raise TypeError(
                    f'A callable `color` should accept `3` parameters, `client, message, name`, meanwhile '
                    f'the given one expects at least `{min_!r}`, got {color!r}.'
                )

            if (min_ != 3) and (max_ < 3) and (not analyzer.accepts_args()):
                raise TypeError(
                    f'A callable `color` should accept `3` parameters, `client, message, name`, meanwhile '
                    f'the given one expects up to `{max_!r}`, got {color!r}.')

            getter = color
            type_ = COLOR_GETTER_TYPE_CALLABLE

        else:
            getter = preconvert_color(color, 'color', False)
            type_ = COLOR_GETTER_TYPE_STATIC

        self = object.__new__(cls)
        self.getter = getter
        self.type = type_
        return self
Exemple #12
0
def _validate_entry_or_exit(point):
    """
    Validates the given entry or exit point, returning `True`, if they passed.
    
    Parameters
    ----------
    point : `None`, `str`, `callable`
        The point to validate.
    
    Raises
    ------
    TypeError
        If `point` was given as `callable`, but accepts less or more positional parameters, as would be given.
    """
    if point is None:
        return True

    if isinstance(point, str):
        return True

    if callable(point):
        analyzer = CallableAnalyzer(point)
        min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
        if min_ > 1:
            raise TypeError(
                f'`{point!r}` excepts at least `{min_!r}` non reserved parameters, meanwhile the event '
                f'expects to pass `1`, got {point!r}')

        if min_ == 1:
            return True

        #min<expected
        if max_ >= 1:
            return True

        if analyzer.accepts_args():
            return True

        raise TypeError(
            f'`{point!r}` expects maximum `{max_!r}` non reserved parameters  meanwhile the event expects '
            f'to pass `1`., got {point!r}')

    return False
Exemple #13
0
    def __new__(cls, parameter_count, default_handler=None, callback=None):
        """
        Creates a new event handler instance form the given parameters.
        
        Parameters
        ---------
        parameter_count : `int`
            How much parameters does the event handler should accept.
        default_handler : `None`, `async-callable` = `None`, Optional
            Default handler to add by default.
        callback : `None`, `callable` = `None`, Optional
            Optional function to run when an event handler is added or removed.
        
        Raises
        ------
        TypeError
            - If `parameter_count` is not `int`.
            - If `default_handler` is neither `None`, `async-callable` and cannot be instanced to async callable either.
            - If `default_handler` accepts different amount of parameters as `parameter_count` defined.
        ValueError
            - If `parameter_count` is negative.
        """

        # Check `parameter_count`
        if type(parameter_count) is int:
            pass
        elif isinstance(parameter_count, int):
            parameter_count = int(parameter_count)
        else:
            raise TypeError(
                f'`parameter_count` can be `int`, got {parameter_count.__class__.__name__}; {parameter_count!r}.'
            )

        if (parameter_count < 0):
            raise ValueError(
                f'`parameter_count` cannot be negative, got {parameter_count!r}.'
            )

        # Check `default_handler`
        if (default_handler is None):
            instance_default_handler = False
        else:
            while True:
                analyzer = CallableAnalyzer(default_handler)

                if analyzer.is_async():
                    min_, max_ = analyzer.get_non_reserved_positional_parameter_range(
                    )
                    if min_ <= parameter_count:
                        if min_ == parameter_count:
                            instance_default_handler = False
                            break

                        # min < expected
                        if max_ >= parameter_count:
                            instance_default_handler = False
                            break

                        if analyzer.accepts_args():
                            instance_default_handler = False
                            break

                    raise TypeError(
                        f'`default_handler` should accept `{parameter_count!r}` parameters as defined, '
                        f'but it accepts [{min_!r}:{max_!r}], got {default_handler!r}.'
                    )

                if analyzer.can_instance_to_async_callable():

                    sub_analyzer = CallableAnalyzer(default_handler.__call__,
                                                    as_method=True)
                    if sub_analyzer.is_async():
                        min_, max_ = sub_analyzer.get_non_reserved_positional_parameter_range(
                        )

                        if min_ <= parameter_count:
                            if min_ == parameter_count:
                                instance_default_handler = True
                                break

                            # min < expected
                            if max_ >= parameter_count:
                                instance_default_handler = True
                                break

                            if sub_analyzer.accepts_args():
                                instance_default_handler = True
                                break

                        raise TypeError(
                            f'`default_handler` should accept `{parameter_count!r}` parameters as '
                            f'defined, but after instancing it accepts [{min_!r}:{max_!r}], got '
                            f'{default_handler!r}.')

                raise TypeError(
                    f'`default_handler` can be `None`, `async-callable`, instantiable to '
                    f'`async-callable`, got {default_handler!r}.')

        # Check `callback`
        # TODO

        self = object.__new__(cls)
        self.parameter_count = parameter_count
        self.default_handler = default_handler
        self.instance_default_handler = instance_default_handler
        self.callback = callback
        return self
Exemple #14
0
    def __new__(cls, color=None, prefix=None, embed_postprocessor=None):
        """
        Creates a new ``SubterraneanHelpCommand``.
        
        Parameters
        ----------
        color : `None`, ``Color``, `int`, `callable` = `None`, Optional
            A color for the generated embeds. If given as a `callable`, then `3` parameters will be passed to it:
            
            +-------------------+-------------------+
            | Respective name   | Parameter type    |
            +===================+===================+
            | client            | ``Client``        |
            +-------------------+-------------------+
            | message           | ``Message``       |
            +-------------------+-------------------+
            | name              | `str`             |
            +-------------------+-------------------+
            
            Async and not async callables are supported as well.
        
        prefix : `None`, `str` = `None`, Optional
            Prefix inserted before commands's display name.
        
        embed_postprocessor : `None`, `callable` = `None`, Optional
            An embed post-processor, what is called with the autogenerated embeds.
            
            `3` parameters are passed to it, which are the following:
            
            +-------------------+-------------------+
            | Respective name   | Parameter type    |
            +===================+===================+
            | client            | ``Client``        |
            +-------------------+-------------------+
            | message           | ``Message``       |
            +-------------------+-------------------+
            | embed             | ``Embed``         |
            +-------------------+-------------------+
        
        Raises
        ------
        TypeError
            If `color` was not given as `None`, `int`, neither as a `callable` accepting `3` parameters.
            If `embed_postprocessor` is given, but not as a `non-async` `callable` accepting `3` parameters.
        ValueError
            If the `color` was given as `int`, but it's value is less than `0` or is over than `0xffffff`.
        """
        color_getter = ColorGetter(color)

        if (embed_postprocessor is not None):
            analyzer = CallableAnalyzer(embed_postprocessor)
            min_, max_ = analyzer.get_non_reserved_positional_parameter_range()
            if min_ > 3:
                raise TypeError(
                    f'`embed_postprocessor` should accept `3` parameters: `client, message, embed`, '
                    f'meanwhile the given one expects at least `{min_!r}`, got {embed_postprocessor!r}.'
                )

            if (min_ != 3) and (max_ < 3) and (not analyzer.accepts_args()):
                raise TypeError(
                    f'`embed_postprocessor` should accept `3` parameters: `client, message, embed`, '
                    f'meanwhile the given one expects up to `{max_!r}`, got {embed_postprocessor!r}.'
                )

            if analyzer.is_async():
                raise TypeError(
                    f'`embed_postprocessor` cannot be async, got {embed_postprocessor}.'
                )

        if prefix is None:
            prefix = DEFAULT_PREFIX
        else:
            prefix = preconvert_str(prefix, 'prefix', 1, 32)

        self = object.__new__(cls)
        self.color_getter = color_getter
        self.embed_postprocessor = embed_postprocessor
        self.prefix = prefix
        return self
Exemple #15
0
def get_prefix_parser(prefix, prefix_ignore_case):
    """
    Validates whether the given prefix is correct.
    
    prefix :  `str`, `tuple` of `str`, `callable`
        Prefix of the command processor.
        
        Can be given as a normal `callable` or as an `async-callable` as well, which should accept `1` parameter:
        
        +-------------------+---------------+
        | Name              | Type          |
        +===================+===============+
        | message           | ``Message``   |
        +-------------------+---------------+
        
        And return the following value:
        
        +-------------------+---------------------------+
        | Name              | Type                      |
        +===================+===========================+
        | prefix            | `str`, `tuple` of `str`   |
        +-------------------+---------------------------+
    
    Returns
    -------
    prefix_parser : `async-callable`
        Async callable prefix parser.
        
        Accepts the following parameters:
        
        +-----------+---------------+
        | Name      | Type          |
        +===========+===============+
        | message   | ``Message``   |
        +-----------+---------------+
        
        Returns the given values:
        
        +-----------+-------------------+
        | Name      | Type              |
        +===========+===================+
        | prefix    | `None`, `str`     |
        +-----------+-------------------+
        | end       | `int`             |
        +-----------+-------------------+
    
    prefix_getter : `async-callable`
        
        Accepts the following parameters:
        
        +-----------+---------------+
        | Name      | Type          |
        +===========+===============+
        | message   | ``Message``   |
        +-----------+---------------+
        
        Returns the given values:
        
        +-----------+-------------------+
        | Name      | Type              |
        +===========+===================+
        | prefix    | `None`, `str`     |
        +-----------+-------------------+
    
    Raises
    ------
    TypeError
        - Prefix's type is incorrect.
        - Prefix is a callable but accepts bad amount of parameters.
    """
    if prefix_ignore_case:
        re_flags = re_ignore_case
    else:
        re_flags = 0

    re_flags |= re_multi_line | re_dotall

    if callable(prefix):
        analyzed = CallableAnalyzer(prefix)
        non_reserved_positional_parameter_count = analyzed.get_non_reserved_positional_parameter_count(
        )
        if non_reserved_positional_parameter_count != 1:
            raise TypeError(
                f'Callable `prefix` should accept `1` non reserved positional parameter, meanwhile it '
                f'accepts: {non_reserved_positional_parameter_count}, got {prefix!r}.'
            )

        if analyzed.is_async():
            prefix_wrapper_function = prefix_wrapper_async_callable
            prefix_getter_function = prefix_getter_async_callable
        else:
            prefix_wrapper_function = prefix_wrapper_sync_callable
            prefix_getter_function = prefix_getter_sync_callable

        prefix_parser = partial_func(prefix_wrapper_function, prefix, re_flags)
        prefix_getter = partial_func(prefix_getter_function, prefix)

    else:
        if isinstance(prefix, str):
            escaped_prefix = re_escape(prefix)
        elif isinstance(prefix, tuple):
            if len(prefix) == 0:
                raise ValueError(f'`prefix` cannot be an empty `tuple`.')

            escaped_prefix = '|'.join(
                re_escape(prefix_part) for prefix_part in prefix)
            prefix = prefix[0]
        else:
            raise TypeError(
                f'`prefix` can be `callable`, `async-callable`, `str`, `tuple` of `str`, got '
                f'{prefix.__class__.__name__}; {prefix!r}.')

        compiled_prefix = re_compile(escaped_prefix, re_flags)

        prefix_parser = partial_func(prefix_wrapper_regex, compiled_prefix)
        prefix_getter = partial_func(prefix_getter_static, prefix)

    return prefix_parser, prefix_getter
Exemple #16
0
def test_name_rule(rule, rule_name):
    """
    Tests the given name rule and raises if it do not passes any requirements.
    
    Parameters
    ----------
    rule : `None`, `function`
        The rule to test.
        
        A name rule should accept the following parameters:
        
        +-------+-------------------+
        | Name  | Type              |
        +=======+===================+
        | name  | `str`             |
        +-------+-------------------+
        
        Should return the following ones:
        
        +-------+-------------------+
        | Name  | Type              |
        +=======+===================+
        | name  | `str`             |
        +-------+-------------------+
    
    rule_name : `str`
        The name of the given rule.
    
    Raises
    ------
    TypeError
        - If `rule` is not `None`, `function`.
        - If `rule` is `async` `function`.
        - If `rule` accepts bad amount of parameters.
        - If `rule` raised exception when `str` was passed to it.
        - If `rule` did not return `str`, when passing `str` to it.
        - If `nullable` is given as `True` and `rule` raised exception when `None` was passed to it.
        - If `nullable` is given as `True` and `rule` did not return `str`, when passing `None` to it.
    """
    if rule is None:
        return

    rule_type = rule.__class__
    if (rule_type is not FunctionType):
        raise TypeError(
            f'`{rule_name}` can be `{FunctionType.__name__}`, got {rule_type.__name__}; {rule!r}.'
        )

    analyzed = CallableAnalyzer(rule)
    if analyzed.is_async():
        raise TypeError(
            f'`{rule_name}` can be a non async function, got {rule!r}.')

    non_reserved_positional_parameter_count = analyzed.get_non_reserved_positional_parameter_count(
    )
    if non_reserved_positional_parameter_count != 1:
        raise TypeError(
            f'`{rule_name}` should accept `1` non reserved positional parameters, meanwhile it expects '
            f'{non_reserved_positional_parameter_count}, got {rule!r}.')

    if analyzed.accepts_args():
        raise TypeError(
            f'`{rule_name}` should accept not expect args, meanwhile it does, got {rule!r}.'
        )

    if analyzed.accepts_kwargs():
        raise TypeError(
            f'`{rule_name}` should accept not expect kwargs, meanwhile it does, got {rule!r}.'
        )

    non_default_keyword_only_parameter_count = analyzed.get_non_default_keyword_only_parameter_count(
    )
    if non_default_keyword_only_parameter_count:
        raise TypeError(
            f'`{rule_name}` should accept `0` keyword only parameters, meanwhile it expects '
            f'{non_default_keyword_only_parameter_count}, got {rule!r}.')

    try:
        result = rule('test-this-name')
    except BaseException as err:
        raise TypeError(
            f'Got unexpected exception meanwhile testing the given {rule_name}: {rule!r}.'
        ) from err

    if (type(result) is not str):
        raise TypeError(
            f'{rule_name}: {rule!r} did not return `str`, meanwhile testing it, got {result.__class__.__name__}.'
        )