httpdbg 0.10.0__tar.gz → 0.11.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {httpdbg-0.10.0 → httpdbg-0.11.0}/PKG-INFO +28 -14
- {httpdbg-0.10.0 → httpdbg-0.11.0}/README.md +27 -13
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/__init__.py +1 -1
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/__main__.py +1 -1
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/args.py +4 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/hooks/aiohttp.py +3 -1
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/hooks/all.py +9 -2
- httpdbg-0.11.0/httpdbg/hooks/generic.py +158 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/hooks/httpx.py +9 -1
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/hooks/requests.py +3 -1
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/hooks/socket.py +7 -5
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/hooks/urllib3.py +6 -1
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/initiator.py +4 -3
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg.egg-info/PKG-INFO +28 -14
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg.egg-info/SOURCES.txt +1 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/pyproject.toml +1 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_hook_aiohttp.py +5 -0
- httpdbg-0.11.0/tests/test_initiator.py +168 -0
- httpdbg-0.10.0/tests/test_initiator.py +0 -103
- {httpdbg-0.10.0 → httpdbg-0.11.0}/LICENSE +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/hooks/__init__.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/hooks/utils.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/mode_console.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/mode_module.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/mode_script.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/records.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/server.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/utils.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/__init__.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/api.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/app.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/preview.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/api.js +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/column.css +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/configuration.js +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/detail.css +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/favicon.ico +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/filter.js +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/download-install-line-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/engine-gears-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/files-papers-outline-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/filter-outline-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/information-mark-circle-outline-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/math-multiplication-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/push-pin-green-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/recycle-bin-line-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/wait-sandclock-icon.svg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/index.htm +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/main.js +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/mustache.min.js +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/render.js +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/style.css +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/table.css +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg.egg-info/dependency_links.txt +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg.egg-info/entry_points.txt +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg.egg-info/top_level.txt +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/setup.cfg +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_api.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_cli.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_context_manager.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_hook_httpx.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_hook_requests.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_hook_urllib3.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_mode_console.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_mode_module_pytest.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_mode_script.py +0 -0
- {httpdbg-0.10.0 → httpdbg-0.11.0}/tests/test_preview.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: httpdbg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: A very simple tool to debug HTTP(S) client requests
|
|
5
5
|
Author-email: cle-b <cle@tictac.pm>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -19,11 +19,13 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
|
|
21
21
|
[](https://github.com/cle-b/httpdbg/actions?query=workflow%3ABuild) [](https://badge.fury.io/py/httpdbg) [](https://coveralls.io/github/cle-b/httpdbg?branch=main)
|
|
22
|
+
|
|
22
23
|
# httpdbg
|
|
23
24
|
|
|
24
25
|
A very simple tool to debug HTTP(S) client requests.
|
|
25
26
|
|
|
26
|
-

|
|
28
|
+
|
|
27
29
|
## installation
|
|
28
30
|
|
|
29
31
|
```
|
|
@@ -79,15 +81,28 @@ For example, you can view which HTTP requests are performed by `pip` when you in
|
|
|
79
81
|
pyhttpdbg -m pip install httpdbg --upgrade
|
|
80
82
|
```
|
|
81
83
|
|
|
84
|
+
## Initiators
|
|
85
|
+
|
|
86
|
+
An initiator is the function/method that is at the origin of the HTTP requests. By default, we already support some packages but you can add your own initiators.
|
|
87
|
+
|
|
88
|
+
To add a new package in the list of initiators, you can use the `-i` command line argument:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
pyhttpdbg -i api_client_pck --script my_script.py
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
You can use any package as an initiator, this is not limited to HTTP requests.
|
|
82
95
|
|
|
83
|
-
|
|
96
|
+
### Already supported packages
|
|
84
97
|
|
|
85
|
-
|
|
|
86
|
-
|
|
87
|
-
| requests
|
|
88
|
-
| urllib3
|
|
89
|
-
| httpx
|
|
90
|
-
| aiohttp
|
|
98
|
+
| packages | status |
|
|
99
|
+
|----------------|-------------------------------------|
|
|
100
|
+
| requests | supported |
|
|
101
|
+
| urllib3 | supported |
|
|
102
|
+
| httpx | supported |
|
|
103
|
+
| aiohttp | supported |
|
|
104
|
+
| pytest | supported |
|
|
105
|
+
| _your_package_ | yes, with the arg _-i your_package_ |
|
|
91
106
|
|
|
92
107
|
## configuration
|
|
93
108
|
|
|
@@ -96,20 +111,19 @@ No configuration is necessary to start but some few settings are available for p
|
|
|
96
111
|
### command line
|
|
97
112
|
|
|
98
113
|
```
|
|
99
|
-
usage: pyhttpdbg [-h] [--port PORT] [--version] [--keep-up | --force-quit]
|
|
114
|
+
usage: pyhttpdbg [-h] [--port PORT] [--version] [--initiator INITIATOR] [--keep-up | --force-quit]
|
|
100
115
|
[--console | --module MODULE | --script SCRIPT]
|
|
101
116
|
|
|
102
117
|
httdbg - a very simple tool to debug HTTP(S) client requests
|
|
103
118
|
|
|
104
119
|
options:
|
|
105
120
|
-h, --help show this help message and exit
|
|
106
|
-
--version, -v print the httpdbg version
|
|
107
|
-
|
|
108
121
|
--port PORT, -p PORT the web interface port
|
|
109
|
-
|
|
122
|
+
--version, -v print the httpdbg version
|
|
123
|
+
--initiator INITIATOR, -i INITIATOR
|
|
124
|
+
add a new initiator (package)
|
|
110
125
|
--keep-up, -k keep the server up even if the requests have been read
|
|
111
126
|
--force-quit, -q stop the server even if the requests have not been read
|
|
112
|
-
|
|
113
127
|
--console run a python console (default)
|
|
114
128
|
--module MODULE, -m MODULE
|
|
115
129
|
run library module as a script (the next args are passed to pytest as is)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
[](https://github.com/cle-b/httpdbg/actions?query=workflow%3ABuild) [](https://badge.fury.io/py/httpdbg) [](https://coveralls.io/github/cle-b/httpdbg?branch=main)
|
|
2
|
+
|
|
2
3
|
# httpdbg
|
|
3
4
|
|
|
4
5
|
A very simple tool to debug HTTP(S) client requests.
|
|
5
6
|
|
|
6
|
-

|
|
8
|
+
|
|
7
9
|
## installation
|
|
8
10
|
|
|
9
11
|
```
|
|
@@ -59,15 +61,28 @@ For example, you can view which HTTP requests are performed by `pip` when you in
|
|
|
59
61
|
pyhttpdbg -m pip install httpdbg --upgrade
|
|
60
62
|
```
|
|
61
63
|
|
|
64
|
+
## Initiators
|
|
65
|
+
|
|
66
|
+
An initiator is the function/method that is at the origin of the HTTP requests. By default, we already support some packages but you can add your own initiators.
|
|
67
|
+
|
|
68
|
+
To add a new package in the list of initiators, you can use the `-i` command line argument:
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
pyhttpdbg -i api_client_pck --script my_script.py
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
You can use any package as an initiator, this is not limited to HTTP requests.
|
|
62
75
|
|
|
63
|
-
|
|
76
|
+
### Already supported packages
|
|
64
77
|
|
|
65
|
-
|
|
|
66
|
-
|
|
67
|
-
| requests
|
|
68
|
-
| urllib3
|
|
69
|
-
| httpx
|
|
70
|
-
| aiohttp
|
|
78
|
+
| packages | status |
|
|
79
|
+
|----------------|-------------------------------------|
|
|
80
|
+
| requests | supported |
|
|
81
|
+
| urllib3 | supported |
|
|
82
|
+
| httpx | supported |
|
|
83
|
+
| aiohttp | supported |
|
|
84
|
+
| pytest | supported |
|
|
85
|
+
| _your_package_ | yes, with the arg _-i your_package_ |
|
|
71
86
|
|
|
72
87
|
## configuration
|
|
73
88
|
|
|
@@ -76,20 +91,19 @@ No configuration is necessary to start but some few settings are available for p
|
|
|
76
91
|
### command line
|
|
77
92
|
|
|
78
93
|
```
|
|
79
|
-
usage: pyhttpdbg [-h] [--port PORT] [--version] [--keep-up | --force-quit]
|
|
94
|
+
usage: pyhttpdbg [-h] [--port PORT] [--version] [--initiator INITIATOR] [--keep-up | --force-quit]
|
|
80
95
|
[--console | --module MODULE | --script SCRIPT]
|
|
81
96
|
|
|
82
97
|
httdbg - a very simple tool to debug HTTP(S) client requests
|
|
83
98
|
|
|
84
99
|
options:
|
|
85
100
|
-h, --help show this help message and exit
|
|
86
|
-
--version, -v print the httpdbg version
|
|
87
|
-
|
|
88
101
|
--port PORT, -p PORT the web interface port
|
|
89
|
-
|
|
102
|
+
--version, -v print the httpdbg version
|
|
103
|
+
--initiator INITIATOR, -i INITIATOR
|
|
104
|
+
add a new initiator (package)
|
|
90
105
|
--keep-up, -k keep the server up even if the requests have been read
|
|
91
106
|
--force-quit, -q stop the server even if the requests have not been read
|
|
92
|
-
|
|
93
107
|
--console run a python console (default)
|
|
94
108
|
--module MODULE, -m MODULE
|
|
95
109
|
run library module as a script (the next args are passed to pytest as is)
|
|
@@ -25,7 +25,7 @@ def pyhttpdbg(params, subparams, test_mode=False):
|
|
|
25
25
|
sys.path.insert(0, "") # to mimic the default python command behavior
|
|
26
26
|
|
|
27
27
|
with httpdbg_srv(params.port) as records:
|
|
28
|
-
with httpdbg(records):
|
|
28
|
+
with httpdbg(records, params.initiator):
|
|
29
29
|
if params.module:
|
|
30
30
|
run_module(subparams)
|
|
31
31
|
elif params.script:
|
|
@@ -23,6 +23,10 @@ def read_args(args: List[str]) -> Tuple[argparse.Namespace, List[str]]:
|
|
|
23
23
|
"--version", "-v", action="store_true", help="print the httpdbg version"
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"--initiator", "-i", action="append", help="add a new initiator (package)"
|
|
28
|
+
)
|
|
29
|
+
|
|
26
30
|
server_state = parser.add_mutually_exclusive_group()
|
|
27
31
|
|
|
28
32
|
server_state.add_argument(
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from contextlib import contextmanager
|
|
3
3
|
import traceback
|
|
4
|
+
from typing import Generator
|
|
4
5
|
|
|
5
6
|
from httpdbg.hooks.utils import getcallargs
|
|
6
7
|
from httpdbg.hooks.utils import decorate
|
|
7
8
|
from httpdbg.hooks.utils import undecorate
|
|
8
9
|
from httpdbg.initiator import httpdbg_initiator
|
|
9
10
|
from httpdbg.records import HTTPRecord
|
|
11
|
+
from httpdbg.records import HTTPRecords
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def set_hook_for_aiohttp_async(records, method):
|
|
@@ -36,7 +38,7 @@ def set_hook_for_aiohttp_async(records, method):
|
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
@contextmanager
|
|
39
|
-
def hook_aiohttp(records):
|
|
41
|
+
def hook_aiohttp(records: HTTPRecords) -> Generator[None, None, None]:
|
|
40
42
|
hooks = False
|
|
41
43
|
try:
|
|
42
44
|
import aiohttp
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from contextlib import contextmanager
|
|
3
|
+
from typing import Generator
|
|
4
|
+
from typing import List
|
|
5
|
+
from typing import Union
|
|
3
6
|
|
|
4
7
|
from httpdbg.hooks.aiohttp import hook_aiohttp
|
|
8
|
+
from httpdbg.hooks.generic import hook_generic
|
|
5
9
|
from httpdbg.hooks.httpx import hook_httpx
|
|
6
10
|
from httpdbg.hooks.requests import hook_requests
|
|
7
11
|
from httpdbg.hooks.socket import hook_socket
|
|
@@ -10,7 +14,9 @@ from httpdbg.records import HTTPRecords
|
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
@contextmanager
|
|
13
|
-
def httpdbg(
|
|
17
|
+
def httpdbg(
|
|
18
|
+
records: HTTPRecords = None, initiators: Union[List[str], None] = None
|
|
19
|
+
) -> Generator[HTTPRecords, None, None]:
|
|
14
20
|
if records is None:
|
|
15
21
|
records = HTTPRecords()
|
|
16
22
|
|
|
@@ -19,4 +25,5 @@ def httpdbg(records=None):
|
|
|
19
25
|
with hook_requests(records):
|
|
20
26
|
with hook_urllib3(records):
|
|
21
27
|
with hook_aiohttp(records):
|
|
22
|
-
|
|
28
|
+
with hook_generic(records, initiators):
|
|
29
|
+
yield records
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
import glob
|
|
4
|
+
import importlib
|
|
5
|
+
import inspect
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import traceback
|
|
8
|
+
from typing import Generator
|
|
9
|
+
from typing import List
|
|
10
|
+
from typing import Union
|
|
11
|
+
|
|
12
|
+
from httpdbg.hooks.utils import decorate
|
|
13
|
+
from httpdbg.hooks.utils import undecorate
|
|
14
|
+
from httpdbg.initiator import httpdbg_initiator
|
|
15
|
+
from httpdbg.records import HTTPRecords
|
|
16
|
+
from httpdbg.utils import logger
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def set_hook_for_generic_async(records, method):
|
|
20
|
+
async def hook(*args, **kwargs):
|
|
21
|
+
with httpdbg_initiator(
|
|
22
|
+
records, traceback.extract_stack(), method, *args, **kwargs
|
|
23
|
+
):
|
|
24
|
+
ret = await method(*args, **kwargs)
|
|
25
|
+
|
|
26
|
+
return ret
|
|
27
|
+
|
|
28
|
+
return hook
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def set_hook_for_generic(records, method):
|
|
32
|
+
def hook(*args, **kwargs):
|
|
33
|
+
with httpdbg_initiator(
|
|
34
|
+
records, traceback.extract_stack(), method, *args, **kwargs
|
|
35
|
+
):
|
|
36
|
+
ret = method(*args, **kwargs)
|
|
37
|
+
|
|
38
|
+
return ret
|
|
39
|
+
|
|
40
|
+
return hook
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@contextmanager
|
|
44
|
+
def hook_generic(
|
|
45
|
+
records: HTTPRecords, initiators: Union[List[str], None] = None
|
|
46
|
+
) -> Generator[None, None, None]:
|
|
47
|
+
hooks = []
|
|
48
|
+
|
|
49
|
+
if not initiators:
|
|
50
|
+
initiators = []
|
|
51
|
+
|
|
52
|
+
for initiator in initiators:
|
|
53
|
+
logger.debug(f"HOOK_GENERIC add package - {initiator}")
|
|
54
|
+
try:
|
|
55
|
+
hooks += list_callables_from_package(records, initiator)
|
|
56
|
+
except Exception as ex:
|
|
57
|
+
logger.debug(f"HOOK_GENERIC exception - {str(ex)}")
|
|
58
|
+
|
|
59
|
+
yield
|
|
60
|
+
|
|
61
|
+
if hooks:
|
|
62
|
+
for fnc in hooks:
|
|
63
|
+
fnc = undecorate(fnc)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def list_callables_from_package(records, package):
|
|
67
|
+
callables = []
|
|
68
|
+
|
|
69
|
+
callables += list_callables_from_module(records, package)
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
imported_package = importlib.import_module(package)
|
|
73
|
+
for p in glob.glob(f"{list(imported_package.__path__)[0]}/*"):
|
|
74
|
+
file_or_dir = Path(p)
|
|
75
|
+
if file_or_dir.is_file():
|
|
76
|
+
if file_or_dir.name.endswith(".py"):
|
|
77
|
+
callables += list_callables_from_module(
|
|
78
|
+
records, f"{package}.{file_or_dir.name[:-3]}"
|
|
79
|
+
)
|
|
80
|
+
elif file_or_dir.is_dir():
|
|
81
|
+
if not file_or_dir.name.startswith("__"): # __pycache__
|
|
82
|
+
callables += list_callables_from_package(
|
|
83
|
+
records, f"{package}.{file_or_dir.name}"
|
|
84
|
+
)
|
|
85
|
+
except ImportError:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
return callables
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def list_callables_from_module(records, module):
|
|
92
|
+
callables = []
|
|
93
|
+
|
|
94
|
+
imported_module = importlib.import_module(module)
|
|
95
|
+
|
|
96
|
+
for name in imported_module.__dict__.keys():
|
|
97
|
+
# hook must be applied only on function/method defined in the current module (not imported)
|
|
98
|
+
from_module = getattr(imported_module.__dict__[name], "__module__", "")
|
|
99
|
+
if from_module and from_module.startswith(module):
|
|
100
|
+
# a coroutine is a function so this condition must be checked first
|
|
101
|
+
if inspect.iscoroutinefunction(imported_module.__dict__[name]):
|
|
102
|
+
imported_module.__dict__[name] = decorate(
|
|
103
|
+
records,
|
|
104
|
+
imported_module.__dict__[name],
|
|
105
|
+
set_hook_for_generic_async,
|
|
106
|
+
)
|
|
107
|
+
callables.append(imported_module.__dict__[name])
|
|
108
|
+
|
|
109
|
+
elif inspect.isfunction(imported_module.__dict__[name]):
|
|
110
|
+
imported_module.__dict__[name] = decorate(
|
|
111
|
+
records,
|
|
112
|
+
imported_module.__dict__[name],
|
|
113
|
+
set_hook_for_generic,
|
|
114
|
+
)
|
|
115
|
+
callables.append(imported_module.__dict__[name])
|
|
116
|
+
|
|
117
|
+
elif inspect.isclass(imported_module.__dict__[name]):
|
|
118
|
+
callables += list_callables_from_class(
|
|
119
|
+
records, imported_module, module, name
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
return callables
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def list_callables_from_class(records, imported_module, module, classname):
|
|
126
|
+
callables = []
|
|
127
|
+
|
|
128
|
+
for name in imported_module.__dict__[classname].__dict__.keys():
|
|
129
|
+
from_module = getattr(
|
|
130
|
+
imported_module.__dict__[classname].__dict__[name], "__module__", ""
|
|
131
|
+
)
|
|
132
|
+
if from_module and from_module.startswith(module):
|
|
133
|
+
if not name.startswith("__"):
|
|
134
|
+
if inspect.iscoroutinefunction(
|
|
135
|
+
imported_module.__dict__[classname].__dict__[name]
|
|
136
|
+
):
|
|
137
|
+
hook = decorate(
|
|
138
|
+
records,
|
|
139
|
+
imported_module.__dict__[classname].__dict__[name],
|
|
140
|
+
set_hook_for_generic_async,
|
|
141
|
+
)
|
|
142
|
+
setattr(
|
|
143
|
+
imported_module.__dict__[classname], name, hook
|
|
144
|
+
) # TypeError: 'mappingproxy' object does not support item assignment
|
|
145
|
+
callables.append(hook)
|
|
146
|
+
|
|
147
|
+
elif inspect.isfunction(
|
|
148
|
+
imported_module.__dict__[classname].__dict__[name]
|
|
149
|
+
):
|
|
150
|
+
hook = decorate(
|
|
151
|
+
records,
|
|
152
|
+
imported_module.__dict__[classname].__dict__[name],
|
|
153
|
+
set_hook_for_generic,
|
|
154
|
+
)
|
|
155
|
+
setattr(imported_module.__dict__[classname], name, hook)
|
|
156
|
+
callables.append(hook)
|
|
157
|
+
|
|
158
|
+
return callables
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from contextlib import contextmanager
|
|
3
3
|
import traceback
|
|
4
|
+
from typing import Generator
|
|
4
5
|
|
|
5
6
|
from httpdbg.hooks.utils import getcallargs
|
|
6
7
|
from httpdbg.hooks.utils import decorate
|
|
7
8
|
from httpdbg.hooks.utils import undecorate
|
|
8
9
|
from httpdbg.initiator import httpdbg_initiator
|
|
9
10
|
from httpdbg.records import HTTPRecord
|
|
11
|
+
from httpdbg.records import HTTPRecords
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def set_hook_for_httpx_async(records, method):
|
|
@@ -62,7 +64,7 @@ def set_hook_for_httpx(records, method):
|
|
|
62
64
|
|
|
63
65
|
|
|
64
66
|
@contextmanager
|
|
65
|
-
def hook_httpx(records):
|
|
67
|
+
def hook_httpx(records: HTTPRecords) -> Generator[None, None, None]:
|
|
66
68
|
hooks = False
|
|
67
69
|
try:
|
|
68
70
|
import httpx
|
|
@@ -88,6 +90,9 @@ def hook_httpx(records):
|
|
|
88
90
|
httpx.AsyncClient.options = decorate(
|
|
89
91
|
records, httpx.AsyncClient.options, set_hook_for_httpx_async
|
|
90
92
|
)
|
|
93
|
+
httpx.AsyncClient.request = decorate(
|
|
94
|
+
records, httpx.AsyncClient.request, set_hook_for_httpx_async
|
|
95
|
+
)
|
|
91
96
|
|
|
92
97
|
httpx.get = decorate(records, httpx.get, set_hook_for_httpx)
|
|
93
98
|
httpx.post = decorate(records, httpx.post, set_hook_for_httpx)
|
|
@@ -96,6 +101,7 @@ def hook_httpx(records):
|
|
|
96
101
|
httpx.delete = decorate(records, httpx.delete, set_hook_for_httpx)
|
|
97
102
|
httpx.head = decorate(records, httpx.head, set_hook_for_httpx)
|
|
98
103
|
httpx.options = decorate(records, httpx.options, set_hook_for_httpx)
|
|
104
|
+
httpx.request = decorate(records, httpx.request, set_hook_for_httpx)
|
|
99
105
|
|
|
100
106
|
hooks = True
|
|
101
107
|
except ImportError:
|
|
@@ -111,6 +117,7 @@ def hook_httpx(records):
|
|
|
111
117
|
httpx.AsyncClient.delete = undecorate(httpx.AsyncClient.delete)
|
|
112
118
|
httpx.AsyncClient.head = undecorate(httpx.AsyncClient.head)
|
|
113
119
|
httpx.AsyncClient.options = undecorate(httpx.AsyncClient.options)
|
|
120
|
+
httpx.AsyncClient.request = undecorate(httpx.AsyncClient.request)
|
|
114
121
|
|
|
115
122
|
httpx.get = undecorate(httpx.get)
|
|
116
123
|
httpx.post = undecorate(httpx.post)
|
|
@@ -119,3 +126,4 @@ def hook_httpx(records):
|
|
|
119
126
|
httpx.delete = undecorate(httpx.delete)
|
|
120
127
|
httpx.head = undecorate(httpx.head)
|
|
121
128
|
httpx.options = undecorate(httpx.options)
|
|
129
|
+
httpx.request = undecorate(httpx.request)
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from contextlib import contextmanager
|
|
3
3
|
import traceback
|
|
4
|
+
from typing import Generator
|
|
4
5
|
|
|
5
6
|
from httpdbg.hooks.utils import getcallargs
|
|
6
7
|
from httpdbg.hooks.utils import decorate
|
|
7
8
|
from httpdbg.hooks.utils import undecorate
|
|
8
9
|
from httpdbg.initiator import httpdbg_initiator
|
|
9
10
|
from httpdbg.records import HTTPRecord
|
|
11
|
+
from httpdbg.records import HTTPRecords
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def set_hook_for_requests(records, method):
|
|
@@ -36,7 +38,7 @@ def set_hook_for_requests(records, method):
|
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
@contextmanager
|
|
39
|
-
def hook_requests(records):
|
|
41
|
+
def hook_requests(records: HTTPRecords) -> Generator[None, None, None]:
|
|
40
42
|
hooks = False
|
|
41
43
|
try:
|
|
42
44
|
import requests
|
|
@@ -6,11 +6,13 @@ import platform
|
|
|
6
6
|
import socket
|
|
7
7
|
import ssl
|
|
8
8
|
import sys
|
|
9
|
+
from typing import Generator
|
|
9
10
|
|
|
10
11
|
from httpdbg.hooks.utils import getcallargs
|
|
11
12
|
from httpdbg.hooks.utils import decorate
|
|
12
13
|
from httpdbg.hooks.utils import undecorate
|
|
13
14
|
from httpdbg.records import HTTPRecord
|
|
15
|
+
from httpdbg.records import HTTPRecords
|
|
14
16
|
from httpdbg.utils import logger
|
|
15
17
|
|
|
16
18
|
|
|
@@ -334,7 +336,7 @@ def set_hook_for_sslobject_read(records, method):
|
|
|
334
336
|
|
|
335
337
|
|
|
336
338
|
@contextmanager
|
|
337
|
-
def hook_socket(records):
|
|
339
|
+
def hook_socket(records: HTTPRecords) -> Generator[None, None, None]:
|
|
338
340
|
socket.socket.__init__ = decorate(
|
|
339
341
|
records, socket.socket.__init__, set_hook_for_socket_init
|
|
340
342
|
)
|
|
@@ -386,9 +388,9 @@ def hook_socket(records):
|
|
|
386
388
|
|
|
387
389
|
# only for async HTTP requests (not HTTPS) on Windows
|
|
388
390
|
if (platform.system().lower() == "windows") and (sys.version_info >= (3, 7)):
|
|
389
|
-
asyncio.proactor_events._ProactorReadPipeTransport._data_received = decorate(
|
|
391
|
+
asyncio.proactor_events._ProactorReadPipeTransport._data_received = decorate( # type: ignore
|
|
390
392
|
records,
|
|
391
|
-
asyncio.proactor_events._ProactorReadPipeTransport._data_received,
|
|
393
|
+
asyncio.proactor_events._ProactorReadPipeTransport._data_received, # type: ignore
|
|
392
394
|
set_hook_for_socket_recv_into,
|
|
393
395
|
)
|
|
394
396
|
asyncio.proactor_events._ProactorBaseWritePipeTransport.write = decorate(
|
|
@@ -426,8 +428,8 @@ def hook_socket(records):
|
|
|
426
428
|
|
|
427
429
|
# only for async HTTP requests (not HTTPS) on Windows
|
|
428
430
|
if (platform.system().lower() == "windows") and (sys.version_info >= (3, 7)):
|
|
429
|
-
asyncio.proactor_events._ProactorReadPipeTransport._data_received = undecorate(
|
|
430
|
-
asyncio.proactor_events._ProactorReadPipeTransport._data_received
|
|
431
|
+
asyncio.proactor_events._ProactorReadPipeTransport._data_received = undecorate( # type: ignore
|
|
432
|
+
asyncio.proactor_events._ProactorReadPipeTransport._data_received # type: ignore
|
|
431
433
|
)
|
|
432
434
|
asyncio.proactor_events._ProactorBaseWritePipeTransport.write = undecorate(
|
|
433
435
|
asyncio.proactor_events._ProactorBaseWritePipeTransport.write
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from contextlib import contextmanager
|
|
3
3
|
import traceback
|
|
4
|
+
from typing import Generator
|
|
4
5
|
|
|
5
6
|
from httpdbg.hooks.utils import getcallargs
|
|
6
7
|
from httpdbg.hooks.utils import decorate
|
|
7
8
|
from httpdbg.hooks.utils import undecorate
|
|
8
9
|
from httpdbg.initiator import httpdbg_initiator
|
|
9
10
|
from httpdbg.records import HTTPRecord
|
|
11
|
+
from httpdbg.records import HTTPRecords
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def set_hook_for_urllib3(records, method):
|
|
@@ -36,7 +38,7 @@ def set_hook_for_urllib3(records, method):
|
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
@contextmanager
|
|
39
|
-
def hook_urllib3(records):
|
|
41
|
+
def hook_urllib3(records: HTTPRecords) -> Generator[None, None, None]:
|
|
40
42
|
hooks = False
|
|
41
43
|
try:
|
|
42
44
|
import urllib3
|
|
@@ -56,3 +58,6 @@ def hook_urllib3(records):
|
|
|
56
58
|
|
|
57
59
|
if hooks:
|
|
58
60
|
urllib3.PoolManager.request = undecorate(urllib3.PoolManager.request)
|
|
61
|
+
urllib3.HTTPConnectionPool.request = undecorate(
|
|
62
|
+
urllib3.HTTPConnectionPool.request
|
|
63
|
+
)
|
|
@@ -82,9 +82,10 @@ def get_current_instruction(
|
|
|
82
82
|
|
|
83
83
|
n_stack = -1
|
|
84
84
|
framesummary = extracted_stack[-2]
|
|
85
|
-
if framesummary.
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
if "asyncio" in framesummary.filename:
|
|
86
|
+
while "asyncio" in framesummary.filename:
|
|
87
|
+
n_stack -= 1
|
|
88
|
+
framesummary = extracted_stack[n_stack - 1]
|
|
88
89
|
|
|
89
90
|
instruction = ""
|
|
90
91
|
short_stack = f'File "{framesummary.filename}", line {framesummary.lineno}, in {framesummary.name}\n'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: httpdbg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: A very simple tool to debug HTTP(S) client requests
|
|
5
5
|
Author-email: cle-b <cle@tictac.pm>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -19,11 +19,13 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
|
|
21
21
|
[](https://github.com/cle-b/httpdbg/actions?query=workflow%3ABuild) [](https://badge.fury.io/py/httpdbg) [](https://coveralls.io/github/cle-b/httpdbg?branch=main)
|
|
22
|
+
|
|
22
23
|
# httpdbg
|
|
23
24
|
|
|
24
25
|
A very simple tool to debug HTTP(S) client requests.
|
|
25
26
|
|
|
26
|
-

|
|
28
|
+
|
|
27
29
|
## installation
|
|
28
30
|
|
|
29
31
|
```
|
|
@@ -79,15 +81,28 @@ For example, you can view which HTTP requests are performed by `pip` when you in
|
|
|
79
81
|
pyhttpdbg -m pip install httpdbg --upgrade
|
|
80
82
|
```
|
|
81
83
|
|
|
84
|
+
## Initiators
|
|
85
|
+
|
|
86
|
+
An initiator is the function/method that is at the origin of the HTTP requests. By default, we already support some packages but you can add your own initiators.
|
|
87
|
+
|
|
88
|
+
To add a new package in the list of initiators, you can use the `-i` command line argument:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
pyhttpdbg -i api_client_pck --script my_script.py
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
You can use any package as an initiator, this is not limited to HTTP requests.
|
|
82
95
|
|
|
83
|
-
|
|
96
|
+
### Already supported packages
|
|
84
97
|
|
|
85
|
-
|
|
|
86
|
-
|
|
87
|
-
| requests
|
|
88
|
-
| urllib3
|
|
89
|
-
| httpx
|
|
90
|
-
| aiohttp
|
|
98
|
+
| packages | status |
|
|
99
|
+
|----------------|-------------------------------------|
|
|
100
|
+
| requests | supported |
|
|
101
|
+
| urllib3 | supported |
|
|
102
|
+
| httpx | supported |
|
|
103
|
+
| aiohttp | supported |
|
|
104
|
+
| pytest | supported |
|
|
105
|
+
| _your_package_ | yes, with the arg _-i your_package_ |
|
|
91
106
|
|
|
92
107
|
## configuration
|
|
93
108
|
|
|
@@ -96,20 +111,19 @@ No configuration is necessary to start but some few settings are available for p
|
|
|
96
111
|
### command line
|
|
97
112
|
|
|
98
113
|
```
|
|
99
|
-
usage: pyhttpdbg [-h] [--port PORT] [--version] [--keep-up | --force-quit]
|
|
114
|
+
usage: pyhttpdbg [-h] [--port PORT] [--version] [--initiator INITIATOR] [--keep-up | --force-quit]
|
|
100
115
|
[--console | --module MODULE | --script SCRIPT]
|
|
101
116
|
|
|
102
117
|
httdbg - a very simple tool to debug HTTP(S) client requests
|
|
103
118
|
|
|
104
119
|
options:
|
|
105
120
|
-h, --help show this help message and exit
|
|
106
|
-
--version, -v print the httpdbg version
|
|
107
|
-
|
|
108
121
|
--port PORT, -p PORT the web interface port
|
|
109
|
-
|
|
122
|
+
--version, -v print the httpdbg version
|
|
123
|
+
--initiator INITIATOR, -i INITIATOR
|
|
124
|
+
add a new initiator (package)
|
|
110
125
|
--keep-up, -k keep the server up even if the requests have been read
|
|
111
126
|
--force-quit, -q stop the server even if the requests have not been read
|
|
112
|
-
|
|
113
127
|
--console run a python console (default)
|
|
114
128
|
--module MODULE, -m MODULE
|
|
115
129
|
run library module as a script (the next args are passed to pytest as is)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
import platform
|
|
2
3
|
import sys
|
|
3
4
|
|
|
4
5
|
import aiohttp
|
|
@@ -213,6 +214,10 @@ async def test_aiohttp_cookies_secure(httpbin_secure):
|
|
|
213
214
|
|
|
214
215
|
@pytest.mark.aiohttp
|
|
215
216
|
@pytest.mark.asyncio
|
|
217
|
+
@pytest.mark.xfail(
|
|
218
|
+
platform.system().lower() == "windows",
|
|
219
|
+
reason="flaky on Windows (sometimes only one request is recorded)",
|
|
220
|
+
)
|
|
216
221
|
async def test_aiohttp_redirect(httpbin_both):
|
|
217
222
|
with httpdbg() as records:
|
|
218
223
|
async with aiohttp.ClientSession(
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import asyncio
|
|
3
|
+
import platform
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from httpdbg.hooks.all import httpdbg
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.mark.xfail(
|
|
13
|
+
platform.system().lower() == "windows",
|
|
14
|
+
reason="problem with stack view in windows",
|
|
15
|
+
)
|
|
16
|
+
@pytest.mark.initiator
|
|
17
|
+
def test_initiator_script(httpbin, monkeypatch):
|
|
18
|
+
with monkeypatch.context() as m:
|
|
19
|
+
m.delenv("PYTEST_CURRENT_TEST")
|
|
20
|
+
with httpdbg() as records:
|
|
21
|
+
requests.get(f"{httpbin.url}/get")
|
|
22
|
+
|
|
23
|
+
assert len(records) == 1
|
|
24
|
+
http_record = records[0]
|
|
25
|
+
|
|
26
|
+
assert http_record.initiator.short_label == 'requests.get(f"{httpbin.url}/get")'
|
|
27
|
+
assert http_record.initiator.long_label is None
|
|
28
|
+
|
|
29
|
+
assert (
|
|
30
|
+
"""test_initiator.py", line 21, in test_initiator_script
|
|
31
|
+
21. requests.get(f"{httpbin.url}/get")
|
|
32
|
+
----------
|
|
33
|
+
requests.api.get(
|
|
34
|
+
url="""
|
|
35
|
+
+ f"{httpbin.url}/get"
|
|
36
|
+
+ """
|
|
37
|
+
)"""
|
|
38
|
+
in http_record.initiator.short_stack
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
assert (
|
|
42
|
+
"""test_initiator.py", line 21,
|
|
43
|
+
17. def test_initiator_script(httpbin, monkeypatch):
|
|
44
|
+
18. with monkeypatch.context() as m:
|
|
45
|
+
19. m.delenv("PYTEST_CURRENT_TEST")
|
|
46
|
+
20. with httpdbg() as records:
|
|
47
|
+
21. requests.get(f"{httpbin.url}/get") <====
|
|
48
|
+
22.
|
|
49
|
+
23. assert len(records) == 1
|
|
50
|
+
24. http_record = records[0]
|
|
51
|
+
25.
|
|
52
|
+
26. assert http_record.initiator.short_label == \'requests.get(f"{httpbin.url}/get")\'
|
|
53
|
+
27. assert http_record.initiator.long_label is None
|
|
54
|
+
28.""" # noqa W291
|
|
55
|
+
in http_record.initiator.stack[0]
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@pytest.mark.initiator
|
|
60
|
+
def test_initiator_same_line_different_initiators(httpbin, monkeypatch):
|
|
61
|
+
with monkeypatch.context() as m:
|
|
62
|
+
m.delenv("PYTEST_CURRENT_TEST")
|
|
63
|
+
with httpdbg() as records:
|
|
64
|
+
for i in range(2):
|
|
65
|
+
requests.get(f"{httpbin.url}/get")
|
|
66
|
+
|
|
67
|
+
assert len(records) == 2
|
|
68
|
+
|
|
69
|
+
assert records[0].initiator is not records[1].initiator
|
|
70
|
+
assert records[0].initiator.id != records[1].initiator.id
|
|
71
|
+
assert records[0].initiator == records[1].initiator
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@pytest.mark.initiator
|
|
75
|
+
def test_initiator_redirection_same_initiator(httpbin, monkeypatch):
|
|
76
|
+
with monkeypatch.context() as m:
|
|
77
|
+
m.delenv("PYTEST_CURRENT_TEST")
|
|
78
|
+
with httpdbg() as records:
|
|
79
|
+
requests.get(
|
|
80
|
+
f"{httpbin.url}/redirect-to?url={httpbin.url}/get", verify=False
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
assert len(records) == 2
|
|
84
|
+
|
|
85
|
+
assert records[0].initiator is records[1].initiator
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@pytest.mark.initiator
|
|
89
|
+
@pytest.mark.xfail(
|
|
90
|
+
platform.system().lower() == "windows",
|
|
91
|
+
reason="problem with stack view in windows",
|
|
92
|
+
)
|
|
93
|
+
def test_initiator_pytest(httpbin):
|
|
94
|
+
with httpdbg() as records:
|
|
95
|
+
requests.get(f"{httpbin.url}/get")
|
|
96
|
+
|
|
97
|
+
assert len(records) == 1
|
|
98
|
+
|
|
99
|
+
assert records[0].initiator.short_label == "test_initiator_pytest"
|
|
100
|
+
assert (
|
|
101
|
+
records[0].initiator.long_label
|
|
102
|
+
== "tests/test_initiator.py::test_initiator_pytest"
|
|
103
|
+
)
|
|
104
|
+
assert 'requests.get(f"{httpbin.url}/get")' in records[0].initiator.short_stack
|
|
105
|
+
assert 'requests.get(f"{httpbin.url}/get") <===' in records[0].initiator.stack[0]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@pytest.mark.initiator
|
|
109
|
+
def test_initiator_add_package_fnc(httpbin, monkeypatch):
|
|
110
|
+
with monkeypatch.context() as m:
|
|
111
|
+
m.delenv("PYTEST_CURRENT_TEST")
|
|
112
|
+
|
|
113
|
+
# all cases must be tested in the same test
|
|
114
|
+
with httpdbg(initiators=["initiator_pck"]) as records:
|
|
115
|
+
from initiator_pck.initiator2.mod2 import fnc_in_subpackage
|
|
116
|
+
from initiator_pck.mod1 import fnc_in_package
|
|
117
|
+
from initiator_pck import fnc_async
|
|
118
|
+
from initiator_pck.initiator2.initiator3 import fnc_in_init
|
|
119
|
+
from initiator_pck.initiator2.mod2 import FakeClient
|
|
120
|
+
|
|
121
|
+
fnc_in_package(f"{httpbin.url}/get")
|
|
122
|
+
fnc_in_subpackage(f"{httpbin.url}/get")
|
|
123
|
+
fnc_in_init(f"{httpbin.url}/get")
|
|
124
|
+
FakeClient().navigate(f"{httpbin.url}/get")
|
|
125
|
+
if sys.version_info >= (3, 7):
|
|
126
|
+
asyncio.run(fnc_async(f"{httpbin.url}/get"))
|
|
127
|
+
|
|
128
|
+
# function in a package
|
|
129
|
+
assert (
|
|
130
|
+
records[0].initiator.short_label == 'fnc_in_package(f"{httpbin.url}/get")'
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# function in a sub package (no __init__)
|
|
134
|
+
assert (
|
|
135
|
+
records[1].initiator.short_label
|
|
136
|
+
== 'fnc_in_subpackage(f"{httpbin.url}/get")'
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# function in a __init__.py file
|
|
140
|
+
assert records[2].initiator.short_label == 'fnc_in_init(f"{httpbin.url}/get")'
|
|
141
|
+
|
|
142
|
+
# method
|
|
143
|
+
assert (
|
|
144
|
+
records[3].initiator.short_label
|
|
145
|
+
== 'FakeClient().navigate(f"{httpbin.url}/get")'
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# async function in a package
|
|
149
|
+
if sys.version_info >= (3, 7):
|
|
150
|
+
assert (
|
|
151
|
+
records[4].initiator.short_label
|
|
152
|
+
== 'asyncio.run(fnc_async(f"{httpbin.url}/get"))'
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
with httpdbg() as records:
|
|
156
|
+
fnc_in_package(f"{httpbin.url}/get")
|
|
157
|
+
fnc_in_subpackage(f"{httpbin.url}/get")
|
|
158
|
+
fnc_in_init(f"{httpbin.url}/get")
|
|
159
|
+
FakeClient().navigate(f"{httpbin.url}/get")
|
|
160
|
+
if sys.version_info >= (3, 7):
|
|
161
|
+
asyncio.run(fnc_async(f"{httpbin.url}/get"))
|
|
162
|
+
|
|
163
|
+
assert records[0].initiator.short_label == "requests.get(url)"
|
|
164
|
+
assert records[1].initiator.short_label == "requests.get(url) # subpackage"
|
|
165
|
+
assert records[2].initiator.short_label == "requests.get(url) # init"
|
|
166
|
+
assert records[3].initiator.short_label == "requests.get(url) # method"
|
|
167
|
+
if sys.version_info >= (3, 7):
|
|
168
|
+
assert records[4].initiator.short_label == "await client.get(url)"
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
import platform
|
|
3
|
-
|
|
4
|
-
import pytest
|
|
5
|
-
import requests
|
|
6
|
-
|
|
7
|
-
from httpdbg.hooks.all import httpdbg
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@pytest.mark.xfail(
|
|
11
|
-
platform.system().lower() == "windows",
|
|
12
|
-
reason="problem with stack view in windows",
|
|
13
|
-
)
|
|
14
|
-
@pytest.mark.initiator
|
|
15
|
-
def test_initiator_script(httpbin, monkeypatch):
|
|
16
|
-
with monkeypatch.context() as m:
|
|
17
|
-
m.delenv("PYTEST_CURRENT_TEST")
|
|
18
|
-
with httpdbg() as records:
|
|
19
|
-
requests.get(f"{httpbin.url}/get")
|
|
20
|
-
|
|
21
|
-
assert len(records) == 1
|
|
22
|
-
http_record = records[0]
|
|
23
|
-
|
|
24
|
-
assert http_record.initiator.short_label == 'requests.get(f"{httpbin.url}/get")'
|
|
25
|
-
assert http_record.initiator.long_label is None
|
|
26
|
-
|
|
27
|
-
assert (
|
|
28
|
-
"""test_initiator.py", line 19, in test_initiator_script
|
|
29
|
-
19. requests.get(f"{httpbin.url}/get")
|
|
30
|
-
----------
|
|
31
|
-
requests.api.get(
|
|
32
|
-
url="""
|
|
33
|
-
+ f"{httpbin.url}/get"
|
|
34
|
-
+ """
|
|
35
|
-
)"""
|
|
36
|
-
in http_record.initiator.short_stack
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
assert (
|
|
40
|
-
"""test_initiator.py", line 19,
|
|
41
|
-
15. def test_initiator_script(httpbin, monkeypatch):
|
|
42
|
-
16. with monkeypatch.context() as m:
|
|
43
|
-
17. m.delenv("PYTEST_CURRENT_TEST")
|
|
44
|
-
18. with httpdbg() as records:
|
|
45
|
-
19. requests.get(f"{httpbin.url}/get") <====
|
|
46
|
-
20.
|
|
47
|
-
21. assert len(records) == 1
|
|
48
|
-
22. http_record = records[0]
|
|
49
|
-
23.
|
|
50
|
-
24. assert http_record.initiator.short_label == \'requests.get(f"{httpbin.url}/get")\'
|
|
51
|
-
25. assert http_record.initiator.long_label is None
|
|
52
|
-
26.""" # noqa W291
|
|
53
|
-
in http_record.initiator.stack[0]
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
@pytest.mark.initiator
|
|
58
|
-
def test_initiator_same_line_different_initiators(httpbin, monkeypatch):
|
|
59
|
-
with monkeypatch.context() as m:
|
|
60
|
-
m.delenv("PYTEST_CURRENT_TEST")
|
|
61
|
-
with httpdbg() as records:
|
|
62
|
-
for i in range(2):
|
|
63
|
-
requests.get(f"{httpbin.url}/get")
|
|
64
|
-
|
|
65
|
-
assert len(records) == 2
|
|
66
|
-
|
|
67
|
-
assert records[0].initiator is not records[1].initiator
|
|
68
|
-
assert records[0].initiator.id != records[1].initiator.id
|
|
69
|
-
assert records[0].initiator == records[1].initiator
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
@pytest.mark.initiator
|
|
73
|
-
def test_initiator_redirection_same_initiator(httpbin, monkeypatch):
|
|
74
|
-
with monkeypatch.context() as m:
|
|
75
|
-
m.delenv("PYTEST_CURRENT_TEST")
|
|
76
|
-
with httpdbg() as records:
|
|
77
|
-
requests.get(
|
|
78
|
-
f"{httpbin.url}/redirect-to?url={httpbin.url}/get", verify=False
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
assert len(records) == 2
|
|
82
|
-
|
|
83
|
-
assert records[0].initiator is records[1].initiator
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@pytest.mark.initiator
|
|
87
|
-
@pytest.mark.xfail(
|
|
88
|
-
platform.system().lower() == "windows",
|
|
89
|
-
reason="problem with stack view in windows",
|
|
90
|
-
)
|
|
91
|
-
def test_initiator_pytest(httpbin):
|
|
92
|
-
with httpdbg() as records:
|
|
93
|
-
requests.get(f"{httpbin.url}/get")
|
|
94
|
-
|
|
95
|
-
assert len(records) == 1
|
|
96
|
-
|
|
97
|
-
assert records[0].initiator.short_label == "test_initiator_pytest"
|
|
98
|
-
assert (
|
|
99
|
-
records[0].initiator.long_label
|
|
100
|
-
== "tests/test_initiator.py::test_initiator_pytest"
|
|
101
|
-
)
|
|
102
|
-
assert 'requests.get(f"{httpbin.url}/get")' in records[0].initiator.short_stack
|
|
103
|
-
assert 'requests.get(f"{httpbin.url}/get") <===' in records[0].initiator.stack[0]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{httpdbg-0.10.0 → httpdbg-0.11.0}/httpdbg/webapp/static/icons/download-install-line-icon.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|