datajoint / datajoint-python

Relational data pipelines for the science lab
https://datajoint.com/docs
GNU Lesser General Public License v2.1
170 stars 85 forks source link

Schema nested in class does not find datajoint elements table #979

Open chrisroat opened 2 years ago

chrisroat commented 2 years ago

Bug Report

Description

When schema tables are nested within a class, datajoint cannot find an elements table. The problem seems to be related to a change in context, but even if I nest the activate call or schema assignment, it is not found.

Reproducibility

Include:

import datajoint as dj
from element_lab import lab
from element_lab.lab import User

lab.activate('acquisition')
schema = dj.schema('acquisition')

class Foo:    
    @schema
    class Acquisition(dj.Manual):
        definition = """
        -> User
        acquisition: varchar(32)
        """

def test_elements():
    User.insert1({"user": "abc", "user_email": "def@ghi.jkl"})
    Foo.Acquisition.insert1({"user": "abc", "acquisition": "mno"})
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
test_elements.py:13: in <module>
    class Foo:
test_elements.py:15: in Foo
    class Acquisition(dj.Manual):
venv/lib/python3.9/site-packages/datajoint/schemas.py:147: in __call__
    self._decorate_master(cls, context)
venv/lib/python3.9/site-packages/datajoint/schemas.py:157: in _decorate_master
    self._decorate_table(cls, context=dict(context, self=cls, **{cls.__name__: cls}))
venv/lib/python3.9/site-packages/datajoint/schemas.py:188: in _decorate_table
    instance.declare(context)
venv/lib/python3.9/site-packages/datajoint/table.py:79: in declare
    sql, external_stores = declare(self.full_table_name, self.definition, context)
venv/lib/python3.9/site-packages/datajoint/declare.py:281: in declare
    table_comment, primary_key, attribute_sql, foreign_key_sql, index_sql, external_stores = prepare_declare(
venv/lib/python3.9/site-packages/datajoint/declare.py:248: in prepare_declare
    compile_foreign_key(line, context, attributes,
venv/lib/python3.9/site-packages/datajoint/declare.py:143: in compile_foreign_key
    raise DataJointError('Foreign key reference %s could not be resolved' % result.ref_table)
E   datajoint.errors.DataJointError: Foreign key reference User could not be resolved

Expected Behavior

The schema should be created without errors.

dimitri-yatsenko commented 2 years ago

If no context is indicated, the schema object uses the local context where it's invoked to look for the table classes. This may get into some of Python's namespace handling quirks. But just as a test, could you try passing the locals() contents explicitly?

schema = dj.schema('acquisition', context=locals())
chrisroat commented 2 years ago

Thanks for the suggestion. I tried that, and then also moving schema inside the class. Neither seems to work.

dimitri-yatsenko commented 2 years ago

We have never considered declaring table classes inside other classes. Here is the line where this evaluation takes place. I don't see why it would not work but Python has a few quirks about how it namespaces are handled with classes.