httpdbg 2.2.0__tar.gz → 2.3.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.
Files changed (98) hide show
  1. {httpdbg-2.2.0 → httpdbg-2.3.0}/PKG-INFO +3 -3
  2. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/__init__.py +1 -1
  3. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/__main__.py +1 -2
  4. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/aiohttp.py +1 -1
  5. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/all.py +2 -3
  6. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/external.py +2 -3
  7. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/fastapi.py +2 -3
  8. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/flask.py +1 -1
  9. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/generic.py +2 -3
  10. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/h2.py +2 -3
  11. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/http.py +1 -2
  12. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/httpx.py +1 -1
  13. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/pytest.py +1 -1
  14. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/record.py +4 -5
  15. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/requests.py +1 -1
  16. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/socket.py +5 -6
  17. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/starlette.py +1 -1
  18. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/template_sitecustomize.py +1 -2
  19. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/unittest.py +1 -1
  20. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/urllib3.py +1 -1
  21. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/uvicorn.py +1 -1
  22. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/initiator.py +2 -3
  23. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/log.py +1 -2
  24. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/mode_console.py +3 -8
  25. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/preview.py +2 -5
  26. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/records.py +3 -4
  27. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/server.py +1 -1
  28. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/api.py +1 -2
  29. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/index.htm +8 -1
  30. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/render.js +8 -0
  31. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg.egg-info/PKG-INFO +3 -3
  32. {httpdbg-2.2.0 → httpdbg-2.3.0}/pyproject.toml +3 -3
  33. {httpdbg-2.2.0 → httpdbg-2.3.0}/LICENSE +0 -0
  34. {httpdbg-2.2.0 → httpdbg-2.3.0}/README.md +0 -0
  35. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/args.py +0 -0
  36. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/env.py +0 -0
  37. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/exception.py +0 -0
  38. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/export.py +0 -0
  39. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/__init__.py +0 -0
  40. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/recordhttp1.py +0 -0
  41. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/recordhttp2.py +0 -0
  42. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/hooks/utils.py +0 -0
  43. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/http_status_code.py +0 -0
  44. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/mode_module.py +0 -0
  45. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/mode_script.py +0 -0
  46. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/utils.py +0 -0
  47. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/__init__.py +0 -0
  48. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/app.py +0 -0
  49. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/api.js +0 -0
  50. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/column.css +0 -0
  51. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/configuration.css +0 -0
  52. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/configuration.js +0 -0
  53. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/detail.css +0 -0
  54. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/favicon.ico +0 -0
  55. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/filter.js +0 -0
  56. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/chevron-direction-top-outline-icon.svg +0 -0
  57. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/download-install-line-icon.svg +0 -0
  58. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/engine-gears-icon.svg +0 -0
  59. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/eye-blind-icon.svg +0 -0
  60. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/eye-icon.svg +0 -0
  61. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/files-papers-outline-icon.svg +0 -0
  62. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/filter-outline-icon.svg +0 -0
  63. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/lock-line-icon.svg +0 -0
  64. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/lock-open-line-icon.svg +0 -0
  65. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/math-multiplication-icon.svg +0 -0
  66. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/push-pin-green-icon.svg +0 -0
  67. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/question-mark-round-line-icon.svg +0 -0
  68. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/recycle-bin-line-icon.svg +0 -0
  69. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/icons/wait-sandclock-icon.svg +0 -0
  70. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/main.js +0 -0
  71. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/mustache.min.js +0 -0
  72. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/style.css +0 -0
  73. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg/webapp/static/table.css +0 -0
  74. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg.egg-info/SOURCES.txt +0 -0
  75. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg.egg-info/dependency_links.txt +0 -0
  76. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg.egg-info/entry_points.txt +0 -0
  77. {httpdbg-2.2.0 → httpdbg-2.3.0}/httpdbg.egg-info/top_level.txt +0 -0
  78. {httpdbg-2.2.0 → httpdbg-2.3.0}/setup.cfg +0 -0
  79. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_api.py +0 -0
  80. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_cli.py +0 -0
  81. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_context_manager.py +0 -0
  82. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_hook_aiohttp.py +0 -0
  83. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_hook_h2.py +0 -0
  84. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_hook_httpx.py +0 -0
  85. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_hook_pytest.py +0 -0
  86. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_hook_requests.py +0 -0
  87. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_hook_unittest.py +0 -0
  88. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_hook_urllib3.py +0 -0
  89. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_initiator.py +0 -0
  90. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_mode_console.py +0 -0
  91. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_mode_module_pytest.py +0 -0
  92. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_mode_script.py +0 -0
  93. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_multiprocess.py +0 -0
  94. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_preview.py +0 -0
  95. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_pyhttpdbg_server.py +0 -0
  96. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_server.py +0 -0
  97. {httpdbg-2.2.0 → httpdbg-2.3.0}/tests/test_server_hook_fastapi.py +0 -0
  98. {httpdbg-2.2.0 → httpdbg-2.3.0}/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.2.0
