From b2d01f1ab0d29951b30bf5454064fa3b1dc5937f Mon Sep 17 00:00:00 2001 From: Ian Roddis <31021769+iroddis@users.noreply.github.com> Date: Tue, 28 Jul 2026 22:17:47 -0300 Subject: [PATCH] Allowing attachment points to be pulled from descriptions on sync --- app/services/augmented_part_sync.py | 44 +++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/app/services/augmented_part_sync.py b/app/services/augmented_part_sync.py index a1da89a..d41be91 100644 --- a/app/services/augmented_part_sync.py +++ b/app/services/augmented_part_sync.py @@ -55,7 +55,7 @@ MM_PER_INCH = 25.4 # M50x.75 - No leading digit on floats # Float pattern: \d*\.?\d+ _ISO_THREAD_RE = re.compile( - r"^M\s*(?P\d*\.?\d+)\s*[xX-]\s*P?(?P\d*\.?\d+)(?P.*)$" + r"M\s*(?P\d*\.?\d+)\s*[xX-]\s*P?(?P\d*\.?\d+)(?P.*)" ) # e.g. @@ -65,8 +65,8 @@ _ISO_THREAD_RE = re.compile( # # Leading digit / period, one or more digits, a dash, then _UNC_THREAD_RE = re.compile( - r"^(?P\d*\.?\d+)\s*-\s*(?P\d*\.?\d+)" - r"\s*(?PUNEF|UNC|UNF|UNS|UN)?$", + r"(?P\d*\.?\d+)\s*-\s*(?P\d*\.?\d+)" + r"\s*(?PUNEF|UNC|UNF|UNS|UN)?", re.IGNORECASE, ) @@ -111,7 +111,9 @@ async def _get_or_create_attachment_point_name(db: AsyncSession, name: str): return apn -async def _add_attachment_point(db: AsyncSession, ap: AugmentedPart, ip: ImportedPart) -> None: +async def _add_attachment_point( + db: AsyncSession, ap: AugmentedPart, ip: ImportedPart +) -> None: """Infer and create an attachment point for a newly-synced AugmentedPart. Preference order: TBXThreadAttribute (ISO/UNC thread) then ProductODmm/in @@ -119,7 +121,11 @@ async def _add_attachment_point(db: AsyncSession, ap: AugmentedPart, ip: Importe attribute is present but unparseable. """ thread_value = (ip.TBXThreadAttribute or "").strip() - parsed = _parse_thread_attribute(thread_value) if thread_value else None + parsed = None + if thread_value: + parsed = _parse_thread_attribute(thread_value) + else: + parsed = _parse_thread_attribute(ip.Description or "") if parsed is not None: kind, fields = parsed @@ -127,7 +133,9 @@ async def _add_attachment_point(db: AsyncSession, ap: AugmentedPart, ip: Importe if kind == "iso": depth_mm = _parse_float(ip.ProductMaxThreadDepthmm) - thread = await iso_thread_crud.get_by_values(db, depth_mm=depth_mm, **fields) + thread = await iso_thread_crud.get_by_values( + db, depth_mm=depth_mm, **fields + ) if thread is None: thread = await iso_thread_crud.create(db, depth_mm=depth_mm, **fields) await attachment_point_crud.create( @@ -138,7 +146,9 @@ async def _add_attachment_point(db: AsyncSession, ap: AugmentedPart, ip: Importe ) elif kind == "unc": depth_in = _parse_float(ip.ProductMaxThreadDepthin) - thread = await unc_thread_crud.get_by_values(db, depth_in=depth_in, **fields) + thread = await unc_thread_crud.get_by_values( + db, depth_in=depth_in, **fields + ) if thread is None: thread = await unc_thread_crud.create(db, depth_in=depth_in, **fields) await attachment_point_crud.create( @@ -236,7 +246,9 @@ 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 @@ -250,7 +262,9 @@ async def sync(db: AsyncSession) -> AugmentedPartSyncResult: # Which AugmentedParts are affected? result = await db.execute( select(augmented_part_imported_parts.c.augmented_part_id).where( - augmented_part_imported_parts.c.imported_part_id.in_(orphaned_import_ids) + augmented_part_imported_parts.c.imported_part_id.in_( + orphaned_import_ids + ) ) ) orphaned_ap_ids: set[int] = {row[0] for row in result.all()} @@ -258,7 +272,9 @@ async def sync(db: AsyncSession) -> AugmentedPartSyncResult: # Remove the stale association rows await db.execute( augmented_part_imported_parts.delete().where( - augmented_part_imported_parts.c.imported_part_id.in_(orphaned_import_ids) + augmented_part_imported_parts.c.imported_part_id.in_( + orphaned_import_ids + ) ) ) await db.flush() @@ -281,7 +297,9 @@ 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 @@ -289,7 +307,9 @@ async def sync(db: AsyncSession) -> AugmentedPartSyncResult: skipped = 0 if not unlinked_ids: - return AugmentedPartSyncResult(created=created, deleted=deleted, skipped=skipped) + return AugmentedPartSyncResult( + created=created, deleted=deleted, skipped=skipped + ) result = await db.execute( select(ImportedPart).where(ImportedPart.InventoryID.in_(unlinked_ids))