Passed
Push — master ( 2a622f...b9909e )
by Max
01:12
created

structured_data.match   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 91
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 9
eloc 53
dl 0
loc 91
rs 10
c 0
b 0
f 0

3 Functions

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