Passed
Push — master ( b9909e...34bb27 )
by Max
01:06
created

structured_data.match._can_overwrite_kind()   A

Complexity

Conditions 3

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
"""Utilities for destructuring values using matchables and match targets.
2
3
Given a value to destructure, called ``value``:
4
5
- Construct a matchable: ``matchable = Matchable(value)``
6
- The matchable is initially falsy, but it will become truthy if it is passed a
7
  **match target** that matches ``value``:
8
  ``assert matchable(some_pattern_that_matches)`` (Matchable returns itself
9
  from the call, so you can put the calls in an if-elif block, and only make a
10
  given call at most once.)
11
- When the matchable is truthy, it can be indexed to access bindings created by
12
  the target.
13
"""
14
15
from __future__ import annotations
16
17
import inspect
18
19
from . import _attribute_constructor
20
from . import _descriptor
21
from ._descriptor import Property
22
from ._destructure import names
23
from ._match_dict import MatchDict
24
from ._matchable import Matchable
25
from ._patterns.basic_patterns import Pattern
26
from ._patterns.bind import Bind
27
from ._patterns.mapping_match import AttrPattern
28
from ._patterns.mapping_match import DictPattern
29
30
# In lower-case for aesthetics.
31
pat = _attribute_constructor.AttributeConstructor(  # pylint: disable=invalid-name
32
    Pattern
33
)
34
35
36
def _can_overwrite_kind(parameter):
37
    if parameter.kind is inspect.Parameter.POSITIONAL_ONLY:
38
        raise ValueError("Signature already contains positional-only arguments")
39
    if parameter.kind is not inspect.Parameter.POSITIONAL_OR_KEYWORD:
40
        raise ValueError("Cannot overwrite non-POSITIONAL_OR_KEYWORD kind")
41
42
43
def _make_args_positional(func, positional_until):
44
    signature = inspect.signature(func)
45
    new_parameters = list(signature.parameters.values())
46
    for index, parameter in enumerate(new_parameters[:positional_until]):
47
        _can_overwrite_kind(parameter)
48
        new_parameters[index] = parameter.replace(kind=inspect.Parameter.POSITIONAL_ONLY)
49
    new_signature = signature.replace(parameters=new_parameters)
50
    if new_signature != signature:
51
        func.__signature__ = new_signature
52
53
54
# This wraps a function that, for reasons, can't be called directly by the code
55
# The function body should probably just be a docstring.
56
def function(_func=None, *, positional_until=0):
57
    """Convert a function to dispatch by value.
58
59
    The original function is not called when the dispatch function is invoked.
60
    """
61
62
    def wrap(func):
63
        _make_args_positional(func, positional_until)
64
        return _descriptor.Function(func)
65
66
    if _func is None:
67
        return wrap
68
69
    return wrap(_func)
70
71
72
def decorate_in_order(*args):
73
    """Apply decorators in the order they're passed to the function."""
74
75
    def decorator(func):
76
        for arg in args:
77
            func = arg(func)
78
        return func
79
80
    return decorator
81
82
83
__all__ = [
84
    "AttrPattern",
85
    "Bind",
86
    "DictPattern",
87
    "MatchDict",
88
    "Matchable",
89
    "Pattern",
90
    "Property",
91
    "decorate_in_order",
92
    "function",
93
    "names",
94
    "pat",
95
]
96