3
+ Version: 2.3.0
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-Expression: Apache-2.0
@@ -10,16 +10,16 @@ Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Operating System :: OS Independent
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
16
  Classifier: Programming Language :: Python :: 3.13
18
17
  Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
19
19
  Classifier: Topic :: Internet :: WWW/HTTP
20
20
  Classifier: Topic :: Software Development :: Testing
21
21
  Classifier: Topic :: Utilities
22
- Requires-Python: >=3.9
22
+ Requires-Python: >=3.10
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  Dynamic: license-file
@@ -1,4 +1,4 @@
1
- __version__ = "2.2.0"
1
+ __version__ = "2.3.0"
2
2
 
3
3
  __all__ = ["export_html", "httprecord", "HTTPRecords"]
4
4
 
@@ -2,7 +2,6 @@ import argparse
2
2
  from pathlib import Path
3
3
  import sys
4
4
  import time
5
- from typing import Union
6
5
 
7
6
  from httpdbg import __version__
8
7
  from httpdbg.args import read_args
@@ -32,7 +31,7 @@ def pyhttpdbg(
32
31
 
33
32
  def run_recorder(
34
33
  records: HTTPRecords,
35
- initiators: Union[list[str], None],
34
+ initiators: list[str] | None,
36
35
  record_server: bool,
37
36
  test_mode: bool,
38
37
  ):
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
- from typing import Generator
4
4
 
5
5
  from httpdbg.hooks.utils import getcallargs
6
6
  from httpdbg.hooks.utils import decorate
@@ -1,6 +1,5 @@
1
+ from collections.abc import Generator
1
2
  from contextlib import contextmanager
2
- from typing import Generator
3
- from typing import Union
4
3
 
5
4
  from httpdbg.hooks.aiohttp import hook_aiohttp
6
5
  from httpdbg.hooks.external import watcher_external
@@ -24,7 +23,7 @@ from httpdbg.records import HTTPRecords
24
23
  @contextmanager
25
24
  def httprecord(
26
25
  records: HTTPRecords = None,
27
- initiators: Union[list[str], None] = None,
26
+ initiators: list[str] | None = None,
28
27
  client: bool = True,
29
28
  server: bool = False,
30
29
  ignore: tuple[tuple[str, int], ...] = (),
@@ -1,12 +1,11 @@
1
+ from collections.abc import Generator
1
2
  from contextlib import contextmanager
2
- from typing import Generator
3
3
  import glob
4
4
  import os
5
5
  import pickle
6
6
  import tempfile
7
7
  import time
8
8
  import threading
9
- from typing import Union
10
9
 
11
10
  from httpdbg.env import HTTPDBG_MULTIPROCESS_DIR
12
11
  from httpdbg.log import logger
@@ -16,7 +15,7 @@ from httpdbg.records import HTTPRecords
16
15
  @contextmanager
17
16
  def watcher_external(
18
17
  records: HTTPRecords,
19
- initiators: Union[list[str], None] = None,
18
+ initiators: list[str] | None = None,
20
19
  server: bool = False,
21
20
  ) -> Generator[HTTPRecords, None, None]:
22
21
  if HTTPDBG_MULTIPROCESS_DIR not in os.environ:
@@ -1,10 +1,9 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
4
+ import datetime
3
5
  import functools
4
6
  from functools import wraps
5
- from typing import Generator
6
-
7
- import datetime
8
7
 
9
8
  from httpdbg.hooks.utils import decorate
10
9
  from httpdbg.hooks.utils import getcallargs
@@ -1,8 +1,8 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
4
  import functools
4
5
  from functools import wraps
5
- from typing import Generator
6
6
 
7
7
 
8
8
  from httpdbg.hooks.utils import getcallargs
@@ -1,13 +1,12 @@
1
1
  import builtins
2
2
  from collections.abc import Callable
3
+ from collections.abc import Generator
3
4
  from contextlib import contextmanager
4
5
  import functools
5
6
  import importlib
6
7
  import inspect
7
8
  from types import ModuleType
8
9
  from typing import Any
9
- from typing import Generator
10
- from typing import Union
11
10
 
12
11
  from httpdbg.hooks.utils import decorate
13
12
  from httpdbg.hooks.utils import undecorate
@@ -42,7 +41,7 @@ def set_hook_for_generic(records: HTTPRecords, method: Any):
42
41
 
43
42
  @contextmanager
44
43
  def hook_generic(
45
- records: HTTPRecords, initiators: Union[list[str], None] = None
44
+ records: HTTPRecords, initiators: list[str] | None = None
46
45
  ) -> Generator[None, None, None]:
47
46
  if initiators:
48
47
  # we add a hook for a generic initiator only if the module is imported
@@ -1,8 +1,7 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
4
  import random
4
- from typing import Generator
5
- from typing import Union
6
5
 
7
6
  from httpdbg.hooks.recordhttp2 import HTTP2Record
8
7
  from httpdbg.hooks.utils import decorate
@@ -67,7 +66,7 @@ class TracerHTTP2:
67
66
  stream_id: int,
68
67
  headers: list[tuple[bytes, bytes]],
69
68
  is_client: bool = True,
70
- ) -> Union[HTTP2Record, None]:
69
+ ) -> HTTP2Record | None:
71
70
  record = None
