Skip to content

chore: add strict type annotations on the entire codebase #169

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

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

.DEFAULT_GOAL := help

PYTHON_FILES = ./code_annotations/ setup.py tests/ test_utils/

define BROWSER_PYSCRIPT
import os, webbrowser, sys
try:
Expand Down Expand Up @@ -42,25 +44,28 @@ COMMON_CONSTRAINTS_TXT=requirements/common_constraints.txt
$(COMMON_CONSTRAINTS_TXT):
wget -O "$(@)" https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt || touch "$(@)"

upgrade: export CUSTOM_COMPILE_COMMAND=make upgrade
upgrade: $(COMMON_CONSTRAINTS_TXT) # update the requirements/*.txt files with the latest packages satisfying requirements/*.in
compile-requirements: export CUSTOM_COMPILE_COMMAND=make upgrade
compile-requirements: $(COMMON_CONSTRAINTS_TXT) ## Re-compile *.in requirements to *.txt
pip install -qr requirements/pip-tools.txt
# Make sure to compile files after any other files they include!
pip-compile --upgrade --allow-unsafe -o requirements/pip.txt requirements/pip.in
pip-compile --upgrade -o requirements/pip-tools.txt requirements/pip-tools.in
pip-compile ${COMPILE_OPTS} --allow-unsafe requirements/pip.in
pip-compile ${COMPILE_OPTS} requirements/pip-tools.in
pip install -qr requirements/pip.txt
pip install -qr requirements/pip-tools.txt
pip-compile --upgrade -o requirements/base.txt requirements/base.in
pip-compile --upgrade -o requirements/django.txt requirements/django.in
pip-compile --upgrade -o requirements/test.txt requirements/test.in
pip-compile --upgrade -o requirements/doc.txt requirements/doc.in
pip-compile --upgrade -o requirements/quality.txt requirements/quality.in
pip-compile --upgrade -o requirements/ci.txt requirements/ci.in
pip-compile --upgrade -o requirements/dev.txt requirements/dev.in
pip-compile ${COMPILE_OPTS} requirements/base.in
pip-compile ${COMPILE_OPTS} requirements/django.in
pip-compile ${COMPILE_OPTS} requirements/test.in
pip-compile ${COMPILE_OPTS} requirements/doc.in
pip-compile ${COMPILE_OPTS} requirements/quality.in
pip-compile ${COMPILE_OPTS} requirements/ci.in
pip-compile ${COMPILE_OPTS} requirements/dev.in
# Let tox control the Django version for tests
sed '/^[dD]jango==/d' requirements/test.txt > requirements/test.tmp
mv requirements/test.tmp requirements/test.txt

upgrade: $(COMMON_CONSTRAINTS_TXT) ## update the requirements/*.txt files with the latest packages satisfying requirements/*.in
$(MAKE) compile-requirements COMPILE_OPTS="--upgrade"

quality: ## check coding style with pycodestyle and pylint
tox -e quality

Expand All @@ -70,9 +75,28 @@ requirements: ## install development environment requirements
pip-sync requirements/dev.txt requirements/test.txt requirements/private.*
pip install -e .

test: clean ## run tests in the current virtualenv
test: clean test-unit test-quality ## run tests in the current virtualenv

test-unit: ## run unit tests
pytest

test-quality: test-lint test-types test-codestyle test-docstyle test-isort selfcheck ## run all quality tests

test-codestyle: ## run pycodestyle tests
pycodestyle ${PYTHON_FILES}

test-docstyle: ## run pydocstyle tests
pydocstyle ${PYTHON_FILES}

test-isort: ## run isort tests
isort --check-only --diff ${PYTHON_FILES}

test-lint: ## run pylint tests
pylint ${PYTHON_FILES}

test-types: ## run mypy tests on the whole codebase
mypy --ignore-missing-imports --strict ${PYTHON_FILES}

diff_cover: test ## find diff lines that need test coverage
diff-cover coverage.xml

Expand Down
24 changes: 12 additions & 12 deletions code_annotations/annotation_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
"""
from collections import namedtuple

AnnotationErrorType = namedtuple(
AnnotationError = namedtuple(
"AnnotationError", ["message", "symbol", "description"]
)

# The TYPES list should contain all AnnotationErrorType instances. This list can then be parsed by others, for instance
# The TYPES list should contain all AnnotationError instances. This list can then be parsed by others, for instance
# to expose errors to pylint.
TYPES = []
TYPES: list[AnnotationError] = []


def add_error_type(message, symbol, description):
def add_error_type(message: str, symbol: str, description: str) -> AnnotationError:
"""
Create an AnnotationErrorType instance and add it to TYPES.
Create an AnnotationError instance and add it to TYPES.
"""
error_type = AnnotationErrorType(
error_type = AnnotationError(
message,
symbol,
description,
Expand All @@ -32,32 +32,32 @@ def add_error_type(message, symbol, description):
# It is important to preserve the insertion order of these error types in the TYPES list, as edx-lint uses the error
# type indices to generate numerical pylint IDs. If the insertion order is changed, the pylint IDs will change too,
# which might cause incompatibilities down the road. Thus, new items should be added at the end.
InvalidChoice = add_error_type(
InvalidChoice: AnnotationError = add_error_type(
'"%s" is not a valid choice for "%s". Expected one of %s.',
"annotation-invalid-choice",
"Emitted when the value of a choice field is not one of the valid choices",
)
DuplicateChoiceValue = add_error_type(
DuplicateChoiceValue: AnnotationError = add_error_type(
'"%s" is already present in this annotation.',
"annotation-duplicate-choice-value",
"Emitted when duplicate values are found in a choice field",
)
MissingChoiceValue = add_error_type(
MissingChoiceValue: AnnotationError = add_error_type(
'no value found for "%s". Expected one of %s.',
"annotation-missing-choice-value",
"Emitted when a choice field does not have any value",
)
InvalidToken = add_error_type(
InvalidToken: AnnotationError = add_error_type(
"'%s' token does not belong to group '%s'. Expected one of: %s",
"annotation-invalid-token",
"Emitted when a token is found in a group for which it is not valid",
)
DuplicateToken = add_error_type(
DuplicateToken: AnnotationError = add_error_type(
"found duplicate token '%s'",
"annotation-duplicate-token",
"Emitted when a token is found twice in a group",
)
MissingToken = add_error_type(
MissingToken: AnnotationError = add_error_type(
"missing non-optional annotation: '%s'",
"annotation-missing-token",
"Emitted when a required token is missing from a group",
Expand Down
Loading