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

cle-b / httpdbg / 14284555682

05 Apr 2025 06:17PM UTC coverage: 88.306% (+0.09%) from 88.221%
14284555682

Pull #187

github

cle-b
xfail for windows
Pull Request #187: add fastapi support

215 of 235 new or added lines in 10 files covered. (91.49%)

3 existing lines in 1 file now uncovered.

2054 of 2326 relevant lines covered (88.31%)

0.88 hits per line

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

94.67
/httpdbg/hooks/fastapi.py
1
# -*- coding: utf-8 -*-
2
from collections.abc import Callable
1✔
3
from contextlib import contextmanager
1✔
4
import functools
1✔
5
from functools import wraps
1✔
6
from typing import Dict
1✔
7
from typing import Generator
1✔
8
from typing import Union
1✔
9

10
import datetime
1✔
11

12
from httpdbg.hooks.utils import getcallargs
1✔
13
from httpdbg.hooks.utils import decorate
1✔
14
from httpdbg.hooks.utils import undecorate
1✔
15
from httpdbg.initiator import httpdbg_endpoint
1✔
16
from httpdbg.records import HTTPRecords
1✔
17

18

19
def set_hook_fastapi_endpoint(records: HTTPRecords, method: Callable):
1✔
20

21
    @wraps(method)
1✔
22
    def hook(*args, **kwargs):
1✔
23

24
        with httpdbg_endpoint(
1✔
25
            records,
26
            method,
27
            *args,
28
            **kwargs,
29
        ):
30
            ret = method(*args, **kwargs)
1✔
31
        return ret
1✔
32

33
    return hook
1✔
34

35

36
def set_hook_fastapi_apirouter_add_api_route(
1✔
37
    records: HTTPRecords,
38
    method: Callable,
39
    already_mapped: Union[Dict[Callable, Callable], None] = None,
40
):
41

42
    @wraps(method)
1✔
43
    def hook(*args, **kwargs):
1✔
44
        callargs = getcallargs(method, *args, **kwargs)
1✔
45

46
        param = "endpoint"
1✔
47

48
        if param in callargs:
1✔
49
            original_view_func = callargs[param]
1✔
50
            if original_view_func not in already_mapped:
1✔
51
                callargs[param] = decorate(
1✔
52
                    records, callargs[param], set_hook_fastapi_endpoint
53
                )
54
                already_mapped[original_view_func] = callargs[param]
1✔
55
            else:
NEW
56
                callargs[param] = already_mapped[original_view_func]
×
57

58
            args = [callargs[param] if x == original_view_func else x for x in args]
1✔
59
            if param in kwargs:
1✔
NEW
60
                kwargs[param] = callargs[param]
×
61

62
        return method(*args, **kwargs)
1✔
63

64
    return hook
1✔
65

66

67
def set_hook_fastapi_app(records: HTTPRecords, method: Callable):
1✔
68

69
    @wraps(method)
1✔
70
    async def hook(*args, **kwargs):
1✔
71

72
        socketdata = None
1✔
73

74
        callargs = getcallargs(method, *args, **kwargs)
1✔
75

76
        if "request" in callargs:
1✔
77
            if hasattr(callargs["request"], "__httpdbg_socketdata"):
1✔
78
                socketdata = callargs["request"].__httpdbg_socketdata
1✔
79

80
        with httpdbg_endpoint(
1✔
81
            records,
82
            method,
83
            *args,
84
            **kwargs,
85
        ) as group:
86
            if group and (group.id in records.groups):
1✔
87
                if socketdata and (socketdata in records._sockets):
1✔
88
                    records.groups[group.id].tbegin = records._sockets[
1✔
89
                        socketdata
90
                    ].record.tbegin - datetime.timedelta(milliseconds=1)
91
                    records._sockets[socketdata].record.group_id = group.id
1✔
92

93
            ret = await method(*args, **kwargs)
1✔
94

95
        return ret
1✔
96

97
    return hook
1✔
98

99

100
def set_hook_fastapi_routing_get_request_handler(
1✔
101
    records: HTTPRecords, method: Callable
102
):
103

104
    @wraps(method)
1✔
105
    def hook(*args, **kwargs):
1✔
106

107
        app = method(*args, **kwargs)
1✔
108

109
        app = decorate(records, app, set_hook_fastapi_app)
1✔
110

111
        return app
1✔
112

113
    return hook
1✔
114

115

116
@contextmanager
1✔
117
def hook_fastapi(records: HTTPRecords) -> Generator[None, None, None]:
1✔
118
    hooks = False
1✔
119
    try:
1✔
120
        import fastapi.routing
1✔
121

122
        already_mapped: Dict[Callable, Callable] = {}
1✔
123

124
        set_hook_fastapi_apirouter_add_api_route_with_already_mapped = (
1✔
125
            functools.partial(
126
                set_hook_fastapi_apirouter_add_api_route, already_mapped=already_mapped
127
            )
128
        )
129

130
        fastapi.routing.APIRouter.add_api_route = decorate(
1✔
131
            records,
132
            fastapi.routing.APIRouter.add_api_route,
133
            set_hook_fastapi_apirouter_add_api_route_with_already_mapped,
134
        )
135

136
        fastapi.routing.get_request_handler = decorate(
1✔
137
            records,
138
            fastapi.routing.get_request_handler,
139
            set_hook_fastapi_routing_get_request_handler,
140
        )
141

142
        hooks = True
1✔
NEW
143
    except ImportError:
×
NEW
144
        pass
×
145

146
    yield
1✔
147

148
    if hooks:
1✔
149
        fastapi.routing.APIRouter.add_api_route = undecorate(
1✔
150
            fastapi.routing.APIRouter.add_api_route
151
        )
152
        fastapi.routing.get_request_handler = undecorate(
1✔
153
            fastapi.routing.get_request_handler
154
        )
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

© 2026 Coveralls, Inc