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

Pylance(reportOptionalMemberAccess) warning squiggle when writing code using SQLAlchemy session interface #4690

Closed
ghost opened this issue Aug 5, 2023 · 2 comments
Assignees
Labels
needs repro Issue has not been reproduced yet

Comments

@ghost
Copy link

ghost commented Aug 5, 2023

Environment data

  • Language Server version: 2023.8.10
  • OS and version: win32 x64
  • Python version (and distribution if applicable, e.g. Anaconda): 3.11.3
  • python.analysis.indexing: true
  • python.analysis.typeCheckingMode: off

Code Snippet

The snippet below produces the expected result, without a Pylance(reportOptionalMemberAccess) warning squiggle under the property .title.

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db"
db.init_app(app)

class Books(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String, unique=True, nullable=False)
    author = db.Column(db.String, nullable=False)
    review = db.Column(db.Float, nullable=False)

with app.app_context():
    book_to_update = db.get_or_404(Books, 1)
    book_to_update.title = "Harry Potter and the Chamber of Secrets"
    db.session.commit() 

Actual behavior

However, using the following code under .app_context() results in a Pylance warning squiggle under the .title property:

with app.app_context():
    book_to_update = db.session.get(Books, 1)
    book_to_update.title = "Harry Potter and the Chamber of Secrets"
    db.session.commit() 

The code executes correctly in both cases (i.e., despite the error squiggle being shown).
It seems to me that db.get_or_404() is part of the legacy SQLAlchemy query interface
(https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/api/#flask_sqlalchemy.SQLAlchemy.session),
whereas db.session.get() is part of the new interface. Perhaps Pylance isn't yet adapted to differences with this new interface?

Logs

As an error is shown only by Pylance, but the code executes correctly, there are no logs.
@github-actions github-actions bot added the needs repro Issue has not been reproduced yet label Aug 5, 2023
@erictraut
Copy link
Contributor

Pylance is doing the right thing here, at least based on the static type information that is provided to it by the respective libraries.

The get_or_404 method is defined here. Its return type is annotated as _O which means that it's based on the type of the value you pass to the entity parameter. This type will not evaluate to None.

The scoped_session.get method is defined here. Its return type is annotated as Optional[_O] which is a union between the types _O and None. That means this function can return a None value under certain circumstances. It may not be returning None when you run your code, but there are other circumstances where it can. If you code doesn't handle this case, it may eventually result in a crash. The purpose of static type checking is to inform you of such potential bugs before they show up at runtime.

If you believe that these type annotations are incorrect, you can file a bug with the respective library project.

If these type annotations are correct (and they likely are), then you have the following options:

  1. Add a conditional check to your code to properly handle the case where get returns None.
  2. Add an assert to your code to document the fact that you believe None will never be returned. This assert not only serves as documentation, it also validates your assumption at runtime and tells the static type checker about your assumption.
    assert book_to_update is not None
  1. Add a # type: ignore comment at the end of the line to suppress the type violation.
  2. Disable type checking entirely by setting python.analysis.typeCheckingMode to "off".

@ghost
Copy link
Author

ghost commented Aug 6, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs repro Issue has not been reproduced yet
Projects
None yet
Development

No branches or pull requests

2 participants