1. Inspect HyperMesh Python API and Session State
Why a Session Baseline Comes First
Every cleanup script you write for HyperMesh will make assumptions: which model is active, which entity types exist, which Python modules are importable, and whether the session is running in a GUI or headless context. If those assumptions are wrong, the script fails in confusing ways — a query returns an empty list because the model was never loaded, or an import raises ModuleNotFoundError because the API path differs from what you expected. The purpose of this first case is to replace assumptions with observed facts. You will write a small, self-contained inspection script that queries the HyperMesh Python API, reports the current model and session state, and prints a baseline you can compare against in every later case.
The baseline is not a one-time curiosity. When a cleanup script behaves unexpectedly, the fastest diagnostic is usually to re-run the inspection and compare the current session against the baseline: did the model change, did the entity counts change, did the API version change after an upgrade? Establishing this habit early saves hours of debugging later.
What the HyperMesh Python API Exposes
HyperMesh exposes its Python interface through the hm module (the HyperMesh Python API), with entity access typically organized under hm.entities and model-level operations under hm.Model. The exact surface depends on your HyperMesh version, so the inspection script should not hard-code assumptions about which attributes exist — it should probe them defensively and report what it finds. The key objects to query are:
- Session context — whether a model is open, the model name, and the working directory.
- API/library availability — which modules import successfully and their reported versions.
- Entity inventory — counts of components, properties, materials, elements, and nodes, which form the numeric baseline.
- Environment — Python version and interpreter path, so results are reproducible across machines.
The SVG below shows how the inspection script fans out from a single entry point to these four query groups and consolidates them into one baseline report. Note that the entity inventory is deliberately shallow here — counting only — because deep enumeration and classification is the job of the next case.
Writing the Inspection Script
The script below is complete and runnable inside a HyperMesh Python session (or via the HyperMesh command-line Python interpreter). It is written defensively: every API access is wrapped so that a missing attribute or a failed import is reported rather than crashing the whole inspection. This matters because the script must work across HyperMesh versions where the API surface differs.
import sys
import os
import platform
import json
from datetime import datetime
def safe(fn, default=None):
"""Run fn, return default on any exception, and record the error."""
try:
return fn()
except Exception as exc:
return {"__error__": f"{type(exc).__name__}: {exc}"}
def inspect_library():
info = {"import_ok": False, "has_entities": False, "version": None}
try:
import hm
info["import_ok"] = True
info["has_entities"] = hasattr(hm, "entities")
info["version"] = safe(lambda: getattr(hm, "__version__", None))
except Exception as exc:
info["import_error"] = f"{type(exc).__name__}: {exc}"
return info
def inspect_session():
import hm
session = {}
session["model_open"] = safe(lambda: hm.Model.IsOpen() if hasattr(hm.Model, "IsOpen") else None)
session["model_name"] = safe(lambda: hm.Model.GetName() if hasattr(hm.Model, "GetName") else None)
session["cwd"] = os.getcwd()
session["gui"] = safe(lambda: hm.Info.IsGraphical() if hasattr(hm.Info, "IsGraphical") else None)
return session
def inspect_entities():
import hm
counts = {}
# Probe common entity collections; report only what exists.
probes = {
"components": "Component",
"properties": "Property",
"materials": "Material",
"elements": "Element",
"nodes": "Node",
}
for label, attr in probes.items():
def _count(attr=attr):
coll = getattr(hm.entities, attr, None)
if coll is None:
return None
return len(coll)
counts[label] = safe(_count)
return counts
def build_baseline():
return {
"timestamp": datetime.now().isoformat(timespec="seconds"),
"python": {
"version": sys.version.split()[0],
"executable": sys.executable,
"platform": platform.platform(),
},
"library": inspect_library(),
"session": inspect_session(),
"entities": inspect_entities(),
}
if __name__ == "__main__":
baseline = build_baseline()
print(json.dumps(baseline, indent=2, default=str))
with open("baseline.json", "w") as fh:
json.dump(baseline, fh, indent=2, default=str)
print("\nBaseline written to baseline.json")
Reading the Output and Judging the Baseline
Run the script and inspect the JSON. A healthy baseline for a loaded model looks roughly like this (values are illustrative — your counts will differ):
{
"timestamp": "2025-01-15T10:42:07",
"python": {
"version": "3.9.13",
"executable": "C:/Program Files/Altair/2023/hwdesktop/altair/scripts/python/python.exe",
"platform": "Windows-10-10.0.19045-SP0"
},
"library": {
"import_ok": true,
"has_entities": true,
"version": "2023.1"
},
"session": {
"model_open": true,
"model_name": "bracket_assembly.hm",
"cwd": "C:/work/cleanup",
"gui": true
},
"entities": {
"components": 42,
"properties": 18,
"materials": 7,
"elements": 152340,
"nodes": 168902
}
}
Use the following checks to decide whether the baseline is trustworthy before you build anything on top of it:
| Field | Expected | If it looks wrong |
|---|---|---|
library.import_ok | true | HyperMesh Python not on sys.path; run inside the HyperMesh interpreter, not system Python. |
library.has_entities | true | API version mismatch; check the hm module layout for your release. |
session.model_open | true | No model loaded; open a .hm file before running cleanup scripts. |
entities.elements | non-zero integer | Model loaded but empty, or entity attribute name differs in your version. |
python.executable | path under HyperMesh install | You are running system Python; the hm import will fail. |
baseline.json alongside each cleanup project. When a later script produces unexpected counts, diff the current inspection output against the saved baseline to see exactly what changed — model, API version, or environment.None as zero. If entities.components is null, the attribute was not found — that is a different problem from a model with zero components. The safe() wrapper preserves this distinction by returning None for missing attributes and an error dict for exceptions.Common Failure Symptoms
ModuleNotFoundError: No module named 'hm'— the script is running under system Python. Launch it from the HyperMesh Python console or the bundled interpreter shown inpython.executable.- All entity counts are
null—hm.entitiesexists but the attribute names differ. Printdir(hm.entities)to discover the actual collection names for your version. model_openisfalsebut counts are non-zero — a stale model reference; reload the model and re-run.- Inconsistent counts between runs — the model was modified between runs; always capture the baseline immediately before the cleanup operation you intend to verify.
With a verified baseline in hand, every subsequent cleanup script has a reference point: you know the model is loaded, the API is reachable, and the entity counts you expect to change. That is the foundation the rest of this course builds on.