Skip to content

Commit

Permalink
Add type hints for tests
Browse files Browse the repository at this point in the history
* mkinit is used to generate `__init__.py` files, removing use of `import *`
* funnel.models uses lazy_loader to defer resolution of circular imports and supplies a `.pyi` file for static type checkers to resolve symbols
* `tests/unit/utils/markdown` had to be renamed because adding `__init__.py` somehow caused Pytest to insert it as a top-level package, overriding the `markdown` package
  • Loading branch information
jace committed Jan 8, 2024
1 parent 642de9a commit 02cf833
Show file tree
Hide file tree
Showing 124 changed files with 2,731 additions and 944 deletions.
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ geckodriver.log
tests/cypress/screenshots
tests/cypress/videos
tests/screenshots
tests/unit/utils/markdown/data/output.html
tests/unit/utils/md/data/output.html
coverage/

# Instance files that should not be checked-in
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ geckodriver.log
tests/cypress/screenshots
tests/cypress/videos
tests/screenshots
tests/unit/utils/markdown/data/output.html
tests/unit/utils/md/data/output.html

# Instance files that should not be checked-in
instance/development.py
Expand Down
5 changes: 4 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ repos:
rev: 7.0.0
hooks:
- id: flake8
additional_dependencies: *flake8deps
name: flake8-pyi
types: [pyi]
additional_dependencies:
- flake8-pyi
- repo: https://github.com/PyCQA/pylint
rev: v3.0.3
hooks:
Expand Down
44 changes: 44 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
ifeq ($(shell test -d .venv/bin && echo 1 || echo 0), 1)
export PATH := .venv/bin:$(PATH)
endif

all:
@echo "You must have an active Python virtualenv (3.11+) before using any of these."
@echo
@echo "For production deployment:"
@echo
@echo " make install # For first time setup and after dependency upgrades"
@echo " make assets # For only Node asset changes"
@echo
@echo "For testing and CI:"
@echo
@echo " make install-test # Install everything needed for a test environment"
@echo " make install-playwright # Install browsers for Playwright-based tests"
@echo
@echo "For development:"
@echo
@echo " make install-dev # For first time setup and after dependency upgrades"
@echo " make deps-noup # Rebuild for dependency changes, but skip upgrades"
@echo " make deps # Scan for dependency upgrades (remember to test!)"
@echo " make deps-python # Scan for Python dependency upgrades"
@echo " make deps-npm # Scan for NPM dependency upgrades"
@echo
@echo "To export a new symbol from any Python file, regenerate '__init__.py' files:"
@echo
@echo " make initpy"
@echo
@echo "After editing any UI strings, regenerate Babel translation databases:"
@echo
@echo " make babel"
@echo
@echo "To upgrade dependencies in a development environment, use all in order and"
@echo "commit changes only if all tests pass:"
@echo
Expand Down Expand Up @@ -101,6 +116,35 @@ deps-noup: deps-python-noup

deps: deps-python deps-npm

initpy: initpy-models initpy-forms initpy-loginproviders initpy-transports initpy-utils

initpy-models:
mkinit --inplace --relative --black --lazy_loader_typed funnel/models/__init__.py
isort funnel/models/__init__.py funnel/models/__init__.pyi
black funnel/models/__init__.py funnel/models/__init__.pyi

initpy-forms:
mkinit --inplace --relative --black funnel/forms/__init__.py
isort funnel/forms/__init__.py
black funnel/forms/__init__.py

initpy-loginproviders:
mkinit --inplace --relative --black funnel/loginproviders/__init__.py
isort funnel/loginproviders/__init__.py
black funnel/loginproviders/__init__.py

initpy-transports:
# Do not auto-gen funnel/transports/__init__.py, only sub-packages
mkinit --inplace --relative --black funnel/transports/email
mkinit --inplace --relative --black funnel/transports/sms
isort funnel/transports/*/__init__.py
black funnel/transports/*/__init__.py

initpy-utils:
mkinit --inplace --relative --black --recursive funnel/utils
isort funnel/utils/__init__.py funnel/utils/*/__init__.py funnel/utils/*/*/__init__.py
black funnel/utils/__init__.py funnel/utils/*/__init__.py funnel/utils/*/*/__init__.py

install-npm:
npm install

Expand Down
266 changes: 248 additions & 18 deletions funnel/forms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,251 @@
"""Forms provide an interface between views and models, validating data before save."""
# flake8: noqa

from __future__ import annotations
# --- Everything below this line is auto-generated using `make initpy` -----------------