72
71
  if not is_client:
73
72
  if f"{socket_id}-{stream_id}" in self.sockets:
@@ -1,7 +1,6 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
- from typing import Generator
4
-
5
4
 
6
5
  from httpdbg.hooks.utils import decorate
7
6
  from httpdbg.hooks.utils import undecorate
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
- from typing import Generator
4
4
 
5
5
  from httpdbg.hooks.utils import getcallargs
6
6
  from httpdbg.hooks.utils import decorate
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
- from typing import Generator
4
4
 
5
5
  from httpdbg.hooks.utils import decorate
6
6
  from httpdbg.hooks.utils import getcallargs
@@ -1,6 +1,5 @@
1
1
  from abc import ABC, abstractmethod
2
2
  import datetime
3
- from typing import Union
4
3
  from urllib.parse import urlparse
5
4
 
6
5
  from httpdbg.utils import get_new_uuid
@@ -98,12 +97,12 @@ class HTTPRecord(ABC):
98
97
  ) -> None:
99
98
  self.id = get_new_uuid()
100
99
  self.address: tuple[str, int] = ("", 0)
101
- self._url: Union[str, None] = None
100
+ self._url: str | None = None
102
101
  self.initiator_id: str = initiator_id
103
- self.exception: Union[Exception, None] = None
104
- self.ssl: Union[bool, None] = None
102
+ self.exception: Exception | None = None
103
+ self.ssl: bool | None = None
105
104
  self.tbegin: datetime.datetime = datetime.datetime.now(datetime.timezone.utc)
106
- self.tag: Union[str, None] = tag
105
+ self.tag: str | None = tag
107
106
  self.group_id: str = group_id
108
107
  self.is_client: bool = is_client
109
108
  if tbegin:
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
- from typing import Generator
4
4
 
5
5
  from httpdbg.hooks.utils import getcallargs
6
6
  from httpdbg.hooks.utils import decorate
@@ -1,14 +1,13 @@
1
1
  import asyncio
2
2
  import asyncio.proactor_events
3
3
  from collections.abc import Callable
4
+ from collections.abc import Generator
4
5
  from contextlib import contextmanager
5
6
  import datetime
6
7
  import platform
7
8
  import socket
8
9
  import ssl
9
10
  import sys
10
- from typing import Generator
11
- from typing import Union
12
11
 
13
12
  from httpdbg.initiator import httpdbg_initiator
14
13
  from httpdbg.log import logger
@@ -28,7 +27,7 @@ class SocketRawData(object):
28
27
  self.address: tuple[str, int] = address
29
28
  self.ssl: bool = ssl
