Skip to content

Commit e71418d

Browse files
document autopopulate.make logic
1 parent a284616 commit e71418d

File tree

1 file changed

+70
-6
lines changed

1 file changed

+70
-6
lines changed

datajoint/autopopulate.py

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,75 @@ def _rename_attributes(table, props):
9393

9494
def make(self, key):
9595
"""
96-
Derived classes must implement method `make` that fetches data from tables
97-
above them in the dependency hierarchy, restricting by the given key,
98-
computes secondary attributes, and inserts the new tuples into self.
96+
This method must be implemented by derived classes to perform automated computation.
97+
The method must implement the following three steps:
98+
99+
1. Fetch data from tables above in the dependency hierarchy, restricted by the given key.
100+
2. Compute secondary attributes based on the fetched data.
101+
3. Insert the new tuples into the current table.
102+
103+
The method can be implemented either as:
104+
(a) Regular method: All three steps are performed in a single database transaction.
105+
The method must return None.
106+
(b) Generator method:
107+
The make method is split into three functions:
108+
- `make_fetch`: Fetches data from the parent tables.
109+
- `make_compute`: Computes secondary attributes based on the fetched data.
110+
- `make_insert`: Inserts the computed data into the current table.
111+
112+
Then populate logic is executes as follows:
113+
114+
<pseudocode>
115+
fetched_data1 = self.make_fetch(key)
116+
computed_result = self.make_compute(key, *fetched_data1)
117+
begin transaction:
118+
fetched_data2 = self.make_fetch(key)
119+
if fetched_data1 != fetched_data2:
120+
cancel transaction
121+
else:
122+
self.make_insert(key, *computed_result)
123+
commit_transaction
124+
<pseudocode>
125+
126+
Importantly, the output of make_fetch is a tuple that serves as the input into `make_compute`.
127+
The output of `make_compute` is a tuple that serves as the input into `make_insert`.
128+
129+
The functionality must be strictly divided between these three methods:
130+
- All database queries must be completed in `make_fetch`.
131+
- All computation must be completed in `make_compute`.
132+
- All database inserts must be completed in `make_insert`.
133+
134+
DataJoint may programmatically enforce this separation in the future.
135+
136+
:param key: The primary key value used to restrict the data fetching.
137+
:raises NotImplementedError: If the derived class does not implement the required methods.
99138
"""
100-
raise NotImplementedError(
101-
"Subclasses of AutoPopulate must implement the method `make`"
102-
)
139+
140+
if not (
141+
hasattr(self, "make_fetch")
142+
and hasattr(self, "make_insert")
143+
and hasattr(self, "make_compute")
144+
):
145+
# user must implement `make`
146+
raise NotImplementedError(
147+
"Subclasses of AutoPopulate must implement the method `make` or (`make_fetch` + `make_compute` + `make_insert`)"
148+
)
149+
150+
# User has implemented `_fetch`, `_compute`, and `_insert` methods instead
151+
152+
# Step 1: Fetch data from parent tables
153+
fetched_data = self.make_fetch(key) # fetched_data is a tuple
154+
computed_result = yield fetched_data # passed as input into make_compute
155+
156+
# Step 2: If computed result is not passed in, compute the result
157+
if computed_result is None:
158+
# this is only executed in the first invocation
159+
computed_result = self.make_compute(key, *fetched_data)
160+
yield computed_result # this is passed to the second invocation of make
161+
162+
# Step 3: Insert the computed result into the current table.
163+
self.make_insert(key, *computed_result)
164+
yield
103165

104166
@property
105167
def target(self):
@@ -347,6 +409,8 @@ def _populate1(
347409
]
348410
): # rollback due to referential integrity fail
349411
self.connection.cancel_transaction()
412+
logger.warning(
413+
f"Referential integrity failed for {key} -> {self.target.full_table_name}")
350414
return False
351415
gen.send(computed_result) # insert
352416

0 commit comments

Comments
 (0)