Skip to content

Conversation

@tampueroc
Copy link

@tampueroc tampueroc commented Oct 22, 2025

Problem

The DUT Summary table currently displays Part ID but not the Part Text (PART_TXT) field from PRR records. While Part ID is often a short internal code, Part Text provides a descriptive human-readable name that helps identify the device under test without referring to external documentation.

Solution

Add a new "Part Text" column to the DUT Summary table displaying the PART_TXT field from PRR records. The column appears between "Part ID" and "Test Head - Site".

Closes #168

Examples

Image
  • STDF FIle DUT Summary with at least one PRR with PART_TXT attribute populated
image

@noonchen
Copy link
Owner

noonchen commented Oct 22, 2025 via email

@tampueroc tampueroc force-pushed the feat/add-part-txt-column branch from 7ce9e8a to 9000e37 Compare October 22, 2025 18:19
@tampueroc
Copy link
Author

Hi Tom, Thanks for the PR, I might need to fix the building pipeline first, it can take a while. I will take a look when I have free time :)

Of couse, no rush! Thank you for all your work with this project.

Problem:
The DUT Summary table currently displays Part ID but not the Part Text
(PART_TXT) field from PRR records. While Part ID is often a short
internal code, Part Text provides a descriptive human-readable name
that helps identify the device under test without referring to external
documentation.

Solution:
Add a new "Part Text" column to the DUT Summary table displaying the
PART_TXT field from PRR records. The column appears between "Part ID"
and "Test Head - Site".

Additional Notes:
The column automatically hides when all DUTs have empty PART_TXT values,
providing a cleaner UI when working with STDF files that don't populate
this optional field.
@tampueroc tampueroc force-pushed the feat/add-part-txt-column branch from 9000e37 to 2878069 Compare October 22, 2025 18:42
TestCount INTEGER,
TestTime INTEGER,
PartID TEXT,
PART_TXT TEXT,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename column to PartText for style consistency.

Comment on lines +744 to +756

# hide Part Text column (column 3) if all values are empty
has_part_txt = False
for row in range(self.tmodel_dut.rowCount()):
part_txt = self.tmodel_dut.data(self.tmodel_dut.index(row, 3), Qt.ItemDataRole.DisplayRole)
if part_txt and part_txt.strip():
has_part_txt = True
break

if not has_part_txt:
self.ui.dutInfoTable.hideColumn(3)
else:
self.ui.dutInfoTable.showColumn(3)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not recommended to check part_txt value in qt model.

  1. it is a sql model and rowCount() only returns count of cached rows, there could be millions of rows not loaded yet and skipped unexpectedly.
  2. python loop is too slow.

The correct way is to query the info from database directly, something like following:

diff --git a/STDF-Viewer.py b/STDF-Viewer.py
index cd82c1b..8c1ffd7 100644
--- a/STDF-Viewer.py
+++ b/STDF-Viewer.py
@@ -4,7 +4,7 @@
 # Author: noonchen - chennoon233@foxmail.com
 # Created Date: December 13th 2020
 # -----
-# Last Modified: Sun Oct 12 2025
+# Last Modified: Fri Oct 24 2025
 # Modified By: noonchen
 # -----
 # Copyright (c) 2020 noonchen
@@ -736,24 +736,14 @@ class MyWindow(QtWidgets.QMainWindow):
         
         # always hide dut index column
         self.ui.dutInfoTable.hideColumn(0)
-        # hide file id column if 1 file is opened
-        if self.data_interface.num_files <= 1:
-            self.ui.dutInfoTable.hideColumn(1)
-        else:
-            self.ui.dutInfoTable.showColumn(1)
-        
-        # hide Part Text column (column 3) if all values are empty
-        has_part_txt = False
-        for row in range(self.tmodel_dut.rowCount()):
-            part_txt = self.tmodel_dut.data(self.tmodel_dut.index(row, 3), Qt.ItemDataRole.DisplayRole)
-            if part_txt and part_txt.strip():
-                has_part_txt = True
-                break
-        
-        if not has_part_txt:
-            self.ui.dutInfoTable.hideColumn(3)
-        else:
-            self.ui.dutInfoTable.showColumn(3)
+        for hideCond, col in [(self.data_interface.num_files <= 1, 1),
+                              (self.data_interface.noPartTXT, 3),
+                              (self.data_interface.noWaferID, 9),
+                              (self.data_interface.noWaferXY, 10)]:
+            if hideCond:
+                self.ui.dutInfoTable.hideColumn(col)
+            else:
+                self.ui.dutInfoTable.showColumn(col)
         # # show all rows
         # while self.tmodel_dut.canFetchMore():
         #     self.tmodel_dut.fetchMore()
diff --git a/deps/DataInterface.py b/deps/DataInterface.py
index f989daa..1ceb039 100644
--- a/deps/DataInterface.py
+++ b/deps/DataInterface.py
@@ -4,7 +4,7 @@
 # Author: noonchen - chennoon233@foxmail.com
 # Created Date: November 3rd 2022
 # -----
-# Last Modified: Sun Oct 12 2025
+# Last Modified: Fri Oct 24 2025
 # Modified By: noonchen
 # -----
 # Copyright (c) 2022 noonchen
@@ -80,6 +80,10 @@ class DataInterface:
         # for UI display
         self.completeTestList = self.DatabaseFetcher.getTestItemsList()
         self.completeWaferList = self.DatabaseFetcher.getWaferList()
+        # for dut summary
+        self.noPartTXT = self.DatabaseFetcher.isDutInfoColumnEmpty("PART_TXT")
+        self.noWaferID = self.DatabaseFetcher.isDutInfoColumnEmpty("WaferIndex")
+        self.noWaferXY = self.DatabaseFetcher.isDutInfoColumnEmpty("XCOORD")
         
         
     def close(self):
diff --git a/deps/DatabaseFetcher.py b/deps/DatabaseFetcher.py
index 80b0bc4..72ce356 100644
--- a/deps/DatabaseFetcher.py
+++ b/deps/DatabaseFetcher.py
@@ -4,7 +4,7 @@
 # Author: noonchen - chennoon233@foxmail.com
 # Created Date: May 15th 2021
 # -----
-# Last Modified: Sun Dec 11 2022
+# Last Modified: Fri Oct 24 2025
 # Modified By: noonchen
 # -----
 # Copyright (c) 2021 noonchen
@@ -89,6 +89,22 @@ class DatabaseFetcher:
         return len(self.file_paths)
     
     
+    def isDutInfoColumnEmpty(self, columnName: str) -> bool:
+        '''return True if the given column of Dut_Info table has no valid value'''
+        if self.cursor is None: raise RuntimeError("No database is connected")
+
+        sql = f'''SELECT EXISTS (
+                    SELECT 1 
+                    FROM Dut_Info 
+                    WHERE {columnName} IS NOT NULL 
+                        AND 
+                        (typeof({columnName}) != 'text' OR trim({columnName}) != "")
+                    )'''
+        
+        validDataExist = self.cursor.execute(sql).fetchone()[0]
+        return not validDataExist
+    
+    
     def getWaferCount(self) -> list[int]:
         '''return a list of int, where list[file_index] = count'''
         if self.cursor is None: raise RuntimeError("No database is connected")

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tampueroc I've added this method to main already, you can use it directly when updated from upstream.

However, it will bring conflicts to your branch, apologies for the inconvenience.

@noonchen
Copy link
Owner

noonchen commented Oct 31, 2025

@tampueroc Sorry to keep you waiting for so long, the pipeline should be working now, please merge main to use the latest pipeline.

Let's get your code merged after resolving the conversation :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add PART_TXT (Part Description Text) column to DUT Summary table

2 participants