Passed
Push — master ( deac8e...af9889 )
by Max
01:03
created

structured_data.match   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 11
eloc 55
dl 0
loc 93
rs 10
c 0
b 0
f 0

3 Functions

Rating   Name   Duplication   Size   Complexity  
B _make_args_positional() 0 14 7
A function() 0 14 2
A decorate_in_order() 0 9 2
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 _make_args_positional(func, positional_until):
37
    signature = inspect.signature(func)
38
    new_parameters = []
39
    for index, parameter in enumerate(signature.parameters.values()):
40
        if positional_until and parameter.kind is inspect.Parameter.POSITIONAL_ONLY:
41
            raise ValueError("Signature already contains positional-only arguments")
42
        if index < positional_until:
43
            if parameter.kind is not inspect.Parameter.POSITIONAL_OR_KEYWORD:
44
                raise ValueError("Cannot overwrite non-POSITIONAL_OR_KEYWORD kind")
45
            parameter = parameter.replace(kind=inspect.Parameter.POSITIONAL_ONLY)
46
        new_parameters.append(parameter)
47
    new_signature = signature.replace(parameters=new_parameters)
48
    if new_signature != signature:
49
        func.__signature__ = new_signature
50
51
52
# This wraps a function that, for reasons, can't be called directly by the code
53
# The function body should probably just be a docstring.
54
def function(_func=None, *, positional_until=0):
55
    """Convert a function to dispatch by value.
56
57
    The original function is not called when the dispatch function is invoked.
58
    """
59
60
    def wrap(func):
61
        _make_args_positional(func, positional_until)
62
        return _descriptor.Function(func)
63
64
    if _func is None:
65
        return wrap
66
67
    return wrap(_func)
68
69
70
def decorate_in_order(*args):
71
    """Apply decorators in the order they're passed to the function."""
72
73
    def decorator(func):
74
        for arg in args:
75
            func = arg(func)
76
        return func
77
78
    return decorator
79
80
81
__all__ = [
82
    "AttrPattern",
83
    "Bind",
84
    "DictPattern",
85
    "MatchDict",
86
    "Matchable",
87
    "Pattern",
88
    "Property",
89
    "decorate_in_order",
90
    "function",
91
    "names",
92
    "pat",
93
]
94