PEP-484 type hints bindings for the Django web framework

Related tags

Django mypy-django
Overview

mypy-django

Type stubs to use the mypy static type-checker with your Django projects

This project includes the PEP-484 compatible "type stubs" for Django APIs. Using a compliant checking tool (typically, mypy), it allows you to document and verify more of your code. Your annotated code will look like:

def vote(request: HttpRequest, question_id: str) -> HttpResponse:
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        return render(request, 'polls/detail.html', {'question': question})
    else:
        selected_choice.votes += 1
        selected_choice.save()
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

If you use incorrect annotations, like in the following example

class ResultsView(generic.DetailView):
    model = Question

    def get_template_names(self) -> str:
        if some_condition():
            return "template_a.html"
        else:
            return "template_b.html"

Running mypy will report the problem:

$ mypy --strict-optional -p polls
...
polls/views.py: note: In class "ResultsView":
polls/views.py:41: error: Return type of "get_template_names" incompatible with supertype "SingleObjectTemplateResponseMixin"
polls/views.py:41: error: Return type of "get_template_names" incompatible with supertype "TemplateResponseMixin"

Mypy Pony

Installation and usage

You'll need to install mypy (other PEP-484 checkers might work, but I haven't tested them). pip install mypy should do the trick. There are no other requirements.

This is not a python package (no actual executable code), so this is not installed with pip or available in PyPI. You can just git clone the latest version from https://github.com/machinalis/mypy-django.git or download and unzip https://github.com/machinalis/mypy-django/archive/master.zip

Once you have your copy, set your MYPYPATH environment variable to point to the files. For example (in Linux/bash):

$ export MYPYPATH=/home/dmoisset/mypy-django/
$ ls $MYPYPATH
django
$ ls $MYPYPATH/django
conf  core  http  __init__.pyi  urls  utils  views

If you don't see the above (the second line might have a few more items in your computer), check that the path exists, and that it points to the correct level in the directory tree.

Motivation

We are building this as a tool at Machinalis to improve the quality of the Django projects we build for our clients. Feel free to contact me if you want to hear more about how we use it or how it can be applied. I can be found at [email protected] or at @dmoisset via Twitter.

In a more general perspective, it makes sense to use static typing for Django given the following:

  1. Much of the user application code for Django projects consists in operating on objects defined by the framework. Unlike other APIs where you mostly pass around standard python data structures, this means that you don't get much benefit from PEP-484 static typing because everything gets annotated as Any (i.e. unchecked)
  2. A large part of the framework follows a very structured, almost declarative approach where you just fill-out a structure (for example, defining models, admin options, generic views, url routers, forms, settings)
  3. Django already has a policy of checking types before starting serving. Many of the system checks performed by manage.py check are actually type checks. So this fits very well with the framework philosophy

Full example

I reimplemented most of the standard Django tutorial with annotations, so you can see how it looks. The code (and a README with some details of problems and solutions found when annotating) are available at https://github.com/machinalis/mypy-django-example

Known issues

  • The current version is mainly focused on supporting Django 1.10 under python 3.x. Given that the APIs I cover are the core components and haven't changed much, you probably can work with older versions of Django and it might work. Python 2.x will not be supported (The code uses str to describe arguments/return values that can be text strings, i.e. unicode).
  • Many django modules that you might import are not supported yet. So you might need to silence with # type: ignore some messages like:
polls/views.py:1: error: No library stub file for module 'django.db.models.query'
  • It's recommended that you run mypy with the --strict-optional option; many of the stubs assume that you do, and you might get some warnings inside the stub files if you don't use it.

Roadmap

v0.1 - Initial release - October 2016

  • Request and Response objects
    • Including supporting classes like QueryDict and file objects
  • Generic views
  • URL resolver
  • Other miscellaneous components required by the above (timezones, cookies, ...)

v0.2 - In development

  • Admin support
  • django.shortcuts
  • Paginators

Probably never

  • Querysets may have some partial support, but complex arguments (like the ones for filter and get queries) or Q and F objects are beyond the expressive possibilities of mypy as it is now.
  • The template language is a separate language and can not be covered by mypy, so any type errors inside the template can not be detected by it.

License

BSD. See LICENSE file for details

Comments
  • class Meta of Models

    class Meta of Models

    I ran into a problem with mypy on the Meta classes of Django models. The mypy issue tracker redirected my to this place.

    Do you have an answer for this question? https://github.com/python/mypy/issues/3855

    opened by ostcar 2
  • WIP: add dispatch, signals and signing, improve http attributes

    WIP: add dispatch, signals and signing, improve http attributes

    I made some new stubs for django dispatch and some core features. I also added the __setattr__ and __getattr__ so that people can tack on attributes dynamically (which is apparently a common pattern).

    WIP: I also want to update MultiValueDict, as the get methods are not correctly typed.

    opened by ethanhs 1
  • Update install command to the latest

    Update install command to the latest

    mypy-lang has moved to mypy now, so in order to install the latest mypy `pip install mypy is needed, not mypy-lang.

    More details here:

    • https://github.com/python/mypy/commit/339ba96d1c36894577db072a0f90656fea83a05a#diff-04c6e90faac2675aa89e2176d2eec7d8
    opened by vinitkumar 1
  • django.core.exceptions.ImproperlyConfigured: django-configurations settings importer wasn't correctly installed.

    django.core.exceptions.ImproperlyConfigured: django-configurations settings importer wasn't correctly installed.

    Bug Report

    when trying to run "mypy" on my company's existing codebase I'm getting an error as follows:

    root@826a40544ab8:/app/wwau/wwau# mypy --config-file=./setup.cfg ./wwau/settings.py 
    Error constructing plugin instance of NewSemanalDjangoPlugin
    
    Traceback (most recent call last):
      File "/usr/local/bin/mypy", line 8, in <module>
        sys.exit(console_entry())
      File "/usr/local/lib/python3.6/site-packages/mypy/__main__.py", line 8, in console_entry
        main(None, sys.stdout, sys.stderr)
      File "mypy/main.py", line 90, in main
      File "mypy/build.py", line 180, in build
      File "mypy/build.py", line 229, in _build
      File "mypy/build.py", line 472, in load_plugins
      File "mypy/build.py", line 450, in load_plugins_from_config
      File "/usr/local/lib/python3.6/site-packages/mypy_django_plugin/main.py", line 100, in __init__
        self.django_context = DjangoContext(django_settings_module)
      File "/usr/local/lib/python3.6/site-packages/mypy_django_plugin/django/context.py", line 88, in __init__
        apps, settings = initialize_django(self.django_settings_module)
      File "/usr/local/lib/python3.6/site-packages/mypy_django_plugin/django/context.py", line 70, in initialize_django
        settings._setup()
      File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 66, in _setup
        self._wrapped = Settings(settings_module)
      File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 157, in __init__
        mod = importlib.import_module(self.SETTINGS_MODULE)
      File "/usr/local/lib/python3.6/importlib/__init__.py", line 126, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 994, in _gcd_import
      File "<frozen importlib._bootstrap>", line 971, in _find_and_load
      File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 678, in exec_module
      File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
      File "/app/wwau/wwau/wwau/settings.py", line 5, in <module>
        from common_settings import CommonBase, CommonLocal, CommonCI, CommonServer, VerboseLoggingMixin
      File "/app/shared/common_settings.py", line 17, in <module>
        class CommonBase(Configuration):
      File "/usr/local/lib/python3.6/site-packages/configurations/base.py", line 28, in __new__
        raise ImproperlyConfigured(install_failure)
    django.core.exceptions.ImproperlyConfigured: django-configurations settings importer wasn't correctly installed. Please use one of the starter functions to install it as mentioned in the docs: https://django-configurations.readthedocs.io/
    

    To Reproduce

    Unable to reproduce in a similar django project sadly.

    Expected Behavior

    Just like in the other project - I'd like to see the mypy type errors in the console.

    Actual Behavior

    as above

    Your Environment

    • Mypy version used: mypy 0.790
    • Mypy command-line flags: none
    • Mypy configuration options from mypy.ini (and other config files): [mypy] files=wwau,../../shared ignore_missing_imports=true plugins = mypy_django_plugin.main

    [mypy.plugins.django-stubs] django_settings_module = "wwau.settings"

    • Python version used: Python 3.6.10
    • Operating system and version: Linux 826a40544ab8 5.8.16-2-MANJARO #1 SMP PREEMPT Mon Oct 19 11:33:03 UTC 2020 x86_64 GNU/Linux
    opened by Niedzwiedzw 0
  • Two-line file, both ignored, leads to errors within mypy-django. Errors disappear if one line removed, get worse if the other.

    Two-line file, both ignored, leads to errors within mypy-django. Errors disappear if one line removed, get worse if the other.

    Encountered against the latest checkouts, with mypy==0.521

    Two lines:

    from django.views import View # type: ignore
    from django.db import models  # type: ignore
    

    Errors:

    $ MYPYPATH=mypy-django mypy --strict-optional --disallow-untyped-calls test_mypy.py 
    mypy-django/django/views/generic/list.pyi:3: error: No library stub file for module 'django.db.models'
    mypy-django/django/views/generic/list.pyi:3: note: (Stub files are from https://github.com/python/typeshed)
    mypy-django/django/views/generic/list.pyi:4: error: No library stub file for module 'django.db.models.query'
    

    One line:

    from django.views import View # type: ignore
    

    Errors:

    $ MYPYPATH=mypy-django mypy --strict-optional --disallow-untyped-calls test_mypy.py 
    mypy-django/django/views/generic/dates.pyi:4: error: No library stub file for module 'django.db'
    mypy-django/django/views/generic/dates.pyi:4: note: (Stub files are from https://github.com/python/typeshed)
    mypy-django/django/views/generic/detail.pyi:3: error: No library stub file for module 'django.db'
    mypy-django/django/views/generic/edit.pyi:3: error: No library stub file for module 'django.db'
    mypy-django/django/views/generic/list.pyi:3: error: No library stub file for module 'django.db.models'
    mypy-django/django/views/generic/list.pyi:4: error: No library stub file for module 'django.db.models.query'
    

    This is stripped down from a more reasonably-sized file that actually did things, but it seems to be the imports themselves that triggered the issues.

    I think this must be some kind of import-order issue.

    (I forget why I was ignoring both lines, but it doesn't seem to really have a tangible effect on the output.)

    opened by mwchase 0
  • State of the project

    State of the project

    Hi, @dmoisset!

    I really like the initiative taken by you and your collegues over at Machinalis. Static type checking for Django on a general basis would be great!

    For the moment it is really difficult to investigate the state of static type checking in the Django community. When searching around I have found this repository and several Google usergroup threads heavily involving you, but more recent information is hard to come by.

    Is it possible to adress this in the README in this repository? Questions I have are:

    • Are there any plans for pulling these stubs into the official python/typeshed repository?
    • Or is it still the plan to pursue pulling this into upstream Django?
    • What has been your general impression of the Django maintainers interest in doing so?
    • Is the plan to wait for Django 2.0, where Python version 3 can be assumed?

    Thanks, Jakob

    opened by JakobGM 8
  • Add integration tests to the project with Travis CI

    Add integration tests to the project with Travis CI

    In order to develop any project, automated testing is essential. I reckon the type stubs can be tested by creating a directory with example files, and by testing the output of mypy after running mypy on those files. We can then ensure that certain symbols are stubbed, that certain types are inferred, etc.

    opened by w0rp 0
  • Support QuerySet with Generic types

    Support QuerySet with Generic types

    I have some modified stubs for QuerySet and Manager so they accept type parameters. This makes the following possible.

    for foo in Foo.objects.all(): # The type of foo is inferred as Foo
    

    Using it requires stubbing models like so.

    # foo.py
    from django.db import models
    
    
    class Foo(models.Model):
        bar = models.CharField(max_length=255)
    
    # foo.pyi
    from django.db import models
    
    
    class Foo(models.Model):
        objects = ... # type: models.Manager['Foo']
        bar = ... # type: str
    

    Would you be interested in adding this to the project if I create a pull request?

    opened by w0rp 0
Owner
Machinalis
Machinalis
💨 Fast, Async-ready, Openapi, type hints based framework for building APIs

Fast to learn, fast to code, fast to run Django Ninja - Fast Django REST Framework Django Ninja is a web framework for building APIs with Django and P

Vitaliy Kucheryaviy 3.8k Jan 1, 2023
django-reversion is an extension to the Django web framework that provides version control for model instances.

django-reversion django-reversion is an extension to the Django web framework that provides version control for model instances. Requirements Python 3

Dave Hall 2.8k Jan 2, 2023
django-dashing is a customisable, modular dashboard application framework for Django to visualize interesting data about your project. Inspired in the dashboard framework Dashing

django-dashing django-dashing is a customisable, modular dashboard application framework for Django to visualize interesting data about your project.

talPor Solutions 703 Dec 22, 2022
Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project

Django URL Shortener Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project Install this package to your Dja

Rishav Sinha 4 Nov 18, 2021
This "I P L Team Project" is developed by Prasanta Kumar Mohanty using Python with Django web framework, HTML & CSS.

I-P-L-Team-Project This "I P L Team Project" is developed by Prasanta Kumar Mohanty using Python with Django web framework, HTML & CSS. Screenshots HO

null 1 Dec 15, 2021
Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly.

Cookiecutter Django Powered by Cookiecutter, Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly. Documentati

Daniel Feldroy 10k Dec 31, 2022
A handy tool for generating Django-based backend projects without coding. On the other hand, it is a code generator of the Django framework.

Django Sage Painless The django-sage-painless is a valuable package based on Django Web Framework & Django Rest Framework for high-level and rapid web

sageteam 51 Sep 15, 2022
APIs for a Chat app. Written with Django Rest framework and Django channels.

ChatAPI APIs for a Chat app. Written with Django Rest framework and Django channels. The documentation for the http end points can be found here This

Victor Aderibigbe 18 Sep 9, 2022
Bringing together django, django rest framework, and htmx

This is Just an Idea There is no code, this README just represents an idea for a minimal library that, as of now, does not exist. django-htmx-rest A l

Jack DeVries 5 Nov 24, 2022
DRF_commands is a Django package that helps you to create django rest framework endpoints faster using manage.py.

DRF_commands is a Django package that helps you to create django rest framework endpoints faster using manage.py.

Mokrani Yacine 2 Sep 28, 2022
RestApi With Django 3.2 And Django Rest Framework

RestApi-With-Django-3.2-And-Django-Rest-Framework Description This repository is a Software of Development with Python. Virtual Using pipenv, virtuale

Daniel Arturo Alejo Alvarez 6 Aug 2, 2022
Django API without Django REST framework.

Django API without DRF This is a API project made with Django, and without Django REST framework. This project was done with: Python 3.9.8 Django 3.2.

Regis Santos 3 Jan 19, 2022
Django-static-site - A simple content site framework that harnesses the power of Django without the hassle

coltrane A simple content site framework that harnesses the power of Django with

Adam Hill 57 Dec 6, 2022
A starter template for building a backend with Django and django-rest-framework using docker with PostgreSQL as the primary DB.

Django-Rest-Template! This is a basic starter template for a backend project with Django as the server and PostgreSQL as the database. About the templ

Akshat Sharma 11 Dec 6, 2022
Django-discord-bot - Framework for creating Discord bots using Django

django-discord-bot Framework for creating Discord bots using Django Uses ASGI fo

Jamie Bliss 1 Mar 4, 2022
Django-Text-to-HTML-converter - The simple Text to HTML Converter using Django framework

Django-Text-to-HTML-converter This is the simple Text to HTML Converter using Dj

Nikit Singh Kanyal 6 Oct 9, 2022
Simple yet powerful and really extendable application for managing a blog within your Django Web site.

Django Blog Zinnia Simple yet powerful and really extendable application for managing a blog within your Django Web site. Zinnia has been made for pub

Julien Fache 2.1k Dec 24, 2022
A simple trivia quizzz web app made using django

Trivia Quizzz A simple trivia quizzz web app made using django Demo http://triviaquizzz.herokuapp.com/ & https://triviaquiz.redcrypt.xyz Features Goog

Rachit Khurana 2 Feb 10, 2022
PWA is a simple Django app to develope and deploy a Progressive Web Application.

PWA PWA is a simple Django app to develope and deploy a Progressive Web Application. Detailed documentation is in the "docs" directory. Quick start Ad

Nima 6 Dec 9, 2022