httpdbg 0.31.6__tar.gz → 0.32.1__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 (86) hide show
  1. {httpdbg-0.31.6 → httpdbg-0.32.1}/PKG-INFO +10 -16
  2. {httpdbg-0.31.6 → httpdbg-0.32.1}/README.md +9 -13
  3. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/__init__.py +1 -1
  4. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/env.py +1 -1
  5. httpdbg-0.32.1/httpdbg/hooks/external.py +80 -0
  6. httpdbg-0.32.1/httpdbg/hooks/template_sitecustomize.py +65 -0
  7. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/mode_script.py +15 -13
  8. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg.egg-info/PKG-INFO +10 -16
  9. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg.egg-info/SOURCES.txt +2 -1
  10. {httpdbg-0.31.6 → httpdbg-0.32.1}/pyproject.toml +0 -3
  11. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_mode_script.py +2 -2
  12. httpdbg-0.32.1/tests/test_multiprocess.py +52 -0
  13. httpdbg-0.31.6/httpdbg/hooks/external.py +0 -61
  14. httpdbg-0.31.6/httpdbg.egg-info/requires.txt +0 -3
  15. {httpdbg-0.31.6 → httpdbg-0.32.1}/LICENSE +0 -0
  16. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/__main__.py +0 -0
  17. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/args.py +0 -0
  18. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/exception.py +0 -0
  19. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/__init__.py +0 -0
  20. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/aiohttp.py +0 -0
  21. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/all.py +0 -0
  22. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/generic.py +0 -0
  23. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/httpx.py +0 -0
  24. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/pytest.py +0 -0
  25. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/requests.py +0 -0
  26. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/socket.py +0 -0
  27. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/unittest.py +0 -0
  28. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/urllib3.py +0 -0
  29. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/hooks/utils.py +0 -0
  30. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/initiator.py +0 -0
  31. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/log.py +0 -0
  32. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/mode_console.py +0 -0
  33. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/mode_module.py +0 -0
  34. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/preview.py +0 -0
  35. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/records.py +0 -0
  36. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/server.py +0 -0
  37. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/utils.py +0 -0
  38. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/__init__.py +0 -0
  39. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/api.py +0 -0
  40. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/app.py +0 -0
  41. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/api.js +0 -0
  42. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/column.css +0 -0
  43. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/configuration.css +0 -0
  44. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/configuration.js +0 -0
  45. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/detail.css +0 -0
  46. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/favicon.ico +0 -0
  47. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/filter.js +0 -0
  48. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/chevron-direction-top-outline-icon.svg +0 -0
  49. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/download-install-line-icon.svg +0 -0
  50. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/engine-gears-icon.svg +0 -0
  51. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/eye-blind-icon.svg +0 -0
  52. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/eye-icon.svg +0 -0
  53. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/files-papers-outline-icon.svg +0 -0
  54. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/filter-outline-icon.svg +0 -0
  55. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/information-mark-circle-outline-icon.svg +0 -0
  56. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/lock-line-icon.svg +0 -0
  57. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/lock-open-line-icon.svg +0 -0
  58. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/math-multiplication-icon.svg +0 -0
  59. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/push-pin-green-icon.svg +0 -0
  60. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/question-mark-round-line-icon.svg +0 -0
  61. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/recycle-bin-line-icon.svg +0 -0
  62. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/icons/wait-sandclock-icon.svg +0 -0
  63. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/index.htm +0 -0
  64. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/main.js +0 -0
  65. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/mustache.min.js +0 -0
  66. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/render.js +0 -0
  67. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/style.css +0 -0
  68. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg/webapp/static/table.css +0 -0
  69. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg.egg-info/dependency_links.txt +0 -0
  70. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg.egg-info/entry_points.txt +0 -0
  71. {httpdbg-0.31.6 → httpdbg-0.32.1}/httpdbg.egg-info/top_level.txt +0 -0
  72. {httpdbg-0.31.6 → httpdbg-0.32.1}/setup.cfg +0 -0
  73. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_api.py +0 -0
  74. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_cli.py +0 -0
  75. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_context_manager.py +0 -0
  76. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_hook_aiohttp.py +0 -0
  77. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_hook_httpx.py +0 -0
  78. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_hook_pytest.py +0 -0
  79. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_hook_requests.py +0 -0
  80. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_hook_unittest.py +0 -0
  81. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_hook_urllib3.py +0 -0
  82. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_initiator.py +0 -0
  83. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_mode_console.py +0 -0
  84. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_mode_module_pytest.py +0 -0
  85. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_preview.py +0 -0
  86. {httpdbg-0.31.6 → httpdbg-0.32.1}/tests/test_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: httpdbg
