httpdbg 2.0.0__tar.gz → 2.0.2__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.
Files changed (98) hide show
  1. {httpdbg-2.0.0 → httpdbg-2.0.2}/PKG-INFO +1 -1
  2. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/__init__.py +1 -2
  3. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/__main__.py +4 -3
  4. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/args.py +7 -2
  5. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/aiohttp.py +1 -3
  6. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/generic.py +2 -8
  7. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/h2.py +3 -10
  8. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/http.py +0 -1
  9. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/httpx.py +2 -3
  10. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/requests.py +1 -3
  11. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/socket.py +4 -11
  12. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/urllib3.py +1 -3
  13. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/uvicorn.py +0 -3
  14. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/initiator.py +64 -57
  15. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg.egg-info/PKG-INFO +1 -1
  16. {httpdbg-2.0.0 → httpdbg-2.0.2}/LICENSE +0 -0
  17. {httpdbg-2.0.0 → httpdbg-2.0.2}/README.md +0 -0
  18. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/env.py +0 -0
  19. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/exception.py +0 -0
  20. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/__init__.py +0 -0
  21. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/all.py +0 -0
  22. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/external.py +0 -0
  23. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/fastapi.py +0 -0
  24. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/flask.py +0 -0
  25. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/pytest.py +0 -0
  26. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/record.py +0 -0
  27. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/recordhttp1.py +0 -0
  28. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/recordhttp2.py +0 -0
  29. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/starlette.py +0 -0
  30. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/template_sitecustomize.py +0 -0
  31. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/unittest.py +0 -0
  32. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/hooks/utils.py +0 -0
  33. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/http_status_code.py +0 -0
  34. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/log.py +0 -0
  35. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/mode_console.py +0 -0
  36. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/mode_module.py +0 -0
  37. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/mode_script.py +0 -0
  38. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/preview.py +0 -0
  39. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/records.py +0 -0
  40. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/server.py +0 -0
  41. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/utils.py +0 -0
  42. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/__init__.py +0 -0
  43. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/api.py +0 -0
  44. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/app.py +0 -0
  45. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/api.js +0 -0
  46. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/column.css +0 -0
  47. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/configuration.css +0 -0
  48. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/configuration.js +0 -0
  49. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/detail.css +0 -0
  50. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/favicon.ico +0 -0
  51. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/filter.js +0 -0
  52. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/chevron-direction-top-outline-icon.svg +0 -0
  53. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/download-install-line-icon.svg +0 -0
  54. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/engine-gears-icon.svg +0 -0
  55. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/eye-blind-icon.svg +0 -0
  56. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/eye-icon.svg +0 -0
  57. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/files-papers-outline-icon.svg +0 -0
  58. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/filter-outline-icon.svg +0 -0
  59. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/information-mark-circle-outline-icon.svg +0 -0
  60. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/lock-line-icon.svg +0 -0
  61. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/lock-open-line-icon.svg +0 -0
  62. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/math-multiplication-icon.svg +0 -0
  63. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/push-pin-green-icon.svg +0 -0
  64. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/question-mark-round-line-icon.svg +0 -0
  65. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/recycle-bin-line-icon.svg +0 -0
  66. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/icons/wait-sandclock-icon.svg +0 -0
  67. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/index.htm +0 -0
  68. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/main.js +0 -0
  69. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/mustache.min.js +0 -0
  70. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/render.js +0 -0
  71. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/style.css +0 -0
  72. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg/webapp/static/table.css +0 -0
  73. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg.egg-info/SOURCES.txt +0 -0
  74. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg.egg-info/dependency_links.txt +0 -0
  75. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg.egg-info/entry_points.txt +0 -0
  76. {httpdbg-2.0.0 → httpdbg-2.0.2}/httpdbg.egg-info/top_level.txt +0 -0
  77. {httpdbg-2.0.0 → httpdbg-2.0.2}/pyproject.toml +0 -0
  78. {httpdbg-2.0.0 → httpdbg-2.0.2}/setup.cfg +0 -0
  79. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_api.py +0 -0
  80. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_cli.py +0 -0
  81. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_context_manager.py +0 -0
  82. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_hook_aiohttp.py +0 -0
  83. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_hook_h2.py +0 -0
  84. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_hook_httpx.py +0 -0
  85. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_hook_pytest.py +0 -0
  86. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_hook_requests.py +0 -0
  87. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_hook_unittest.py +0 -0
  88. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_hook_urllib3.py +0 -0
  89. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_initiator.py +0 -0
  90. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_mode_console.py +0 -0
  91. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_mode_module_pytest.py +0 -0
  92. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_mode_script.py +0 -0
  93. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_multiprocess.py +0 -0
  94. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_preview.py +0 -0
  95. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_pyhttpdbg_server.py +0 -0
  96. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_server.py +0 -0
  97. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_server_hook_fastapi.py +0 -0
  98. {httpdbg-2.0.0 → httpdbg-2.0.2}/tests/test_server_hook_flask.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httpdbg
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: A very simple tool to debug HTTP(S) client and server requests.
5
5
  Author-email: cle-b <cle@tictac.pm>
6
6
  License: Apache-2.0
@@ -1,8 +1,7 @@
1
- # -*- coding: utf-8 -*-
2
1
  from httpdbg.hooks.all import httprecord
3
2
  from httpdbg.records import HTTPRecords
4
3
 
5
4
 
6
- __version__ = "2.0.0"
5
+ __version__ = "2.0.2"
7
6
 
8
7
  __all__ = ["httprecord", "HTTPRecords"]
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  import sys
3
2
  import time
4
3
 
@@ -24,7 +23,8 @@ def pyhttpdbg(params, subparams, test_mode=False):
24
23
 
25
24
  url = f"http://{params.host}:{params.port}/{'?hi=on' if params.console else ''}"
26
25
 
27
- print_msg(f" httpdbg - HTTP(S) requests available at {url}")
26
+ if not params.no_banner:
27
+ print_msg(f" httpdbg - HTTP(S) requests available at {url}")
28
28
 
29
29
  sys.path.insert(0, "") # to mimic the default python command behavior
30
30
 
@@ -39,7 +39,8 @@ def pyhttpdbg(params, subparams, test_mode=False):
39
39
  run_console(records, test_mode)
40
40
 
41
41
  if not (params.force_quit or test_mode):
42
- print_msg(f" httpdbg - HTTP(S) requests available at {url}")
42
+ if not params.no_banner:
43
+ print_msg(f" httpdbg - HTTP(S) requests available at {url}")
43
44
 
44
45
  if params.keep_up:
45
46
  input("Press enter to quit")
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  import argparse
3
2
  from pathlib import Path
4
3
 
@@ -65,7 +64,13 @@ def read_args(args: list[str]) -> tuple[argparse.Namespace, list[str]]:
65
64
  help="The log level",
66
65
  )
67
66
 
68
- parser.add_argument("--log", type=Path, help="Path to the log file.")
67
+ parser.add_argument("--log", type=Path, help="path to the log file.")
68
+
69
+ parser.add_argument(
70
+ "--no-banner",
71
+ action="store_true",
72
+ help="do not print the banner in the console",
73
+ )
69
74
 
70
75
  actions = parser.add_mutually_exclusive_group()
71
76
 
@@ -1,7 +1,5 @@
1
- # -*- coding: utf-8 -*-
2
1
  from collections.abc import Callable
3
2
  from contextlib import contextmanager
4
- import traceback
5
3
  from typing import Generator
6
4
 
7
5
  from httpdbg.hooks.utils import getcallargs
@@ -16,7 +14,7 @@ def set_hook_for_aiohttp_async(records: HTTPRecords, method: Callable):
16
14
  initiator_and_group = None
17
15
  try:
18
16
  with httpdbg_initiator(
19
- records, traceback.extract_stack(), method, *args, **kwargs
17
+ records, method, *args, **kwargs
20
18
  ) as initiator_and_group:
21
19
  ret = await method(*args, **kwargs)
22
20
  return ret
@@ -1,11 +1,9 @@
1
- # -*- coding: utf-8 -*-
2
1
  import builtins
3
2
  from collections.abc import Callable
4
3
  from contextlib import contextmanager
5
4
  import functools
6
5
  import importlib
7
6
  import inspect
8
- import traceback
9
7
  from types import ModuleType
10
8
  from typing import Any
11
9
  from typing import Generator
@@ -22,9 +20,7 @@ def set_hook_for_generic_async(records: HTTPRecords, method: Any):
22
20
  logger().info(f"SET_HOOK_FOR_GENERIC_ASYNC {method}")
23
21
 
24
22
  async def hook(*args, **kwargs):
25
- with httpdbg_initiator(
26
- records, traceback.extract_stack(), method, *args, **kwargs
27
- ):
23
+ with httpdbg_initiator(records, method, *args, **kwargs):
28
24
  ret = await method(*args, **kwargs)
29
25
 
30
26
  return ret
@@ -36,9 +32,7 @@ def set_hook_for_generic(records: HTTPRecords, method: Any):
36
32
  logger().info(f"SET_HOOK_FOR_GENERIC {method}")
37
33
 
38
34
  def hook(*args, **kwargs):
39
- with httpdbg_initiator(
40
- records, traceback.extract_stack(), method, *args, **kwargs
41
- ):
35
+ with httpdbg_initiator(records, method, *args, **kwargs):
42
36
  ret = method(*args, **kwargs)
43
37
 
44
38
  return ret
@@ -1,7 +1,6 @@
1
1
  from collections.abc import Callable
2
2
  from contextlib import contextmanager
3
3
  import random
4
- import traceback
5
4
  from typing import Generator
6
5
  from typing import Union
7
6
 
@@ -101,9 +100,7 @@ def set_hook_for_h2_send_headers(records: HTTPRecords, method: Callable):
101
100
  stream_id = callargs.get("stream_id")
102
101
  headers = callargs.get("headers")
103
102
 
104
- with httpdbg_initiator(
105
- records, traceback.extract_stack(), method, *args, **kwargs
106
- ) as initiator_and_group:
103
+ with httpdbg_initiator(records, method, *args, **kwargs) as initiator_and_group:
107
104
  initiator, group, _ = initiator_and_group
108
105
  if all(x is not None for x in (self, stream_id, headers)):
109
106
  logger().debug(
@@ -127,9 +124,7 @@ def set_hook_for_h2_send_data(records: HTTPRecords, method: Callable):
127
124
  stream_id = callargs.get("stream_id")
128
125
  data = callargs.get("data")
129
126
 
130
- with httpdbg_initiator(
131
- records, traceback.extract_stack(), method, *args, **kwargs
132
- ):
127
+ with httpdbg_initiator(records, method, *args, **kwargs):
133
128
  if all(x is not None for x in (self, stream_id, data)):
134
129
  logger().debug(
135
130
  f"H2 send_data - self={id(self)} steam_id={stream_id} data={data[:20]!r}"
@@ -146,9 +141,7 @@ def set_hook_for_h2_receive_data(records: HTTPRecords, method: Callable):
146
141
  callargs = getcallargs(method, *args, **kwargs)
147
142
  self = callargs.get("self")
148
143
 
149
- with httpdbg_initiator(
150
- records, traceback.extract_stack(), method, *args, **kwargs
151
- ) as initiator_and_group:
144
+ with httpdbg_initiator(records, method, *args, **kwargs) as initiator_and_group:
152
145
  initiator, group, _ = initiator_and_group
153
146
  ret = method(*args, **kwargs)
154
147
 
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  from collections.abc import Callable
3
2
  from contextlib import contextmanager
4
3
  from typing import Generator
@@ -1,6 +1,5 @@
1
1
  from collections.abc import Callable
2
2
  from contextlib import contextmanager
3
- import traceback
4
3
  from typing import Generator
5
4
 
6
5
  from httpdbg.hooks.utils import getcallargs
@@ -15,7 +14,7 @@ def set_hook_for_httpx_async(records: HTTPRecords, method: Callable):
15
14
  initiator_and_group = None
16
15
  try:
17
16
  with httpdbg_initiator(
18
- records, traceback.extract_stack(), method, *args, **kwargs
17
+ records, method, *args, **kwargs
19
18
  ) as initiator_and_group:
20
19
  ret = await method(*args, **kwargs)
21
20
  return ret
@@ -39,7 +38,7 @@ def set_hook_for_httpx(records: HTTPRecords, method: Callable):
39
38
  initiator_and_group = None
40
39
  try:
41
40
  with httpdbg_initiator(
42
- records, traceback.extract_stack(), method, *args, **kwargs
41
+ records, method, *args, **kwargs
43
42
  ) as initiator_and_group:
44
43
  ret = method(*args, **kwargs)
45
44
  return ret
@@ -1,7 +1,5 @@
1
- # -*- coding: utf-8 -*-
2
1
  from collections.abc import Callable
3
2
  from contextlib import contextmanager
4
- import traceback
5
3
  from typing import Generator
6
4
 
7
5
  from httpdbg.hooks.utils import getcallargs
@@ -16,7 +14,7 @@ def set_hook_for_requests(records: HTTPRecords, method: Callable):
16
14
  initiator_and_group = None
17
15
  try:
18
16
  with httpdbg_initiator(
19
- records, traceback.extract_stack(), method, *args, **kwargs
17
+ records, method, *args, **kwargs
20
18
  ) as initiator_and_group:
21
19
  ret = method(*args, **kwargs)
22
20
  return ret
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  import asyncio
3
2
  import asyncio.proactor_events
4
3
  from collections.abc import Callable
@@ -8,7 +7,6 @@ import platform
8
7
  import socket
9
8
  import ssl
10
9
  import sys
11
- import traceback
12
10
  from typing import Generator
13
11
  from typing import Union
14
12
 
@@ -193,7 +191,7 @@ def set_hook_for_socket_connect(records: HTTPRecords, method: Callable):
193
191
  ): # BlockingIOError for async, OSError for ipv6
194
192
  if records.client:
195
193
  with httpdbg_initiator(
196
- records, traceback.extract_stack(), method, *args, **kwargs
194
+ records, method, *args, **kwargs
197
195
  ) as initiator_and_group:
198
196
  initiator, group, is_new = initiator_and_group
199
197
  if is_new:
@@ -221,7 +219,7 @@ def set_hook_for_ssl_wrap_socket(records: HTTPRecords, method: Callable):
221
219
  except Exception as ex:
222
220
  if records.client:
223
221
  with httpdbg_initiator(
224
- records, traceback.extract_stack(), method, *args, **kwargs
222
+ records, method, *args, **kwargs
225
223
  ) as initiator_and_group:
226
224
  initiator, group, is_new = initiator_and_group
227
225
  if is_new:
@@ -256,7 +254,7 @@ def set_hook_for_sslcontext_wrap_socket(records: HTTPRecords, method: Callable):
256
254
  except Exception as ex:
257
255
  if records.client:
258
256
  with httpdbg_initiator(
259
- records, traceback.extract_stack(), method, *args, **kwargs
257
+ records, method, *args, **kwargs
260
258
  ) as initiator_and_group:
261
259
  initiator, group, is_new = initiator_and_group
262
260
  if is_new:
@@ -291,7 +289,7 @@ def set_hook_for_socket_wrap_bio(records: HTTPRecords, method: Callable):
291
289
  except Exception as ex:
292
290
  if records.client:
293
291
  with httpdbg_initiator(
294
- records, traceback.extract_stack(), method, *args, **kwargs
292
+ records, method, *args, **kwargs
295
293
  ) as initiator_and_group:
296
294
  initiator, group, is_new = initiator_and_group
297
295
  if is_new:
@@ -345,7 +343,6 @@ def set_hook_for_socket_recv_into(records: HTTPRecords, method: Callable):
345
343
  )
