Skip to content

Commit a40ca9b

Browse files
test draft
1 parent cb24dcd commit a40ca9b

File tree

3 files changed

+182
-1
lines changed

3 files changed

+182
-1
lines changed

python/content_understanding_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ def begin_analyze(self, analyzer_id: str, file_location: str) -> Response:
323323
]
324324
}
325325
headers = {"Content-Type": "application/json"}
326-
elif file_path.is_file() and self.is_supported_type_by_file_path(file_path):
326+
elif file_path.is_file():
327327
with open(file_location, "rb") as file:
328328
data = file.read()
329329
headers = {"Content-Type": "application/octet-stream"}

tools/README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# test_notebooks.py
2+
3+
This script is designed to automatically execute Jupyter notebooks in the `notebooks/` directory (or a specified directory) and report their execution status. It is useful for validating that all notebooks in the repository run successfully from start to finish, which is especially helpful for CI/CD pipelines or for contributors to verify their changes.
4+
5+
## Features
6+
- **Automatic Discovery:** Recursively scans a directory for `.ipynb` files (excluding hidden files).
7+
- **Selective Skipping:** Supports a skip list to exclude specific notebooks from execution (e.g., those requiring manual input).
8+
- **Execution Reporting:** Prints a summary of successful and failed notebooks, including error messages for failures.
9+
- **Command Line Usage:** Can run all notebooks in a directory or a specified list of notebook files.
10+
11+
## Usage
12+
13+
### Run All Notebooks in a Directory
14+
15+
```bash
16+
python3 tools/test_notebooks.py
17+
```
18+
This will scan the `notebooks/` directory by default, skipping any notebooks listed in the `skip_list` variable.
19+
20+
### Run Specific Notebooks
21+
22+
```bash
23+
python3 tools/test_notebooks.py notebooks/example1.ipynb notebooks/example2.ipynb
24+
```
25+
This will execute only the specified notebooks.
26+
27+
## Skip List
28+
You can modify the `skip_list` variable in the script to add or remove notebooks that should be skipped during execution. The skip list can contain full paths or substrings.
29+
30+
## Dependencies
31+
- Python 3
32+
- `nbformat`
33+
- `nbconvert`
34+
35+
Install dependencies with:
36+
```bash
37+
pip3 install nbformat nbconvert
38+
```
39+
40+
## Exit Codes
41+
- Returns `0` if all notebooks succeed.
42+
- Returns `1` if any notebook fails or if no notebooks are found.
43+
44+
## Example Output
45+
```
46+
🔍 Scanning for notebooks in: /path/to/notebooks
47+
▶️ Running: /path/to/notebooks/example.ipynb
48+
✅ Success: /path/to/notebooks/example.ipynb
49+
...
50+
🧾 Notebook Execution Summary
51+
✅ 3 succeeded
52+
❌ 1 failed
53+
🚨 Failed notebooks:
54+
- /path/to/notebooks/failing.ipynb
55+
↳ Traceback (most recent call last): ...
56+
```
57+
58+
## Notes
59+
- Notebooks that require manual input or special setup should be added to the skip list.
60+
- The script is intended for use in development, CI, or pre-merge validation workflows.

