hte-cli 0.2.8__tar.gz → 0.2.9__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 (27) hide show
  1. {hte_cli-0.2.8 → hte_cli-0.2.9}/PKG-INFO +1 -1
  2. {hte_cli-0.2.8 → hte_cli-0.2.9}/pyproject.toml +1 -1
  3. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/image_utils.py +62 -13
  4. {hte_cli-0.2.8 → hte_cli-0.2.9}/.gitignore +0 -0
  5. {hte_cli-0.2.8 → hte_cli-0.2.9}/README.md +0 -0
  6. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/__init__.py +0 -0
  7. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/__main__.py +0 -0
  8. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/api_client.py +0 -0
  9. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/cli.py +0 -0
  10. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/config.py +0 -0
  11. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/errors.py +0 -0
  12. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/events.py +0 -0
  13. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/runner.py +0 -0
  14. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/scorers.py +0 -0
  15. {hte_cli-0.2.8 → hte_cli-0.2.9}/src/hte_cli/version_check.py +0 -0
  16. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/__init__.py +0 -0
  17. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/__init__.py +0 -0
  18. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/automated_runner.py +0 -0
  19. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/conftest.py +0 -0
  20. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/e2e_test.py +0 -0
  21. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/test_benchmark_flows.py +0 -0
  22. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/test_eval_logs.py +0 -0
  23. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/test_infrastructure.py +0 -0
  24. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/test_runtime_imports.py +0 -0
  25. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/test_session_lifecycle.py +0 -0
  26. {hte_cli-0.2.8 → hte_cli-0.2.9}/tests/e2e/verify_docker_deps.py +0 -0
  27. {hte_cli-0.2.8 → hte_cli-0.2.9}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hte-cli
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Human Time-to-Completion Evaluation CLI
5
5
  Project-URL: Homepage, https://github.com/sean-peters-au/lyptus-mono
6
6
  Author: Lyptus Research
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hte-cli"
3
- version = "0.2.8"
3
+ version = "0.2.9"
4
4
  description = "Human Time-to-Completion Evaluation CLI"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,6 +1,10 @@
1
1
  """Docker image utilities for pre-pulling compose images."""
2
2
 
3
3
  import logging
4
+ import os
5
+ import pty
6
+ import re
7
+ import select
4
8
  import subprocess
5
9
  from collections.abc import Callable
6
10
 
@@ -61,32 +65,77 @@ def pull_image_with_progress(
61
65
  on_complete: Callable[[str, bool], None] | None = None,
62
66
  ) -> bool:
63
67
  """
64
- Pull a Docker image with progress callbacks.
68
+ Pull a Docker image with progress callbacks using PTY for real progress output.
65
69
 
66
70
  Args:
67
71
  image: Image name to pull
68
- on_progress: Callback(image, status_line) called for each line of output
72
+ on_progress: Callback(image, status_line) called for each progress update
69
73
  on_complete: Callback(image, success) called when pull completes
70
74
 
71
75
  Returns:
72
76
  True if pull succeeded, False otherwise
73
77
  """
74
78
  try:
79
+ # Use PTY to get real progress output from docker
80
+ master_fd, slave_fd = pty.openpty()
81
+
75
82
  process = subprocess.Popen(
76
83
  ["docker", "pull", image],
77
- stdout=subprocess.PIPE,
78
- stderr=subprocess.STDOUT,
79
- text=True,
80
- bufsize=1,
84
+ stdout=slave_fd,
85
+ stderr=slave_fd,
86
+ stdin=slave_fd,
87
+ close_fds=True,
81
88
  )
82
89
 
83
- # Stream output line by line
84
- for line in iter(process.stdout.readline, ""):
85
- line = line.strip()
86
- if line and on_progress:
87
- on_progress(image, line)
90
+ os.close(slave_fd) # Close slave in parent
91
+
92
+ # Read output from master with timeout
93
+ output_buffer = ""
94
+ # Regex to parse docker progress: "abc123: Downloading [===> ] 10.5MB/50MB"
95
+ progress_pattern = re.compile(
96
+ r"([a-f0-9]+):\s*(Downloading|Extracting|Verifying Checksum|Download complete|Pull complete|Already exists|Waiting)(?:\s+\[.*?\]\s+)?(\d+\.?\d*\s*[kMG]?B)?(?:/(\d+\.?\d*\s*[kMG]?B))?"
97
+ )
88
98
 
89
- process.wait()
99
+ while True:
100
+ # Check if process is done
101
+ ret = process.poll()
102
+ if ret is not None:
103
+ # Read any remaining output
104
+ try:
105
+ while True:
106
+ ready, _, _ = select.select([master_fd], [], [], 0.1)
107
+ if not ready:
108
+ break
109
+ chunk = os.read(master_fd, 4096)
110
+ if not chunk:
111
+ break
112
+ except OSError:
113
+ pass
114
+ break
115
+
116
+ # Read available output
117
+ try:
118
+ ready, _, _ = select.select([master_fd], [], [], 0.1)
119
+ if ready:
120
+ chunk = os.read(master_fd, 4096)
121
+ if chunk:
122
+ output_buffer += chunk.decode("utf-8", errors="replace")
123
+
124
+ # Parse and report progress
125
+ # Docker uses carriage returns to update lines in place
126
+ lines = output_buffer.replace("\r", "\n").split("\n")
127
+ output_buffer = lines[-1] # Keep incomplete line
128
+
129
+ for line in lines[:-1]:
130
+ line = line.strip()
131
+ # Strip ANSI escape codes
132
+ line = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", line)
133
+ if line and on_progress:
134
+ on_progress(image, line)
135
+ except OSError:
136
+ break
137
+
138
+ os.close(master_fd)
90
139
  success = process.returncode == 0
91
140
 
92
141
  if on_complete:
@@ -94,7 +143,7 @@ def pull_image_with_progress(
94
143
 
95
144
  return success
96
145
 
97
- except (subprocess.TimeoutExpired, FileNotFoundError, OSError) as e:
146
+ except (FileNotFoundError, OSError) as e:
98
147
  logger.error(f"Failed to pull {image}: {e}")
99
148
  if on_complete:
100
149
  on_complete(image, False)
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