3
- Version: 0.31.6
3
+ Version: 0.32.1
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
@@ -23,8 +23,6 @@ Classifier: Topic :: Utilities
23
23
  Requires-Python: >=3.9
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
- Provides-Extra: pytest
27
- Requires-Dist: pytest-httpdbg>=0.6.0; extra == "pytest"
28
26
 
29
27
  # httpdbg
30
28
 
@@ -71,30 +69,26 @@ You can trace all the HTTP requests performed by a script
71
69
  pyhttpdbg --script filename.py [arg1 --arg2 ...]
72
70
  ```
73
71
 
74
- ### pytest
75
-
76
- You can trace all the HTTP requests performed during your tests
72
+ ### module
77
73
 
78
- ```console
79
- pyhttpdbg -m pytest [arg1 --arg2 ...]
80
- ```
74
+ You can trace all the HTTP requests performed by a library module run as a script using the `-m` command line argument.
81
75
 
82
- If you use the `pytest-xdist` plugin to execute your tests in parallel, then you must install the `pytest-httpdbg` plugin if you want to trace the requests done by the pytest workers.
76
+ For example, you can view which HTTP requests are performed by `pip` when you install a package.
83
77
 
84
78
  ```console
85
- pip install httpdbg[pytest]
79
+ pyhttpdbg -m pip install hookdns --upgrade
86
80
  ```
87
81
 
88
- ### module
89
-
90
- You can trace all the HTTP requests performed by a library module run as a script using the `-m` command line argument.
82
+ ### test frameworks
91
83
 
92
- For example, you can view which HTTP requests are performed by `pip` when you install a package.
84
+ You can trace all HTTP requests made during your tests (pytest, unittest).
93
85
 
94
86
  ```console
95
- pyhttpdbg -m pip install hookdns --upgrade
87
+ pyhttpdbg -m pytest [arg1 --arg2 ...]
96
88
  ```
97
89
 
90
+ In that case, the requests will be grouped by test, and any requests made within a fixture or the setup/teardown methods will be identified by a tag.
91
+
98
92
  ## Initiators
99
93
 
100
94
  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.
@@ -43,30 +43,26 @@ You can trace all the HTTP requests performed by a script
43
43
  pyhttpdbg --script filename.py [arg1 --arg2 ...]
44
44
  ```
45
45
 
46
- ### pytest
47
-
48
- You can trace all the HTTP requests performed during your tests
46
+ ### module
49
47
 
50
- ```console
51
- pyhttpdbg -m pytest [arg1 --arg2 ...]
52
- ```
48
+ You can trace all the HTTP requests performed by a library module run as a script using the `-m` command line argument.
53
49
 
54
- If you use the `pytest-xdist` plugin to execute your tests in parallel, then you must install the `pytest-httpdbg` plugin if you want to trace the requests done by the pytest workers.
50
+ For example, you can view which HTTP requests are performed by `pip` when you install a package.
55
51
 
56
52
  ```console
57
- pip install httpdbg[pytest]
53
+ pyhttpdbg -m pip install hookdns --upgrade
58
54
  ```
59
55
 
60
- ### module
61
-
62
- You can trace all the HTTP requests performed by a library module run as a script using the `-m` command line argument.
56
+ ### test frameworks
63
57
 
64
- For example, you can view which HTTP requests are performed by `pip` when you install a package.
58
+ You can trace all HTTP requests made during your tests (pytest, unittest).
65
59
 
66
60
  ```console
67
- pyhttpdbg -m pip install hookdns --upgrade
61
+ pyhttpdbg -m pytest [arg1 --arg2 ...]
68
62
  ```
69
63
 
64
+ In that case, the requests will be grouped by test, and any requests made within a fixture or the setup/teardown methods will be identified by a tag.
65
+
70
66
  ## Initiators
71
67
 
72
68
  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.
@@ -3,6 +3,6 @@ from httpdbg.hooks.all import httprecord
3
3
  from httpdbg.records import HTTPRecords
4
4
 
5
5
 
6
- __version__ = "0.31.6"
6
+ __version__ = "0.32.1"
7
7
 
8
8
  __all__ = ["httprecord", "HTTPRecords"]
@@ -1,7 +1,7 @@
1
1
  HTTPDBG_CURRENT_GROUP = "HTTPDBG_CURRENT_GROUP"
2
2
  HTTPDBG_CURRENT_INITIATOR = "HTTPDBG_CURRENT_INITIATOR"
3
3
  HTTPDBG_CURRENT_TAG = "HTTPDBG_CURRENT_TAG"
4
- HTTPDBG_SUBPROCESS_DIR = "HTTPDBG_SUBPROCESS_DIR"
4
+ HTTPDBG_MULTIPROCESS_DIR = "HTTPDBG_MULTIPROCESS_DIR"
5
5
 
6
6
  HTTPDBG_LOG_LEVEL = "HTTPDBG_LOG_LEVEL"
7
7
  HTTPDBG_LOG_PATH = "HTTPDBG_LOG_PATH"
@@ -0,0 +1,80 @@
1
+ # -*- coding: utf-8 -*-
2
+ from contextlib import contextmanager
3
+ from typing import Generator
4
+ import glob
5
+ import os
6
+ import pickle
7
+ import shutil
8
+ import tempfile
9
+ import time
10
+ import threading
11
+
12
+ from httpdbg.env import HTTPDBG_MULTIPROCESS_DIR
13
+ from httpdbg.log import logger
14
+ from httpdbg.records import HTTPRecords
15
+
16
+
17
+ @contextmanager
18
+ def watcher_external(records: HTTPRecords) -> Generator[HTTPRecords, None, None]:
19
+ if HTTPDBG_MULTIPROCESS_DIR not in os.environ:
20
+ with tempfile.TemporaryDirectory(prefix="httpdbg_") as httpdbg_multiprocess_dir:
21
+
22
+ logger().info(f"watcher_external {httpdbg_multiprocess_dir}")
23
+ os.environ[HTTPDBG_MULTIPROCESS_DIR] = httpdbg_multiprocess_dir
24
+
25
+ # we use a custom sitecustomize.py script to record the request in the subprocesses.
26
+ # It doesn't work if the subprocess is created using the "fork" method
27
+ # instead of the "spawn" method.
28
+ template = os.path.join(
29
+ os.path.dirname(os.path.abspath(__file__)),
30
+ "template_sitecustomize.py",
31
+ )
32
+ sitecustomize = os.path.join(httpdbg_multiprocess_dir, "sitecustomize.py")
33
+
34
+ shutil.copy(template, sitecustomize)
35
+
36
+ if "PYTHONPATH" in os.environ:
37
+ os.environ["PYTHONPATH"] = (
38
+ f"{httpdbg_multiprocess_dir}:{os.environ['PYTHONPATH']}"
39
+ )
40
+ else:
41
+ os.environ["PYTHONPATH"] = httpdbg_multiprocess_dir
42
+
43
+ try:
44
+ watcher = WatcherSubprocessDirThread(
45
+ records, httpdbg_multiprocess_dir, 1.0
46
+ )
47
+ watcher.start()
48
+
49
+ yield records
50
+ finally:
51
+ watcher.shutdown()
52
+ else:
53
+ yield records
54
+
55
+
56
+ class WatcherSubprocessDirThread(threading.Thread):
57
+ def __init__(self, records: HTTPRecords, directory: str, delay: float) -> None:
58
+ self.records: HTTPRecords = records
59
+ self.directory: str = directory
60
+ self.delay: float = delay
61
+ self._running: bool = True
62
+ threading.Thread.__init__(self)
63
+
64
+ def load_dump(self):
65
+ for dump in glob.glob(os.path.join(self.directory, "*.httpdbgrecords")):
66
+ with open(dump, "rb") as dumpfile:
67
+ newrecords: HTTPRecords = pickle.load(dumpfile)
68
+ self.records.requests.update(newrecords.requests)
69
+ self.records.initiators.update(newrecords.initiators)
70
+ self.records.groups.update(newrecords.groups)
71
+
72
+ def run(self):
73
+ while self._running:
74
+ self.load_dump()
75
+ time.sleep(self.delay)
76
+
77
+ def shutdown(self):
78
+ self._running = False
79
+ self.join(timeout=5)
80
+ self.load_dump()
@@ -0,0 +1,65 @@
1
+ import atexit
2
+ import os
3
+ import pickle
4
+ import sys
5
+ import time
6
+ import threading
7
+ from typing import Union
8
+ import uuid
9
+
10
+ from httpdbg.hooks.all import httprecord
11
+ from httpdbg import HTTPRecords
12
+
13
+
14
+ class HttpdbgRecorder:
15
+ """Records the HTTP requests in subprocesses and saves them to disk."""
16
+
17
+ def __init__(self):
18
+ self._running: bool = False
19
+ self.fname: str = os.path.join(
20
+ os.environ["HTTPDBG_MULTIPROCESS_DIR"], str(uuid.uuid1())
21
+ )
22
+ self.context = None
23
+ self.records: Union[HTTPRecords, None] = None
24
+
25
+ def _save_to_disk_loop(self):
26
+ while self._running:
27
+ self.save_to_disk()
28
+ time.sleep(1)
29
+
30
+ def save_to_disk(self):
31
+ if self.records and len(self.records.requests) > 0:
32
+ with open(f"{self.fname}.httpdbgrecords.tmp", "wb") as f:
33
+ pickle.dump(self.records, f)
34
+ os.replace(
35
+ f"{self.fname}.httpdbgrecords.tmp", f"{self.fname}.httpdbgrecords"
36
+ )
37
+
38
+ def start(self):
39
+ """Start recording."""
40
+ self.context = httprecord()
41
+ self.records = self.context.__enter__()
42
+ self._running = True
43
+ self._thread = threading.Thread(target=self._save_to_disk_loop, daemon=True)
44
+ self._thread.start()
45
+
46
+ def stop(self):
47
+ """Stop recording."""
48
+ self._running = False
49
+ if self._thread:
50
+ self._thread.join(timeout=5)
51
+ self.save_to_disk()
52
+ if self.context:
53
+ self.context.__exit__(None, None, None)
54
+
55
+
56
+ if "HTTPDBG_MULTIPROCESS_DIR" in os.environ:
57
+
58
+ if not hasattr(sys, "_httpdbg_enabled"):
59
+ sys._httpdbg_enabled = True # type: ignore[attr-defined]
60
+
61
+ # start recording when the process starts and stop it when process exists
62
+ httprecorder = HttpdbgRecorder()
63
+ httprecorder.start()
64
+
65
+ atexit.register(httprecorder.stop)
@@ -1,5 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
- import importlib
2
+ import os
3
+ import runpy
3
4
  import sys
4
5
  import traceback
5
6
  from typing import List
@@ -8,24 +9,25 @@ from httpdbg.log import logger
8
9
 
9
10
 
10
11
  def run_script(argv: List[str]) -> None:
11
- sys.argv = argv
12
+
12
13
  if len(argv) == 0:
13
14
  exit("script mode - error - python file required, but none set")
15
+
14
16
  try:
15
- spec = importlib.util.spec_from_file_location("__main__", argv[0]) # type: ignore
16
- module = importlib.util.module_from_spec(spec) # type: ignore
17
- except AttributeError:
18
- exit("script mode - error - the first argument shall be a python file")
19
- try:
20
- original__main___module = sys.modules["__main__"]
21
- sys.modules["__main__"] = module # mandatory to execute a unittest test file.
22
- spec.loader.exec_module(module) # type: ignore
23
- except Exception:
24
- traceback.print_exc()
17
+ original_sys_path = sys.path
18
+ original_sys_argv = sys.argv
19
+
20
+ sys.path.insert(0, os.path.abspath(argv[0]))
21
+ sys.argv = argv
22
+
23
+ runpy.run_path(argv[0], run_name="__main__")
25
24
  except SystemExit as ex:
26
25
  # in some case, for example when executing unittest tests from a script,
27
26
  # the SystemExit exception is raised by the script itself so we catch it.
28
27
  # TODO propagate the SystemExit value when httpdbg terminates.
29
28
  logger().info(f"run_script - exception SystemExit - {str(ex)}")
29
+ except Exception:
30
+ traceback.print_exc()
30
31
  finally:
31
- sys.modules["__main__"] = original__main___module
32
+ sys.path = original_sys_path
33
+ sys.argv = original_sys_argv
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: httpdbg
3
- Version: 0.31.6
3
+ Version: 0.32.1
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
@@ -23,8 +23,6 @@ Classifier: Topic :: Utilities
23
23
  Requires-Python: >=3.9
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
- Provides-Extra: pytest
27
- Requires-Dist: pytest-httpdbg>=0.6.0; extra == "pytest"
28
26
 
29
27
  # httpdbg
30
28
 
@@ -71,30 +69,26 @@ You can trace all the HTTP requests performed by a script
71
69
  pyhttpdbg --script filename.py [arg1 --arg2 ...]
72
70
  ```
73
71
 
74
- ### pytest
75
-
76
- You can trace all the HTTP requests performed during your tests
72
+ ### module
77
73
 
78
- ```console
79
- pyhttpdbg -m pytest [arg1 --arg2 ...]
80
- ```
74
+ You can trace all the HTTP requests performed by a library module run as a script using the `-m` command line argument.
81
75
 
82
- If you use the `pytest-xdist` plugin to execute your tests in parallel, then you must install the `pytest-httpdbg` plugin if you want to trace the requests done by the pytest workers.
76
+ For example, you can view which HTTP requests are performed by `pip` when you install a package.
83
77
 
84
78
  ```console
85
- pip install httpdbg[pytest]
79
+ pyhttpdbg -m pip install hookdns --upgrade
86
80
  ```
87
81
 
88
- ### module
89
-
90
- You can trace all the HTTP requests performed by a library module run as a script using the `-m` command line argument.
82
+ ### test frameworks
91
83
 
92
- For example, you can view which HTTP requests are performed by `pip` when you install a package.
84
+ You can trace all HTTP requests made during your tests (pytest, unittest).
93
85
 
94
86
  ```console
95
- pyhttpdbg -m pip install hookdns --upgrade
87
+ pyhttpdbg -m pytest [arg1 --arg2 ...]
96
88
  ```
97
89
 
90
+ In that case, the requests will be grouped by test, and any requests made within a fixture or the setup/teardown methods will be identified by a tag.
91
+
98
92
  ## Initiators
99
93
 
100
94
  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.
@@ -20,7 +20,6 @@ httpdbg.egg-info/PKG-INFO
20
20
  httpdbg.egg-info/SOURCES.txt
21
21
  httpdbg.egg-info/dependency_links.txt
22
22
  httpdbg.egg-info/entry_points.txt
23
- httpdbg.egg-info/requires.txt
24
23
  httpdbg.egg-info/top_level.txt
25
24
  httpdbg/hooks/__init__.py
26
25
  httpdbg/hooks/aiohttp.py
@@ -31,6 +30,7 @@ httpdbg/hooks/httpx.py
31
30
  httpdbg/hooks/pytest.py
32
31
  httpdbg/hooks/requests.py
33
32
  httpdbg/hooks/socket.py
33
+ httpdbg/hooks/template_sitecustomize.py
34
34
  httpdbg/hooks/unittest.py
35
35
  httpdbg/hooks/urllib3.py
36
36
  httpdbg/hooks/utils.py
@@ -78,5 +78,6 @@ tests/test_initiator.py
78
78
  tests/test_mode_console.py
79
79
  tests/test_mode_module_pytest.py
80
80
  tests/test_mode_script.py
81
+ tests/test_multiprocess.py
81
82
  tests/test_preview.py
82
83
  tests/test_server.py
@@ -46,9 +46,6 @@ no_implicit_optional = false
46
46
  disable_error_code= ["method-assign",]
47
47
  files = ["httpdbg"]
48
48
 
49
- [project.optional-dependencies]
50
- pytest = ["pytest-httpdbg>=0.6.0"]
51
-
52
49
  [project.urls]
53
50
  Source = "https://github.com/cle-b/httpdbg/"
54
51
  Documentation = "https://httpdbg.readthedocs.io/"
@@ -67,8 +67,8 @@ def test_run_script_no_args(httpbin, capsys):
67
67
 
68
68
  @pytest.mark.script
69
69
  def test_run_script_not_a_python_script(httpbin, capsys):
70
- with pytest.raises(SystemExit):
71
- run_script(["not_a_path_to_a_python_script"])
70
+ # should not raise an exception
71
+ run_script(["not_a_path_to_a_python_script"])
72
72
 
73
73
 
74
74
  @pytest.mark.api
@@ -0,0 +1,52 @@
1
+ import os
2
+ import platform
3
+
4
+ import pytest
5
+
6
+ from httpdbg import httprecord
7
+ from httpdbg.env import HTTPDBG_MULTIPROCESS_DIR
8
+ from httpdbg.mode_script import run_script
9
+
10
+
11
+ @pytest.mark.script
12
+ def test_run_script_multithread(httpbin):
13
+
14
+ if HTTPDBG_MULTIPROCESS_DIR in os.environ:
15
+ del os.environ[HTTPDBG_MULTIPROCESS_DIR]
16
+
17
+ with httprecord() as records:
18
+ os.environ["HTTPDBG_TEST_MULTITHREAD_BASE_URL"] = httpbin.url
19
+ script_to_run = os.path.join(
20
+ os.path.dirname(os.path.realpath(__file__)), "demo_run_multithread.py"
21
+ )
22
+ run_script([script_to_run, httpbin.url])
23
+
24
+ assert len(records) == 3
25
+ pids = []
26
+ for record in records:
27
+ pids.append(record.url.split("/")[-1])
28
+ assert len(set(pids)) == 1
29
+
30
+
31
+ @pytest.mark.script
32
+ @pytest.mark.xfail(
33
+ platform.system().lower() == "windows",
34
+ reason="the test fails on the CI but the feature works on windows",
35
+ )
36
+ def test_run_script_multiprocess(httpbin):
37
+
38
+ if HTTPDBG_MULTIPROCESS_DIR in os.environ:
39
+ del os.environ[HTTPDBG_MULTIPROCESS_DIR]
40
+
41
+ with httprecord() as records:
42
+ os.environ["HTTPDBG_TEST_MULTIPROCESS_BASE_URL"] = httpbin.url
43
+ script_to_run = os.path.join(
44
+ os.path.dirname(os.path.realpath(__file__)), "demo_run_multiprocess.py"
45
+ )
46
+ run_script([script_to_run, httpbin.url])
47
+
48
+ assert len(records) == 3
49
+ pids = []
50
+ for record in records:
51
+ pids.append(record.url.split("/")[-1])
52
+ assert len(set(pids)) == 3
@@ -1,61 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- from contextlib import contextmanager
3
- from typing import Generator
4
- import glob
5
- import os
6
- import pickle
7
- import tempfile
8
- import time
9
- import threading
10
-
11
- from httpdbg.env import HTTPDBG_SUBPROCESS_DIR
12
- from httpdbg.records import HTTPRecords
13
-
14
-
15
- @contextmanager
16
- def watcher_external(records: HTTPRecords) -> Generator[HTTPRecords, None, None]:
17
- try:
18
- watcher = None
19
- if HTTPDBG_SUBPROCESS_DIR not in os.environ:
20
- with tempfile.TemporaryDirectory(
21
- prefix="httpdbg"
22
- ) as httpdbg_subprocess_dir:
23
- os.environ[HTTPDBG_SUBPROCESS_DIR] = httpdbg_subprocess_dir
24
-
25
- watcher = WatcherSubprocessDirThread(records)
26
- watcher.start()
27
-
28
- yield records
29
-
30
- watcher.shutdown()
31
- watcher.join()
32
- else:
33
- yield records
34
- except Exception as ex:
35
- if watcher:
36
- watcher.shutdown()
37
- raise ex
38
-
39
-
40
- class WatcherSubprocessDirThread(threading.Thread):
41
- def __init__(self, records: HTTPRecords, delay: int = 2) -> None:
42
- self.stop = False
43
- self.records = records
44
- self.delay = delay
45
- threading.Thread.__init__(self)
46
-
47
- def load_dump(self):
48
- for dump in glob.glob(f"{os.environ[HTTPDBG_SUBPROCESS_DIR]}/*.httpdbgrecords"):
49
- with open(dump, "rb") as dumpfile:
50
- newrecords: HTTPRecords = pickle.load(dumpfile)
51
- self.records.requests.update(newrecords.requests)
52
- self.records.initiators.update(newrecords.initiators)
53
- self.records.groups.update(newrecords.groups)
54
-
55
- def run(self):
56
- while not self.stop:
57
- time.sleep(self.delay)
58
- self.load_dump()
59
-
60
- def shutdown(self):
61
- self.stop = True
@@ -1,3 +0,0 @@
1
-
2
- [pytest]
3
- pytest-httpdbg>=0.6.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