tools/test_notebooks.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import os
2+
import sys
3+
from typing import Tuple, Optional, List
4+
5+
import nbformat
6+
from nbconvert.preprocessors import ExecutePreprocessor
7+
8+
9+
SINGLE_NOTEBOOK_TIMEOUT = 1200
10+
11+
12+
def should_skip(notebook_path: str, skip_list: List[str]) -> bool:
13+
return any(skip in notebook_path for skip in skip_list)
14+
15+
16+
def run_notebook(notebook_path: str, root: str) -> Tuple[bool, Optional[str]]:
17+
"""Execute a single notebook."""
18+
try:
19+
with open(notebook_path, encoding="utf-8") as f:
20+
nb = nbformat.read(f, as_version=4)
21+
22+
ep = ExecutePreprocessor(
23+
timeout=SINGLE_NOTEBOOK_TIMEOUT,
24+
kernel_name="python3")
25+
ep.preprocess(nb, {"metadata": {"path": root}})
26+
return True, None
27+
except Exception as e:
28+
return False, str(e)
29+
30+
31+
def run_all_notebooks(path: str = ".", skip_list: List[str] = None) -> None:
32+
abs_path = os.path.abspath(path)
33+
print(f"🔍 Scanning for notebooks in: {abs_path}\n")
34+
35+
skip_list = skip_list or []
36+
37+
notebook_found: int = 0
38+
success_notebooks: List[str] = []
39+
failed_notebooks: List[Tuple[str, str]] = []
40+
41+
for root, _, files in os.walk(abs_path):
42+
for file in files:
43+
if file.endswith(".ipynb") and not file.startswith("."):
44+
notebook_path = os.path.join(root, file)
45+
46+
if should_skip(notebook_path, skip_list):
47+
print(f"⏭️ Skipped: {notebook_path}")
48+
continue
49+
50+
notebook_found += 1
51+
print(f"▶️ Running: {notebook_path}")
52+
success, error = run_notebook(notebook_path, root)
53+
54+
if success:
55+
print(f"✅ Success: {notebook_path}\n")
56+
success_notebooks.append(notebook_path)
57+
else:
58+
print(f"❌ Failed: {notebook_path}\nError: {error}\n")
59+
failed_notebooks.append((notebook_path, error))
60+
61+
# 📋 Summary
62+
print("🧾 Notebook Execution Summary")
63+
print(f"✅ {len(success_notebooks)} succeeded")
64+
print(f"❌ {len(failed_notebooks)} failed\n")
65+
66+
if failed_notebooks:
67+
print("🚨 Failed notebooks:")
68+
for nb, error in failed_notebooks:
69+
last_line = error.strip().splitlines()[-1] if error else "Unknown error"
70+
print(f" - {nb}\n{last_line}")
71+
sys.exit(1)
72+
73+
if notebook_found == 0:
74+
print("❌ No notebooks were found. Check the folder path or repo contents.")
75+
sys.exit(1)
76+
77+
print("🏁 All notebooks completed successfully.")
78+
79+
80+
if __name__ == "__main__":
81+
args: List[str] = sys.argv[1:]
82+
83+
# NOTE: Define skip list (can use full paths or substrings)
84+
skip_list = [
85+
"build_person_directory.ipynb", # Skip due to "new_face_image_path" needed to be added manually
86+
]
87+
88+
if not args:
89+
run_all_notebooks("notebooks", skip_list=skip_list)
90+
else:
91+
failed: List[Tuple[str, str]] = []
92+
for notebook_path in args:
93+
if should_skip(notebook_path, skip_list):
94+
print(f"⏭️ Skipped: {notebook_path}")
95+
continue
96+
97+
if notebook_path.endswith(".ipynb") and os.path.isfile(notebook_path):
98+
print(f"▶️ Running: {notebook_path}")
99+
success, error = run_notebook(notebook_path, os.path.dirname(notebook_path))
100+
if success:
101+
print(f"✅ Success: {notebook_path}\n")
102+
else:
103+
print(f"❌ Failed: {notebook_path}\nError: {error}\n")
104+
failed.append((notebook_path, error))
105+
else:
106+
print(f"⚠️ Not a valid notebook file: {notebook_path}")
107+
failed.append((notebook_path, "Invalid path or not a .ipynb file"))
108+
109+
# Summary
110+
print("🧾 Execution Summary")
111+
print(f"✅ {len(args) - len(failed)} succeeded")
112+
print(f"❌ {len(failed)} failed")
113+
114+
if failed:
115+
print("🚨 Failed notebooks:")
116+
for nb, error in failed:
117+
last_line = error.strip().splitlines()[-1] if error else "Unknown error"
118+
print(f" - {nb}\n{last_line}")
119+
sys.exit(1)
120+
else:
121+
print("🏁 All selected notebooks completed successfully.")

0 commit comments

Comments
 (0)