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

Django generic views are not recognized if imported with "from django.views import generic" statement #234

Closed
dimaulupov opened this issue Aug 13, 2020 · 12 comments
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version

Comments

@dimaulupov
Copy link

When Django's generic views are imported with the statement from django.views import generic and referred to with generic.TemplateView Pylance shows error: "TemplateView" is not a known member of module.

Environment data

  • Language Server version: Pylance language server 2020.8.0 (pyright 4b16a648)
  • OS and version: Ubuntu
  • Python version: Python 3.8.3
  • Django version: 3.0.8

Expected behaviour

Following code not cause an issue:

from django.views import generic

class MyView(generic.TemplateView):
    pass

Actual behaviour

This code causes error by Pylance.

from django.views import generic

class MyView(generic.TemplateView): # at this line error: "TemplateView" is not a known member of module
    pass

Error:

{
	"resource": "project/web/views.py",
	"owner": "_generated_diagnostic_collection_name_#0",
	"severity": 8,
	"message": "\"TemplateView\" is not a known member of module",
	"source": "Pylance (reportGeneralTypeIssues)",
....
}

Code Snippet / Additional information

First of all, line from django.views import generic is not the recommended way of importing generic views in Django.
In current version of the Django documentation it is only mentioned on the Step 4 of the tutorial.
If TemplateView is imported like this from django.views.generic.base import TemplateView there is no error and no problem.

But looking through our 7 year old project (we recently switched to absolutely fabulous and amazing Pylance) we always used from django.views import generic code.
And looking through the GitHub there are 32,008 code results for the string "from django.views import generic".

So the import maybe wrong and not officially recommended but it works and used by a lot of projects.

Is there any possibility that Pylance will be able to parse the code inside django.generic.views to understand where those classes coming from?

@jakebailey
Copy link
Member

This should be working, because https://github.com/typeddjango/django-stubs/blob/master/django-stubs/views/generic/__init__.pyi declares that TemplateView is re-exported.

@jakebailey jakebailey added bug Something isn't working needs investigation Could be an issue - needs investigation labels Aug 13, 2020
@github-actions github-actions bot removed the triage label Aug 13, 2020
@jakebailey
Copy link
Member

Returning to this, from django.views import generic appears to not work because in the django-stub project, https://github.com/typeddjango/django-stubs/blob/master/django-stubs/views/__init__.pyi does not re-export the submodule, but I'm not certain that it needs to do this.

@erictraut Do you know if this file needs to explicitly re-export the generic submodule (in a subfolder), or is this a bug in the import resolver or binder where should be accepting this code?

Maybe this code was valid due to some import side effect, but that'd strike me as strange to allow import django.views.generic but not from django.views import generic.

@jakebailey
Copy link
Member

image

@erictraut
Copy link
Contributor

The current stub is doing something very strange. It's implicitly importing (and re-exporting) the submodule ".generic.base", but it's not implicitly or explicitly importing/exporting the submodule ".generic".

I think the correct fix here is to change the stub to:

from .generic.base import View as View
from . import generic as generic

@jakebailey
Copy link
Member

The thing is that generic already exists as a submodule of views; why does it need to be explicitly exported?

import django.views.generic as generic  # works
from django.views import generic        # doesn't?

image

image

@erictraut
Copy link
Contributor

why does it need to be explicitly exported?

Type stubs are meant to be very explicit about which symbols are exported from where. By default, imported symbols are not re-exported, and submodules are not implicitly re-exported.

@jakebailey
Copy link
Member

I don't know what's different between this case and say urllib: https://github.com/python/typeshed/tree/master/stdlib/urllib

Its __init__.py is empty (does not reexport its submodules), and yet we understand the form that's broken for django:

image

I don't think this is a case where the submodule needs to explicitly be re-exported; I'm not writing:

import django.views

django.views.generic

That does require a re-export.

In fact, if you remove the contents of view's __init__.py, it does work:

image

@jakebailey
Copy link
Member

That last case to me says there's a bug where it's hiding generic for some reason when from .generic.base import View as View is present.

@erictraut
Copy link
Contributor

The statement import a.b allows you to access symbols in the a.b module. If you want to access symbols in the a module, you should include the statement import a.

Likewise, the statement from .a.b import c implicitly causes submodule .a.b to be imported, but it doesn't cause .a to be imported (or re-exported). If you want .a to be imported (or re-exported), you should do so explicitly.

The Python module loader unfortunately has a bunch of side effects that developers sometimes unknowingly rely upon. This is dangerous and fragile, and pyright intentionally honors only the explicit intent of an import statement.

In this case, the stub includes the statement from .generic.base import View as View. If the intent is to import (and re-export) .generic from this module, it needs to be made explicit.

@bschnurr

This comment has been minimized.

@bschnurr bschnurr added waiting for user response Requires more information from user and removed needs investigation Could be an issue - needs investigation labels Apr 23, 2021
@jakebailey jakebailey added fixed in next version (main) A fix has been implemented and will appear in an upcoming version and removed waiting for user response Requires more information from user labels Apr 23, 2021
@jakebailey
Copy link
Member

This should be fixed in the next release.

@jakebailey
Copy link
Member

This issue has been fixed in version 2021.4.3, which we've just released. You can find the changelog here: https://github.com/microsoft/pylance-release/blob/main/CHANGELOG.md#202143-29-april-2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version
Projects
None yet
Development

No branches or pull requests

5 participants