This commit is contained in:
John Whitlock 2022-05-20 19:47:13 -05:00
Родитель 851b332bbc
Коммит 12901bdecd
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 082C735D154FB750
4 изменённых файлов: 150 добавлений и 5 удалений

44
mypy_stubs/README.md Normal file
Просмотреть файл

@ -0,0 +1,44 @@
# mypy type hints for 3rd party modules
This folder contains type hints for 3rd party Python modules, used by
[mypy](https://mypy.readthedocs.io/en/latest/index.html) for static
analysis of Python code.
## Generation and Maintenance
The files are initially generated with `stubgen` from `mypy`. They can be
generated for a whole package:
```
stubgen -o mypy_stubs -p package_name
```
They can be generated for just one module:
```
stubgen -o mypy_stubs -m package_name.submodule
```
Some Django packages require `DJANGO_SETTINGS_MODULE`, or `stubgen` will fail:
```
export DJANGO_SETTINGS_MODULE=privaterelay.settings
stubgen -o mypy_stubs -p package_name
```
The generated stubs are placeholders, and often require significant
modifications to run without errors. They are also tied to the specific
version of the package. For this reason, we don't require stubs for
all third-party packages.
## Documentation
When generating stubs, add a docstring header to the file that specifies the
`pip` package name and header. This gives us a chance to recognize that the
stub is out-of-date when updating the package.
Add the same data here:
|package name|version|module name|
|-:|-:|-:|
|`python-decouple`|3.6|`decouple`|

100
mypy_stubs/decouple.pyi Normal file
Просмотреть файл

@ -0,0 +1,100 @@
"""
Typing hints for python-decouple 3.6
Generated with:
stubgen -o mypy_stubs -p decouple
Changes:
* Comment out globals and classes unused by Relay
* Add overrides for AutoConfig.__call__ for different scenarios
* Simplified interfaces of Csv and Choices to our usage
"""
from pathlib import Path
from typing import Any, Callable, Sequence, TypeVar, Union, overload
# PYVERSION: Any
# text_type = str
# read_config: Any
# DEFAULT_ENCODING: str
# TRUE_VALUES: Any
# FALSE_VALUES: Any
def strtobool(value: Union[str, bool]) -> bool: ...
# class UndefinedValueError(Exception): ...
class Undefined: ...
# class Config:
# repository: Any
# def __init__(self, repository) -> None: ...
# def get(self, option, default=..., cast=...): ...
# def __call__(self, *args, **kwargs): ...
# class RepositoryEmpty:
# def __init__(self, source: str = ..., encoding=...) -> None: ...
# def __contains__(self, key): ...
# def __getitem__(self, key) -> None: ...
# class RepositoryIni(RepositoryEmpty):
# SECTION: str
# parser: Any
# def __init__(self, source, encoding=...) -> None: ...
# def __contains__(self, key): ...
# def __getitem__(self, key): ...
# class RepositoryEnv(RepositoryEmpty):
# data: Any
# def __init__(self, source, encoding=...) -> None: ...
# def __contains__(self, key): ...
# def __getitem__(self, key): ...
# class RepositorySecret(RepositoryEmpty):
# data: Any
# def __init__(self, source: str = ...) -> None: ...
# def __contains__(self, key): ...
# def __getitem__(self, key): ...
DefaultType = TypeVar("DefaultType")
CastRetType = TypeVar("CastRetType")
class AutoConfig:
def __init__(self, search_path: Union[str, Path, None] = ...) -> None: ...
@overload
def __call__(self, option: str) -> str: ...
@overload
def __call__(self, option: str, default: str) -> str: ...
@overload
def __call__(
self, option: str, default: DefaultType
) -> Union[str, DefaultType]: ...
@overload
def __call__(
self, option: str, cast: Callable[[Any], CastRetType]
) -> CastRetType: ...
@overload
def __call__(
self, option: str, default: Any, cast: Callable[[Any], CastRetType]
) -> CastRetType: ...
config: AutoConfig
class Csv:
# Full signature has several optional params
# def __init__(
# self, cast=..., delimiter: str = ..., strip=..., post_process=...
# ) -> None: ...
def __init__(self) -> None: ...
def __call__(self, value: str) -> list: ...
class Choices:
# Full signature has choices param
# def __init__(
# self, flat: Any | None = ..., cast=..., choices: Any | None = ...
# ) -> None: ...
def __init__(
self,
flat: Sequence[CastRetType] = ...,
cast: Callable[[Any], CastRetType] = ...,
) -> None: ...
def __call__(self, value: Any) -> CastRetType: ...

Просмотреть файл

@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/2.2/ref/settings/
import ipaddress
import os, sys
from datetime import datetime
from typing import Optional
from decouple import config, Choices, Csv
@ -56,7 +57,7 @@ ORIGIN_CHANNEL_MAP = {
RELAY_CHANNEL = ORIGIN_CHANNEL_MAP.get(SITE_ORIGIN, "prod")
DEBUG = config("DEBUG", False, cast=bool)
if DEBUG:
INTERNAL_IPS = config("DJANGO_INTERNAL_IPS", default=[])
INTERNAL_IPS = config("DJANGO_INTERNAL_IPS", default="", cast=Csv())
IN_PYTEST = "pytest" in sys.modules
USE_SILK = DEBUG and HAS_SILK and not IN_PYTEST
@ -418,10 +419,10 @@ PREMIUM_PLAN_COUNTRY_LANG_MAPPING = {
}
SUBSCRIPTIONS_WITH_UNLIMITED = config("SUBSCRIPTIONS_WITH_UNLIMITED", default="")
PREMIUM_RELEASE_DATE = config(
_RAW_PREMIUM_RELEASE_DATE = config(
"PREMIUM_RELEASE_DATE", "2021-10-27 17:00:00+00:00", cast=str
)
PREMIUM_RELEASE_DATE = datetime.fromisoformat(PREMIUM_RELEASE_DATE)
PREMIUM_RELEASE_DATE = datetime.fromisoformat(_RAW_PREMIUM_RELEASE_DATE)
DOMAIN_REGISTRATION_MODAL = config("DOMAIN_REGISTRATION_MODAL", False, cast=bool)
MAX_ONBOARDING_AVAILABLE = config("MAX_ONBOARDING_AVAILABLE", 0, cast=int)
@ -665,7 +666,7 @@ CIRCLE_TAG = config("CIRCLE_TAG", "")
CIRCLE_BRANCH = config("CIRCLE_BRANCH", "")
if SENTRY_RELEASE:
sentry_release = SENTRY_RELEASE
sentry_release: Optional[str] = SENTRY_RELEASE
elif CIRCLE_TAG and CIRCLE_TAG != "unknown":
sentry_release = CIRCLE_TAG
elif (

Просмотреть файл

@ -1,5 +1,6 @@
[tool.mypy]
plugins = ["mypy_django_plugin.main"]
mypy_path = "$MYPY_CONFIG_FILE_DIR/mypy_stubs"
python_version = "3.9"
show_error_codes = true
warn_return_any = true
@ -22,7 +23,6 @@ module = [
"botocore.exceptions",
"codetiming",
"debug_toolbar",
"decouple",
"dj_database_url",
"django_filters",
"django_ftl.bundles",