In October 2010, I sent this question to the Sqlalchemy user list. At that time, I just used the clear_mappers mentioned in the post and did not try to figure out what the problem was. It was very naughty. Today I again ran into this error and decided to build the minimal example that appears below. Michael also addressed what was probably the same problem back in 2006. I decided to continue here to give Michael a break from my dumb questions.
So, the result seems to be that for a given class definition, you cannot define more than one defined one. In my case, I have a Pheno class declared in the module scope (I assume this is the top-level scope here), and every time make_tables is make_tables , it tries to define a different make_tables .
Mike wrote: βBased on the description of the problem above, you need to ensure that your Python classes are declared in the same scope as your mappers. The error message you get assumes thatβ Pheno βis being declared at the module level.β This will take care of the problem, but how can I get around this without changing my current structure? What other options do I have, if any? Apparently, mapper does not have such an option as "if the determinant is already defined, exit without doing anything", which will take care of this beautifully. I think I could define a wrapper function, but that would be pretty ugly.
from sqlalchemy import * from sqlalchemy.orm import * def make_pheno_table(meta, schema, name='pheno'): pheno_table = Table( name, meta, Column('patientid', String(60), primary_key=True), schema=schema, ) return pheno_table class Pheno(object): def __init__(self, patientid): self.patientid = patientid def make_tables(schema): from sqlalchemy import MetaData meta = MetaData() pheno_table = make_pheno_table(meta, schema) mapper(Pheno, pheno_table) table_dict = {'metadata': meta, 'pheno_table':pheno_table} return table_dict table_dict = make_tables('foo') table_dict = make_tables('bar')
An error message will appear. Tested with SQLAlchemy 0.6.3-3 on Debian compression.
$ python test.py Traceback (most recent call last): File "test.py", line 25, in <module> table_dict = make_tables('bar') File "test.py", line 20, in make_tables mapper(Pheno, pheno_table) File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/__init__.py", line 818, in mapper return Mapper(class_, local_table, *args, **params) File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/mapper.py", line 209, in __init__ self._configure_class_instrumentation() File "/usr/lib/python2.6/dist-packages/sqlalchemy/orm/mapper.py", line 381, in _configure_class_instrumentation self.class_) sqlalchemy.exc.ArgumentError: Class '<class '__main__.Pheno'>' already has a primary mapper defined. Use non_primary=True to create a non primary Mapper. clear_mappers() will remove *all* current mappers from all classes.
EDIT: in the SQLAlchemy documentation : mapper () API , I could replace mapper(Pheno, pheno_table) above with
from sqlalchemy.orm.exc import UnmappedClassError try: class_mapper(Pheno) except UnmappedClassError: mapper(Pheno, pheno_table)
If no qualifier is defined for Pheno, it throws an UnmappedClassError . This at least does not return an error in my test script, but I did not check if it really works. Comments?
EDIT2: At the suggestion of Denis, the following works:
class Tables(object): def make_tables(self, schema): class Pheno(object): def __init__(self, patientid): self.patientid = patientid from sqlalchemy import MetaData from sqlalchemy.orm.exc import UnmappedClassError meta = MetaData() pheno_table = make_pheno_table(meta, schema) mapper(Pheno, pheno_table) table_dict = {'metadata': meta, 'pheno_table':pheno_table, 'Pheno':Pheno} return table_dict table_dict = Tables().make_tables('foo') table_dict = Tables().make_tables('bar')
However superficially similar
# does not work class Tables(object): class Pheno(object): def __init__(self, patientid): self.patientid = patientid def make_tables(self, schema): from sqlalchemy import MetaData from sqlalchemy.orm.exc import UnmappedClassError meta = MetaData() pheno_table = make_pheno_table(meta, schema) mapper(self.Pheno, pheno_table) table_dict = {'metadata': meta, 'pheno_table':pheno_table, 'Pheno':self.Pheno} return table_dict table_dict = Tables().make_tables('foo') table_dict = Tables().make_tables('bar')
no. I get the same error message as before. I do not understand the review problems very well to say why. Isn't this the Pheno class in both cases in some local area?