Skip to content

AttributeError: 'function' object has no attribute '_yield_per' when upgrading to SQLAlchemy 1.4 #281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mvanbaak opened this issue Mar 25, 2021 · 9 comments
Assignees

Comments

@mvanbaak
Copy link

Traceback (most recent call last):
  File "/Users/mvanbaak/dev/frontrow/public-api/src/fr_public_api/helpers/brandresolver.py", line 36, in resolve_brand_for_apikey
    key = db.session.query(ApiKey).filter_by(key=api_key).one()
  File "/Users/mvanbaak/.dotfiles/virtualenvs/fr_public_api/lib/python3.7/site-packages/aws_xray_sdk/ext/sqlalchemy/util/decorators.py", line 63, in wrapper
    res = func(*args, **kw)
  File "/Users/mvanbaak/.dotfiles/virtualenvs/fr_public_api/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 2730, in one
    return self._iter().one()
  File "/Users/mvanbaak/.dotfiles/virtualenvs/fr_public_api/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 2771, in _iter
    execution_options={"_sa_orm_load_options": self.load_options},
  File "/Users/mvanbaak/.dotfiles/virtualenvs/fr_public_api/lib/python3.7/site-packages/aws_xray_sdk/ext/sqlalchemy/util/decorators.py", line 63, in wrapper
    res = func(*args, **kw)
  File "/Users/mvanbaak/.dotfiles/virtualenvs/fr_public_api/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1616, in execute
    _parent_execute_state is not None,
  File "/Users/mvanbaak/.dotfiles/virtualenvs/fr_public_api/lib/python3.7/site-packages/sqlalchemy/orm/context.py", line 253, in orm_pre_session_exec
    if "yield_per" in execution_options or load_options._yield_per:
AttributeError: 'function' object has no attribute '_yield_per'

Versions:

Flask==1.1.2
SQLAlchemy==1.4.2
Flask-SQLAlchemy==2.5.1

boto3==1.17.35
botocore==1.20.36
aws-xray-sdk==2.7.0

I get the same error with SQLAlchemy 1.4.0 and 1.4.1, things work fine with 1.3.23.

Confirmed it's an xray issue with the following change to my code which made things work again:

-db = XRayFlaskSqlAlchemy(model_class=Base)
+db = SQLAlchemy(model_class=Base)
@srprash
Copy link
Contributor

srprash commented Mar 26, 2021

Hi @mvanbaak
Thanks for bringing this to our notice. We noticed this issue as well when our unit tests started failing for the recent SQLAlchemy update. I'll take a look into what's the root cause of this incompatibility with SQLAlchemy >= 1.4.0 and will update soon.

@srprash srprash self-assigned this Mar 30, 2021
@peterdeme
Copy link

👋 Any updates?

@srprash
Copy link
Contributor

srprash commented Apr 12, 2021

I did some digging and found out that SQLAlchemy is making some gradual changes for 2.0 starting in 1.4.0. The major change which is breaking the X-Ray SDK is the removal of the Query object.
The patching of flask sqlalchemy in the XRay SDK depends on the query and this is where we need to address the issue.

@mvanbaak @peterdeme Do you encouter this issue when using Flask SqlAlchemy or using SqlAlchemy alone?

@mvanbaak
Copy link
Author

I haven't tested it with sqlalchemy alone, always in a flask_sqlalchemy context.
If needed, I think I can test it tomorrow with only sqlalchemy though.

@peterdeme
Copy link

peterdeme commented Apr 13, 2021

@srprash I use plain SQLAlchemy.

@srprash
Copy link
Contributor

srprash commented Apr 19, 2021

Upon further investigation, i can say that the root cause of this issue is in the method decorate_all_functions which monkey-patches all the non-private functions in the sqlalchemy.orm.Query class with a xray wrapper function.

However, the problem started with v1.4.0 of sqlalchemy where the sqlalchemy.orm.Query class introduced a new non-private member load_options which is of type Class and this load_options member sneaks past this check in xray patching because both functions and classes are callables in Python. Now the load_options is patched as a function whereas this line expects it to be the original class, and therefore the AttributeError occurs.

To test this I modified the check to if name.startswith("_") or name == "load_options": to skip patching the load_options and was able to run the aplication fine. I think the fix for this would be to have a better checking mechanism than callable to differentiate a function from a class.

@mvanbaak
Copy link
Author

Any ETA now that a PR is out there?

@peterdeme
Copy link

Hey, is this released?

@srprash
Copy link
Contributor

srprash commented Jun 11, 2021

Hey @peterdeme
Yes. The fix was released in v2.8.0 of the SDK. Please see the changelog here:https://github.com/aws/aws-xray-sdk-python/blob/master/CHANGELOG.rst#280
Sorry we missed on updating the issue about the release.
I'll close this now. Feel free to open a new one if you run into any problems. Thanks

@srprash srprash closed this as completed Jun 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants