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.
Following code not cause an issue:
from django.views import generic
class MyView(generic.TemplateView):
pass
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)",
....
}
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?
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.
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.

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
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?


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.
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:

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:

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.
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.
@dimaulupov as a workaround you can add your own stub under your root folder to override our stub
typings\django\views\__init__.pyi
import django.views.generic as generic
from django.views.generic.base import View as View
Update: I think you'll have to copy all of our bundled django stubs to typings\django and then modify it there.
This should be fixed in the next release.
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
Most helpful comment
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