from .account import *
from .auth_client import *
from .comment import *
from .helpers import *
from .label import *
from .login import *
from .membership import *
from .notification import *
from .organization import *
from .profile import *
from .project import *
from .proposal import *
from .session import *
from .sync_ticket import *
from .update import *
from .venue import *
from . import (
account,
auth_client,
comment,
helpers,
label,
login,
membership,
notification,
organization,
profile,
project,
proposal,
session,
sync_ticket,
update,
venue,
)
from .account import (
AccountDeleteForm,
AccountForm,
EmailPrimaryForm,
ModeratorReportForm,
NewEmailAddressForm,
NewPhoneForm,
PasswordChangeForm,
PasswordCreateForm,
PasswordForm,
PasswordPolicyForm,
PasswordResetForm,
PasswordResetRequestForm,
PhonePrimaryForm,
UsernameAvailableForm,
pwned_password_validator,
supported_locales,
timezone_identifiers,
)
from .auth_client import (
AuthClientCredentialForm,
AuthClientForm,
AuthClientPermissionEditForm,
UserPermissionAssignForm,
)
from .comment import CommentForm, CommentsetSubscribeForm
from .helpers import (
MSG_EMAIL_BLOCKED,
MSG_EMAIL_INVALID,
MSG_INCORRECT_OTP,
MSG_INCORRECT_PASSWORD,
MSG_NO_ACCOUNT,
MSG_NO_LOGIN_SESSION,
MSG_PHONE_BLOCKED,
MSG_PHONE_NO_SMS,
AccountSelectField,
EmailAddressAvailable,
PhoneNumberAvailable,
format_json,
image_url_validator,
nullable_json_filters,
nullable_strip_filters,
strip_filters,
tostr,
validate_and_convert_json,
video_url_list_validator,
video_url_validator,
)
from .label import LabelForm, LabelOptionForm
from .login import (
EmailOtpForm,
LoginForm,
LoginPasswordResetException,
LoginPasswordWeakException,
LoginWithOtp,
LogoutForm,
OtpForm,
RegisterOtpForm,
RegisterWithOtp,
)
from .membership import (
OrganizationMembershipForm,
ProjectCrewMembershipForm,
ProjectCrewMembershipInviteForm,
)
from .notification import (
SetNotificationPreferenceForm,
UnsubscribeForm,
transport_labels,
)
from .organization import OrganizationForm, TeamForm
from .profile import (
ProfileBannerForm,
ProfileForm,
ProfileLogoForm,
ProfileTransitionForm,
)
from .project import (
CfpForm,
ProjectBannerForm,
ProjectCfpTransitionForm,
ProjectFeaturedForm,
ProjectForm,
ProjectLivestreamForm,
ProjectNameForm,
ProjectRegisterForm,
ProjectSponsorForm,
ProjectTransitionForm,
RsvpTransitionForm,
SavedProjectForm,
)
from .proposal import (
ProposalFeaturedForm,
ProposalForm,
ProposalLabelsAdminForm,
ProposalLabelsForm,
ProposalMemberForm,
ProposalMoveForm,
ProposalTransitionForm,
)
from .session import SavedSessionForm, SessionForm
from .sync_ticket import (
FORM_SCHEMA_PLACEHOLDER,
ProjectBoxofficeForm,
TicketClientForm,
TicketEventForm,
TicketParticipantBadgeForm,
TicketParticipantForm,
TicketTypeForm,
)
from .update import UpdateForm
from .venue import VenueForm, VenuePrimaryForm, VenueRoomForm

__all__ = [
"AccountDeleteForm",
"AccountForm",
"AccountSelectField",
"AuthClientCredentialForm",
"AuthClientForm",
"AuthClientPermissionEditForm",
"CfpForm",
"CommentForm",
"CommentsetSubscribeForm",
"EmailAddressAvailable",
"EmailOtpForm",
"EmailPrimaryForm",
"FORM_SCHEMA_PLACEHOLDER",
"LabelForm",
"LabelOptionForm",
"LoginForm",
"LoginPasswordResetException",
"LoginPasswordWeakException",
"LoginWithOtp",
"LogoutForm",
"MSG_EMAIL_BLOCKED",
"MSG_EMAIL_INVALID",
"MSG_INCORRECT_OTP",
"MSG_INCORRECT_PASSWORD",
"MSG_NO_ACCOUNT",
"MSG_NO_LOGIN_SESSION",
"MSG_PHONE_BLOCKED",
"MSG_PHONE_NO_SMS",
"ModeratorReportForm",
"NewEmailAddressForm",
"NewPhoneForm",
"OrganizationForm",
"OrganizationMembershipForm",
"OtpForm",
"PasswordChangeForm",
"PasswordCreateForm",
"PasswordForm",
"PasswordPolicyForm",
"PasswordResetForm",
"PasswordResetRequestForm",
"PhoneNumberAvailable",
"PhonePrimaryForm",
"ProfileBannerForm",
"ProfileForm",
"ProfileLogoForm",
"ProfileTransitionForm",
"ProjectBannerForm",
"ProjectBoxofficeForm",
"ProjectCfpTransitionForm",
"ProjectCrewMembershipForm",
"ProjectCrewMembershipInviteForm",
"ProjectFeaturedForm",
"ProjectForm",
"ProjectLivestreamForm",
"ProjectNameForm",
"ProjectRegisterForm",
"ProjectSponsorForm",
"ProjectTransitionForm",
"ProposalFeaturedForm",
"ProposalForm",
"ProposalLabelsAdminForm",
"ProposalLabelsForm",
"ProposalMemberForm",
"ProposalMoveForm",
"ProposalTransitionForm",
"RegisterOtpForm",
"RegisterWithOtp",
"RsvpTransitionForm",
"SavedProjectForm",
"SavedSessionForm",
"SessionForm",
"SetNotificationPreferenceForm",
"TeamForm",
"TicketClientForm",
"TicketEventForm",
"TicketParticipantBadgeForm",
"TicketParticipantForm",
"TicketTypeForm",
"UnsubscribeForm",
"UpdateForm",
"UserPermissionAssignForm",
"UsernameAvailableForm",
"VenueForm",
"VenuePrimaryForm",
"VenueRoomForm",
"account",
"auth_client",
"comment",
"format_json",
"helpers",
"image_url_validator",
"label",
"login",
"membership",
"notification",
"nullable_json_filters",
"nullable_strip_filters",
"organization",
"profile",
"project",
"proposal",
"pwned_password_validator",
"session",
"strip_filters",
"supported_locales",
"sync_ticket",
"timezone_identifiers",
"tostr",
"transport_labels",
"update",
"validate_and_convert_json",
"venue",
"video_url_list_validator",
"video_url_validator",
]
Loading

0 comments on commit 02cf833

Please sign in to comment.