Skip to content

Commit aabc88d

Browse files
fix: address @mweitzel review comments
1. Remove dead get_master() from utils.py — replaced by extract_master() in dependencies.py, no remaining callers. 2. Replace max_passes=10 magic number in _propagate_restrictions with a while loop. Termination is guaranteed because the dependency graph is a DAG and propagated_edges prevents re-processing. Comment explains why multiple passes are needed (part_integrity="cascade" upward propagation). 3. Replace bare except: with except Exception: in Table.delete(). Lets KeyboardInterrupt and SystemExit propagate without attempting cancel_transaction on a dying process. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ee344d9 commit aabc88d

File tree

4 files changed

+9
-49
lines changed

4 files changed

+9
-49
lines changed

pixi.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/datajoint/diagram.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,12 @@ def _propagate_restrictions(self, start_node, mode, part_integrity="enforce"):
459459

460460
restrictions = self._cascade_restrictions if mode == "cascade" else self._restrict_conditions
461461

462-
# Multiple passes to handle part_integrity="cascade" upward propagation
463-
max_passes = 10
464-
for _ in range(max_passes):
462+
# Multiple passes to handle part_integrity="cascade" upward propagation.
463+
# When a part table triggers its master to join the cascade, the master's
464+
# other descendants need processing in a subsequent pass. The loop
465+
# terminates when no new nodes are added — guaranteed in a DAG.
466+
any_new = True
467+
while any_new:
465468
any_new = False
466469

467470
for node in sorted_nodes:
@@ -539,9 +542,6 @@ def _propagate_restrictions(self, start_node, mode, part_integrity="enforce"):
539542
allowed_nodes.update(nx.descendants(self, master_name))
540543
any_new = True
541544

542-
if not any_new:
543-
break
544-
545545
def _apply_propagation_rule(
546546
self,
547547
parent_ft,

src/datajoint/table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ def delete(
10671067
"deleting.".format(child=match["child"])
10681068
) from None
10691069
raise DataJointError("Delete blocked by FK in unloaded/inaccessible schema.") from None
1070-
except:
1070+
except Exception:
10711071
if transaction:
10721072
conn.cancel_transaction()
10731073
raise

src/datajoint/utils.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -37,46 +37,6 @@ def user_choice(prompt, choices=("yes", "no"), default=None):
3737
return response
3838

3939

40-
def get_master(full_table_name: str, adapter=None) -> str:
41-
"""
42-
Get the master table name from a part table name.
43-
44-
If the table name is that of a part table, then return what the master table name would be.
45-
This follows DataJoint's table naming convention where a master and a part must be in the
46-
same schema and the part table is prefixed with the master table name + ``__``.
47-
48-
Parameters
49-
----------
50-
full_table_name : str
51-
Full table name including part.
52-
adapter : DatabaseAdapter, optional
53-
Database adapter for backend-specific parsing. Default None.
54-
55-
Returns
56-
-------
57-
str
58-
Supposed master full table name or empty string if not a part table name.
59-
60-
Examples
61-
--------
62-
>>> get_master('`ephys`.`session__recording`') # MySQL part table
63-
'`ephys`.`session`'
64-
>>> get_master('"ephys"."session__recording"') # PostgreSQL part table
65-
'"ephys"."session"'
66-
>>> get_master('`ephys`.`session`') # Not a part table
67-
''
68-
"""
69-
if adapter is not None:
70-
result = adapter.get_master_table_name(full_table_name)
71-
return result if result else ""
72-
73-
# Fallback: handle both MySQL backticks and PostgreSQL double quotes
74-
match = re.match(r'(?P<master>(?P<q>[`"])[\w]+(?P=q)\.(?P=q)[\w]+)__[\w]+(?P=q)', full_table_name)
75-
if match:
76-
return match["master"] + match["q"]
77-
return ""
78-
79-
8040
def is_camel_case(s):
8141
"""
8242
Check if a string is in CamelCase notation.

0 commit comments

Comments
 (0)