Lettore di metadati per file nativi Creo Parametric
Prototipo CLI in Python che estrae parametri e proprieta' dai file .prt senza avviare Creo e senza SDK commerciali. Solo libreria standard. I file nativi Creo sono container con header ASCII e un indice delle sezioni (UGC_TOC); la maggior parte delle sezioni non e' compressa e la tabella dei parametri e' leggibile direttamente. Ogni parametro compare in due rappresentazioni indipendenti (tabella estesa in LargeText e copia neutra in NeuPrtSld). Il lettore le confronta entrambe, e ne ricava: - confidence: 0.99 quando le due copie concordano, valori inferiori se il dato compare una volta sola o se divergono (status "conflict"); - owner: distingue i parametri del modello da quelli delle feature, che vivono solo nella copia neutra. I parametri numerici (PESO, DENSITA) usano una codifica a lunghezza variabile non ancora risolta: vengono riportati come "encoded_not_decoded" conservando i byte grezzi, senza inventare valori. Validato su file PART e PART/SHEETMETAL scritti da Creo 9.0.3.0. Assiemi, family table e versioni precedenti non sono ancora stati verificati. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
"""Test di regressione sui file campione presenti nella cartella.
|
||||
|
||||
Il parser si appoggia alla struttura binaria del formato Creo: qualsiasi
|
||||
modifica alle espressioni di ricerca va verificata contro file reali. Il test
|
||||
si limita ai file effettivamente presenti, quindi resta eseguibile anche su
|
||||
un archivio diverso.
|
||||
|
||||
python3 -m unittest test_regression -v
|
||||
"""
|
||||
|
||||
import glob
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from creoparams.extract import extract, latest_versions, split_filename
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
#: Parametri che ci aspettiamo di leggere da ogni .prt aziendale.
|
||||
REQUIRED = ["CODICE", "DENOMINAZIONE", "REVISIONE", "STAMPIGLIATURA",
|
||||
"MATERIALE", "DISEGNATORE", "DATA"]
|
||||
|
||||
#: Valori verificati manualmente. Vanno estesi man mano che si confrontano
|
||||
#: altri file con Creo: e' questa la rete di sicurezza vera.
|
||||
KNOWN = {
|
||||
"9258400201.prt": {
|
||||
"CODICE": "9258400201",
|
||||
"DENOMINAZIONE": "Carter lato destro",
|
||||
"MATERIALE": "ACC.INOX LAMIERA SP.4",
|
||||
"DISEGNATORE": "Grilli",
|
||||
"DATA": "9/02/2026",
|
||||
},
|
||||
"9258400205.prt": {
|
||||
"CODICE": "9258400205",
|
||||
"DENOMINAZIONE": "Tirante carter lateriali",
|
||||
"MATERIALE": "AISI 304 TONDO D.12",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _parts():
|
||||
paths = latest_versions(glob.glob(os.path.join(HERE, "*.prt*")))
|
||||
return [p for p in paths if split_filename(os.path.basename(p))[1] == "prt"]
|
||||
|
||||
|
||||
class TestEstrazione(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.parts = _parts()
|
||||
if not cls.parts:
|
||||
raise unittest.SkipTest("nessun file .prt nella cartella")
|
||||
cls.records = {
|
||||
os.path.basename(p): extract(p) for p in cls.parts
|
||||
}
|
||||
|
||||
def test_header_riconosciuto(self):
|
||||
for name, record in self.records.items():
|
||||
with self.subTest(file=name):
|
||||
self.assertEqual(record["model"]["kind"], "PART")
|
||||
self.assertTrue(record["model"]["creo_version"])
|
||||
self.assertGreater(record["extraction"]["sections"], 0)
|
||||
|
||||
def test_parametri_obbligatori_presenti(self):
|
||||
for name, record in self.records.items():
|
||||
for param in REQUIRED:
|
||||
with self.subTest(file=name, param=param):
|
||||
entry = record["parameters"].get(param)
|
||||
self.assertIsNotNone(entry, f"{param} non trovato")
|
||||
self.assertEqual(entry["status"], "found")
|
||||
|
||||
def test_confidenza_alta(self):
|
||||
"""Ogni parametro obbligatorio deve essere confermato in due
|
||||
rappresentazioni indipendenti del file."""
|
||||
for name, record in self.records.items():
|
||||
for param in REQUIRED:
|
||||
with self.subTest(file=name, param=param):
|
||||
self.assertGreaterEqual(
|
||||
record["parameters"][param]["confidence"], 0.95
|
||||
)
|
||||
|
||||
def test_valori_noti(self):
|
||||
for stem, expected in KNOWN.items():
|
||||
matching = [
|
||||
r for r in self.records.values()
|
||||
if r["model"]["file_name"] == stem
|
||||
]
|
||||
if not matching:
|
||||
continue
|
||||
record = matching[0]
|
||||
for param, value in expected.items():
|
||||
with self.subTest(file=stem, param=param):
|
||||
self.assertEqual(record["parameters"][param]["value"], value)
|
||||
|
||||
def test_codice_coerente_col_nome_file(self):
|
||||
for name, record in self.records.items():
|
||||
with self.subTest(file=name):
|
||||
self.assertEqual(
|
||||
record["parameters"]["CODICE"]["value"],
|
||||
record["model"]["name"],
|
||||
)
|
||||
|
||||
def test_parametri_feature_separati(self):
|
||||
"""I parametri dei fori non devono finire tra quelli del modello."""
|
||||
for name, record in self.records.items():
|
||||
for param, entry in record["parameters"].items():
|
||||
if param in ("SCREW_SIZE", "DRILL_DIAMETER", "CSINK_ANGLE"):
|
||||
with self.subTest(file=name, param=param):
|
||||
self.assertEqual(entry["owner"], "feature")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user