diff --git a/datajoint/declare.py b/datajoint/declare.py index 683e34759..0c9d0266b 100644 --- a/datajoint/declare.py +++ b/datajoint/declare.py @@ -5,6 +5,7 @@ import re import pyparsing as pp import logging +from hashlib import sha1 from .errors import DataJointError, _support_filepath_types, FILEPATH_FEATURE_SWITCH from .attribute_adapter import get_adapter from .condition import translate_attribute @@ -309,6 +310,20 @@ def declare(full_table_name, definition, context): external_stores, ) = prepare_declare(definition, context) + metadata_attr_sql = [ + "`_{full_table_name}_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP" + ] + attribute_sql.extend( + [ + attr.format( + full_table_name=sha1( + full_table_name.replace("`", "").encode("utf-8") + ).hexdigest() + ) + for attr in metadata_attr_sql + ] + ) + if not primary_key: raise DataJointError("Table must have a primary key") diff --git a/datajoint/heading.py b/datajoint/heading.py index 9a782fc0e..c2d8ed527 100644 --- a/datajoint/heading.py +++ b/datajoint/heading.py @@ -33,6 +33,7 @@ is_attachment=False, is_filepath=False, is_external=False, + is_hidden=False, adapter=None, store=None, unsupported=False, @@ -120,7 +121,7 @@ def table_status(self): def attributes(self): if self._attributes is None: self._init_from_database() # lazy loading from database - return self._attributes + return {k: v for k, v in self._attributes.items() if not v.is_hidden} @property def names(self): @@ -298,6 +299,7 @@ def _init_from_database(self): store=None, is_external=False, attribute_expression=None, + is_hidden=attr["name"].startswith("_"), ) if any(TYPE_PATTERN[t].match(attr["type"]) for t in ("INTEGER", "FLOAT")): diff --git a/tests_old/test_blob_matlab.py b/tests_old/test_blob_matlab.py index 6104c9291..a2fa67fd8 100644 --- a/tests_old/test_blob_matlab.py +++ b/tests_old/test_blob_matlab.py @@ -40,7 +40,7 @@ def insert_blobs(): schema.connection.query( """ - INSERT INTO {table_name} VALUES + INSERT INTO {table_name} (`id`, `comment`, `blob`) VALUES (1,'simple string',0x6D596D00410200000000000000010000000000000010000000000000000400000000000000630068006100720061006300740065007200200073007400720069006E006700), (2,'1D vector',0x6D596D0041020000000000000001000000000000000C000000000000000600000000000000000000000000F03F00000000000030400000000000003F4000000000000047400000000000804E4000000000000053400000000000C056400000000000805A400000000000405E4000000000000061400000000000E062400000000000C06440), (3,'string array',0x6D596D00430200000000000000010000000000000002000000000000002F0000000000000041020000000000000001000000000000000700000000000000040000000000000073007400720069006E00670031002F0000000000000041020000000000000001000000000000000700000000000000040000000000000073007400720069006E0067003200), diff --git a/tests_old/test_declare.py b/tests_old/test_declare.py index 67f532449..8c2c2caff 100644 --- a/tests_old/test_declare.py +++ b/tests_old/test_declare.py @@ -341,3 +341,18 @@ class WithSuchALongPartNameThatItCrashesMySQL(dj.Part): definition = """ -> (master) """ + + @staticmethod + def test_hidden_attributes(): + assert ( + list(Experiment().heading._attributes.keys())[-1].split("_")[2] + == "timestamp" + ) + assert ( + len([a for a in Experiment().heading._attributes.values() if a.is_hidden]) + != 0 + ) + assert ( + len([a for a in Experiment().heading.attributes.values() if a.is_hidden]) + == 0 + )