Skip to content
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

fix: session get bind signature #955

Closed
wants to merge 2 commits into from

Conversation

dpgaspar
Copy link

@dpgaspar dpgaspar commented Apr 14, 2021

The SignallingSession get_bind is being called without any parameters, this is probably due to the new SQLAlchemy proxied mechanism for registering scoped sessions

(None, None, None, None, False) {}

This is a simple fix that just uses the exact method signature from SQLAlchemy for get_bind of the current session

Checklist:

  • Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
  • Add or update relevant docs, in the docs folder and in code.
  • Add an entry in CHANGES.rst summarizing the change and linking to the issue.
  • Add .. versionchanged:: entries in any relevant code docs.
  • Run pre-commit hooks and fix any issues.
  • Run pytest and tox, no tests failed.

CHANGES.rst Outdated Show resolved Hide resolved
@dpgaspar dpgaspar requested a review from davidism April 15, 2021 11:57
CHANGES.rst Outdated Show resolved Hide resolved
@dpgaspar dpgaspar requested a review from davidism April 15, 2021 12:09
CHANGES.rst Show resolved Hide resolved
@dpgaspar dpgaspar requested a review from davidism April 15, 2021 12:10
davidism
davidism previously approved these changes Apr 15, 2021
@davidism
Copy link
Member

davidism commented Apr 15, 2021

Needs to be rebased to 2.x branch, since it's a fix against 2.x. You don't need to re-request my review, I get notifications on events already.

@dpgaspar dpgaspar force-pushed the fix/get-bind-session branch from 4bfebc1 to 070bf10 Compare April 15, 2021 13:10
Copy link

@ashb ashb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding *args is less fragile

src/flask_sqlalchemy/__init__.py Outdated Show resolved Hide resolved
@dpgaspar
Copy link
Author

Needs to be rebased to 2.x branch, since it's a fix against 2.x. You don't need to re-request my review, I get notifications on events already.

I can do that, but if this affects master wouldn't it be desirable to merge this to master, then cherry pick into 2.x?

I can also open a new PR from 2.x to 2.x with this patch?

@ashb
Copy link

ashb commented Apr 15, 2021

I'd love to know what is causing the default args to be put in to args in the first place.

From some playing it's something to do with the scoped_session/session factory.

This doesn't work without this PR or something like it:

session.get_bind()

But this does:

session().get_bind()

@dpgaspar
Copy link
Author

I'd love to know what is causing the default args to be put in to args in the first place.

From some playing it's something to do with the scoped_session/session factory.

This doesn't work without this PR or something like it:

session.get_bind()

But this does:

session().get_bind()

For sure, on SQLAlchemy < 1.4 was pretty simple, get_bind would get called with:
return getattr(self.registry(), name)(*args, **kwargs)

But now, I confess I don't follow what is going on

@ashb
Copy link

ashb commented Apr 15, 2021

[22] > /home/ash/.virtualenvs/flask-sqla/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py(658)instrument()
-> proxy_fn = _exec_code_in_env(code, env, fn.__name__)
(Pdb++) pp code
'def get_bind(self, mapper=None, clause=None, bind=None, _sa_skip_events=None, _sa_skip_for_implicit_returning=False):\n    return self._proxied.get_bind(mapper, clause, bind, _sa_skip_events, _sa_skip_for_implicit_returning)'
(Pdb++) print(code)
def get_bind(self, mapper=None, clause=None, bind=None, _sa_skip_events=None, _sa_skip_for_implicit_returning=False):
    return self._proxied.get_bind(mapper, clause, bind, _sa_skip_events, _sa_skip_for_implicit_returning)

https://github.com/sqlalchemy/sqlalchemy/blob/93ea31df86fc925a9e1df2a7dc80dd39f7ae4b9e/lib/sqlalchemy/util/langhelpers.py#L613

This seems to be the source of the extra arguments.

@zzzeek Is there a particular reason the proxy is including the defaults as explicit parameters, rather than letting python defaults do their thing? (i.e. using *args, **kwargs)?

@dpgaspar
Copy link
Author

@davidism
I opened another PR from branch 2.x to branch 2.x: #956
(it if helps)

Copy link

@ashb ashb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to have to use the *args approach as SQLA 1.3 only has 2 args.

(That, or update the dep on SQLAlchemy to >=1.4)

Edit: Daniel gave me access to his fork, and I've made this change there

@zzzeek
Copy link

zzzeek commented Apr 15, 2021

[22] > /home/ash/.virtualenvs/flask-sqla/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py(658)instrument()
-> proxy_fn = _exec_code_in_env(code, env, fn.__name__)
(Pdb++) pp code
'def get_bind(self, mapper=None, clause=None, bind=None, _sa_skip_events=None, _sa_skip_for_implicit_returning=False):\n    return self._proxied.get_bind(mapper, clause, bind, _sa_skip_events, _sa_skip_for_implicit_returning)'
(Pdb++) print(code)
def get_bind(self, mapper=None, clause=None, bind=None, _sa_skip_events=None, _sa_skip_for_implicit_returning=False):
    return self._proxied.get_bind(mapper, clause, bind, _sa_skip_events, _sa_skip_for_implicit_returning)

https://github.com/sqlalchemy/sqlalchemy/blob/93ea31df86fc925a9e1df2a7dc80dd39f7ae4b9e/lib/sqlalchemy/util/langhelpers.py#L613

This seems to be the source of the extra arguments.

@zzzeek Is there a particular reason the proxy is including the defaults as explicit parameters, rather than letting python defaults do their thing? (i.e. using *args, **kwargs)?

I would assume so they get included in the docstrings.

im not seeing the whole context here, it looks like you're subclassing Session which is fine. Is it going wrong with scoped_session()?

@ashb
Copy link

ashb commented Apr 15, 2021

@zzzeek Yeah, subclassing Session.

Given the dynamic function is via a string-eval, that won't show up in docstrings I don't think? Isn't functools.update_wrapper or similar a better approach for getting docstrings?

Very rough reproduction steps

class ExpSQLAlchemy(SQLAlchemy):
    def create_session(self, options):
        return sessionmaker(class_=SignallingSession, db=self, **options)


app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.sqlite"
db = ExpSQLAlchemy(app)

session = db.session
# This is fine
print(db.session().get_bind())
# This errors with "wrong number of positional arguments)
print(session.get_bind())

Because of the subclassing as it was defined;

     def get_bind(self, mapper=None, **kwargs):

that used to work, but on SQLA 1.4 that now doesn't, as the proxy code passes them all as positional.

@zzzeek
Copy link

zzzeek commented Apr 15, 2021

not sure if you noticed check out sqlalchemy/sqlalchemy#6285 but I just put out 1.4.8, so might not get to this for some days

@davidism davidism dismissed their stale review April 15, 2021 16:21

waiting to hear about upstream fix

@dpgaspar
Copy link
Author

@zzzeek Thank you

@dpgaspar
Copy link
Author

Going to close this, since SQLAlchemy is fixed and flask-sqlalchemy master looks good now

@dpgaspar dpgaspar closed this Jun 23, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Possible issue on session get_bind
4 participants