346
344
  with httpdbg_initiator(
347
345
  records,
348
- traceback.extract_stack(),
349
346
  method,
350
347
  self,
351
348
  buffer,
@@ -404,7 +401,6 @@ def set_hook_for_socket_recv(records: HTTPRecords, method: Callable):
404
401
  logger().info("RECV - http detected")
405
402
  with httpdbg_initiator(
406
403
  records,
407
- traceback.extract_stack(),
408
404
  method,
409
405
  self,
410
406
  bufsize,
@@ -459,7 +455,6 @@ def set_hook_for_socket_sendall(records: HTTPRecords, method: Callable):
459
455
  logger().info("SENDALL - http detected")
460
456
  with httpdbg_initiator(
461
457
  records,
462
- traceback.extract_stack(),
463
458
  method,
464
459
  self,
465
460
  data,
@@ -515,7 +510,6 @@ def set_hook_for_socket_send(records: HTTPRecords, method: Callable):
515
510
  if http_detected:
516
511
  with httpdbg_initiator(
517
512
  records,
518
- traceback.extract_stack(),
519
513
  method,
520
514
  self,
521
515
  data,
@@ -595,7 +589,6 @@ def set_hook_for_sslobject_write(records: HTTPRecords, method: Callable):
595
589
  if http_detected:
596
590
  with httpdbg_initiator(
597
591
  records,
598
- traceback.extract_stack(),
599
592
  method,
600
593
  self,
601
594
  buf,
@@ -1,7 +1,5 @@
1
- # -*- coding: utf-8 -*-
2
1
  from collections.abc import Callable
3
2
  from contextlib import contextmanager
4
- import traceback
5
3
  from typing import Generator
6
4
 
7
5
  from httpdbg.hooks.utils import getcallargs
@@ -16,7 +14,7 @@ def set_hook_for_urllib3(records: HTTPRecords, method: Callable):
16
14
  initiator_and_group = None
17
15
  try:
18
16
  with httpdbg_initiator(
19
- records, traceback.extract_stack(), method, *args, **kwargs
17
+ records, method, *args, **kwargs
20
18
  ) as initiator_and_group:
21
19
  ret = method(*args, **kwargs)
22
20
  return ret
@@ -1,8 +1,6 @@
1
- # -*- coding: utf-8 -*-
2
1
  from collections.abc import Callable
3
2
  from contextlib import contextmanager
4
3
  import datetime
5
- import traceback
6
4
  import typing
7
5
  from typing import Generator
8
6
 
@@ -66,7 +64,6 @@ def set_hook_uvicorn_data_received(records: HTTPRecords, method: Callable):
66
64
  logger().info("UVICORN - http detected")
67
65
  with httpdbg_initiator(
68
66
  records,
69
- traceback.extract_stack(),
70
67
  method,
71
68
  self,
72
69
  data,
@@ -2,7 +2,9 @@
2
2
  from collections.abc import Callable
3
3
  from contextlib import contextmanager
4
4
  import datetime
5
+ import functools
5
6
  import inspect
7
+ import linecache
6
8
  import os
7
9
  import platform
8
10
  import traceback
@@ -98,33 +100,27 @@ def in_lib(line: str, packages: list[str] = None):
98
100
  def get_current_instruction(
99
101
  extracted_stack: traceback.StackSummary,
100
102
  ) -> tuple[str, str, list[str]]:
101
- instruction = ""
102
- short_stack = ""
103
- stack = []
103
+ instruction: str = ""
104
+ short_stack: str = ""
105
+ stack: list[str] = []
104
106
 
105
107
  try:
106
- n_stack = -1
107
- framesummary = extracted_stack[-2]
108
- while "asyncio" in framesummary.filename:
109
- n_stack -= 1
110
- framesummary = extracted_stack[n_stack - 1]
108
+ n_stack = -2
109
+ framesummary = extracted_stack[-3]
111
110
 
112
- while ("httpdbg/hooks" in framesummary.filename) or (
113
- "httpdbg\\hooks" in framesummary.filename
111
+ while (
112
+ ("httpdbg/hooks" in framesummary.filename)
113
+ or ("httpdbg\\hooks" in framesummary.filename)
114
+ or ("asyncio" in framesummary.filename)
114
115
  ):
115
116
  n_stack -= 1
116
117
  framesummary = extracted_stack[n_stack - 1]
117
118
 
118
- short_stack = f'File "{framesummary.filename}", line {framesummary.lineno}, in {framesummary.name}\n'
119
119
  if os.path.exists(framesummary.filename) and framesummary.lineno is not None:
120
- instruction, s_stack = extract_short_stack_from_file(
121
- framesummary.filename, framesummary.lineno, 0, 8
122
- )
123
- short_stack += s_stack
124
120
 
125
121
  # stack
126
122
  to_include = False
127
- for i_stack in range(6, len(extracted_stack) + n_stack):
123
+ for i_stack in range(7, len(extracted_stack) + n_stack):
128
124
  last_stack = i_stack == len(extracted_stack) + n_stack - 1
129
125
  fs = extracted_stack[i_stack]
130
126
  to_include = to_include or (
@@ -132,14 +128,20 @@ def get_current_instruction(
132
128
  and ("importlib" not in fs.filename)
133
129
  ) # remove the stack before to start the user part
134
130
  if to_include:
135
- _, s_stack = extract_short_stack_from_file(
131
+ instruction, s_stack, l_stack = extract_short_stack_from_file(
136
132
  fs.filename,
137
133
  fs.lineno if fs.lineno else 0,
138
- 4 if last_stack else 0,
139
- 8,
140
134
  not last_stack,
141
135
  )
142
- stack.append(f'File "{fs.filename}", line {fs.lineno}, \n{s_stack}')
136
+ if last_stack:
137
+ short_stack = (
138
+ f'File "{fs.filename}", line {fs.lineno}, in {fs.name}\n'
139
+ )
140
+ short_stack += s_stack
141
+
142
+ stack.append(
143
+ f'File "{fs.filename}", line {fs.lineno}, \n{l_stack}\n'
144
+ )
143
145
 
144
146
  else:
145
147
  instruction = framesummary.line if framesummary.line else "console"
@@ -153,52 +155,57 @@ def get_current_instruction(
153
155
  return instruction.replace("\n", " "), short_stack, stack
154
156
 
155
157
 
158
+ @functools.cache
156
159
  def extract_short_stack_from_file(
157
160
  filename: str,
158
161
  lineno: int,
159
- before: int,
160
- after: int,
161
162
  stop_if_instruction_ends: bool = True,
162
- ) -> tuple[str, str]:
163
- instruction = ""
164
- short_stack = ""
163
+ ) -> tuple[str, str, str]:
164
+ before: int = 4
165
+ after: int = 8
166
+ instruction: str = ""
167
+ short_stack: str = ""
168
+ long_stack: str = ""
165
169
 
166
170
  try:
167
171
  if os.path.exists(filename):
168
- with open(filename, "r") as src:
169
- lines = src.read().splitlines()
170
-
171
- # copy the lines before
172
- for i in range(
173
- max(0, lineno - 1 - before), min(lineno - 1, len(lines))
174
- ):
175
- line = lines[i]
176
- short_stack += f" {i+1}. {line}\n"
177
-
178
- # try to recompose the instruction if on multi-lines
179
- end_of_instruction_found = False
180
- for i in range(max(0, lineno - 1), min(lineno - 1 + after, len(lines))):
181
- line = lines[i]
182
- if not end_of_instruction_found:
183
- instruction += line.strip()
184
- short_stack += f" {i+1}. {line}{' <====' if (before > 0 and i + 1 == lineno) else ''}\n"
185
- nb_parenthesis = 0
186
- for c in instruction[instruction.find("(") :]:
187
- if c == "(":
188
- nb_parenthesis += 1
189
- if c == ")":
190
- nb_parenthesis -= 1
191
- if nb_parenthesis == 0:
192
- end_of_instruction_found = True
193
- break
194
- if end_of_instruction_found and stop_if_instruction_ends:
172
+ # copy the lines before, only for the "long" stack (if they are not empty)
173
+ copyit = False
174
+ for i in range(max(0, lineno - before), lineno):
175
+ line = linecache.getline(filename, i).removesuffix("\n").rstrip()
176
+ copyit = copyit or (line != "")
177
+ if copyit:
178
+ long_stack += f" {i}. {line}\n"
179
+
180
+ # try to recompose the instruction if on multi-lines
181
+ end_of_instruction_found = False
182
+ for i in range(max(0, lineno), lineno + after):
183
+ line = linecache.getline(filename, i).removesuffix("\n").rstrip()
184
+ if not end_of_instruction_found:
185
+ instruction += line.strip()
186
+ short_stack += f" {i}. {line}\n"
187
+ long_stack += (
188
+ f" {i}. {line}{' <====' if (before > 0 and i == lineno) else ''}\n"
189
+ )
190
+ nb_parenthesis = 0
191
+ for c in instruction[instruction.find("(") :]:
192
+ if c == "(":
193
+ nb_parenthesis += 1
194
+ if c == ")":
195
+ nb_parenthesis -= 1
196
+ if nb_parenthesis == 0:
197
+ end_of_instruction_found = True
195
198
  break
199
+ if end_of_instruction_found and stop_if_instruction_ends:
200
+ break
196
201
  except Exception as ex:
202
+ tb = traceback.extract_tb(ex.__traceback__)
203
+ _, lineno, _, _ = tb[-1]
197
204
  logger().info(
198
- f"EXTRACT_SHORT_STACK_FROM_FILE {filename} lineno={lineno} before={before} after={after}- error - {str(ex)}"
205
+ f"EXTRACT_SHORT_STACK_FROM_FILE {filename} lineno={lineno} before={before} after={after}- error (line {lineno}) - {str(ex)}",
199
206
  )
200
207
 
201
- return instruction, short_stack
208
+ return instruction, short_stack, long_stack
202
209
 
203
210
 
204
211
  def construct_call_str(original_method, *args, **kwargs):
@@ -237,16 +244,16 @@ def construct_call_str(original_method, *args, **kwargs):
237
244
  @contextmanager
238
245
  def httpdbg_initiator(
239
246
  records: "HTTPRecords",
240
- extracted_stack: traceback.StackSummary,
241
247
  original_method: Callable,
242
248
  *args,
243
249
  **kwargs,
244
250
  ) -> Generator[tuple[Initiator, Group, bool], None, None]:
245
-
246
251
  try:
247
252
  if records.current_initiator is None:
248
253
  initiator_already_set = False
249
254
 
255
+ extracted_stack: traceback.StackSummary = traceback.extract_stack()
256
+
250
257
  # temporary set a fake initiator env variable to avoid a recursion error
251
258
  # RecursionError: maximum recursion depth exceeded while calling a Python object
252
259
  # TL;DR When we construct the short_stack string, a recursion error occurs if there
@@ -346,7 +353,7 @@ def httpdbg_endpoint(
346
353
  filename = inspect.getsourcefile(original_method)
347
354
  if filename:
348
355
  _, lineno = inspect.getsourcelines(original_method)
349
- instruction, s_stack = extract_short_stack_from_file(filename, lineno, 0, 8)
356
+ instruction, s_stack, _ = extract_short_stack_from_file(filename, lineno)
350
357
  full_label = (
351
358
  f'File "{filename}", line {lineno}, in {original_method.__name__}\n'
352
359
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httpdbg
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: A very simple tool to debug HTTP(S) client and server requests.
5
5
  Author-email: cle-b <cle@tictac.pm>
6
6
  License: Apache-2.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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes