Skip to content

solidworks_mcp.selftest.report

solidworks_mcp.selftest.report

The selftest's report: a line per area, a Markdown summary, and an issue link.

Attributes

ISSUE_FORM_URL module-attribute

ISSUE_FORM_URL = 'https://github.com/andrewbartels1/SolidworksMCP-python/issues/new?template=compatibility.yml'
MAX_LINK_LENGTH = 8000

Classes

AreaResult dataclass

AreaResult(name: str, outcome: Outcome, checks: list[Check] = list(), calls: list[str] = list(), note: str | None = None)

One area's outcome, its checks, the tools it called, and why if not PASS.

Attributes
passed_count property
passed_count: int

The number of checks that passed.

Check dataclass

Check(name: str, expected: Any, measured: Any, tolerance: Any = None, unit: str = '', passed: bool | None = None)

One value read back from SolidWorks against the hand calculation.

passed is None when the value could not be measured, which counts as a failure.

Outcome

Bases: StrEnum

An area's result.

Functions:

_expected

_expected(check: Check) -> str

A check's expected value with its unit, if it has one.

Source code in src/solidworks_mcp/selftest/report.py
def _expected(check: Check) -> str:
    """A check's expected value with its unit, if it has one."""
    return f"{_value(check.expected)} {_unit(check.unit)}".rstrip()

_templates

_templates(templates: dict[str, Any]) -> str

The default templates by file name, marking any that are missing.

Source code in src/solidworks_mcp/selftest/report.py
def _templates(templates: dict[str, Any]) -> str:
    """The default templates by file name, marking any that are missing."""
    shown = []
    for kind in ("part", "assembly", "drawing"):
        entry = templates.get(kind) or {}
        name = entry.get("file_name") or "not set"
        missing = "" if entry.get("exists") else " (missing)"
        shown.append(f"{kind}: {name}{missing}")
    return "; ".join(shown)

_tolerance

_tolerance(check: Check) -> str

A check's tolerance: relative for a volume, absolute otherwise.

A count is "exact"; a yes/no or a condition such as "> 0" has none.

Source code in src/solidworks_mcp/selftest/report.py
def _tolerance(check: Check) -> str:
    """A check's tolerance: relative for a volume, absolute otherwise.

    A count is "exact"; a yes/no or a condition such as "> 0" has none.
    """
    if check.tolerance is None:
        return "-" if isinstance(check.expected, (bool, str)) else "exact"
    if "³" in check.unit:
        return f"{check.tolerance * 100:g} %"
    return f"{_value(check.tolerance)} {_unit(check.unit)}"

_tools

_tools(calls: list[str]) -> str

The tools an area called, in first-call order, with repeat counts.

Source code in src/solidworks_mcp/selftest/report.py
def _tools(calls: list[str]) -> str:
    """The tools an area called, in first-call order, with repeat counts."""
    counts = Counter(calls)
    return ", ".join(
        f"`{name}`" + (f" x{counts[name]}" if counts[name] > 1 else "")
        for name in dict.fromkeys(calls)
    )

_unit

_unit(unit: str) -> str

A unit in plain ASCII, so a Windows console prints it.

Source code in src/solidworks_mcp/selftest/report.py
def _unit(unit: str) -> str:
    """A unit in plain ASCII, so a Windows console prints it."""
    return unit.replace("³", "3")

_value

_value(value: Any) -> str

A check value as the report shows it.

Source code in src/solidworks_mcp/selftest/report.py
def _value(value: Any) -> str:
    """A check value as the report shows it."""
    if value is None:
        return "not measured"
    if isinstance(value, bool):
        return "yes" if value else "no"
    if isinstance(value, float):
        return f"{value:,.2f}" if abs(value) >= 1 else f"{value:g}"
    if isinstance(value, list):
        return "[" + ", ".join(_value(v) for v in value) + "]"
    return str(value)

area_line

area_line(result: AreaResult) -> str

One line for an area: outcome, name, checks passed, and why if not PASS.

Parameters:

Name Type Description Default
result AreaResult

The area's result.

required

Returns:

Name Type Description
str str

e.g. PASS part 8/8 checks.

Source code in src/solidworks_mcp/selftest/report.py
def area_line(result: AreaResult) -> str:
    """One line for an area: outcome, name, checks passed, and why if not PASS.

    Args:
        result: The area's result.

    Returns:
        str: e.g. ``PASS  part       8/8 checks``.
    """
    line = f"{result.outcome.value}  {result.name:<9}"
    if result.outcome is not Outcome.SKIP:
        line += f"  {result.passed_count}/{len(result.checks)} checks"
    if result.note:
        line += f"  {result.note}"
    return line
