Skip to content

Commit 15a9d79

Browse files
authored
Re-enables MyPy in non-failure mode (apache#19890)
This PR enables mypy back as pre-commit for local changes after the apache#19317 switched to Python 3.7 but also it separates out mypy to a separate non-failing step in CI. In the CI we will be able to see remaining mypy errors. This will allow us to gradually fix all the mypy errors and enable mypy back when we got all the problems fixed.
1 parent 33a4502 commit 15a9d79

10 files changed

+68
-37
lines changed

.github/workflows/ci.yml

+8-2
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,6 @@ jobs:
429429
needs: [build-info, ci-images]
430430
env:
431431
RUNS_ON: ${{ fromJson(needs.build-info.outputs.runsOn) }}
432-
SKIP: "identity"
433432
MOUNT_SELECTED_LOCAL_SOURCES: "true"
434433
PYTHON_MAJOR_MINOR_VERSION: ${{needs.build-info.outputs.defaultPythonVersion}}
435434
if: needs.build-info.outputs.basic-checks-only == 'false'
@@ -471,10 +470,17 @@ ${{ hashFiles('.pre-commit-config.yaml') }}"
471470
with:
472471
path: 'airflow/ui/node_modules'
473472
key: ${{ runner.os }}-ui-node-modules-${{ hashFiles('airflow/ui/**/yarn.lock') }}
474-
- name: "Static checks"
473+
- name: "Static checks (no mypy)"
475474
run: ./scripts/ci/static_checks/run_static_checks.sh
476475
env:
477476
VERBOSE: false
477+
SKIP: "identity,mypy"
478+
- name: "MyPy static checks"
479+
run: ./scripts/ci/static_checks/run_static_checks.sh mypy
480+
env:
481+
VERBOSE: false
482+
DO_NOT_FAIL_ON_ERROR: "true"
483+
COLUMNS: 300
478484

479485
# Those checks are run if no image needs to be built for checks. This is for simple changes that
480486
# Do not touch any of the python code or any of the important files that might require building

.pre-commit-config.yaml

+5-4
Original file line numberDiff line numberDiff line change
@@ -721,22 +721,23 @@ repos:
721721
- id: mypy
722722
name: Run mypy
723723
language: system
724-
entry: ./scripts/ci/pre_commit/pre_commit_mypy.sh
724+
entry: ./scripts/ci/pre_commit/pre_commit_mypy.sh --namespace-packages
725725
files: \.py$
726-
exclude: ^dev|^provider_packages|^chart|^docs|^airflow/_vendor/
726+
exclude: ^provider_packages|^chart|^docs|^airflow/_vendor/
727+
require_serial: true
727728
- id: mypy
728729
name: Run mypy for helm chart tests
729730
language: system
730731
entry: ./scripts/ci/pre_commit/pre_commit_mypy.sh
731732
files: ^chart/.*\.py$
732-
require_serial: false
733+
require_serial: true
733734
- id: mypy
734735
name: Run mypy for /docs/ folder
735736
language: system
736737
entry: ./scripts/ci/pre_commit/pre_commit_mypy.sh
737738
files: ^docs/.*\.py$
738739
exclude: rtd-deprecation
739-
require_serial: false
740+
require_serial: true
740741
- id: flake8
741742
name: Run flake8
742743
language: system

scripts/ci/pre_commit/pre_commit_check_pre_commit_hook_names.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
try:
2828
from yaml import CSafeLoader as SafeLoader
2929
except ImportError:
30-
from yaml import SafeLoader # type: ignore[no-redef]
30+
from yaml import SafeLoader # type: ignore
3131

3232

3333
def main() -> int:

scripts/ci/pre_commit/pre_commit_check_provider_yaml_files.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from collections import Counter
2424
from glob import glob
2525
from itertools import chain, product
26-
from typing import Any, Dict, Iterable, List
26+
from typing import Any, Dict, Iterable, List, Set
2727

2828
import jsonschema
2929
import yaml
@@ -34,7 +34,7 @@
3434
try:
3535
from yaml import CSafeLoader as SafeLoader
3636
except ImportError:
37-
from yaml import SafeLoader # type: ignore[no-redef]
37+
from yaml import SafeLoader # type: ignore
3838

3939
if __name__ != "__main__":
4040
raise Exception(
@@ -80,7 +80,7 @@ def _load_package_data(package_paths: Iterable[str]):
8080
return result
8181

8282

83-
def get_all_integration_names(yaml_files):
83+
def get_all_integration_names(yaml_files) -> List[str]:
8484
all_integrations = [
8585
i['integration-name'] for f in yaml_files.values() if 'integrations' in f for i in f["integrations"]
8686
]
@@ -137,7 +137,7 @@ def assert_sets_equal(set1, set2):
137137

138138

139139
def check_if_objects_belongs_to_package(
140-
object_names: List[str], provider_package: str, yaml_file_path: str, resource_type: str
140+
object_names: Set[str], provider_package: str, yaml_file_path: str, resource_type: str
141141
):
142142
for object_name in object_names:
143143
if not object_name.startswith(provider_package):
@@ -283,8 +283,8 @@ def check_invalid_integration(yaml_files: Dict[str, Dict]):
283283

284284
def check_doc_files(yaml_files: Dict[str, Dict]):
285285
print("Checking doc files")
286-
current_doc_urls = []
287-
current_logo_urls = []
286+
current_doc_urls: List[str] = []
287+
current_logo_urls: List[str] = []
288288
for provider in yaml_files.values():
289289
if 'integrations' in provider:
290290
current_doc_urls.extend(

scripts/ci/pre_commit/pre_commit_json_schema.py

+2
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ def _default_validator(validator, default, instance, schema):
149149
def _load_spec(spec_file: Optional[str], spec_url: Optional[str]):
150150
if spec_url:
151151
spec_file = fetch_and_cache(url=spec_url, output_filename=re.sub(r"[^a-zA-Z0-9]", "-", spec_url))
152+
if not spec_file:
153+
raise Exception(f"The {spec_file} was None and {spec_url} did not lead to any file loading.")
152154
with open(spec_file) as schema_file:
153155
schema = json.loads(schema_file.read())
154156
return schema

scripts/ci/pre_commit/pre_commit_mypy.sh

-3
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,5 @@ export FORCE_ANSWER_TO_QUESTIONS=${FORCE_ANSWER_TO_QUESTIONS:="quit"}
2020
export REMEMBER_LAST_ANSWER="true"
2121
export PRINT_INFO_FROM_SCRIPTS="false"
2222

23-
# Temporarily remove mypy checks until we fix them for Python 3.7
24-
exit 0
25-
2623
# shellcheck source=scripts/ci/static_checks/mypy.sh
2724
. "$( dirname "${BASH_SOURCE[0]}" )/../static_checks/mypy.sh" "${@}"

scripts/ci/static_checks/mypy.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function run_mypy() {
2626
files=("$@")
2727
fi
2828

29-
docker_v run "${EXTRA_DOCKER_FLAGS[@]}" \
29+
docker_v run "${EXTRA_DOCKER_FLAGS[@]}" -t \
3030
--entrypoint "/usr/local/bin/dumb-init" \
3131
"-v" "${AIRFLOW_SOURCES}/.mypy_cache:/opt/airflow/.mypy_cache" \
3232
"${AIRFLOW_CI_IMAGE_WITH_TAG}" \

scripts/ci/static_checks/run_static_checks.sh

+11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ python -m pip install --user pre-commit \
3434

3535
export PATH=~/.local/bin:${PATH}
3636

37+
if [[ ${DO_NOT_FAIL_ON_ERROR=} != "" ]]; then
38+
echo
39+
echo "Skip failing on error"
40+
echo
41+
set +e
42+
fi
43+
3744
if [[ $# == "0" ]]; then
3845
pre-commit run --all-files --show-diff-on-failure --color always
3946
else
@@ -42,3 +49,7 @@ else
4249
pre-commit run "${pre_commit_check}" --all-files --show-diff-on-failure --color always
4350
done
4451
fi
52+
53+
if [[ ${DO_NOT_FAIL_ON_ERROR=} != "" ]]; then
54+
exit 0
55+
fi

scripts/in_container/run_mypy.sh

+1-15
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,4 @@
2020
. "$( dirname "${BASH_SOURCE[0]}" )/_in_container_script_init.sh"
2121
export PYTHONPATH=${AIRFLOW_SOURCES}
2222

23-
mypy_args=()
24-
25-
# Mypy doesn't cope very well with namespace packages when give filenames (it gets confused about the lack of __init__.py in airflow.providers, and thinks airflow.providers.docker is the same as a "docker" top level module).
26-
#
27-
# So we instead need to convert the file names in to module names to check
28-
for filename in "$@";
29-
do
30-
if [[ "${filename}" == docs/* ]]; then
31-
mypy_args+=("$filename")
32-
else
33-
mypy_args+=("-m" "$(filename_to_python_module "$filename")")
34-
fi
35-
done
36-
37-
mypy --namespace-packages "${mypy_args[@]}"
23+
mypy "${@}"

setup.py

+33-5
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,31 @@ def write_version(filename: str = os.path.join(*[my_dir, "airflow", "git_version
513513
]
514514
# End dependencies group
515515

516+
# Mypy 0.900 and above ships only with stubs from stdlib so if we need other stubs, we need to install them
517+
# manually as `types-*`. See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
518+
# for details. Wy want to install them explicitly because we want to eventually move to
519+
# mypyd which does not support installing the types dynamically with --install-types
520+
mypy_dependencies = [
521+
'mypy==0.910',
522+
'types-croniter',
523+
'types-docutils',
524+
'types-freezegun',
525+
'types-paramiko',
526+
'types-protobuf',
527+
'types-python-dateutil',
528+
'types-python-slugify',
529+
'types-pytz',
530+
'types-redis',
531+
'types-requests',
532+
'types-setuptools',
533+
'types-termcolor',
534+
'types-tabulate',
535+
'types-Markdown',
536+
'types-PyMySQL',
537+
'types-PyYAML',
538+
]
539+
540+
# Dependencies needed for development only
516541
devel_only = [
517542
'aws_xray_sdk',
518543
'beautifulsoup4~=4.7.1',
@@ -533,7 +558,6 @@ def write_version(filename: str = os.path.join(*[my_dir, "airflow", "git_version
533558
'jsondiff',
534559
'mongomock',
535560
'moto~=2.2, >=2.2.12',
536-
'mypy==0.770',
537561
'parameterized',
538562
'paramiko',
539563
'pipdeptree',
@@ -558,7 +582,7 @@ def write_version(filename: str = os.path.join(*[my_dir, "airflow", "git_version
558582
'yamllint',
559583
]
560584

561-
devel = cgroups + devel_only + doc + kubernetes + mysql + pandas + password
585+
devel = cgroups + devel_only + doc + kubernetes + mypy_dependencies + mysql + pandas + password
562586
devel_hadoop = devel + hdfs + hive + kerberos + presto + webhdfs
563587

564588
# Dict of all providers which are part of the Apache Airflow repository together with their requirements
@@ -893,6 +917,10 @@ def get_all_provider_packages() -> str:
893917
class AirflowDistribution(Distribution):
894918
"""The setuptools.Distribution subclass with Airflow specific behaviour"""
895919

920+
def __init__(self, attrs=None):
921+
super().__init__(attrs)
922+
self.install_requires = None
923+
896924
def parse_config_files(self, *args, **kwargs) -> None:
897925
"""
898926
Ensure that when we have been asked to install providers from sources
@@ -989,7 +1017,7 @@ def add_all_provider_packages() -> None:
9891017
class Develop(develop_orig):
9901018
"""Forces removal of providers in editable mode."""
9911019

992-
def run(self) -> None:
1020+
def run(self) -> None: # type: ignore
9931021
self.announce('Installing in editable mode. Uninstalling provider packages!', level=log.INFO)
9941022
# We need to run "python3 -m pip" because it might be that older PIP binary is in the path
9951023
# And it results with an error when running pip directly (cannot import pip module)
@@ -1052,11 +1080,11 @@ def include_provider_namespace_packages_when_installing_from_sources() -> None:
10521080
'extra_clean': CleanCommand,
10531081
'compile_assets': CompileAssets,
10541082
'list_extras': ListExtras,
1055-
'install': Install,
1083+
'install': Install, # type: ignore
10561084
'develop': Develop,
10571085
},
10581086
test_suite='setup.airflow_test_suite',
1059-
**setup_kwargs,
1087+
**setup_kwargs, # type: ignore
10601088
)
10611089

10621090

0 commit comments

Comments
 (0)