docs: Add documentation for `if False` mypy pattern in scripts.

This should help make it clear what's going on with these scripts.
This commit is contained in:
Tim Abbott 2018-12-17 10:52:08 -08:00
parent 209df75ffa
commit 2558f101af
26 changed files with 59 additions and 7 deletions

View File

@ -96,6 +96,36 @@ an `Any` or `# type: ignore` so you're not blocked waiting for help,
add a `# TODO: ` comment so it doesn't get forgotten in code review, add a `# TODO: ` comment so it doesn't get forgotten in code review,
and ask for help in chat.zulip.org. and ask for help in chat.zulip.org.
## mypy in production scripts
While in most of the Zulip codebase, we can consistently use the
`typing` module (Part of the standard library in Python 3.5, but
present as an installable module with older Python), in our installer
and other production scripts that might run outside a Zulip
virtualenv, we cannot rely on the `typing` module being present on the
system.
To solve this problem, we use the following (semi-standard in the mypy
community) hack in those scripts:
```
if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import List
```
and then use the Python 2 style type comment syntax for annotating
those files. This way, the Python interpreters for Python 2.7 and 3.4
will ignore this line, and thus not crash. But we can still get all
the benefits of type annotations in that codebase, since the `mypy`
type checker ignores the `if False` and thus still is able to
type-check the file using those imports.
The exception to this rule is that any scripts which use
`setup_path_on_import` before they import from the `typing` module are
safe. These, we generally declare in the relevant exclude line in
`tools/linter_lib/custom_check.py`
## mypy stubs for third-party modules. ## mypy stubs for third-party modules.
For the Python standard library and some popular third-party modules, For the Python standard library and some popular third-party modules,

View File

@ -5,8 +5,8 @@ file output by the cron job is correct.
import sys import sys
import time import time
# Avoid requiring the typing module to be installed
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Tuple from typing import Tuple
def nagios_from_file(results_file: str, max_time_diff: int=60 * 2) -> 'Tuple[int, str]': def nagios_from_file(results_file: str, max_time_diff: int=60 * 2) -> 'Tuple[int, str]':

View File

@ -5,6 +5,7 @@ Nagios plugin to check the difference between the primary and
secondary Postgres servers' xlog location. secondary Postgres servers' xlog location.
""" """
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from mypy_extensions import NoReturn from mypy_extensions import NoReturn
import subprocess import subprocess

View File

@ -9,6 +9,7 @@ mirrors when they receive the messages sent every minute by
/etc/cron.d/test_zephyr_personal_mirrors /etc/cron.d/test_zephyr_personal_mirrors
""" """
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Dict from typing import Dict
import os import os

View File

@ -26,6 +26,7 @@ django.setup()
from zerver.models import UserActivity from zerver.models import UserActivity
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Any, Dict, Set, Optional from typing import Any, Dict, Set, Optional
states = { states = {

View File

@ -10,6 +10,7 @@ run out of cron.
See puppet/zulip_ops/files/cron.d/zephyr-mirror for the crontab details. See puppet/zulip_ops/files/cron.d/zephyr-mirror for the crontab details.
""" """
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Dict from typing import Dict
import os import os

View File

@ -54,6 +54,7 @@ import sys
import boto.utils import boto.utils
import netifaces import netifaces
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Optional from typing import Optional
def address_of(device_id): def address_of(device_id):

View File

@ -4,6 +4,7 @@ import os
import sys import sys
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Set from typing import Set
ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

View File

@ -5,6 +5,7 @@ import subprocess
import sys import sys
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Set from typing import Set
ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

View File

@ -4,8 +4,7 @@ import os
import sys import sys
if False: if False:
# Typing module isn't always available when this is run on older # See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
# Python 3.4 (Trusty).
from typing import Set from typing import Set
ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

View File

@ -1,12 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import sys import sys
import argparse import argparse
import hashlib import hashlib
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Iterable, List, MutableSet from typing import Iterable, List, MutableSet
def expand_reqs_helper(fpath, visited): def expand_reqs_helper(fpath, visited):

View File

@ -4,6 +4,7 @@ import hashlib
import json import json
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Optional, List, IO, Tuple, Any from typing import Optional, List, IO, Tuple, Any
from scripts.lib.zulip_tools import subprocess_text_output, run from scripts.lib.zulip_tools import subprocess_text_output, run

View File

@ -13,7 +13,7 @@ if 'TRAVIS' in os.environ:
VENV_CACHE_PATH = "/home/travis/zulip-venv-cache" VENV_CACHE_PATH = "/home/travis/zulip-venv-cache"
if False: if False:
# Don't add a runtime dependency on typing # See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import List, Optional, Tuple, Set from typing import List, Optional, Tuple, Set
VENV_DEPENDENCIES = [ VENV_DEPENDENCIES = [

View File

@ -18,6 +18,7 @@ import uuid
import configparser import configparser
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Sequence, Set, Any, Dict, List, Optional from typing import Sequence, Set, Any, Dict, List, Optional
DEPLOYMENTS_DIR = "/home/zulip/deployments" DEPLOYMENTS_DIR = "/home/zulip/deployments"

View File

@ -9,6 +9,7 @@ import os
import subprocess import subprocess
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Any, Dict, Optional, Union from typing import Any, Dict, Optional, Union
states = { states = {

View File

@ -1,7 +1,7 @@
import time import time
# Avoid requiring the typing module to be installed
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Tuple from typing import Tuple
def nagios_from_file(results_file): def nagios_from_file(results_file):

View File

@ -5,6 +5,7 @@ import subprocess
import sys import sys
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Set from typing import Set
ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

View File

@ -4,6 +4,7 @@
import sys import sys
import os import os
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Dict, List, Optional from typing import Dict, List, Optional
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

View File

@ -7,6 +7,7 @@ import sys
import subprocess import subprocess
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Callable, List from typing import Callable, List
TOOLS_DIR = os.path.dirname(__file__) TOOLS_DIR = os.path.dirname(__file__)

View File

@ -25,6 +25,7 @@ from scripts.lib.node_cache import setup_node_modules, NODE_MODULES_CACHE_PATH
from version import PROVISION_VERSION from version import PROVISION_VERSION
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Any, List from typing import Any, List
from tools.setup.generate_zulip_bots_static_files import generate_zulip_bots_static_files from tools.setup.generate_zulip_bots_static_files import generate_zulip_bots_static_files

View File

@ -877,6 +877,10 @@ def build_custom_checkers(by_lang):
'description': 'Linkified markdown URLs should use cleaner <http://example.com> syntax.'}, 'description': 'Linkified markdown URLs should use cleaner <http://example.com> syntax.'},
{'pattern': 'https://zulip.readthedocs.io/en/latest/[a-zA-Z0-9]', {'pattern': 'https://zulip.readthedocs.io/en/latest/[a-zA-Z0-9]',
'exclude': ['docs/overview/contributing.md', 'docs/overview/readme.md', 'docs/README.md'], 'exclude': ['docs/overview/contributing.md', 'docs/overview/readme.md', 'docs/README.md'],
'exclude_line': set([
('docs/testing/mypy.md',
'# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts')
]),
'include_only': set(['docs/']), 'include_only': set(['docs/']),
'description': "Use relative links (../foo/bar.html) to other documents in docs/", 'description': "Use relative links (../foo/bar.html) to other documents in docs/",
}, },

View File

@ -10,6 +10,7 @@ import subprocess
import sys import sys
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Any, Callable, Dict, List, Optional from typing import Any, Callable, Dict, List, Optional
from zulint.printer import print_err, colors from zulint.printer import print_err, colors

View File

@ -3,6 +3,7 @@ from __future__ import absolute_import
import subprocess import subprocess
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import List from typing import List
from zulint.printer import print_err, colors from zulint.printer import print_err, colors

View File

@ -11,6 +11,7 @@ import argparse
from six.moves import filter from six.moves import filter
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Union, List, Dict from typing import Union, List, Dict
def get_ftype(fpath, use_shebang): def get_ftype(fpath, use_shebang):

View File

@ -5,6 +5,7 @@ import sys
import os import os
from itertools import cycle from itertools import cycle
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from typing import Union, Text from typing import Union, Text
# Terminal Color codes for use in differentiatng linters # Terminal Color codes for use in differentiatng linters

View File

@ -1,3 +1,4 @@
# This file is used by both Python 2.7 (thumbor) and 3 (zulip).
from __future__ import absolute_import from __future__ import absolute_import
import os import os
@ -7,6 +8,7 @@ from six.moves.urllib.parse import urlparse
from typing import Any, Text, Tuple, Optional from typing import Any, Text, Tuple, Optional
if False: if False:
# See https://zulip.readthedocs.io/en/latest/testing/mypy.html#mypy-in-production-scripts
from thumbor.context import Context from thumbor.context import Context
ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath('__file__')))) ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath('__file__'))))