From 64ba65cc5c866c56d8237cf019fd362ec02f8f10 Mon Sep 17 00:00:00 2001 From: Andy Dirnberger Date: Mon, 12 Oct 2020 11:56:46 -0400 Subject: [PATCH] Switch to mypy This is a work-in-progress attempt at switching over to mypy as part of #85. There's still some work to be done (e.g. mypy ignore comments need to be added where appropriate) and I'm currently working with some local changes pyre's stubs, but I wanted to track the work being done. --- src/.coveragerc => .coveragerc | 2 +- .editorconfig | 4 --- .flake8 | 17 +----------- README.rst | 4 +-- .../applications => applications}/__init__.py | 0 {src/applications => applications}/admin.py | 0 {src/applications => applications}/apps.py | 0 {src/applications => applications}/forms.py | 26 +++---------------- .../migrations/0001_initial.py | 0 .../migrations/0002_application_type.py | 0 .../migrations/0003_auto_20200507_0125.py | 1 - .../migrations/__init__.py | 0 {src/applications => applications}/models.py | 9 ------- .../templates/applications/form.html | 0 .../templates/applications/view.html | 0 .../test_forms.py | 1 - .../test_views.py | 11 ++------ {src/applications => applications}/tests.py | 0 {src/applications => applications}/urls.py | 4 --- {src/applications => applications}/views.py | 0 {src/awards => awards}/__init__.py | 0 {src/awards => awards}/asgi.py | 0 {src/awards => awards}/settings/__init__.py | 0 {src/awards => awards}/settings/base.py | 9 ++++--- {src/awards => awards}/settings/ci.py | 0 {src/awards => awards}/settings/dev.py | 0 {src/awards => awards}/settings/prod.py | 2 +- {src/awards => awards}/templates/base.html | 0 {src/awards => awards}/urls.py | 11 +------- {src/awards => awards}/wsgi.py | 0 conftest.py | 5 ++++ {src/homepage => homepage}/__init__.py | 0 {src/homepage => homepage}/apps.py | 0 .../templates/homepage/index.html | 0 {src/homepage => homepage}/test_views.py | 7 ++--- src/manage.py => manage.py | 0 mypy.ini | 10 +++++++ src/.pyre_configuration | 12 --------- src/.watchmanconfig | 1 - src/conftest.py | 7 ----- tox.ini | 7 +++-- {src/users => users}/__init__.py | 0 {src/users => users}/admin.py | 0 {src/users => users}/apps.py | 0 {src/users => users}/forms.py | 1 - .../migrations/0001_initial.py | 4 +-- .../migrations/0002_user_is_admin.py | 0 {src/users => users}/migrations/__init__.py | 0 {src/users => users}/models.py | 13 +++------- .../templates/users/login.html | 0 .../templates/users/profile.html | 0 {src/users => users}/test_models.py | 1 - {src/users => users}/test_views.py | 3 --- {src/users => users}/urls.py | 1 - {src/users => users}/views.py | 3 +-- 55 files changed, 43 insertions(+), 133 deletions(-) rename src/.coveragerc => .coveragerc (75%) rename {src/applications => applications}/__init__.py (100%) rename {src/applications => applications}/admin.py (100%) rename {src/applications => applications}/apps.py (100%) rename {src/applications => applications}/forms.py (62%) rename {src/applications => applications}/migrations/0001_initial.py (100%) rename {src/applications => applications}/migrations/0002_application_type.py (100%) rename {src/applications => applications}/migrations/0003_auto_20200507_0125.py (86%) rename {src/applications => applications}/migrations/__init__.py (100%) rename {src/applications => applications}/models.py (58%) rename {src/applications => applications}/templates/applications/form.html (100%) rename {src/applications => applications}/templates/applications/view.html (100%) rename {src/applications => applications}/test_forms.py (93%) rename {src/applications => applications}/test_views.py (77%) rename {src/applications => applications}/tests.py (100%) rename {src/applications => applications}/urls.py (60%) rename {src/applications => applications}/views.py (100%) rename {src/awards => awards}/__init__.py (100%) rename {src/awards => awards}/asgi.py (100%) rename {src/awards => awards}/settings/__init__.py (100%) rename {src/awards => awards}/settings/base.py (94%) rename {src/awards => awards}/settings/ci.py (100%) rename {src/awards => awards}/settings/dev.py (100%) rename {src/awards => awards}/settings/prod.py (90%) rename {src/awards => awards}/templates/base.html (100%) rename {src/awards => awards}/urls.py (56%) rename {src/awards => awards}/wsgi.py (100%) create mode 100644 conftest.py rename {src/homepage => homepage}/__init__.py (100%) rename {src/homepage => homepage}/apps.py (100%) rename {src/homepage => homepage}/templates/homepage/index.html (100%) rename {src/homepage => homepage}/test_views.py (67%) rename src/manage.py => manage.py (100%) create mode 100644 mypy.ini delete mode 100644 src/.pyre_configuration delete mode 100644 src/.watchmanconfig delete mode 100644 src/conftest.py rename {src/users => users}/__init__.py (100%) rename {src/users => users}/admin.py (100%) rename {src/users => users}/apps.py (100%) rename {src/users => users}/forms.py (70%) rename {src/users => users}/migrations/0001_initial.py (88%) rename {src/users => users}/migrations/0002_user_is_admin.py (100%) rename {src/users => users}/migrations/__init__.py (100%) rename {src/users => users}/models.py (65%) rename {src/users => users}/templates/users/login.html (100%) rename {src/users => users}/templates/users/profile.html (100%) rename {src/users => users}/test_models.py (90%) rename {src/users => users}/test_views.py (71%) rename {src/users => users}/urls.py (62%) rename {src/users => users}/views.py (92%) diff --git a/src/.coveragerc b/.coveragerc similarity index 75% rename from src/.coveragerc rename to .coveragerc index 1e9e529..9a676a4 100644 --- a/src/.coveragerc +++ b/.coveragerc @@ -5,4 +5,4 @@ omit = [run] branch = true -data_file = ../.coverage +data_file = .coverage diff --git a/.editorconfig b/.editorconfig index ca6ce40..e0d5985 100644 --- a/.editorconfig +++ b/.editorconfig @@ -31,10 +31,6 @@ force_sort_within_sections = true include_trailing_comma = true multi_line_output = 3 -[.pyre_configuration] -indent_size = 2 -indent_style = space - [*.rst] indent_size = 4 indent_style = space diff --git a/.flake8 b/.flake8 index 59125dd..56264b1 100644 --- a/.flake8 +++ b/.flake8 @@ -4,20 +4,5 @@ ignore = E203, E231, E266, E501, W503 max-line-length = 80 max-complexity = 18 per-file-ignores = - src/awards/settings/dev.py: F405 - # TODO: Remove these once - # https://github.com/facebook/pyre-check/pull/256, - # https://github.com/facebook/pyre-check/pull/260, - # https://github.com/facebook/pyre-check/pull/261, and - # https://github.com/facebook/pyre-check/pull/262 can be used. - src/applications/forms.py: B950 - src/applications/migrations/0003_auto_20200507_0125.py: B950 - src/applications/models.py: B950 - src/applications/test_views.py: B950 - src/awards/urls.py: B950 - src/homepage/test_views.py: B950 - src/users/migrations/0001_initial.py: B950 - src/users/forms.py: B950 - src/users/models.py: B950 - src/users/views.py: B950 + awards/settings/dev.py: F405 select = B,C,E,F,W,T4,B9 diff --git a/README.rst b/README.rst index 66022e5..a030788 100644 --- a/README.rst +++ b/README.rst @@ -70,7 +70,7 @@ environment. It can be output without running the unit tests with:: Type checks ----------- -The type checks are done using pyre_ and can be run with:: +The type checks are done using Mypy_ and can be run with:: $ tox -e types @@ -128,9 +128,9 @@ will be removed from the repository. .. _citext: https://www.postgresql.org/docs/current/citext.html .. _Hacktoberfest: https://hacktoberfest.digitalocean.com .. _ipython: https://ipython.readthedocs.io +.. _Mypy: https://mypy.readthedocs.io .. _PostgreSQL: https://www.postgresql.org .. _psql: https://www.postgresql.org/docs/current/app-psql.html -.. _pyre: https://pyre-check.org .. _tox: https://tox.readthedocs.io .. _watchman: https://facebook.github.io/watchman/ diff --git a/src/applications/__init__.py b/applications/__init__.py similarity index 100% rename from src/applications/__init__.py rename to applications/__init__.py diff --git a/src/applications/admin.py b/applications/admin.py similarity index 100% rename from src/applications/admin.py rename to applications/admin.py diff --git a/src/applications/apps.py b/applications/apps.py similarity index 100% rename from src/applications/apps.py rename to applications/apps.py diff --git a/src/applications/forms.py b/applications/forms.py similarity index 62% rename from src/applications/forms.py rename to applications/forms.py index f067156..6fdf434 100644 --- a/src/applications/forms.py +++ b/applications/forms.py @@ -17,7 +17,6 @@ class FinancialAidApplicationForm(ApplicationForm): type = Application.Type.FINANCIAL_AID travel_requested = forms.BooleanField( - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. label=_("Do you need assistance with travel?"), required=False, ) @@ -32,13 +31,9 @@ class Meta: "lodging_requested", ) labels = { - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. "background": _("Tell us a little bit more about yourself"), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. "lodging_requested": _("Do you need assistance with lodging?"), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. "reason_to_attend": _("Why are you interested in attending PyGotham?"), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. "travel_amount": _("What is the estimated cost (USD)?"), } widgets = { @@ -51,12 +46,7 @@ def clean(self) -> Dict[str, Any]: travel_amount = cleaned_data.get("travel_amount") or 0 if travel_amount < 0: raise forms.ValidationError( - { - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. - "travel_amount": _( - "Your estimated travel costs cannot be negative." - ) - } + {"travel_amount": _("Your estimated travel costs cannot be negative.")} ) travel_requested = cleaned_data.get("travel_requested") @@ -64,26 +54,20 @@ def clean(self) -> Dict[str, Any]: if not travel_amount: raise forms.ValidationError( { - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. "travel_amount": _( "Your estimated travel costs must be greater than $0.00." ) } ) elif travel_amount: - raise forms.ValidationError( - { - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. - "travel_requested": _( - "You must request travel assistance before providing an estimated cost." - ) - } + msg = _( + "You must request travel assistance before providing an estimated cost." ) + raise forms.ValidationError({"travel_requested": msg}) return cleaned_data def clean_lodging_requested(self) -> bool: - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/261. return bool(self.cleaned_data.get("lodging_requested")) @@ -94,9 +78,7 @@ class Meta: model = Application fields = ("background", "reason_to_attend") labels = { - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. "background": _("Tell us a little bit about yourself"), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. "reason_to_attend": _("Why are you interested in attending PyGotham?"), } diff --git a/src/applications/migrations/0001_initial.py b/applications/migrations/0001_initial.py similarity index 100% rename from src/applications/migrations/0001_initial.py rename to applications/migrations/0001_initial.py diff --git a/src/applications/migrations/0002_application_type.py b/applications/migrations/0002_application_type.py similarity index 100% rename from src/applications/migrations/0002_application_type.py rename to applications/migrations/0002_application_type.py diff --git a/src/applications/migrations/0003_auto_20200507_0125.py b/applications/migrations/0003_auto_20200507_0125.py similarity index 86% rename from src/applications/migrations/0003_auto_20200507_0125.py rename to applications/migrations/0003_auto_20200507_0125.py index 0284654..6a47770 100644 --- a/src/applications/migrations/0003_auto_20200507_0125.py +++ b/applications/migrations/0003_auto_20200507_0125.py @@ -18,7 +18,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="application", name="travel_amount", - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/260. field=models.DecimalField( blank=True, decimal_places=2, max_digits=10, null=True ), diff --git a/src/applications/migrations/__init__.py b/applications/migrations/__init__.py similarity index 100% rename from src/applications/migrations/__init__.py rename to applications/migrations/__init__.py diff --git a/src/applications/models.py b/applications/models.py similarity index 58% rename from src/applications/models.py rename to applications/models.py index cec730d..cb05d8c 100644 --- a/src/applications/models.py +++ b/applications/models.py @@ -4,44 +4,35 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -# pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. User = get_user_model() class Application(models.Model): - # pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. class Status(models.TextChoices): PENDING = "pending" - # pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. class Type(models.TextChoices): FINANCIAL_AID = "finaid" SCHOLARSHIP = "scholarship" - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. applicant = models.ForeignKey(User, on_delete=models.DO_NOTHING) background = models.TextField(_("applicant background")) reason_to_attend = models.TextField(_("reason the applicant wishes to attend")) status = models.CharField( max_length=20, - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. choices=Status.choices, default=Status.PENDING, ) type = models.CharField( max_length=11, - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. choices=Type.choices, default=Type.SCHOLARSHIP, ) - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/260. travel_amount = models.DecimalField( max_digits=10, decimal_places=2, blank=True, null=True ) lodging_requested = models.BooleanField(null=True) def __str__(self) -> str: - # pyre-ignore[19]: This is fixed by https://github.com/facebook/pyre-check/pull/256. type_ = Application.Type(self.type) - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. return f"{type_.label} application for {self.applicant}" diff --git a/src/applications/templates/applications/form.html b/applications/templates/applications/form.html similarity index 100% rename from src/applications/templates/applications/form.html rename to applications/templates/applications/form.html diff --git a/src/applications/templates/applications/view.html b/applications/templates/applications/view.html similarity index 100% rename from src/applications/templates/applications/view.html rename to applications/templates/applications/view.html diff --git a/src/applications/test_forms.py b/applications/test_forms.py similarity index 93% rename from src/applications/test_forms.py rename to applications/test_forms.py index c048ba4..ed07642 100644 --- a/src/applications/test_forms.py +++ b/applications/test_forms.py @@ -6,7 +6,6 @@ def test_financial_aid_lodging_requested_is_treated_as_boolean() -> None: form = FinancialAidApplicationForm(other_fields) assert form.is_valid() - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/261. assert form.cleaned_data["lodging_requested"] is False diff --git a/src/applications/test_views.py b/applications/test_views.py similarity index 77% rename from src/applications/test_views.py rename to applications/test_views.py index 0f138b1..45ab5be 100644 --- a/src/applications/test_views.py +++ b/applications/test_views.py @@ -3,15 +3,14 @@ from django.contrib.auth import get_user_model from django.http import Http404, HttpRequest from django.test import Client -from factory.django import DjangoModelFactory +from factory.django import DjangoModelFactory # type: ignore[import] import pytest -from sesame.utils import get_query_string +from sesame.utils import get_query_string # type: ignore[import] from applications.models import Application from applications.views import apply -# pyre-ignore[13]: Investigate type stubs for factory-boy. class ApplicationFactory(DjangoModelFactory): class Meta: model = Application @@ -24,7 +23,6 @@ class Meta: class UserFactory(DjangoModelFactory): class Meta: - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. model = get_user_model() django_get_or_create = ("email",) @@ -32,7 +30,6 @@ class Meta: @pytest.mark.django_db -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. def test_that_one_of_form_type_and_pk_is_required_by_apply(client: Client) -> None: user = UserFactory() qs = get_query_string(user) @@ -40,13 +37,11 @@ def test_that_one_of_form_type_and_pk_is_required_by_apply(client: Client) -> No request = HttpRequest() request.user = user - # pyre-ignore[16]: pyre doesn't think ExceptionInfo as an __enter__. with pytest.raises(Http404): apply(request, form_type=None, pk=None) @pytest.mark.django_db -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. def test_user_can_edit_their_application(client: Client) -> None: user = UserFactory() qs = get_query_string(user) @@ -67,7 +62,6 @@ def test_user_can_edit_their_application(client: Client) -> None: @pytest.mark.django_db -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. def test_user_can_view_their_application(client: Client) -> None: user = UserFactory() qs = get_query_string(user) @@ -80,7 +74,6 @@ def test_user_can_view_their_application(client: Client) -> None: @pytest.mark.django_db -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. def test_user_cant_view_someone_elses_application(client: Client) -> None: user = UserFactory() other = UserFactory(email=f"other+{user.email}") diff --git a/src/applications/tests.py b/applications/tests.py similarity index 100% rename from src/applications/tests.py rename to applications/tests.py diff --git a/src/applications/urls.py b/applications/urls.py similarity index 60% rename from src/applications/urls.py rename to applications/urls.py index 0dcc925..6bc01c5 100644 --- a/src/applications/urls.py +++ b/applications/urls.py @@ -9,19 +9,15 @@ app_name = "applications" urlpatterns = [ - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("edit/", apply, name="edit"), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path( "financial-aid", apply, {"form_type": FinancialAidApplicationForm}, name="financial_aid", ), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path( "ticket", apply, {"form_type": ScholarshipApplicationForm}, name="scholarship" ), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("view/", view, name="view"), ] diff --git a/src/applications/views.py b/applications/views.py similarity index 100% rename from src/applications/views.py rename to applications/views.py diff --git a/src/awards/__init__.py b/awards/__init__.py similarity index 100% rename from src/awards/__init__.py rename to awards/__init__.py diff --git a/src/awards/asgi.py b/awards/asgi.py similarity index 100% rename from src/awards/asgi.py rename to awards/asgi.py diff --git a/src/awards/settings/__init__.py b/awards/settings/__init__.py similarity index 100% rename from src/awards/settings/__init__.py rename to awards/settings/__init__.py diff --git a/src/awards/settings/base.py b/awards/settings/base.py similarity index 94% rename from src/awards/settings/base.py rename to awards/settings/base.py index bcbf564..8e7b259 100644 --- a/src/awards/settings/base.py +++ b/awards/settings/base.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import os +from typing import List -from decouple import config +from decouple import config # type: ignore[import] # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -9,7 +12,7 @@ # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ -ALLOWED_HOSTS = [] +ALLOWED_HOSTS: List[str] = [] # Application definition @@ -77,7 +80,7 @@ # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators # Password-based login isn't supported. -AUTH_PASSWORD_VALIDATORS = [] +AUTH_PASSWORD_VALIDATORS: List[str] = [] AUTH_USER_MODEL = "users.User" diff --git a/src/awards/settings/ci.py b/awards/settings/ci.py similarity index 100% rename from src/awards/settings/ci.py rename to awards/settings/ci.py diff --git a/src/awards/settings/dev.py b/awards/settings/dev.py similarity index 100% rename from src/awards/settings/dev.py rename to awards/settings/dev.py diff --git a/src/awards/settings/prod.py b/awards/settings/prod.py similarity index 90% rename from src/awards/settings/prod.py rename to awards/settings/prod.py index 8b0c319..e36a336 100644 --- a/src/awards/settings/prod.py +++ b/awards/settings/prod.py @@ -1,4 +1,4 @@ -from decouple import config +from decouple import config # type: ignore[import] from awards.settings.base import * # NOQA diff --git a/src/awards/templates/base.html b/awards/templates/base.html similarity index 100% rename from src/awards/templates/base.html rename to awards/templates/base.html diff --git a/src/awards/urls.py b/awards/urls.py similarity index 56% rename from src/awards/urls.py rename to awards/urls.py index a7ec1cb..2542623 100644 --- a/src/awards/urls.py +++ b/awards/urls.py @@ -7,36 +7,27 @@ from users.views import login, magic_login urlpatterns = [ - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path( "", TemplateView.as_view(template_name="homepage/index.html"), name="homepage" ), # pyre doesn't include stubs for the Django admin. - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path( "admin/login/", RedirectView.as_view( pattern_name=settings.LOGIN_URL, permanent=True, query_string=True ), ), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("admin/", admin.site.urls), # type: ignore - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("apply/", include("applications.urls", namespace="applications")), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("login", login, name="login"), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("login/magic", magic_login, name="magic-login"), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("logout", LogoutView.as_view(), name="logout"), - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("users/", include("users.urls", namespace="users")), ] if settings.DEBUG: - import debug_toolbar + import debug_toolbar # type: ignore[import] urlpatterns = [ - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("__debug__/", include(debug_toolbar.urls)), ] + urlpatterns diff --git a/src/awards/wsgi.py b/awards/wsgi.py similarity index 100% rename from src/awards/wsgi.py rename to awards/wsgi.py diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..0d6bfec --- /dev/null +++ b/conftest.py @@ -0,0 +1,5 @@ +from django.test import Client + + +def client() -> Client: + return Client() diff --git a/src/homepage/__init__.py b/homepage/__init__.py similarity index 100% rename from src/homepage/__init__.py rename to homepage/__init__.py diff --git a/src/homepage/apps.py b/homepage/apps.py similarity index 100% rename from src/homepage/apps.py rename to homepage/apps.py diff --git a/src/homepage/templates/homepage/index.html b/homepage/templates/homepage/index.html similarity index 100% rename from src/homepage/templates/homepage/index.html rename to homepage/templates/homepage/index.html diff --git a/src/homepage/test_views.py b/homepage/test_views.py similarity index 67% rename from src/homepage/test_views.py rename to homepage/test_views.py index 645c45a..b5c7c2a 100644 --- a/src/homepage/test_views.py +++ b/homepage/test_views.py @@ -2,14 +2,13 @@ from django.contrib.auth import get_user_model from django.test import Client -from factory.django import DjangoModelFactory +from factory.django import DjangoModelFactory # type: ignore[import] import pytest -from sesame.utils import get_query_string +from sesame.utils import get_query_string # type: ignore[import] class UserFactory(DjangoModelFactory): class Meta: - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. model = get_user_model() django_get_or_create = ("email",) @@ -17,7 +16,6 @@ class Meta: @pytest.mark.django_db -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. def test_login_link_is_not_shown_to_logged_in_users(client: Client) -> None: user = UserFactory() qs = get_query_string(user) @@ -27,7 +25,6 @@ def test_login_link_is_not_shown_to_logged_in_users(client: Client) -> None: assert b"log in" not in response.content.lower() -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. def test_login_link_is_shown_to_guests(client: Client) -> None: response = client.get("/") assert b"log in" in response.content.lower() diff --git a/src/manage.py b/manage.py similarity index 100% rename from src/manage.py rename to manage.py diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..2c92b15 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,10 @@ +[mypy] +files = . +mypy_path = ../.tox/types/lib/pyre_check/stubs + +; pyre overrides some Django imports but doesn't seem to include stubs for them. +; The reasoning is hidden inside Facebook's internal instance of Phabricator +; (see https://github.com/facebook/pyre-check/pull/223). This will silence the +; error(s) about this that mypy reports. +[mypy-util.asyncio.*] +ignore_missing_imports = True diff --git a/src/.pyre_configuration b/src/.pyre_configuration deleted file mode 100644 index 669973e..0000000 --- a/src/.pyre_configuration +++ /dev/null @@ -1,12 +0,0 @@ -{ - "binary": "../.tox/types/bin/pyre.bin", - "search_path": [ - "../.tox/types/lib/pyre_check/stubs", - "../.tox/types/lib/python3.9/site-packages" - ], - "source_directories": [ - "." - ], - "taint_models_path": "../.tox/types/lib/pyre_check/taint/", - "typeshed": "../.tox/types/lib/pyre_check/typeshed/" -} diff --git a/src/.watchmanconfig b/src/.watchmanconfig deleted file mode 100644 index 0967ef4..0000000 --- a/src/.watchmanconfig +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/src/conftest.py b/src/conftest.py deleted file mode 100644 index 76393b0..0000000 --- a/src/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.test import Client - - -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. -def client() -> Client: - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. - return Client() diff --git a/tox.ini b/tox.ini index 2cbeb60..90baaab 100644 --- a/tox.ini +++ b/tox.ini @@ -15,8 +15,6 @@ setenv = DATABASE_USER = {env:DATABASE_USER:postgres} DJANGO_SETTINGS_MODULE = awards.settings.dev unit: DJANGO_SETTINGS_MODULE = awards.settings.ci -changedir = - {toxinidir}/src [testenv:createsuperuser] commands = @@ -70,11 +68,12 @@ commands = [testenv:types] deps = factory-boy==3.0.1 - pyre-check==0.0.46 + mypy + pyre-check==0.0.58 pytest {[testenv]deps} commands = - pyre {posargs} + mypy {posargs} [testenv:unit] deps = diff --git a/src/users/__init__.py b/users/__init__.py similarity index 100% rename from src/users/__init__.py rename to users/__init__.py diff --git a/src/users/admin.py b/users/admin.py similarity index 100% rename from src/users/admin.py rename to users/admin.py diff --git a/src/users/apps.py b/users/apps.py similarity index 100% rename from src/users/apps.py rename to users/apps.py diff --git a/src/users/forms.py b/users/forms.py similarity index 70% rename from src/users/forms.py rename to users/forms.py index edc81fe..76411a9 100644 --- a/src/users/forms.py +++ b/users/forms.py @@ -4,6 +4,5 @@ class LoginForm(forms.Form): email = forms.EmailField( - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/262. widget=forms.EmailInput(attrs={"placeholder": _("Email address")}) ) diff --git a/src/users/migrations/0001_initial.py b/users/migrations/0001_initial.py similarity index 88% rename from src/users/migrations/0001_initial.py rename to users/migrations/0001_initial.py index d194f7c..6718f62 100644 --- a/src/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -9,7 +9,7 @@ class Migration(migrations.Migration): initial = True # type: ignore - dependencies = [] + dependencies = [] # type: ignore operations = [ migrations.RunSQL( @@ -41,7 +41,6 @@ class Migration(migrations.Migration): ), ( "email", - # pyre-ignore[28]: This is fixed by https://github.com/facebook/pyre-check/pull/256. django.contrib.postgres.fields.citext.CIEmailField( max_length=254, unique=True, verbose_name="email address" ), @@ -49,7 +48,6 @@ class Migration(migrations.Migration): ( "date_joined", models.DateTimeField( - # pyre-ignore[6]: This is fixed by https://github.com/facebook/pyre-check/pull/256. default=django.utils.timezone.now, verbose_name="date joined", ), diff --git a/src/users/migrations/0002_user_is_admin.py b/users/migrations/0002_user_is_admin.py similarity index 100% rename from src/users/migrations/0002_user_is_admin.py rename to users/migrations/0002_user_is_admin.py diff --git a/src/users/migrations/__init__.py b/users/migrations/__init__.py similarity index 100% rename from src/users/migrations/__init__.py rename to users/migrations/__init__.py diff --git a/src/users/models.py b/users/models.py similarity index 65% rename from src/users/models.py rename to users/models.py index 0ba2d12..d57f9bf 100644 --- a/src/users/models.py +++ b/users/models.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing import List + from django.contrib.auth.models import AbstractBaseUser, BaseUserManager from django.contrib.postgres.fields import CIEmailField from django.db import models @@ -7,44 +9,35 @@ from django.utils.translation import ugettext_lazy as _ -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/272. class UserManager(BaseUserManager): def create_user(self, email: str, password: str) -> User: - # pyre-ignore[28]: This is fixed by https://github.com/facebook/pyre-check/pull/256. user = User(email=email) - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. user.save() return user def create_superuser(self, email: str, password: str) -> User: - # pyre-ignore[28]: This is fixed by https://github.com/facebook/pyre-check/pull/256. user = User(email=email, is_staff=True) - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. user.save() return user -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. class User(AbstractBaseUser): - # pyre-ignore[28]: This is fixed by https://github.com/facebook/pyre-check/pull/256. email = CIEmailField(_("email address"), unique=True) # Blank passwords are allowed since we only allow applicants to use # magic links to log in. password = models.CharField(_("password"), max_length=128, blank=True) - # pyre-ignore[6]: This is fixed by https://github.com/facebook/pyre-check/pull/256. date_joined = models.DateTimeField(_("date joined"), default=timezone.now) is_staff = models.BooleanField(_("user can access the admin"), default=False) USERNAME_FIELD = "email" - REQUIRED_FIELDS = [] + REQUIRED_FIELDS = [] # type: List[str] objects = UserManager() is_active = True def __str__(self) -> str: - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. username, domain = self.email.split("@", 1) # Hide the characters in the username other than the first one. diff --git a/src/users/templates/users/login.html b/users/templates/users/login.html similarity index 100% rename from src/users/templates/users/login.html rename to users/templates/users/login.html diff --git a/src/users/templates/users/profile.html b/users/templates/users/profile.html similarity index 100% rename from src/users/templates/users/profile.html rename to users/templates/users/profile.html diff --git a/src/users/test_models.py b/users/test_models.py similarity index 90% rename from src/users/test_models.py rename to users/test_models.py index a60ae52..7b35b96 100644 --- a/src/users/test_models.py +++ b/users/test_models.py @@ -6,7 +6,6 @@ pytestmark = pytest.mark.django_db -# pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. User = get_user_model() diff --git a/src/users/test_views.py b/users/test_views.py similarity index 71% rename from src/users/test_views.py rename to users/test_views.py index a7615f3..ff4950f 100644 --- a/src/users/test_views.py +++ b/users/test_views.py @@ -6,19 +6,16 @@ TEST_EMAIL = "user@example.org" -# pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. User = get_user_model() @pytest.mark.django_db -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. def test_login_creates_new_user(client: Client) -> None: assert not User.objects.filter(email=TEST_EMAIL) client.post("/login", {"email": TEST_EMAIL}) assert User.objects.get(email=TEST_EMAIL) -# pyre-ignore[11]: This is fixed by https://github.com/facebook/pyre-check/pull/256. def test_login_requires_email(client: Client) -> None: response = client.post("/login") assert response.status_code not in (301, 302) diff --git a/src/users/urls.py b/users/urls.py similarity index 62% rename from src/users/urls.py rename to users/urls.py index 27449f9..6eeb8a8 100644 --- a/src/users/urls.py +++ b/users/urls.py @@ -5,6 +5,5 @@ app_name = "users" urlpatterns = [ - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. path("profile", profile, name="profile"), ] diff --git a/src/users/views.py b/users/views.py similarity index 92% rename from src/users/views.py rename to users/views.py index a7b0af4..c03d1e2 100644 --- a/src/users/views.py +++ b/users/views.py @@ -7,7 +7,7 @@ from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect, render from django.urls import reverse -from sesame.utils import get_query_string, get_user +from sesame.utils import get_query_string, get_user # type: ignore[import] from applications.models import Application from users.forms import LoginForm @@ -15,7 +15,6 @@ def login(request: HttpRequest) -> HttpResponse: if request.method == "POST": - # pyre-ignore[16]: This is fixed by https://github.com/facebook/pyre-check/pull/256. User = get_user_model() form = LoginForm(request.POST)