• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SlowAPI / fast-json-pointer / 3746375261

pending completion
3746375261

push

github

Tristan Sweeney
Take first stab at resolver and write some tests

62 of 62 new or added lines in 2 files covered. (100.0%)

140 of 144 relevant lines covered (97.22%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.33
/src/fast_json_pointer/resolver.py
1
from dataclasses import dataclass, field
1✔
2
from typing import *
1✔
3

4
from .pointer import JsonPointer, RelativeJsonPointer
1✔
5

6
from .exceptions import ResolutionException
1✔
7

8
JsonType = dict[str, "JsonType"] | list["JsonType"] | str | bool | int | float | None
1✔
9

10
@dataclass
1✔
11
class JsonRef:
1✔
12
    ref: JsonType
1✔
13
    pointer: JsonPointer
1✔
14

15

16
def _resolve_ref(doc: JsonType, part: str, base_pointer: JsonPointer) -> JsonRef:
1✔
17
    base_pointer = JsonPointer([*base_pointer.parts, part])
1✔
18

19
    match doc:
1✔
20
        case dict():
1✔
21
            if part not in doc:
1✔
22
                raise ResolutionException(f"Key '{part}' not in '{doc}' '{base_pointer}'")
1✔
23

24
            doc = doc[part]
1✔
25

26
        case list():
1✔
27
            part_idx = int(part)
1✔
28
            if part_idx >= len(doc):
1✔
29
                raise ResolutionException(f"Index '{part_idx}' not in '{doc}' '{base_pointer}'")
1✔
30

31
            doc = doc[part_idx]
1✔
32

33
        case _:
1✔
34
            raise ResolutionException(f"Unnvaigable doc type '{type(part)}' '{doc}' '{base_pointer}'")
1✔
35
    
36
    return JsonRef(doc, base_pointer)
1✔
37
                
38

39

40
def _resolve(doc: JsonType, parts: list[str], *, base_pointer: JsonPointer | None = None) -> list[JsonRef]:
1✔
41
    base_pointer = base_pointer or JsonPointer.parse("")
1✔
42
    doc_refs = [JsonRef(doc, base_pointer)]
1✔
43

44
    for part in parts:
1✔
45
        ref = _resolve_ref(doc, part, base_pointer)
1✔
46
        doc_refs.append(ref)
1✔
47
        doc = ref.ref
1✔
48
        base_pointer = ref.pointer
1✔
49

50
    return doc_refs
1✔
51

52

53
def get(doc: JsonType, pointer: JsonPointer, *, rel_pointer: RelativeJsonPointer | None = None) -> JsonType:
1✔
54
    '''
55
    
56
    >>> get({}, JsonPointer.parse(""))
57
    {}
58
    >>> get({'x': 5}, JsonPointer.parse("/x"))
59
    5
60
    >>> get({'x': {'': 3}}, JsonPointer.parse("/x/"))
61
    3
62
    >>> get({'x': {'': 3, 'z': 12}}, JsonPointer.parse("/x/"), rel_pointer=RelativeJsonPointer.parse("1/z"))
63
    12
64
    >>> get({'x': {'': 3}, 'z': 12}, JsonPointer.parse("/x/"), rel_pointer=RelativeJsonPointer.parse("1#"))
65
    'x'
66
    >>> get([{'x': {'': 3}}, 4], JsonPointer.parse("/0/x"), rel_pointer=RelativeJsonPointer.parse("1#"))
67
    '0'
68
    >>> get([{'x': {'': 3}}, 4], JsonPointer.parse("/0/x"), rel_pointer=RelativeJsonPointer.parse("0//does-not-exist"))
69
    Traceback (most recent call last):
70
    fast_json_pointer.exceptions.ResolutionException: ...
71
    >>> get([{'x': {'': 3}}, 4], JsonPointer.parse("/3"))
72
    Traceback (most recent call last):
73
    fast_json_pointer.exceptions.ResolutionException: ...
74
    >>> get([{'x': {'': 3}}, 4], JsonPointer.parse("/0/z"))
75
    Traceback (most recent call last):
76
    fast_json_pointer.exceptions.ResolutionException: ...
77
    '''
78
    doc_refs = _resolve(doc, pointer.parts)
1✔
79
    
80
    if rel_pointer:
1✔
81
        if rel_pointer.offset > 0:
1✔
82
            doc_refs = doc_refs[:-rel_pointer.offset]
1✔
83
        pointer = doc_refs[-1].pointer
1✔
84

85
        
86
        if rel_pointer.is_index_ref:
1✔
87
            return pointer.parts[-1]
1✔
88

89
        new_refs = _resolve(doc_refs[-1].ref, rel_pointer.parts, base_pointer=pointer)
1✔
90
        doc_refs.extend(new_refs)
1✔
91

92
    return doc_refs[-1].ref
1✔
93

94
def set(doc: JsonType, pointer: JsonPointer, value: JsonType, *, rel_pointer: RelativeJsonPointer | None = None) -> None:
1✔
95
    '''
96
    >>> x = {}
97
    >>> set(x, JsonPointer.parse("/x"), 2)
98
    >>> x
99
    {'x': 2}
100

101
    >>> x = {'x': 2}
102
    >>> set(x, JsonPointer.parse("/x"), 3, rel_pointer=RelativeJsonPointer.parse("1/y"))
103
    >>> x = {'x': 2, 'y': 3}
104
    '''
105
    doc_refs = _resolve(doc, pointer.parts[:-1])
1✔
106
    try:
1✔
107
        new_refs = _resolve_ref(doc_refs[-1].ref, pointer.parts[-1], base_pointer=doc_refs[-1].pointer)
1✔
108
        match doc_refs[-1].ref:
1✔
109
            case dict():
1✔
110
                doc_refs[-1].ref[pointer.parts[-1]] = value
1✔
111
            case list():
×
112
                doc_refs[-1].ref[int(pointer.parts[-1])] = value
×
113

114
    except ResolutionException:
1✔
115
        if rel_pointer is None:
1✔
116
            match doc_refs[-1].ref:
1✔
117
                    case dict():
1✔
118
                        doc_refs[-1].ref[pointer.parts[-1]] = value
1✔
119
                    case list():
×
120
                        doc_refs[-1].ref[int(pointer.parts[-1])] = value
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc