question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AttributeError: entity

See original GitHub issue

Python 3.7.4 SQLAlchemy 1.3.7 graphene-sqlalchemy 2.2.2 Flask 1.1.1 Flask-SQLAlchemy 2.4.0 psycopg2 2.8.3

Linux xxx 5.1.21-200.fc29.x86_64 #1 SMP Mon Jul 29 15:30:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

The following code snippets show just a simple One-to-Many Relationship. I tried it with and back_populates and with backref, Uni- and Bidirectional. I also tried Many-to-Many relationships with a association Table. But nothing helped.

I always get the error shown in the last Bash-snippet.

Whats wrong here? I found out, that sqlalchemy.orm.relationships.RelationshipProperty give that exception when I try to call .entity on it.

I already opened an issue on the sqlalchemy github https://github.com/sqlalchemy/sqlalchemy/issues/4819 and got the answer above. Hopefully it helps you to help me to fix this issue 😉

that stack trace is not very easy to create as it involves an unusual attribute error being generated when mappings are being resolved, and it is masquerading as an attribute error for the “entity” attribute, which is in fact a function. in python 3, any ofher kind of exception will be displayed as is, so it’s very strange for it to be an attribute error.

in case that doesn’t make sense, it means there is another exception happening that we’re not able to see.

I unfortunately cannot reproduce your error with your mappings. The condition may be due to whatever graphene-sqlalchemy is doing, The method call here:

File “/home/david/projects/Qubic/lib64/python3.7/site-packages/graphene/utils/subclass_with_meta.py”, line 52, in init_subclass super_class.init_subclass_with_meta(**options)

which is then calling down to class_mapper(), looks suspicious to me; I would first off not be using a metaclass for anything in conjunction wtih SQLAlchemy declarative because metaclasses are very unwieldy and declarative is already using one (they should use mixin classes or class decorators for whatever it is they need to add to SQLAlchemy models) and if I were, I’d not be trying to run class_mapper() inside of it as this could in theory lead to some difficult re-entrant conditions which is likely what’s happening here.

in short I think you need to report this to graphene-sqlalchemy.

It is happen in sqlalchemy/orm/mapper.py(1947)_post_configure_properties() on line 1947

1932        def _post_configure_properties(self):                                                                                                                                   │
1933            """Call the ``init()`` method on all ``MapperProperties``                                                                                                           │
1934            attached to this mapper.                                                                                                                                            │
1935                                                                                                                                                                                │
1936            This is a deferred configuration step which is intended                                                                                                             │
1937            to execute once all mappers have been constructed.                                                                                                                  │
1938                                                                                                                                                                                │
1939            """                                                                                                                                                                 │
1940                                                                                                                                                                                │
1941            self._log("_post_configure_properties() started")                                                                                                                   │
1942            l = [(key, prop) for key, prop in self._props.items()]                                                                                                              │
1943            for key, prop in l:                                                                                                                                                 │
1944                self._log("initialize prop %s", key)                                                                                                                            │
1945                                                                                                                                                                                │
1946                if prop.parent is self and not prop._configure_started:                                                                                                         │
1947 ->                 prop.init()                                                                                                                                                 │
1948                                                                                                                                                                                │
1949                if prop._configure_finished:                                                                                                                                    │
1950                    prop.post_instrument_class(self)                                                                                                                            │
1951                                                                                      
(Pdb) dir(prop)
['Comparator', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__gt__', '__hash__', '__init__','__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', '_add_reverse_property', '_all_strategies', '_cascade', '_check_cascade_settings', '_check_conflicts', '_columns_are_mapped', '_configure_finished', '_configure_started', '_create_joins', '_creation_order', '_default_path_loader_key', '_dependency_processor', '_fallback_getattr', '_generate_backref', '_get_attr_w_warn_on_none', '_get_cascade', '_get_context_loader', '_get_strategy', '_is_internal_proxy', '_is_self_referential', '_lazy_none_clause', '_memoized_attr__default_path_loader_key', '_memoized_attr_wildcard_token', '_memoized_attr_info', '_optimized_compare', '_persists_for', '_post_init', '_process_dependent_arguments', '_reverse_property', '_set_cascade', '_setup_join_conditions', '_should_log_debug', '_should_log_info', '_strategies', '_strategy_lookup', '_use_get', '_user_defined_foreign_keys', '_value_as_iterable', '_wildcard_token', '_with_parent', 'active_history', 'argument', 'back_populates', 'backref', 'bake_queries', 'cascade', 'cascade_backrefs', 'cascade_iterator', 'class_attribute', 'collection_class', 'comparator', 'comparator_factory', 'create_row_processor', 'direction', 'distinct_target_key', 'do_init', 'doc', 'enable_typechecks', 'entity', 'extension', 'extension_type', 'info', 'init', 'innerjoin', 'instrument_class', 'is_aliased_class', 'is_attribute', 'is_clause_element', 'is_instance', 'is_mapper', 'is_property', 'is_selectable', 'join_depth', 'key', 'lazy', 'load_on_pending', 'local_remote_pairs', 'logger', 'mapper', 'merge', 'omit_join', 'order_by', 'parent', 'passive_deletes', 'passive_updates', 'post_instrument_class', 'post_update', 'primaryjoin', 'query_class', 'remote_side', 'secondary', 'secondaryjoin', 'set_parent', 'setup', 'single_parent', 'strategy', 'strategy_for', 'strategy_key', 'strategy_wildcard_key', 'uselist', 'viewonly']
(Pdb) prop.entity
*** AttributeError: entity                                   
(Pdb) prop.__class__
<class 'sqlalchemy.orm.relationships.RelationshipProperty'>

app/models/roles.py

from ..models import db, bcrypt
from sqlalchemy import Column, Integer, String, Boolean, Binary

class Role(db.Model):
  __tablename__ = "roles" 

  id = Column(Integer, primary_key=True, autoincrement=True)
  name = Column(String(80), unique=True)
  description = Column(String(255))
  users = db.relationship("models.User", backref=db.backref('role', lazy='joined'), lazy=True)

  def __repr__(self):
    return '<Role %r>' % (self.name)

__all__ = [ Role ]

app/models/users.py

from ..models import db, bcrypt
from sqlalchemy import Column, Integer, String, Boolean, Binary, DateTime, Text, ForeignKey
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method

class User(db.Model):
  __tablename__ = "users" 

  id = Column(Integer, primary_key=True, autoincrement=True)
  first_name = Column(String(255), nullable=False)
  last_name = Column(String(255), nullable=False)
  email = Column(String(255), unique=True, nullable=False)
  public_key = Column(Text, unique=True)
  _secret_access_key = Column(Binary(60), unique=True)
  access_key_id = Column(String(255), unique=True)
  active = Column(Boolean())
  confirmed_at = Column(DateTime())
  confirmation_token = Column(String(255), unique=True)
  confirmation_sent_at = Column(DateTime())
  role_id = Column(Integer, ForeignKey("roles.id"), nullable=False)

  @hybrid_property
  def secret_access_key(self):
    return self._secret_access_key

  @secret_access_key.setter
  def secret_access_key(self, plaintext_key):
    self._secret_access_key = bcrypt.generate_password_hash(plaintext_key, 15)
 
  @hybrid_method
  def is_correct_secret_access_key(self, plaintext_key):
    return bcrypt.check_password_hash(self.secret_access_key, plaintext_key)

  def __repr__(self):
    return '<User %r %r>' % (self.first_name, self.last_name)

__all__ = [ User ]

app/models/init.py

from flask.cli import with_appcontext
import click
from flask.cli import AppGroup
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
import pdb

db = SQLAlchemy()
bcrypt = Bcrypt()

role_cli = AppGroup('role')
user_cli = AppGroup('user')

def init_app(app):
  print("app.models.__init__.init_app()")

  db.init_app(app)
  bcrypt.init_app(app)
  app.cli.add_command(role_cli)
  app.cli.add_command(user_cli)
  app.cli.add_command(init_db)
  app.cli.add_command(seed)

@click.command('init-db')
@with_appcontext
def init_db():
  pdb.set_trace()
  db.create_all()
  click.echo('Initialized the database.')

@role_cli.command('create')
@click.argument("name")
@click.argument("description")
@with_appcontext
def create_role(name, description):
  from .roles import Role
  role = Role(name=name, description=description)
  db.session.add(role)
  db.session.commit()
  click.echo('Role created.')

@user_cli.command('create')
@click.argument("first_name")
@click.argument("last_name")
@click.argument("email")
@with_appcontext
def create_role(first_name, last_name, email):
  from .users import User
  from ..tasks.mailer import send_confirmation_mail
  user = User(first_name=first_name, last_name=last_name, email=email)
  db.session.add(user)
  db.session.commit()
  send_confirmation_mail.delay({'subject': 'Please complete your registration confirmation', 'to': user.email, 'from': 'xxx@yyy.zz'})
  click.echo('User created.')

@click.command('seed')
@with_appcontext
def seed():
  from .roles import Role
  from .users import User
  from flask import current_app
  from datetime import datetime
  import secrets

  entities = []
  entities.append(Role(name='Admin', description='Administrator'))
  entities.append(Role(name='ClusterAdmin', description='Administrator of one Redis Cluster'))
  
  secret_access_key=secrets.token_hex()
  entities.append(User(
    first_name=current_app.config["ADMIN"]["FIRST_NAME"], 
    last_name=current_app.config["ADMIN"]["LAST_NAME"],
    email=current_app.config["ADMIN"]["EMAIL"],
    confirmed_at=datetime.now(),
    public_key=current_app.config["ADMIN"]["PUBLIC_KEY"],
    access_key_id=secrets.token_hex(),
    secret_access_key=secret_access_key
  ))

  for entity in entities:
    try:
      db.session.add(entity)
      db.session.commit()
      click.echo("Add Entity " + str(entity) +" to Database.")
      if isinstance(entity, User):
        click.echo("SECRET_ACCESS_KEY: " + secret_access_key)
        click.echo("ACCESS_KEY_ID: " + entity.access_key_id)
    except Exception as err:
      click.echo("Entity " + str(entity) + " already exist!")

  click.echo('Database seeding Done.')

from .users import User
from .roles import Role
from .clusters import Cluster
from .groups import Group
from .workers import Worker
__all__ = [Role, User, Worker, Cluster, Group]
(Qubic) [david@doha Qubic]$ export FLASK_APP=app
(Qubic) [david@doha Qubic]$ export FLASK_ENV=development
(Qubic) [david@doha Qubic]$ flask init-db
app.schemas.user.UserObject
Traceback (most recent call last):
  File "/home/david/projects/Qubic/bin/flask", line 11, in <module>
    sys.exit(main())
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/flask/cli.py", line 966, in main
    cli.main(prog_name="python -m flask" if as_module else None)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/flask/cli.py", line 586, in main
    return super(FlaskGroup, self).main(*args, **kwargs)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/click/core.py", line 1132, in invoke
    cmd_name, cmd, args = self.resolve_command(ctx, args)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/click/core.py", line 1171, in resolve_command
    cmd = self.get_command(ctx, cmd_name)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/flask/cli.py", line 542, in get_command
    rv = info.load_app().cli.get_command(ctx, name)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/flask/cli.py", line 388, in load_app
    app = locate_app(self, import_name, name)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/flask/cli.py", line 240, in locate_app
    __import__(module_name)
  File "/home/david/projects/Qubic/app/__init__.py", line 6, in <module>
    from . import schemas
  File "/home/david/projects/Qubic/app/schemas/__init__.py", line 14, in <module>
    from .user import UserObject, UserObjectConnection, CreateUser, UpdateUser, DeleteUser, DeleteAllUser, ConfirmUser
  File "/home/david/projects/Qubic/app/schemas/user.py", line 18, in <module>
    class UserObject(SQLAlchemyObjectType):
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/graphene/utils/subclass_with_meta.py", line 52, in __init_subclass__
    super_class.__init_subclass_with_meta__(**options)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/graphene_sqlalchemy/types.py", line 224, in __init_subclass_with_meta__
    assert is_mapped_class(model), (
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/graphene_sqlalchemy/utils.py", line 28, in is_mapped_class
    class_mapper(cls)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/orm/base.py", line 441, in class_mapper
    mapper = _inspect_mapped_class(class_, configure=configure)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/orm/base.py", line 420, in _inspect_mapped_class
    mapper._configure_all()
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 1337, in _configure_all
    configure_mappers()
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 3229, in configure_mappers
    mapper._post_configure_properties()
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/orm/mapper.py", line 1947, in _post_configure_properties
    prop.init()
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/orm/interfaces.py", line 196, in init
    self.do_init()
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/orm/relationships.py", line 1860, in do_init
    self._process_dependent_arguments()
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/orm/relationships.py", line 1922, in _process_dependent_arguments
    self.target = self.entity.persist_selectable
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 949, in __getattr__
    return self._fallback_getattr(key)
  File "/home/david/projects/Qubic/lib64/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 923, in _fallback_getattr
    raise AttributeError(key)
AttributeError: entity

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5

github_iconTop GitHub Comments

3reactions
zzzeekcommented, Aug 27, 2019

note that the model as given works fine in an isolated test case without all the flask/graphene-sqlalchemy imports added, so the model as given is fine, I ran it and it has no issues. someone needs to pdb into the exception to see what the ultimate AttributeError (I assume it’s an AttributeError) is being raised.

0reactions
shaozicommented, Nov 30, 2021

I eventually found the answer. The reason for the error is that the model resolution needs the model to be imported somewhere before. So try to import the model in the beginning of the app fixed my issue.

The accepted answer in this stack overflow hit the nail on the head: https://stackoverflow.com/questions/45534903/python-sqlalchemy-attributeerror-mapper/45540141#45540141

Read more comments on GitHub >

github_iconTop Results From Across the Web

AttributeError: entity · Issue #4819 · sqlalchemy/ ...
orm.relationships.RelationshipProperty give that exception when I try to call .entity on it. It is happen in sqlalchemy/orm/mapper.py(1947)_ ...
Read more >
Python SqlAlchemy - AttributeError: mapper
mapper is a memoized property of a relationship that resolves the given argument, but for some reason this fails for you with an...
Read more >
Source code for sqlalchemy_utils.functions.orm
class Entity(Base): __tablename__ = 'entity' id = sa. ... __table__.name except AttributeError: pass def getattrs(obj, attrs): return map(partial(getattr, ...
Read more >
AttributeError: entity in SQLAlchemy after migration : r/flask
I have a project in python 2.7 and started migrating it to 3.9, after some upgrades I started getting this error "AttributeError: entity" ......
Read more >
ORM Internals
“state getter” callables should raise either KeyError or AttributeError if no InstanceState could be found for the instance.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found