mirror of
https://github.com/TinyTapeout/tt-support-tools.git
synced 2026-11-03 04:36:09 +01:00
feat(tt_tools): --check-docs now prints all errors
Previously, it only printed the first error it encountered, causing more iterations when fixing info.yaml and info.md errors
This commit is contained in:
-19
@@ -668,25 +668,6 @@ class Project:
|
|||||||
|
|
||||||
logging.info(f"Bitstream created successfully: {build_dir}/{base_name}.bin")
|
logging.info(f"Bitstream created successfully: {build_dir}/{base_name}.bin")
|
||||||
|
|
||||||
# doc check
|
|
||||||
# makes sure that the basic info is present
|
|
||||||
def check_docs(self):
|
|
||||||
info_md = os.path.join(self.local_dir, "docs/info.md")
|
|
||||||
if not os.path.exists(info_md):
|
|
||||||
logging.error("Missing docs/info.md file")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
with open(info_md) as fh:
|
|
||||||
info_md_content = fh.read()
|
|
||||||
|
|
||||||
if "# How it works\n\nExplain how your project works" in info_md_content:
|
|
||||||
logging.error("Missing 'How it works' section in docs/info.md")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if "# How to test\n\nExplain how to use your project" in info_md_content:
|
|
||||||
logging.error("Missing 'How to test' section in docs/info.md")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# use pandoc to create a single page PDF preview
|
# use pandoc to create a single page PDF preview
|
||||||
def create_pdf(self):
|
def create_pdf(self):
|
||||||
template_args = copy.deepcopy(self.info.__dict__)
|
template_args = copy.deepcopy(self.info.__dict__)
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from project_info import ProjectInfo, ProjectYamlError
|
||||||
|
|
||||||
|
|
||||||
|
def check_info_md(project_dir: str) -> list[str]:
|
||||||
|
info_md = os.path.join(project_dir, "docs/info.md")
|
||||||
|
if not os.path.exists(info_md):
|
||||||
|
return ["Missing docs/info.md file"]
|
||||||
|
|
||||||
|
with open(info_md) as fh:
|
||||||
|
info_md_content = fh.read()
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
if "# How it works\n\nExplain how your project works" in info_md_content:
|
||||||
|
errors += ["Missing 'How it works' section in docs/info.md"]
|
||||||
|
|
||||||
|
if "# How to test\n\nExplain how to use your project" in info_md_content:
|
||||||
|
errors += ["Missing 'How to test' section in docs/info.md"]
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def check_info_yaml(project_dir: str, pdk: str) -> list[str]:
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
info_yaml = os.path.join(project_dir, "info.yaml")
|
||||||
|
if not os.path.exists(info_yaml):
|
||||||
|
return ["Missing info.yaml file"]
|
||||||
|
|
||||||
|
with open(info_yaml) as fh:
|
||||||
|
try:
|
||||||
|
yaml_data = yaml.safe_load(fh)
|
||||||
|
except yaml.YAMLError as e:
|
||||||
|
return [f"Error parsing info.yaml: {e}"]
|
||||||
|
|
||||||
|
tile_sizes_yaml = f"tech/{pdk}/tile_sizes.yaml"
|
||||||
|
tt_tools_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
with open(os.path.join(tt_tools_dir, tile_sizes_yaml), "r") as f:
|
||||||
|
tile_sizes = yaml.safe_load(f)
|
||||||
|
|
||||||
|
try:
|
||||||
|
_ = ProjectInfo(yaml_data, tile_sizes)
|
||||||
|
except Exception as e:
|
||||||
|
if isinstance(e, ProjectYamlError):
|
||||||
|
return e.errors
|
||||||
|
|
||||||
|
return [] # No errors
|
||||||
|
|
||||||
|
|
||||||
|
def check_project_docs(project_dir: str, pdk: str) -> None:
|
||||||
|
info_md_errors = check_info_md(project_dir)
|
||||||
|
info_yaml_errors = check_info_yaml(project_dir, pdk)
|
||||||
|
errors = info_md_errors + info_yaml_errors
|
||||||
|
if errors:
|
||||||
|
if info_yaml_errors:
|
||||||
|
print("## Errors in info.yaml")
|
||||||
|
for error in info_yaml_errors:
|
||||||
|
print(f"- {error}")
|
||||||
|
print()
|
||||||
|
if info_md_errors:
|
||||||
|
print("## Errors in docs/info.md")
|
||||||
|
for error in info_md_errors:
|
||||||
|
print(f"- {error}")
|
||||||
|
print()
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("Documentation check passed successfully.")
|
||||||
+89
-56
@@ -4,26 +4,35 @@ YAML_VERSION = 6
|
|||||||
|
|
||||||
|
|
||||||
class ProjectYamlError(Exception):
|
class ProjectYamlError(Exception):
|
||||||
pass
|
def __init__(self, errors: List[str]):
|
||||||
|
if isinstance(errors, str):
|
||||||
|
errors = [errors]
|
||||||
|
self.errors = errors
|
||||||
|
super().__init__(", ".join(errors))
|
||||||
|
|
||||||
|
|
||||||
class PinoutSection:
|
class PinoutSection:
|
||||||
def __init__(self, yaml_data: Dict[str, Any]):
|
def __init__(self, yaml_data: Dict[str, Any], errors: List[str]):
|
||||||
self.__nonEmptyPins = 0
|
self.__nonEmptyPins = 0
|
||||||
yaml_data = yaml_data.copy()
|
yaml_data = yaml_data.copy()
|
||||||
self.ui = self._pins(yaml_data, "ui", 8)
|
self.ui = self._pins(yaml_data, "ui", 8, errors)
|
||||||
self.uo = self._pins(yaml_data, "uo", 8)
|
self.uo = self._pins(yaml_data, "uo", 8, errors)
|
||||||
self.uio = self._pins(yaml_data, "uio", 8)
|
self.uio = self._pins(yaml_data, "uio", 8, errors)
|
||||||
self.ua = self._pins(yaml_data, "ua", 6, True)
|
self.ua = self._pins(yaml_data, "ua", 6, errors, True)
|
||||||
if self.__nonEmptyPins == 0:
|
if self.__nonEmptyPins == 0:
|
||||||
raise ProjectYamlError("Please fill in the 'pinout' section")
|
errors.append("Please fill in the 'pinout' section")
|
||||||
if len(yaml_data) > 0:
|
if len(yaml_data) > 0:
|
||||||
raise ProjectYamlError(
|
errors.append(
|
||||||
f"Invalid keys {list(yaml_data.keys())} in 'pinout' section. Please remove them."
|
f"Invalid keys {list(yaml_data.keys())} in 'pinout' section. Please remove them."
|
||||||
)
|
)
|
||||||
|
|
||||||
def _pins(
|
def _pins(
|
||||||
self, yaml_data: Dict[str, Any], name: str, count: int, optional: bool = False
|
self,
|
||||||
|
yaml_data: Dict[str, Any],
|
||||||
|
name: str,
|
||||||
|
count: int,
|
||||||
|
errors: List[str],
|
||||||
|
optional: bool = False,
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
result: List[str] = []
|
result: List[str] = []
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
@@ -32,7 +41,9 @@ class PinoutSection:
|
|||||||
if pin is None:
|
if pin is None:
|
||||||
if optional and i == 0:
|
if optional and i == 0:
|
||||||
break
|
break
|
||||||
raise ProjectYamlError(f"Missing '{name}[{i}]' in 'pinout' section")
|
errors.append(f"Missing '{name}[{i}]' in 'pinout' section")
|
||||||
|
# Continue to collect more errors
|
||||||
|
continue
|
||||||
if pin != "":
|
if pin != "":
|
||||||
self.__nonEmptyPins += 1
|
self.__nonEmptyPins += 1
|
||||||
result.append(pin)
|
result.append(pin)
|
||||||
@@ -45,113 +56,135 @@ class ProjectInfo:
|
|||||||
source_files: List[str]
|
source_files: List[str]
|
||||||
|
|
||||||
def __init__(self, yaml_data: Dict[str, Any], tile_sizes: Dict[str, str]):
|
def __init__(self, yaml_data: Dict[str, Any], tile_sizes: Dict[str, str]):
|
||||||
|
errors: List[str] = []
|
||||||
|
|
||||||
# Validate Version
|
# Validate Version
|
||||||
yaml_version = yaml_data.get("yaml_version")
|
yaml_version = yaml_data.get("yaml_version")
|
||||||
if yaml_version is None:
|
if yaml_version is None:
|
||||||
raise ProjectYamlError("Missing 'yaml_version'")
|
errors.append("Missing 'yaml_version'")
|
||||||
if yaml_version != YAML_VERSION:
|
elif yaml_version != YAML_VERSION:
|
||||||
raise ProjectYamlError(
|
errors.append(
|
||||||
f"Unsupported YAML version: {yaml_data['yaml_version']}, expected {YAML_VERSION}"
|
f"Unsupported YAML version: {yaml_data['yaml_version']}, expected {YAML_VERSION}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Read "project" Section
|
# Read "project" Section
|
||||||
project_section: Optional[Dict[str, Any]] = yaml_data.get("project")
|
project_section: Optional[Dict[str, Any]] = yaml_data.get("project")
|
||||||
if project_section is None:
|
if project_section is None:
|
||||||
raise ProjectYamlError("Missing 'project' section")
|
errors.append("Missing 'project' section")
|
||||||
|
# Can't continue without project section
|
||||||
|
raise ProjectYamlError(errors)
|
||||||
|
|
||||||
|
# Validate all required fields in project section
|
||||||
title = project_section.get("title")
|
title = project_section.get("title")
|
||||||
if title is None:
|
if title is None:
|
||||||
raise ProjectYamlError("Missing key 'title' in 'project' section")
|
errors.append("Missing key 'title' in 'project' section")
|
||||||
if title == "":
|
elif title == "":
|
||||||
raise ProjectYamlError("Project title cannot be empty")
|
errors.append("Project title cannot be empty")
|
||||||
|
else:
|
||||||
self.title: str = title
|
self.title: str = title
|
||||||
|
|
||||||
author = project_section.get("author")
|
author = project_section.get("author")
|
||||||
if author is None:
|
if author is None:
|
||||||
raise ProjectYamlError("Missing key 'author' in 'project' section")
|
errors.append("Missing key 'author' in 'project' section")
|
||||||
if author == "":
|
elif author == "":
|
||||||
raise ProjectYamlError("Project author cannot be empty")
|
errors.append("Project author cannot be empty")
|
||||||
|
else:
|
||||||
self.author: str = author
|
self.author: str = author
|
||||||
|
|
||||||
description = project_section.get("description")
|
description = project_section.get("description")
|
||||||
if description is None:
|
if description is None:
|
||||||
raise ProjectYamlError("Missing key 'description' in 'project' section")
|
errors.append("Missing key 'description' in 'project' section")
|
||||||
if description == "":
|
elif description == "":
|
||||||
raise ProjectYamlError("Project description cannot be empty")
|
errors.append("Project description cannot be empty")
|
||||||
|
else:
|
||||||
self.description: str = description
|
self.description: str = description
|
||||||
|
|
||||||
tiles = project_section.get("tiles")
|
tiles = project_section.get("tiles")
|
||||||
if tiles is None:
|
if tiles is None:
|
||||||
raise ProjectYamlError("Missing key 'tiles' in 'project' section")
|
errors.append("Missing key 'tiles' in 'project' section")
|
||||||
if tiles not in tile_sizes.keys():
|
elif tiles not in tile_sizes.keys():
|
||||||
raise ProjectYamlError(
|
errors.append(f"Invalid value for 'tiles' in 'project' section: {tiles}")
|
||||||
f"Invalid value for 'tiles' in 'project' section: {tiles}"
|
else:
|
||||||
)
|
|
||||||
self.tiles: str = tiles
|
self.tiles: str = tiles
|
||||||
|
|
||||||
analog_pins = project_section.get("analog_pins", 0)
|
analog_pins = project_section.get("analog_pins", 0)
|
||||||
if not isinstance(analog_pins, int):
|
if not isinstance(analog_pins, int):
|
||||||
raise ProjectYamlError(
|
errors.append(
|
||||||
"Invalid value for 'analog_pins' in 'project' section, must be an integer"
|
"Invalid value for 'analog_pins' in 'project' section, must be an integer"
|
||||||
)
|
)
|
||||||
if analog_pins < 0 or analog_pins > 6:
|
analog_pins = 0 # Set default for further validation
|
||||||
raise ProjectYamlError(
|
elif analog_pins < 0 or analog_pins > 6:
|
||||||
|
errors.append(
|
||||||
"Invalid value for 'analog_pins' in 'project' section, must be between 0 and 6"
|
"Invalid value for 'analog_pins' in 'project' section, must be between 0 and 6"
|
||||||
)
|
)
|
||||||
|
analog_pins = 0 # Set default for further validation
|
||||||
self.analog_pins: int = analog_pins
|
self.analog_pins: int = analog_pins
|
||||||
self.is_analog: bool = self.analog_pins > 0
|
self.is_analog: bool = self.analog_pins > 0
|
||||||
|
|
||||||
self.uses_3v3: bool = project_section.get("uses_3v3", False)
|
uses_3v3: bool = project_section.get("uses_3v3", False)
|
||||||
if self.uses_3v3 and not self.is_analog:
|
self.uses_3v3: bool = uses_3v3
|
||||||
raise ProjectYamlError(
|
if uses_3v3 and not self.is_analog:
|
||||||
"Projects with 3v3 power need at least one analog pin"
|
errors.append("Projects with 3v3 power need at least one analog pin")
|
||||||
)
|
|
||||||
|
|
||||||
language = project_section.get("language")
|
language = project_section.get("language")
|
||||||
if language is None:
|
if language is None:
|
||||||
raise ProjectYamlError("Missing key 'language' in 'project' section")
|
errors.append("Missing key 'language' in 'project' section")
|
||||||
if language == "":
|
language = "" # Set default for further validation
|
||||||
raise ProjectYamlError("Project language cannot be empty")
|
elif language == "":
|
||||||
|
errors.append("Project language cannot be empty")
|
||||||
|
else:
|
||||||
self.language: str = language
|
self.language: str = language
|
||||||
|
|
||||||
|
# Language-specific validation
|
||||||
if language == "Wokwi":
|
if language == "Wokwi":
|
||||||
wokwi_id = project_section.get("wokwi_id")
|
wokwi_id = project_section.get("wokwi_id")
|
||||||
if wokwi_id is None:
|
if wokwi_id is None:
|
||||||
raise ProjectYamlError("Missing key 'wokwi_id' in 'project' section")
|
errors.append("Missing key 'wokwi_id' in 'project' section")
|
||||||
if wokwi_id == "" or wokwi_id == "0":
|
elif wokwi_id == "" or wokwi_id == "0":
|
||||||
raise ProjectYamlError("Please provide a valid Wokwi project ID")
|
errors.append("Please provide a valid Wokwi project ID")
|
||||||
|
else:
|
||||||
self.wokwi_id: Optional[int] = wokwi_id
|
self.wokwi_id: Optional[int] = wokwi_id
|
||||||
self.top_module = f"tt_um_wokwi_{wokwi_id}"
|
self.top_module = f"tt_um_wokwi_{wokwi_id}"
|
||||||
self.source_files = [f"tt_um_wokwi_{self.wokwi_id}.v", f"cells.v"]
|
self.source_files = [f"tt_um_wokwi_{self.wokwi_id}.v", f"cells.v"]
|
||||||
else:
|
elif language != "":
|
||||||
|
# Only validate these if language is not empty (error already added above)
|
||||||
top_module = project_section.get("top_module")
|
top_module = project_section.get("top_module")
|
||||||
if top_module is None:
|
if top_module is None:
|
||||||
raise ProjectYamlError("Missing key 'top_module' in 'project' section")
|
errors.append("Missing key 'top_module' in 'project' section")
|
||||||
if not top_module.startswith("tt_um_"):
|
elif not top_module.startswith("tt_um_"):
|
||||||
raise ProjectYamlError(
|
errors.append(
|
||||||
"Top module must start with 'tt_um_' (e.g. tt_um_my_project)"
|
"Top module must start with 'tt_um_' (e.g. tt_um_my_project)"
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
self.top_module = top_module
|
self.top_module = top_module
|
||||||
|
|
||||||
if "source_files" not in project_section:
|
if "source_files" not in project_section:
|
||||||
raise ProjectYamlError(
|
errors.append("Missing key 'source_files' in 'project' section")
|
||||||
"Missing key 'source_files' in 'project' section"
|
elif len(project_section["source_files"]) == 0:
|
||||||
)
|
errors.append("No source files specified")
|
||||||
if len(project_section["source_files"]) == 0:
|
else:
|
||||||
raise ProjectYamlError("No source files specified")
|
|
||||||
self.source_files = project_section["source_files"]
|
self.source_files = project_section["source_files"]
|
||||||
|
|
||||||
|
# Validate clock_hz
|
||||||
if "clock_hz" not in project_section:
|
if "clock_hz" not in project_section:
|
||||||
raise ProjectYamlError("Missing key 'clock_hz' in 'project' section")
|
errors.append("Missing key 'clock_hz' in 'project' section")
|
||||||
if not isinstance(project_section["clock_hz"], int):
|
elif not isinstance(project_section["clock_hz"], int):
|
||||||
raise ProjectYamlError(
|
errors.append(
|
||||||
"Invalid value for 'clock_hz' in 'project' section, must be an integer"
|
"Invalid value for 'clock_hz' in 'project' section, must be an integer"
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
self.clock_hz: int = project_section["clock_hz"]
|
self.clock_hz: int = project_section["clock_hz"]
|
||||||
|
|
||||||
|
# Validate pinout section
|
||||||
if "pinout" not in yaml_data:
|
if "pinout" not in yaml_data:
|
||||||
raise ProjectYamlError("Missing 'pinout' section")
|
errors.append("Missing 'pinout' section")
|
||||||
self.pinout = PinoutSection(yaml_data["pinout"])
|
else:
|
||||||
|
self.pinout = PinoutSection(yaml_data["pinout"], errors)
|
||||||
|
|
||||||
|
# Optional fields
|
||||||
self.discord: Optional[str] = project_section.get("discord")
|
self.discord: Optional[str] = project_section.get("discord")
|
||||||
self.doc_link: Optional[str] = project_section.get("doc_link")
|
self.doc_link: Optional[str] = project_section.get("doc_link")
|
||||||
|
|
||||||
|
# Raise all errors if any were collected
|
||||||
|
if errors:
|
||||||
|
raise ProjectYamlError(errors)
|
||||||
|
|||||||
@@ -422,6 +422,104 @@ class TestProjectInfoValidCombinations:
|
|||||||
assert project_info.pinout.uio[0] == ""
|
assert project_info.pinout.uio[0] == ""
|
||||||
|
|
||||||
|
|
||||||
|
class TestMultipleErrors:
|
||||||
|
"""Test that multiple errors are collected and reported together"""
|
||||||
|
|
||||||
|
def test_multiple_project_errors(self, valid_yaml_data, tile_sizes):
|
||||||
|
"""Test that multiple errors in project section are collected"""
|
||||||
|
del valid_yaml_data["project"]["title"]
|
||||||
|
del valid_yaml_data["project"]["author"]
|
||||||
|
valid_yaml_data["project"]["description"] = ""
|
||||||
|
|
||||||
|
with pytest.raises(ProjectYamlError) as exc_info:
|
||||||
|
ProjectInfo(valid_yaml_data, tile_sizes)
|
||||||
|
|
||||||
|
assert sorted(exc_info.value.errors) == sorted(
|
||||||
|
[
|
||||||
|
"Missing key 'title' in 'project' section",
|
||||||
|
"Missing key 'author' in 'project' section",
|
||||||
|
"Project description cannot be empty",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_multiple_pinout_errors(self, valid_yaml_data, tile_sizes):
|
||||||
|
"""Test that multiple errors in pinout section are collected"""
|
||||||
|
del valid_yaml_data["pinout"]["ui[0]"]
|
||||||
|
del valid_yaml_data["pinout"]["uo[3]"]
|
||||||
|
del valid_yaml_data["pinout"]["uio[7]"]
|
||||||
|
|
||||||
|
with pytest.raises(ProjectYamlError) as exc_info:
|
||||||
|
ProjectInfo(valid_yaml_data, tile_sizes)
|
||||||
|
|
||||||
|
assert sorted(exc_info.value.errors) == sorted(
|
||||||
|
[
|
||||||
|
"Missing 'ui[0]' in 'pinout' section",
|
||||||
|
"Missing 'uo[3]' in 'pinout' section",
|
||||||
|
"Missing 'uio[7]' in 'pinout' section",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_errors_across_sections(self, valid_yaml_data, tile_sizes):
|
||||||
|
"""Test that errors across different sections are all collected"""
|
||||||
|
del valid_yaml_data["yaml_version"]
|
||||||
|
del valid_yaml_data["project"]["title"]
|
||||||
|
valid_yaml_data["project"]["analog_pins"] = -1
|
||||||
|
del valid_yaml_data["pinout"]["ui[0]"]
|
||||||
|
|
||||||
|
with pytest.raises(ProjectYamlError) as exc_info:
|
||||||
|
ProjectInfo(valid_yaml_data, tile_sizes)
|
||||||
|
|
||||||
|
assert sorted(exc_info.value.errors) == sorted(
|
||||||
|
[
|
||||||
|
"Missing 'yaml_version'",
|
||||||
|
"Missing key 'title' in 'project' section",
|
||||||
|
"Invalid value for 'analog_pins' in 'project' section, must be between 0 and 6",
|
||||||
|
"Missing 'ui[0]' in 'pinout' section",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_comprehensive_validation_errors(self, valid_yaml_data, tile_sizes):
|
||||||
|
"""Test a comprehensive set of validation errors"""
|
||||||
|
valid_yaml_data["yaml_version"] = 999
|
||||||
|
valid_yaml_data["project"]["title"] = ""
|
||||||
|
valid_yaml_data["project"]["author"] = ""
|
||||||
|
valid_yaml_data["project"]["tiles"] = "invalid"
|
||||||
|
valid_yaml_data["project"]["analog_pins"] = 10
|
||||||
|
del valid_yaml_data["project"]["clock_hz"]
|
||||||
|
del valid_yaml_data["pinout"]["uo[0]"]
|
||||||
|
valid_yaml_data["pinout"]["invalid_key"] = "value"
|
||||||
|
|
||||||
|
with pytest.raises(ProjectYamlError) as exc_info:
|
||||||
|
ProjectInfo(valid_yaml_data, tile_sizes)
|
||||||
|
|
||||||
|
assert sorted(exc_info.value.errors) == sorted(
|
||||||
|
[
|
||||||
|
"Unsupported YAML version: 999, expected 6",
|
||||||
|
"Project title cannot be empty",
|
||||||
|
"Project author cannot be empty",
|
||||||
|
"Invalid value for 'tiles' in 'project' section: invalid",
|
||||||
|
"Invalid value for 'analog_pins' in 'project' section, must be between 0 and 6",
|
||||||
|
"Missing key 'clock_hz' in 'project' section",
|
||||||
|
"Missing 'uo[0]' in 'pinout' section",
|
||||||
|
"Invalid keys ['invalid_key'] in 'pinout' section. Please remove them.",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_error_message_formatting(self, valid_yaml_data, tile_sizes):
|
||||||
|
"""Test that error message contains all errors separated by commas"""
|
||||||
|
del valid_yaml_data["project"]["title"]
|
||||||
|
del valid_yaml_data["project"]["author"]
|
||||||
|
|
||||||
|
with pytest.raises(ProjectYamlError) as exc_info:
|
||||||
|
ProjectInfo(valid_yaml_data, tile_sizes)
|
||||||
|
|
||||||
|
error_message = str(exc_info.value)
|
||||||
|
assert (
|
||||||
|
"Missing key 'title' in 'project' section, Missing key 'author' in 'project' section"
|
||||||
|
== error_message
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestProjectInfoIntegration:
|
class TestProjectInfoIntegration:
|
||||||
"""Integration tests with real YAML files"""
|
"""Integration tests with real YAML files"""
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -4,6 +4,7 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from project import Project
|
from project import Project
|
||||||
|
from project_checks import check_project_docs
|
||||||
from tech import TechName
|
from tech import TechName
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@@ -167,13 +168,13 @@ if __name__ == "__main__":
|
|||||||
log.addHandler(ch)
|
log.addHandler(ch)
|
||||||
|
|
||||||
pdk: TechName = "ihp-sg13g2" if args.ihp else "gf180mcuD" if args.gf else "sky130A"
|
pdk: TechName = "ihp-sg13g2" if args.ihp else "gf180mcuD" if args.gf else "sky130A"
|
||||||
|
|
||||||
|
if args.check_docs:
|
||||||
|
check_project_docs(args.project_dir, pdk)
|
||||||
|
|
||||||
project = Project(0, "unknown", args.project_dir, pdk, is_user_project=True)
|
project = Project(0, "unknown", args.project_dir, pdk, is_user_project=True)
|
||||||
project.post_clone_setup()
|
project.post_clone_setup()
|
||||||
|
|
||||||
# handle the options
|
|
||||||
if args.check_docs:
|
|
||||||
project.check_docs()
|
|
||||||
|
|
||||||
if args.print_cell_summary or args.print_cell_category:
|
if args.print_cell_summary or args.print_cell_category:
|
||||||
project.summarize(
|
project.summarize(
|
||||||
print_cell_category=args.print_cell_category,
|
print_cell_category=args.print_cell_category,
|
||||||
|
|||||||
Reference in New Issue
Block a user