-
Notifications
You must be signed in to change notification settings - Fork 92
Open
Labels
enhancementIndicates new improvementsIndicates new improvementstriageIndicates issues, pull requests, or discussions need to be reviewed for the first timeIndicates issues, pull requests, or discussions need to be reviewed for the first time
Description
Improvement Request
Problem
Table().insert1(dict()) raises an assertion error that says 'Empty Tuple', even if the table has default values for all fields. 'Empty Tuple' may be confusing if the inserted item was an empty dict
Example Script
from datetime import datetime
import datajoint as dj
schema = dj.Schema("cbroz_temp")
@schema
class TestEmptyInsert(dj.Manual):
definition = """
id: int auto_increment
---
dt=CURRENT_TIMESTAMP : datetime
"""
if __name__ == "__main__":
# Accepts either field
TestEmptyInsert().insert1(dict(id=1))
TestEmptyInsert().insert1(dict(dt=datetime(2024, 1, 1, 12, 0, 0)))
# Accepts as None
TestEmptyInsert().insert1(dict(id=None))
TestEmptyInsert().insert1(dict(dt=None))
# Raises AssertionError "Empty tuple"
TestEmptyInsert().insert1(dict())Error Stack
AssertionError Traceback (most recent call last)
File ~/wrk/spyglass/3pm/temp-insert-empty.py:25
23 TestEmptyInsert().insert1(dict(dt=None))
24 # Accepts empty dict
---> 25 TestEmptyInsert().insert1(dict())
File ~/wrk/datajoint-python/datajoint/table.py:349, in Table.insert1(self, row, **kwargs)
342 def insert1(self, row, **kwargs):
343 """
344 Insert one data record into the table. For ``kwargs``, see ``insert()``.
345
346 :param row: a numpy record, a dict-like object, or an ordered sequence to be inserted
347 as one row.
348 """
--> 349 self.insert((row,), **kwargs)
File ~/wrk/datajoint-python/datajoint/table.py:432, in Table.insert(self, rows, replace, skip_duplicates, ignore_extra_fields, allow_direct_insert)
430 # collects the field list from first row (passed by reference)
431 field_list = []
--> 432 rows = list(
433 self.__make_row_to_insert(row, field_list, ignore_extra_fields)
434 for row in rows
435 )
436 if rows:
437 try:
File ~/wrk/datajoint-python/datajoint/table.py:433, in <genexpr>(.0)
430 # collects the field list from first row (passed by reference)
431 field_list = []
432 rows = list(
--> 433 self.__make_row_to_insert(row, field_list, ignore_extra_fields)
434 for row in rows
435 )
436 if rows:
437 try:
File ~/wrk/datajoint-python/datajoint/table.py:940, in Table.__make_row_to_insert(self, row, field_list, ignore_extra_fields)
937 if ignore_extra_fields:
938 attributes = [a for a in attributes if a is not None]
--> 940 assert len(attributes), "Empty tuple"
941 row_to_insert = dict(zip(("names", "placeholders", "values"), zip(*attributes)))
942 if not field_list:
943 # first row sets the composition of the field list
AssertionError: Empty tupleRequirements
Either...
- Accept empty entries with tables that have all default-value fields
- Improve error message specificity: "Insert must specify at least one key: {row}"
The following could be added to insert1 ~L940 ...
all_defaults=True # Worth caching, maybe as functools.cached_property
for attr in self.heading.attributes.values():
if attr.default or attr.autoincrement:
continue
all_defaults=False
break
if not all_defaults and not len(attributes):
raise DataJointError(f"Cannot insert empty row when there are non-default attributes: {row}")Justification
Allows easier insertion for supported table configurations, specifically tables that log events with inserts
Alternative Considerations
I can specify dict(my_pk=None)
Related Errors
Please include steps to reproduce provided errors as follows:
- OS: Linux
- Python Version: 3.11.13
- MySQL Version: 8.0.34
- MySQL Deployment Strategy: local-docker
- DataJoint Version: 0.14.6
- Minimum number of steps to reliably reproduce the issue: see above
- Complete error stack as a result of evaluating the above steps: see above
Screenshots
n/a
Additional Research and Context
n/a
Metadata
Metadata
Assignees
Labels
enhancementIndicates new improvementsIndicates new improvementstriageIndicates issues, pull requests, or discussions need to be reviewed for the first timeIndicates issues, pull requests, or discussions need to be reviewed for the first time