issue_link(summary: str) -> str | None

The issue-form link with summary filled in, if it's short enough.

Parameters:

Name Type Description Default
summary str

The Markdown summary.

required

Returns:

Type Description
str | None

str | None: The link, or None when it would be too long.

Source code in src/solidworks_mcp/selftest/report.py
def issue_link(summary: str) -> str | None:
    """The issue-form link with ``summary`` filled in, if it's short enough.

    Args:
        summary: The Markdown summary.

    Returns:
        str | None: The link, or ``None`` when it would be too long.
    """
    link = f"{ISSUE_FORM_URL}&summary={quote(summary)}"
    return link if len(link) <= MAX_LINK_LENGTH else None

render

render(environment: dict[str, Any], results: list[AreaResult], problems: list[str]) -> str

Everything the command prints after the run.

Parameters:

Name Type Description Default
environment dict[str, Any]

From read_environment.

required
results list[AreaResult]

The areas' results.

required
problems list[str]

Cleanup problems, printed but kept out of the summary.

required

Returns:

Name Type Description
str str

The area lines, any cleanup problems, the summary and the link.

Source code in src/solidworks_mcp/selftest/report.py
def render(
    environment: dict[str, Any], results: list[AreaResult], problems: list[str]
) -> str:
    """Everything the command prints after the run.

    Args:
        environment: From ``read_environment``.
        results: The areas' results.
        problems: Cleanup problems, printed but kept out of the summary.

    Returns:
        str: The area lines, any cleanup problems, the summary and the link.
    """
    summary = summary_markdown(environment, results)
    parts = ["\n".join(area_line(r) for r in results)]
    if problems:
        parts.append("Cleanup:\n" + "\n".join(f"  {p}" for p in problems))
    parts.append("Summary to paste into a compatibility report:\n\n" + summary)
    link = issue_link(summary)
    if link:
        parts.append(f"Open the report form with this summary filled in:\n{link}")
    else:
        parts.append(
            "Open the report form and paste the summary above:\n" + ISSUE_FORM_URL
        )
    return "\n\n".join(parts) + "\n"

summary_markdown

summary_markdown(environment: dict[str, Any], results: list[AreaResult]) -> str

The summary to paste into a compatibility issue.

Parameters:

Name Type Description Default
environment dict[str, Any]

From read_environment.

required
results list[AreaResult]

The areas' results.

required

Returns:

Name Type Description
str str

Markdown: the environment, then each area's checks and tools.

Source code in src/solidworks_mcp/selftest/report.py
def summary_markdown(environment: dict[str, Any], results: list[AreaResult]) -> str:
    """The summary to paste into a compatibility issue.

    Args:
        environment: From ``read_environment``.
        results: The areas' results.

    Returns:
        str: Markdown: the environment, then each area's checks and tools.
    """
    sw = environment.get("solidworks") or {}
    passed = sum(1 for r in results if r.outcome is Outcome.PASS)
    lines = [
        f"### Selftest: {passed} of {len(results)} areas passed",
        "",
        "| | |",
        "| --- | --- |",
        f"| SolidWorks | {_value(sw.get('revision'))} "
        f"(year {_value(sw.get('year'))}), {_value(sw.get('language'))} |",
        f"| Templates | {_templates(sw.get('templates') or {})} |",
        f"| OS | {_value(environment.get('os'))} |",
        f"| Python | {_value(environment.get('python'))}, "
        f"pywin32 {_value(environment.get('pywin32'))} |",
        f"| solidworks-mcp-python | {_value(environment.get('solidworks_mcp'))} |",
    ]
    for result in results:
        lines += ["", f"#### {result.name}: {result.outcome.value}"]
        if result.note:
            lines += ["", result.note]
        if result.checks:
            lines += [
                "",
                "| Check | Expected | Measured | Tolerance | Result |",
                "| --- | --- | --- | --- | --- |",
            ]
            lines += [
                f"| {c.name} | {_expected(c)} | "
                f"{_value(c.measured)} | {_tolerance(c)} | "
                f"{'pass' if c.passed else 'FAIL'} |"
                for c in result.checks
            ]
        if result.calls:
            lines += ["", f"Tools: {_tools(result.calls)}"]
    return "\n".join(lines) + "\n"