fix/feat: P0 bug fixes, type annotations, docstrings, and more tests - #7
Conversation
…overage P0 fixes: - prompts/gen_text2image.py: fix nanochart -> igenbench import - eval_engine.py: guard response with isinstance(dict) before .get() - vis_item.py: correct generation field type Optional[dict] -> Dict[str,Any] - utils/io.py: rename senmantic->semantic, add boundary check with ValueError P1 improvements: - pyproject.toml: add authors, keywords, classifiers, project URLs - pyproject.toml: add pytest-cov to dev deps - CLI functions: add -> None return type annotations - gen_engine.py: add PILImage return type to text2image() - caller_registry.py: add docstring + correct return type annotation - llm_caller.py: add docstrings to all three LLMCaller abstract methods - client.py: add docstrings to call_text/image_generation/understanding - ci.yml: add --cov flag and upload coverage artifact New tests (41 total, up from 17): - tests/test_io.py: 9 tests for extract_from_markdown + split_semantic - tests/test_eval_engine.py: 6 tests for EvalEngine (mocked LLMClient) - tests/test_caller_registry.py: 4 tests for @register_caller decorator - tests/test_cli_score.py: 5 tests for igenbench score command P2: - AGENTS.md: expand deprecated Question -> EvalEntry migration guide
There was a problem hiding this comment.
Code Review
This pull request adds comprehensive type annotations, docstrings, metadata, and unit tests across the repository, alongside minor bug fixes such as correcting an import path and handling non-dict LLM responses. Reviewer feedback highlights several opportunities to improve robustness through defensive programming, specifically by handling potential None or empty values in LLM responses and prompt inputs to prevent runtime errors like AttributeError and TypeError.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| text_response = self._caller.generate_text(model, prompt, **kwargs) | ||
| return extract_from_markdown(text_response) |
There was a problem hiding this comment.
If the LLM provider returns an empty response or None (for example, due to safety filters or generation limits), passing it directly to extract_from_markdown will raise an AttributeError when calling .strip(). Adding a check to return an empty string when text_response is falsy prevents runtime crashes.
text_response = self._caller.generate_text(model, prompt, **kwargs)
if not text_response:
return ""
return extract_from_markdown(text_response)| text_response = self._caller.understand_image( | ||
| model, prompt, image_path, **kwargs | ||
| ) | ||
| return extract_from_markdown(text_response) |
There was a problem hiding this comment.
Similar to call_text_generation, if understand_image returns None or an empty response, passing it directly to extract_from_markdown will cause an AttributeError. Adding a defensive check here ensures the engine handles empty or blocked responses gracefully.
| text_response = self._caller.understand_image( | |
| model, prompt, image_path, **kwargs | |
| ) | |
| return extract_from_markdown(text_response) | |
| text_response = self._caller.understand_image( | |
| model, prompt, image_path, **kwargs | |
| ) | |
| if not text_response: | |
| return "" | |
| return extract_from_markdown(text_response) |
| if isinstance(response, dict): | ||
| analysis = response.get("analysis", "") | ||
| answer = response.get("answer", "") | ||
| else: | ||
| analysis = str(response) | ||
| answer = "" |
There was a problem hiding this comment.
If response is None (e.g., if the API call failed or returned an empty response), calling str(response) will set analysis to the literal string "None". It is better to default to an empty string "" to avoid saving "None" as the analysis result.
| if isinstance(response, dict): | |
| analysis = response.get("analysis", "") | |
| answer = response.get("answer", "") | |
| else: | |
| analysis = str(response) | |
| answer = "" | |
| if isinstance(response, dict): | |
| analysis = response.get("analysis", "") | |
| answer = response.get("answer", "") | |
| else: | |
| analysis = str(response) if response is not None else "" | |
| answer = "" |
| separator = "The given data is:" | ||
| if separator not in t2i_prompt: |
There was a problem hiding this comment.
If t2i_prompt is None or empty, checking separator not in t2i_prompt will raise a TypeError. Adding a defensive check at the beginning of the function ensures we raise a clear, descriptive ValueError instead of a generic runtime error.
if not t2i_prompt:
raise ValueError("Prompt cannot be empty or None.")
separator = "The given data is:"
if separator not in t2i_prompt:…onses - client.py: return '' early when provider returns None/empty in call_text_generation and call_image_understanding - io.py: raise ValueError early when prompt is None or empty in split_semantic_and_data_in_t2i_prompt - eval_engine.py: avoid literal 'None' string by checking response is not None before str() conversion - test_io.py: add tests for empty string and None prompt inputs
Summary
P0 — 致命 bug 修复
prompts/gen_text2image.py: 修复错误的nanochart导入 →igenbencheval_engine.py:call_image_understanding返回值可能是str,增加isinstance(dict)判断,避免AttributeErrorvis_item.py:generation字段类型由错误的Optional[dict]改为Dict[str, Any]utils/io.py: 函数名拼写错误senmantic→semantic,并添加 separator 不存在时的ValueErrorP1 — 元数据与类型
pyproject.toml补全authors、keywords、classifiers、[project.urls]-> None返回类型;GenEngine.text2image添加-> PILImagecaller_registry.py/llm_caller.py/client.py补全 docstring 和返回类型注解pytest --cov和 coverage artifact 上传新增测试(41 个,较之前 17 个增加 141%)
test_io.py:9 个测试覆盖extract_from_markdown和split_semantic_and_data_in_t2i_prompttest_eval_engine.py:6 个测试覆盖EvalEngine(mock LLMClient,无需 API key)test_caller_registry.py:4 个测试覆盖@register_caller装饰器test_cli_score.py:5 个测试覆盖igenbench scoreCLI 命令P2 — 文档
AGENTS.md:补全废弃Question→EvalEntry的字段迁移说明Test plan
uv run pytest tests/ -v— 41/41 passed 本地验证uv run ruff check .— All checks passeduv run ruff format --check .— All files formattedGenerated by Claude Code