diff --git a/app/services/augmented_part_sync.py b/app/services/augmented_part_sync.py index 027ac1d..21d42f5 100644 --- a/app/services/augmented_part_sync.py +++ b/app/services/augmented_part_sync.py @@ -49,9 +49,19 @@ from app.schemas.augmented_part import AugmentedPartSyncResult ATTACHMENT_POINT_NAME = "Occular" MM_PER_INCH = 25.4 +# e.g. +# M8-1.25 - 8mm OD, 1.25 mm pitch +# M8 x 1.25 _ISO_THREAD_RE = re.compile( - r"^M\s*(?P\d+(?:\.\d+)?)\s*[xX]\s*(?P\d+(?:\.\d+)?)$" + r"^M\s*(?P\d+(?:\.\d+)?)\s*[xX-]\s*(?P\d+(?:\.\d+)?)(?P.*)$" ) + +# e.g. +# 1.750-32 UNS +# 1.750-32 +# 1.5625-40 +# +# Leading digit / period, one or more digits, a dash, then _UNC_THREAD_RE = re.compile( r"^(?P\d+(?:\.\d+)?(?:/\d+)?)\s*-\s*(?P\d+)" r"\s*(?PUNEF|UNC|UNF|UNS|UN)?$", @@ -73,15 +83,14 @@ def _parse_float(value: str | None) -> float | None: def _parse_thread_attribute(value: str) -> tuple[str, dict] | None: """Parse a TBXThreadAttribute string as an ISO metric or UNC/UNF thread spec.""" - m = _ISO_THREAD_RE.match(value) - if m: + if m := _ISO_THREAD_RE.match(value): return "iso", { "diameter_mm": float(m.group("diameter")), "pitch_mm": float(m.group("pitch")), + "extra": float(m.group("extra")), } - m = _UNC_THREAD_RE.match(value) - if m: + if m := _UNC_THREAD_RE.match(value): # Source data often omits the series letters; UNS ("unified special") is the # correct designation when the diameter/TPI pairing isn't a standard pitch. series = UncSeries((m.group("series") or "UNS").upper()) @@ -126,7 +135,7 @@ async def _add_attachment_point(db: AsyncSession, ap: AugmentedPart, ip: Importe attachment_point_name_id=apn.id, iso_thread_id=thread.id, ) - else: + elif kind == "unc": depth_in = _parse_float(ip.ProductMaxThreadDepthin) thread = await unc_thread_crud.get_by_values(db, depth_in=depth_in, **fields) if thread is None: @@ -224,9 +233,7 @@ async def sync(db: AsyncSession) -> AugmentedPartSyncResult: # ------------------------------------------------------------------ phase 1 # IDs referenced in existing associations - result = await db.execute( - select(augmented_part_imported_parts.c.imported_part_id).distinct() - ) + result = await db.execute(select(augmented_part_imported_parts.c.imported_part_id).distinct()) all_linked_ids: set[str] = {row[0] for row in result.all()} # IDs that still exist in imported_parts @@ -271,9 +278,7 @@ async def sync(db: AsyncSession) -> AugmentedPartSyncResult: # ------------------------------------------------------------------ phase 2 # Re-query linked IDs after phase 1 cleanup - result = await db.execute( - select(augmented_part_imported_parts.c.imported_part_id).distinct() - ) + result = await db.execute(select(augmented_part_imported_parts.c.imported_part_id).distinct()) now_linked_ids: set[str] = {row[0] for row in result.all()} unlinked_ids = current_ids - now_linked_ids