home · contact · privacy
Add recording, and guessing, and verification, of BrickDesign LDRAW paths. master
authorPlom Heller <plom@plomlompom.com>
Mon, 15 Jun 2026 18:26:17 +0000 (20:26 +0200)
committerPlom Heller <plom@plomlompom.com>
Mon, 15 Jun 2026 18:26:17 +0000 (20:26 +0200)
bricksplom.py

index 28116fa33f65da0e9491075b5e6dc4825563df06..67ca7f2f5f1a2bf7e7cb7168c7ce080ae8f5d85b 100755 (executable)
@@ -12,6 +12,7 @@ PATH_SETS = 'sets.txt'
 PATH_COLORS = 'colors.txt'
 PATH_DESIGNS = 'designs.txt'
 PATH_BRICKS = 'bricks.txt'
 PATH_COLORS = 'colors.txt'
 PATH_DESIGNS = 'designs.txt'
 PATH_BRICKS = 'bricks.txt'
+NAME_ENV_LDRAW = 'PATH_LDRAW'
 
 CHAR_NEWLINE = '\n'
 CHAR_SEP_TOKEN = ' '
 
 CHAR_NEWLINE = '\n'
 CHAR_SEP_TOKEN = ' '
@@ -230,6 +231,7 @@ class BrickDesignData:
     'Lookupables for BrickDesign besides .id.'
     n_studs: int = -1
     description: str = '?'
     'Lookupables for BrickDesign besides .id.'
     n_studs: int = -1
     description: str = '?'
+    ldraw: str = ''
 
 
 class BrickDesign(Textfiled, Lookupable):
 
 
 class BrickDesign(Textfiled, Lookupable):
@@ -633,13 +635,24 @@ class BricksDb:
 
     def __init__(
             self,
 
     def __init__(
             self,
-            path_tables: str
+            path_tables: str,
+            path_ldraw: str,
+            ldraw_mode: str
             ) -> None:
         self.colors = BrickColor.from_textfile((path_tables, PATH_COLORS))
         self.bricks = Brick.from_textfile((path_tables, PATH_BRICKS), db=self)
         self.sets = BrickSet.from_textfile((path_tables, PATH_SETS), db=self)
         self.designs = BrickDesign.from_textfile((path_tables, PATH_DESIGNS))
             ) -> None:
         self.colors = BrickColor.from_textfile((path_tables, PATH_COLORS))
         self.bricks = Brick.from_textfile((path_tables, PATH_BRICKS), db=self)
         self.sets = BrickSet.from_textfile((path_tables, PATH_SETS), db=self)
         self.designs = BrickDesign.from_textfile((path_tables, PATH_DESIGNS))
-        self._check_consistencies_between_tables()
+        self._path_ldraw = Path(path_ldraw).joinpath('parts')
+        self._ldraw_mode = ldraw_mode.split(',')
+        if 'fill' in self._ldraw_mode:
+            for design in [design for design in self.designs.values()
+                           if not (design.alternate_to or design.ldraw)]:
+                filename = f'{design.id_}.dat'
+                if self._path_ldraw.joinpath(filename).exists():
+                    assert design.direct_attrs is not None
+                    design.direct_attrs.ldraw = filename
+        self._check_consistencies(verify_ldraw='verify' in self._ldraw_mode)
 
     def boxes(
             self
 
     def boxes(
             self
@@ -652,8 +665,9 @@ class BricksDb:
             collected[box_id] = Box(box_id, bricks_set, db=self)
         return collected
 
             collected[box_id] = Box(box_id, bricks_set, db=self)
         return collected
 
-    def _check_consistencies_between_tables(
-            self
+    def _check_consistencies(
+            self,
+            verify_ldraw=False
             ) -> None:
         fails = []
 
             ) -> None:
         fails = []
 
@@ -690,6 +704,16 @@ class BricksDb:
                                 if v != 0]:
             fails += [f'invalid count for brick of ID: {brick_id} ({count})']
 
                                 if v != 0]:
             fails += [f'invalid count for brick of ID: {brick_id} ({count})']
 
+        # hunt for dangling Design.ldraw references
+        if verify_ldraw:
+            for design in [
+                    design for design in self.designs.values()
+                    if (not design.alternate_to)
+                    and design.ldraw
+                    and not self._path_ldraw.joinpath(design.ldraw).exists()]:
+                fails += [f'unresolved ldraw reference for design of ID: '
+                          f'{design.id_} ({design.ldraw})']
+
         # print, and crash on, collected fails, if any
         for fail in fails:
             print(fail)
         # print, and crash on, collected fails, if any
         for fail in fails:
             print(fail)
@@ -747,14 +771,17 @@ def main(
             return (candidates + (arg, ))[0]
         action = parser.add_argument(argname, choices=choices, type=complete)
 
             return (candidates + (arg, ))[0]
         action = parser.add_argument(argname, choices=choices, type=complete)
 
-    db = BricksDb(environ.get(NAME_ENV_DIRNAME, '.'))
     parser = ArgumentParser()
     parser = ArgumentParser()
-    add_abbrev_choices_arg(parser, 'table', set(db.lookupable))
+    add_abbrev_choices_arg(parser, 'table', set(BricksDb.lookupable))
     parser.add_argument('item_id', nargs='?', metavar='ITEM_ID')
     parser.add_argument('-r', '--raw', action='store_true')
     parser.add_argument('-m', '--match-by', action='store')
     parser.add_argument('-s', '--sort-by', action='store', default=TOK_SORT_ID)
     parser.add_argument('item_id', nargs='?', metavar='ITEM_ID')
     parser.add_argument('-r', '--raw', action='store_true')
     parser.add_argument('-m', '--match-by', action='store')
     parser.add_argument('-s', '--sort-by', action='store', default=TOK_SORT_ID)
+    parser.add_argument('-l', '--ldraw', action='store')
     args = parser.parse_args()
     args = parser.parse_args()
+    db = BricksDb(environ.get(NAME_ENV_DIRNAME, '.'),
+                  environ.get(NAME_ENV_LDRAW, ''),
+                  args.ldraw)
     print(
         db.lookup(
             table_name=args.table,
     print(
         db.lookup(
             table_name=args.table,