30
29
  self._rawdata: bytes = bytes()
31
- self.record: Union[HTTP1Record, None] = None
30
+ self.record: HTTP1Record | None = None
32
31
  self.tbegin: datetime.datetime = datetime.datetime.now(datetime.timezone.utc)
33
32
 
34
33
  @property
@@ -42,7 +41,7 @@ class SocketRawData(object):
42
41
  )
43
42
  self._rawdata = value
44
43
 
45
- def http_detected(self) -> Union[bool, None]:
44
+ def http_detected(self) -> bool | None:
46
45
  end_of_first_line = self.rawdata[:2048].find(b"\r\n")
47
46
  if end_of_first_line == -1:
48
47
  if len(self.rawdata) > 2048:
@@ -66,14 +65,14 @@ class TracerHTTP1:
66
65
  self,
67
66
  ignore: tuple[tuple[str, int], ...] = (),
68
67
  ):
69
- self.sockets: dict[int, Union[SocketRawData, None]] = (
68
+ self.sockets: dict[int, SocketRawData | None] = (
70
69
  {}
71
70
  ) # if None, this is not a HTTP/1 request
72
71
  self.ignore: tuple[tuple[str, int], ...] = ignore
73
72
 
74
73
  def get_socket_data(
75
74
  self, obj, extra_sock=None, force_new=False, request=None, is_uvicorn=False
76
- ) -> Union[SocketRawData, None]:
75
+ ) -> SocketRawData | None:
77
76
  """Record a new SocketRawData (or get an existing one) and return it."""
78
77
  socketdata = None
79
78
 
@@ -1,7 +1,7 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
4
  from functools import wraps
4
- from typing import Generator
5
5
 
6
6
  from httpdbg.hooks.utils import decorate
7
7
  from httpdbg.hooks.utils import getcallargs
@@ -4,7 +4,6 @@ import pickle
4
4
  import sys
5
5
  import time
6
6
  import threading
7
- from typing import Union
8
7
  import uuid
9
8
 
10
9
  from httpdbg import HTTPRecords
@@ -25,7 +24,7 @@ class HttpdbgRecorder:
25
24
  os.environ[HTTPDBG_MULTIPROCESS_DIR], str(uuid.uuid1())
26
25
  )
27
26
  self.context = None
28
- self.records: Union[HTTPRecords, None] = None
27
+ self.records: HTTPRecords | None = None
29
28
 
30
29
  def _save_to_disk_loop(self):
31
30
  while self._running:
@@ -1,9 +1,9 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
4
  import inspect
4
5
  import os
5
6
  import typing
6
- from typing import Generator
7
7
 
8
8
  from httpdbg.initiator import httpdbg_group
9
9
  from httpdbg.initiator import httpdbg_tag
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
- from typing import Generator
4
4
 
5
5
  from httpdbg.hooks.utils import getcallargs
6
6
  from httpdbg.hooks.utils import decorate
@@ -1,8 +1,8 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
4
  import datetime
4
5
  import typing
5
- from typing import Generator
6
6
 
7
7
  from httpdbg.hooks.utils import decorate
8
8
  from httpdbg.hooks.utils import undecorate
@@ -1,4 +1,5 @@
1
1
  from collections.abc import Callable
2
+ from collections.abc import Generator
2
3
  from contextlib import contextmanager
3
4
  import datetime
4
5
  import functools
@@ -7,8 +8,6 @@ import linecache
7
8
  import os
8
9
  import platform
9
10
  import traceback
10
- from typing import Generator
11
- from typing import Union
12
11
  from typing import TYPE_CHECKING
13
12
 
14
13
  if TYPE_CHECKING:
@@ -347,7 +346,7 @@ def httpdbg_group(
347
346
  @contextmanager
348
347
  def httpdbg_endpoint(
349
348
  records: "HTTPRecords", original_method: Callable, *args, **kwargs
350
- ) -> Generator[Union[Group, None], None, None]:
349
+ ) -> Generator[Group | None, None, None]:
351
350
 
352
351
  filename = inspect.getsourcefile(original_method)
353
352
  if filename:
@@ -3,7 +3,6 @@ from functools import cache
3
3
  import logging
4
4
  import os
5
5
  from pathlib import Path
6
- from typing import Union
7
6
 
8
7
  from httpdbg.env import HTTPDBG_LOG_LEVEL
9
8
  from httpdbg.env import HTTPDBG_LOG_PATH
@@ -18,7 +17,7 @@ class LogLevel(Enum):
18
17
  CRITICAL = "critical"
19
18
 
20
19
 
21
- def set_env_for_logging(log_level: LogLevel, path: Union[Path, None]):
20
+ def set_env_for_logging(log_level: LogLevel, path: Path | None):
22
21
 
23
22
  os.environ[HTTPDBG_LOG_LEVEL] = str(
24
23
  {
@@ -1,6 +1,4 @@
1
1
  import code
2
- from typing import Optional
3
- from typing import Union
4
2
 
5
3
  from httpdbg.records import HTTPRecords
6
4
  from httpdbg.initiator import httpdbg_group
@@ -18,7 +16,7 @@ class InteractiveConsoleWithHistory(code.InteractiveConsole):
18
16
  self.incomplete_block: bool = False
19
17
  super().__init__(locals)
20
18
 
21
- def push(self, line: str, filename: Optional[str] = None) -> bool:
19
+ def push(self, line: str, *args, **kwargs) -> bool:
22
20
  if line: # if the line is empty, we don't add it in the history
23
21
  if (
24
22
  self.incomplete_block
@@ -43,17 +41,14 @@ class InteractiveConsoleWithHistory(code.InteractiveConsole):
43
41
  full_label = ">>> " + "\n>>> ".join(latest_history)
44
42
 
45
43
  with httpdbg_group(self.records, label, full_label):
46
- if filename is None:
47
- self.incomplete_block = super().push(line)
48
- else:
49
- self.incomplete_block = super().push(line, filename)
44
+ self.incomplete_block = super().push(line, *args, **kwargs)
50
45
 
51
46
  return self.incomplete_block
52
47
 
53
48
 
54
49
  def run_console(
55
50
  records: HTTPRecords, test_mode: bool = False
56
- ) -> Union[InteractiveConsoleWithHistory, None]:
51
+ ) -> InteractiveConsoleWithHistory | None:
57
52
  try:
58
53
  vars = globals()
59
54
  vars.update(locals())
@@ -1,6 +1,3 @@
1
- from typing import Union
2
-
3
-
4
1
  def parse_content_type(content_type: str) -> tuple[str, dict[str, str]]:
5
2
  s = content_type.split(";")
6
3
  media_type = s[0]
@@ -14,8 +11,8 @@ def parse_content_type(content_type: str) -> tuple[str, dict[str, str]]:
14
11
 
15
12
  def generate_preview(
16
13
  raw_data: bytes, content_type: str, content_encoding: str
17
- ) -> dict[str, Union[str, bool]]:
18
- body: dict[str, Union[str, bool]] = {}
14
+ ) -> dict[str, str | bool]:
15
+ body: dict[str, str | bool] = {}
19
16
 
20
17
  body["content_type"] = content_type
21
18
 
@@ -1,6 +1,5 @@
1
1
  import datetime
2
2
  import sys
3
- from typing import Union
4
3
 
5
4
  from httpdbg.hooks.record import HTTPRecord
6
5
  from httpdbg.initiator import Group
@@ -38,10 +37,10 @@ class HTTPRecords:
38
37
  self.requests: dict[str, HTTPRecord] = {}
39
38
  self.requests_already_loaded = 0
40
39
  self.initiators: dict[str, Initiator] = {}
41
- self.current_initiator: Union[str, None] = None
40
+ self.current_initiator: str | None = None
42
41
  self.groups: dict[str, Group] = {}
43
- self.current_group: Union[str, None] = None
44
- self.current_tag: Union[str, None] = None
42
+ self.current_group: str | None = None
43
+ self.current_tag: str | None = None
45
44
  self._tracerhttp1: TracerHTTP1 = TracerHTTP1(ignore=self.ignore)
46
45
  self._tracerhttp2: TracerHTTP2 = TracerHTTP2(ignore=self.ignore)
47
46
 
@@ -1,7 +1,7 @@
1
+ from collections.abc import Generator
1
2
  from contextlib import contextmanager
2
3
  from http.server import HTTPServer
3
4
  import threading
4
- from typing import Generator
5
5
 
6
6
  from httpdbg.exception import HttpdbgException
7
7
  from httpdbg.records import HTTPRecords
@@ -1,7 +1,6 @@
1
1
  from json import JSONEncoder
2
2
  import traceback
3
3
  from typing import Any
4
- from typing import Union
5
4
 
6
5
  from httpdbg.records import HTTPRecords
7
6
  from httpdbg.records import HTTPRecord
@@ -71,7 +70,7 @@ class RequestListPayload(JSONEncoder):
71
70
  records, HTTPRecords
72
71
  ), "This encoder works only for HTTPRecords object."
73
72
 
74
- payload: dict[str, dict[str, Union[str, dict]]] = {
73
+ payload: dict[str, dict[str, str | dict]] = {
75
74
  "session": {
76
75
  "id": records.session.id,
77
76
  "command_line": records.session.command_line,
@@ -299,7 +299,14 @@
299
299
  </div>
300
300
 
301
301
  <script id="template_headers" type="x-tmpl-mustache">
302
- <b>{{ method }}</b> <a href="{{ url }}">{{ url }}</a>
302
+ <button title="copy to clipboard" onclick="navigator.clipboard.writeText({{url_to_clipboard}});"><svg class="icon"><use href="#files-papers-outline-icon"></use></svg></button>
303
+ <span class="header-cookie-key">{{verb}}</span>
304
+ {{#is_http}}
305
+ <a class="header-cookie-value" target="_blank" href="{{url}}">{{url}}</a>
306
+ {{/is_http}}
307
+ {{^is_http}}
308
+ <span class="header-cookie-value" title="Warning: This URL uses a non-HTTP/HTTPS scheme and has been disabled for security reasons.">{{url}}</span>
309
+ {{/is_http}}
303
310
  <hr>
304
311
  <span class="header-cookie-key">status:</span>
305
312
  <span class="header-cookie-value">{{ status_code }} {{ reason }} {{#http100}}(after 100 Continue){{/http100}}</span>
@@ -156,6 +156,14 @@ function fill_content(request_id, name) {
156
156
 
157
157
  var req = global.requests[request_id];
158
158
 
159
+ try {
160
+ const parsed_url = new URL(req.url);
161
+ req.is_http = ["http:", "https:"].includes(parsed_url.protocol);
162
+ } catch {
163
+ req.is_http = false;
164
+ }
165
+ req.url_to_clipboard = "global.requests['" + request_id + "'].url";
166
+
159
167
  update_with_template("template_title", document.querySelector("#title > div[name='" + name + "']"), req);
160
168
 
161
169
  update_with_template("template_headers", document.querySelector("#headers > div[name='" + name + "']"), req);
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httpdbg
3
- Version: 2.2.0
3
+ Version: 2.3.0
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-Expression: Apache-2.0
@@ -10,16 +10,16 @@ Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Operating System :: OS Independent
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
16
  Classifier: Programming Language :: Python :: 3.13
18
17
  Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
19
19
  Classifier: Topic :: Internet :: WWW/HTTP
20
20
  Classifier: Topic :: Software Development :: Testing
21
21
  Classifier: Topic :: Utilities
22
- Requires-Python: >=3.9
22
+ Requires-Python: >=3.10
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  Dynamic: license-file
@@ -9,7 +9,7 @@ authors = [
9
9
  ]
10
10
  description="A very simple tool to debug HTTP(S) client and server requests."
11
11
  readme="README.md"
12
- requires-python = ">=3.9"
12
+ requires-python = ">=3.10"
13
13
  license = "Apache-2.0"
14
14
  license-files = ["LICENSE"]
15
15
  classifiers = [
@@ -17,12 +17,12 @@ classifiers = [
17
17
  "Intended Audience :: Developers",
18
18
  "Operating System :: OS Independent",
19
19
  "Programming Language :: Python :: 3",
20
- "Programming Language :: Python :: 3.9",
21
20
  "Programming Language :: Python :: 3.10",
22
21
  "Programming Language :: Python :: 3.11",
23
22
  "Programming Language :: Python :: 3.12",
24
23
  "Programming Language :: Python :: 3.13",
25
- "Programming Language :: Python :: 3.14",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Programming Language :: Python :: 3.15",
26
26
  "Topic :: Internet :: WWW/HTTP",
27
27
  "Topic :: Software Development :: Testing",
28
28
  "Topic :: Utilities",
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