bounded_subprocess 2.5.0__tar.gz → 2.6.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 (39) hide show
  1. bounded_subprocess-2.6.0/.claude/settings.local.json +8 -0
  2. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/PKG-INFO +1 -1
  3. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/pyproject.toml +1 -1
  4. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/src/bounded_subprocess/bounded_subprocess_async.py +6 -0
  5. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/test_async.py +29 -0
  6. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/uv.lock +2 -2
  7. bounded_subprocess-2.5.0/.git +0 -1
  8. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/.github/workflows/docs.yaml +0 -0
  9. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/.github/workflows/test.yml +0 -0
  10. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/.gitignore +0 -0
  11. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/AGENTS.md +0 -0
  12. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/LICENSE.txt +0 -0
  13. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/Makefile +0 -0
  14. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/README.md +0 -0
  15. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/cspell.config.yaml +0 -0
  16. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/docs/index.md +0 -0
  17. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/mkdocs.yaml +0 -0
  18. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/src/bounded_subprocess/__init__.py +0 -0
  19. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/src/bounded_subprocess/bounded_subprocess.py +0 -0
  20. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/src/bounded_subprocess/interactive.py +0 -0
  21. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/src/bounded_subprocess/interactive_async.py +0 -0
  22. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/src/bounded_subprocess/util.py +0 -0
  23. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/__init__.py +0 -0
  24. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/block_on_inputs.py +0 -0
  25. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/close_outputs.py +0 -0
  26. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/dies_shortly_after_launch.py +0 -0
  27. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/dies_while_writing.py +0 -0
  28. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/does_not_read.py +0 -0
  29. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/echo_stdin.py +0 -0
  30. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/fork_bomb.py +0 -0
  31. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/fork_once.py +0 -0
  32. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/long_stdout.py +0 -0
  33. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/read_one_line.py +0 -0
  34. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/sleep_forever.py +0 -0
  35. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/unbounded_output.py +0 -0
  36. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/evil_programs/write_forever_but_no_newline.py +0 -0
  37. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/module_test.py +0 -0
  38. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/test_interactive.py +0 -0
  39. {bounded_subprocess-2.5.0 → bounded_subprocess-2.6.0}/test/test_interactive_async.py +0 -0
@@ -0,0 +1,8 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(python -m pytest:*)",
5
+ "Bash(uv run pytest:*)"
6
+ ]
7
+ }
8
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bounded_subprocess
3
- Version: 2.5.0
3
+ Version: 2.6.0
4
4
  Summary: A library to facilitate running subprocesses that may misbehave.
5
5
  Project-URL: Homepage, https://github.com/arjunguha/bounded_subprocess
6
6
  Project-URL: Bug Tracker, https://github.com/arjunguha/bounded_subprocess
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bounded_subprocess"
3
- version = "2.5.0"
3
+ version = "2.6.0"
4
4
  authors = [
5
5
  { name="Arjun Guha" },
6
6
  { name="Ming-Ho Yee" },
@@ -165,6 +165,7 @@ async def podman_run(
165
165
  stdin_write_timeout: Optional[int] = None,
166
166
  volumes: List[str] = [],
167
167
  cwd: Optional[str] = None,
168
+ memory_limit_mb: Optional[int] = None,
168
169
  ) -> Result:
169
170
  """
170
171
  Run a subprocess in a podman container asynchronously with bounded stdout/stderr capture.
@@ -184,6 +185,7 @@ async def podman_run(
184
185
  stdin_write_timeout: Optional timeout for writing stdin data.
185
186
  volumes: Optional list of volume mount specifications (e.g., ["/host/path:/container/path"]).
186
187
  cwd: Optional working directory path inside the container.
188
+ memory_limit_mb: Optional memory limit in megabytes for the container.
187
189
 
188
190
  Example:
189
191
 
@@ -228,6 +230,10 @@ async def podman_run(
228
230
  for volume in volumes:
229
231
  podman_args.extend(["-v", volume])
230
232
 
233
+ # Handle memory limit
234
+ if memory_limit_mb is not None:
235
+ podman_args.extend(["--memory", f"{memory_limit_mb}m", "--memory-swap", f"{memory_limit_mb}m"])
236
+
231
237
  # Handle working directory
232
238
  if cwd is not None:
233
239
  podman_args.extend(["-w", cwd])
@@ -216,3 +216,32 @@ async def test_podman_run_cwd():
216
216
  assert result.exit_code == 0
217
217
  assert result.timeout is False
218
218
  assert result.stdout.strip() == "/tmp"
219
+
220
+
221
+ @pytest.mark.asyncio
222
+ async def test_podman_run_memory_limit_ok():
223
+ """Test podman_run with memory limit that is sufficient."""
224
+ result = await podman_run(
225
+ ["echo", "hello"],
226
+ image="alpine:latest",
227
+ timeout_seconds=10,
228
+ max_output_size=1024,
229
+ memory_limit_mb=64,
230
+ )
231
+ assert result.exit_code == 0
232
+ assert result.timeout is False
233
+ assert result.stdout.strip() == "hello"
234
+
235
+
236
+ @pytest.mark.asyncio
237
+ async def test_podman_run_memory_limit_oom():
238
+ """Test podman_run where the process exceeds the memory limit."""
239
+ # Allocate ~128MB in a container limited to 32MB
240
+ result = await podman_run(
241
+ ["python3", "-c", "x = bytearray(128 * 1024 * 1024)"],
242
+ image="python:3.12-alpine",
243
+ timeout_seconds=30,
244
+ max_output_size=4096,
245
+ memory_limit_mb=32,
246
+ )
247
+ assert result.exit_code != 0
@@ -1,5 +1,5 @@
1
1
  version = 1
2
- revision = 2
2
+ revision = 3
3
3
  requires-python = ">=3.9"
4
4
  resolution-markers = [
5
5
  "python_full_version >= '3.10'",
@@ -31,7 +31,7 @@ wheels = [
31
31
 
32
32
  [[package]]
33
33
  name = "bounded-subprocess"
34
- version = "2.5.0"
34
+ version = "2.6.0"
35
35
  source = { editable = "." }
36
36
  dependencies = [
37
37
  { name = "typeguard" },
@@ -1 +0,0 @@
1
- gitdir: /media/external0/arjun-nosudo/repos/arjunguha/bounded_subprocess/bare/worktrees/main