parent
927c0e082e
commit
6fc3381229
|
@ -21,6 +21,12 @@ matrix:
|
||||||
dist: xenial
|
dist: xenial
|
||||||
sudo: true
|
sudo: true
|
||||||
name: "Python 3.7 without Extensions"
|
name: "Python 3.7 without Extensions"
|
||||||
|
- env: TOX_ENV=type-checking
|
||||||
|
python: 3.6
|
||||||
|
name: "Python 3.6 Type checks"
|
||||||
|
- env: TOX_ENV=type-checking
|
||||||
|
python: 3.7
|
||||||
|
name: "Python 3.7 Type checks"
|
||||||
- env: TOX_ENV=lint
|
- env: TOX_ENV=lint
|
||||||
python: 3.6
|
python: 3.6
|
||||||
name: "Python 3.6 Linter checks"
|
name: "Python 3.6 Linter checks"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from sanic.app import Sanic
|
from sanic.app import Sanic
|
||||||
from sanic.log import logger
|
from sanic.log import logger
|
||||||
|
@ -35,7 +36,10 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if args.cert is not None or args.key is not None:
|
if args.cert is not None or args.key is not None:
|
||||||
ssl = {"cert": args.cert, "key": args.key}
|
ssl = {
|
||||||
|
"cert": args.cert,
|
||||||
|
"key": args.key,
|
||||||
|
} # type: Optional[Dict[str, Any]]
|
||||||
else:
|
else:
|
||||||
ssl = None
|
ssl = None
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ from inspect import getmodulename, isawaitable, signature, stack
|
||||||
from socket import socket
|
from socket import socket
|
||||||
from ssl import Purpose, SSLContext, create_default_context
|
from ssl import Purpose, SSLContext, create_default_context
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from typing import Any, Optional, Type, Union
|
from typing import Any, Dict, Optional, Type, Union
|
||||||
from urllib.parse import urlencode, urlunparse
|
from urllib.parse import urlencode, urlunparse
|
||||||
|
|
||||||
from sanic import reloader_helpers
|
from sanic import reloader_helpers
|
||||||
|
@ -768,7 +768,7 @@ class Sanic:
|
||||||
URLBuildError
|
URLBuildError
|
||||||
"""
|
"""
|
||||||
# find the route by the supplied view name
|
# find the route by the supplied view name
|
||||||
kw = {}
|
kw: Dict[str, str] = {}
|
||||||
# special static files url_for
|
# special static files url_for
|
||||||
if view_name == "static":
|
if view_name == "static":
|
||||||
kw.update(name=kwargs.pop("name", "static"))
|
kw.update(name=kwargs.pop("name", "static"))
|
||||||
|
|
|
@ -2,9 +2,23 @@ import asyncio
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from inspect import isawaitable
|
from inspect import isawaitable
|
||||||
from typing import Any, Awaitable, Callable, MutableMapping, Union
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Awaitable,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
List,
|
||||||
|
MutableMapping,
|
||||||
|
Optional,
|
||||||
|
Tuple,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
from requests_async import ASGISession # type: ignore
|
||||||
|
|
||||||
|
import sanic.app # noqa
|
||||||
|
|
||||||
from sanic.compat import Header
|
from sanic.compat import Header
|
||||||
from sanic.exceptions import InvalidUsage, ServerError
|
from sanic.exceptions import InvalidUsage, ServerError
|
||||||
from sanic.log import logger
|
from sanic.log import logger
|
||||||
|
@ -54,6 +68,8 @@ class MockProtocol:
|
||||||
|
|
||||||
|
|
||||||
class MockTransport:
|
class MockTransport:
|
||||||
|
_protocol: Optional[MockProtocol]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, scope: ASGIScope, receive: ASGIReceive, send: ASGISend
|
self, scope: ASGIScope, receive: ASGIReceive, send: ASGISend
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -68,11 +84,12 @@ class MockTransport:
|
||||||
self._protocol = MockProtocol(self, self.loop)
|
self._protocol = MockProtocol(self, self.loop)
|
||||||
return self._protocol
|
return self._protocol
|
||||||
|
|
||||||
def get_extra_info(self, info: str) -> Union[str, bool]:
|
def get_extra_info(self, info: str) -> Union[str, bool, None]:
|
||||||
if info == "peername":
|
if info == "peername":
|
||||||
return self.scope.get("server")
|
return self.scope.get("server")
|
||||||
elif info == "sslcontext":
|
elif info == "sslcontext":
|
||||||
return self.scope.get("scheme") in ["https", "wss"]
|
return self.scope.get("scheme") in ["https", "wss"]
|
||||||
|
return None
|
||||||
|
|
||||||
def get_websocket_connection(self) -> WebSocketConnection:
|
def get_websocket_connection(self) -> WebSocketConnection:
|
||||||
try:
|
try:
|
||||||
|
@ -172,6 +189,13 @@ class Lifespan:
|
||||||
|
|
||||||
|
|
||||||
class ASGIApp:
|
class ASGIApp:
|
||||||
|
sanic_app: Union[ASGISession, "sanic.app.Sanic"]
|
||||||
|
request: Request
|
||||||
|
transport: MockTransport
|
||||||
|
do_stream: bool
|
||||||
|
lifespan: Lifespan
|
||||||
|
ws: Optional[WebSocketConnection]
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.ws = None
|
self.ws = None
|
||||||
|
|
||||||
|
@ -182,8 +206,8 @@ class ASGIApp:
|
||||||
instance = cls()
|
instance = cls()
|
||||||
instance.sanic_app = sanic_app
|
instance.sanic_app = sanic_app
|
||||||
instance.transport = MockTransport(scope, receive, send)
|
instance.transport = MockTransport(scope, receive, send)
|
||||||
instance.transport.add_task = sanic_app.loop.create_task
|
|
||||||
instance.transport.loop = sanic_app.loop
|
instance.transport.loop = sanic_app.loop
|
||||||
|
setattr(instance.transport, "add_task", sanic_app.loop.create_task)
|
||||||
|
|
||||||
headers = Header(
|
headers = Header(
|
||||||
[
|
[
|
||||||
|
@ -286,8 +310,8 @@ class ASGIApp:
|
||||||
"""
|
"""
|
||||||
Write the response.
|
Write the response.
|
||||||
"""
|
"""
|
||||||
headers = []
|
headers: List[Tuple[bytes, bytes]] = []
|
||||||
cookies = {}
|
cookies: Dict[str, str] = {}
|
||||||
try:
|
try:
|
||||||
cookies = {
|
cookies = {
|
||||||
v.key: v
|
v.key: v
|
||||||
|
|
|
@ -56,7 +56,7 @@ class BlueprintGroup(MutableSequence):
|
||||||
"""
|
"""
|
||||||
return self._blueprints[item]
|
return self._blueprints[item]
|
||||||
|
|
||||||
def __setitem__(self, index: int, item: object) -> None:
|
def __setitem__(self, index, item) -> None:
|
||||||
"""
|
"""
|
||||||
Abstract method implemented to turn the `BlueprintGroup` class
|
Abstract method implemented to turn the `BlueprintGroup` class
|
||||||
into a list like object to support all the existing behavior.
|
into a list like object to support all the existing behavior.
|
||||||
|
@ -69,7 +69,7 @@ class BlueprintGroup(MutableSequence):
|
||||||
"""
|
"""
|
||||||
self._blueprints[index] = item
|
self._blueprints[index] = item
|
||||||
|
|
||||||
def __delitem__(self, index: int) -> None:
|
def __delitem__(self, index) -> None:
|
||||||
"""
|
"""
|
||||||
Abstract method implemented to turn the `BlueprintGroup` class
|
Abstract method implemented to turn the `BlueprintGroup` class
|
||||||
into a list like object to support all the existing behavior.
|
into a list like object to support all the existing behavior.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from multidict import CIMultiDict
|
from multidict import CIMultiDict # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Header(CIMultiDict):
|
class Header(CIMultiDict):
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from typing import Dict, Iterable, Optional, Tuple
|
from typing import Dict, Iterable, List, Optional, Tuple, Union
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
|
||||||
Options = Dict[str, str] # key=value fields in various headers
|
Options = Dict[str, Union[int, str]] # key=value fields in various headers
|
||||||
OptionsIterable = Iterable[Tuple[str, str]] # May contain duplicate keys
|
OptionsIterable = Iterable[Tuple[str, str]] # May contain duplicate keys
|
||||||
|
|
||||||
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
|
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
|
||||||
|
@ -35,7 +35,7 @@ def parse_content_header(value: str) -> Tuple[str, Options]:
|
||||||
value = _firefox_quote_escape.sub("%22", value)
|
value = _firefox_quote_escape.sub("%22", value)
|
||||||
pos = value.find(";")
|
pos = value.find(";")
|
||||||
if pos == -1:
|
if pos == -1:
|
||||||
options = {}
|
options: Dict[str, Union[int, str]] = {}
|
||||||
else:
|
else:
|
||||||
options = {
|
options = {
|
||||||
m.group(1).lower(): m.group(2) or m.group(3).replace("%22", '"')
|
m.group(1).lower(): m.group(2) or m.group(3).replace("%22", '"')
|
||||||
|
@ -67,7 +67,7 @@ def parse_forwarded(headers, config) -> Optional[Options]:
|
||||||
return None
|
return None
|
||||||
# Loop over <separator><key>=<value> elements from right to left
|
# Loop over <separator><key>=<value> elements from right to left
|
||||||
sep = pos = None
|
sep = pos = None
|
||||||
options = []
|
options: List[Tuple[str, str]] = []
|
||||||
found = False
|
found = False
|
||||||
for m in _rparam.finditer(header[::-1]):
|
for m in _rparam.finditer(header[::-1]):
|
||||||
# Start of new element? (on parser skips and non-semicolon right sep)
|
# Start of new element? (on parser skips and non-semicolon right sep)
|
||||||
|
@ -101,8 +101,13 @@ def parse_xforwarded(headers, config) -> Optional[Options]:
|
||||||
try:
|
try:
|
||||||
# Combine, split and filter multiple headers' entries
|
# Combine, split and filter multiple headers' entries
|
||||||
forwarded_for = headers.getall(config.FORWARDED_FOR_HEADER)
|
forwarded_for = headers.getall(config.FORWARDED_FOR_HEADER)
|
||||||
proxies = (p.strip() for h in forwarded_for for p in h.split(","))
|
proxies = [
|
||||||
proxies = [p for p in proxies if p]
|
p
|
||||||
|
for p in (
|
||||||
|
p.strip() for h in forwarded_for for p in h.split(",")
|
||||||
|
)
|
||||||
|
if p
|
||||||
|
]
|
||||||
addr = proxies[-proxies_count]
|
addr = proxies[-proxies_count]
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
pass
|
pass
|
||||||
|
@ -126,7 +131,7 @@ def parse_xforwarded(headers, config) -> Optional[Options]:
|
||||||
|
|
||||||
def fwd_normalize(fwd: OptionsIterable) -> Options:
|
def fwd_normalize(fwd: OptionsIterable) -> Options:
|
||||||
"""Normalize and convert values extracted from forwarded headers."""
|
"""Normalize and convert values extracted from forwarded headers."""
|
||||||
ret = {}
|
ret: Dict[str, Union[int, str]] = {}
|
||||||
for key, val in fwd:
|
for key, val in fwd:
|
||||||
if val is not None:
|
if val is not None:
|
||||||
try:
|
try:
|
||||||
|
@ -164,4 +169,4 @@ def parse_host(host: str) -> Tuple[Optional[str], Optional[int]]:
|
||||||
if not m:
|
if not m:
|
||||||
return None, None
|
return None, None
|
||||||
host, port = m.groups()
|
host, port = m.groups()
|
||||||
return host.lower(), port and int(port)
|
return host.lower(), int(port) if port is not None else None
|
||||||
|
|
|
@ -6,7 +6,7 @@ from collections import defaultdict, namedtuple
|
||||||
from http.cookies import SimpleCookie
|
from http.cookies import SimpleCookie
|
||||||
from urllib.parse import parse_qs, parse_qsl, unquote, urlunparse
|
from urllib.parse import parse_qs, parse_qsl, unquote, urlunparse
|
||||||
|
|
||||||
from httptools import parse_url
|
from httptools import parse_url # type: ignore
|
||||||
|
|
||||||
from sanic.exceptions import InvalidUsage
|
from sanic.exceptions import InvalidUsage
|
||||||
from sanic.headers import (
|
from sanic.headers import (
|
||||||
|
@ -19,9 +19,9 @@ from sanic.log import error_logger, logger
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from ujson import loads as json_loads
|
from ujson import loads as json_loads # type: ignore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from json import loads as json_loads
|
from json import loads as json_loads # type: ignore
|
||||||
|
|
||||||
DEFAULT_HTTP_CONTENT_TYPE = "application/octet-stream"
|
DEFAULT_HTTP_CONTENT_TYPE = "application/octet-stream"
|
||||||
EXPECT_HEADER = "EXPECT"
|
EXPECT_HEADER = "EXPECT"
|
||||||
|
|
|
@ -3,7 +3,7 @@ from mimetypes import guess_type
|
||||||
from os import path
|
from os import path
|
||||||
from urllib.parse import quote_plus
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
from aiofiles import open as open_async
|
from aiofiles import open as open_async # type: ignore
|
||||||
|
|
||||||
from sanic.compat import Header
|
from sanic.compat import Header
|
||||||
from sanic.cookies import CookieJar
|
from sanic.cookies import CookieJar
|
||||||
|
|
|
@ -10,8 +10,8 @@ from signal import signal as signal_func
|
||||||
from socket import SO_REUSEADDR, SOL_SOCKET, socket
|
from socket import SO_REUSEADDR, SOL_SOCKET, socket
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from httptools import HttpRequestParser
|
from httptools import HttpRequestParser # type: ignore
|
||||||
from httptools.parser.errors import HttpParserError
|
from httptools.parser.errors import HttpParserError # type: ignore
|
||||||
|
|
||||||
from sanic.compat import Header
|
from sanic.compat import Header
|
||||||
from sanic.exceptions import (
|
from sanic.exceptions import (
|
||||||
|
@ -28,7 +28,7 @@ from sanic.response import HTTPResponse
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import uvloop
|
import uvloop # type: ignore
|
||||||
|
|
||||||
if not isinstance(asyncio.get_event_loop_policy(), uvloop.EventLoopPolicy):
|
if not isinstance(asyncio.get_event_loop_policy(), uvloop.EventLoopPolicy):
|
||||||
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||||
|
|
|
@ -4,7 +4,7 @@ from re import sub
|
||||||
from time import gmtime, strftime
|
from time import gmtime, strftime
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
from aiofiles.os import stat
|
from aiofiles.os import stat # type: ignore
|
||||||
|
|
||||||
from sanic.exceptions import (
|
from sanic.exceptions import (
|
||||||
ContentRangeError,
|
ContentRangeError,
|
||||||
|
|
|
@ -6,9 +6,9 @@ from json import JSONDecodeError
|
||||||
from socket import socket
|
from socket import socket
|
||||||
from urllib.parse import unquote, urlsplit
|
from urllib.parse import unquote, urlsplit
|
||||||
|
|
||||||
import httpcore
|
import httpcore # type: ignore
|
||||||
import requests_async as requests
|
import requests_async as requests # type: ignore
|
||||||
import websockets
|
import websockets # type: ignore
|
||||||
|
|
||||||
from sanic.asgi import ASGIApp
|
from sanic.asgi import ASGIApp
|
||||||
from sanic.exceptions import MethodNotSupported
|
from sanic.exceptions import MethodNotSupported
|
||||||
|
@ -288,6 +288,14 @@ class SanicASGIAdapter(requests.asgi.ASGIAdapter): # noqa
|
||||||
request_complete = True
|
request_complete = True
|
||||||
return {"type": "http.request", "body": body_bytes}
|
return {"type": "http.request", "body": body_bytes}
|
||||||
|
|
||||||
|
request_complete = False
|
||||||
|
response_started = False
|
||||||
|
response_complete = False
|
||||||
|
raw_kwargs = {"content": b""} # type: typing.Dict[str, typing.Any]
|
||||||
|
template = None
|
||||||
|
context = None
|
||||||
|
return_value = None
|
||||||
|
|
||||||
async def send(message) -> None:
|
async def send(message) -> None:
|
||||||
nonlocal raw_kwargs, response_started, response_complete, template, context # noqa
|
nonlocal raw_kwargs, response_started, response_complete, template, context # noqa
|
||||||
|
|
||||||
|
@ -316,14 +324,6 @@ class SanicASGIAdapter(requests.asgi.ASGIAdapter): # noqa
|
||||||
template = message["template"]
|
template = message["template"]
|
||||||
context = message["context"]
|
context = message["context"]
|
||||||
|
|
||||||
request_complete = False
|
|
||||||
response_started = False
|
|
||||||
response_complete = False
|
|
||||||
raw_kwargs = {"content": b""} # type: typing.Dict[str, typing.Any]
|
|
||||||
template = None
|
|
||||||
context = None
|
|
||||||
return_value = None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return_value = await self.app(scope, receive, send)
|
return_value = await self.app(scope, receive, send)
|
||||||
except BaseException as exc:
|
except BaseException as exc:
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from typing import Any, Callable, List
|
||||||
|
|
||||||
from sanic.constants import HTTP_METHODS
|
from sanic.constants import HTTP_METHODS
|
||||||
from sanic.exceptions import InvalidUsage
|
from sanic.exceptions import InvalidUsage
|
||||||
|
|
||||||
|
@ -37,7 +39,7 @@ class HTTPMethodView:
|
||||||
To add any decorator you could set it into decorators variable
|
To add any decorator you could set it into decorators variable
|
||||||
"""
|
"""
|
||||||
|
|
||||||
decorators = []
|
decorators: List[Callable[[Callable[..., Any]], Callable[..., Any]]] = []
|
||||||
|
|
||||||
def dispatch_request(self, request, *args, **kwargs):
|
def dispatch_request(self, request, *args, **kwargs):
|
||||||
handler = getattr(self, request.method.lower(), None)
|
handler = getattr(self, request.method.lower(), None)
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
from typing import Any, Awaitable, Callable, MutableMapping, Optional, Union
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Awaitable,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
MutableMapping,
|
||||||
|
Optional,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
from httptools import HttpParserUpgrade
|
from httptools import HttpParserUpgrade # type: ignore
|
||||||
from websockets import ConnectionClosed # noqa
|
from websockets import ( # type: ignore
|
||||||
from websockets import InvalidHandshake, WebSocketCommonProtocol, handshake
|
ConnectionClosed,
|
||||||
|
InvalidHandshake,
|
||||||
|
WebSocketCommonProtocol,
|
||||||
|
handshake,
|
||||||
|
)
|
||||||
|
|
||||||
from sanic.exceptions import InvalidUsage
|
from sanic.exceptions import InvalidUsage
|
||||||
from sanic.server import HttpProtocol
|
from sanic.server import HttpProtocol
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["ConnectionClosed", "WebSocketProtocol", "WebSocketConnection"]
|
||||||
|
|
||||||
ASIMessage = MutableMapping[str, Any]
|
ASIMessage = MutableMapping[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,14 +139,12 @@ class WebSocketConnection:
|
||||||
self._receive = receive
|
self._receive = receive
|
||||||
|
|
||||||
async def send(self, data: Union[str, bytes], *args, **kwargs) -> None:
|
async def send(self, data: Union[str, bytes], *args, **kwargs) -> None:
|
||||||
message = {"type": "websocket.send"}
|
message: Dict[str, Union[str, bytes]] = {"type": "websocket.send"}
|
||||||
|
|
||||||
try:
|
if isinstance(data, bytes):
|
||||||
data.decode()
|
|
||||||
except AttributeError:
|
|
||||||
message.update({"text": str(data)})
|
|
||||||
else:
|
|
||||||
message.update({"bytes": data})
|
message.update({"bytes": data})
|
||||||
|
else:
|
||||||
|
message.update({"text": str(data)})
|
||||||
|
|
||||||
await self._send(message)
|
await self._send(message)
|
||||||
|
|
||||||
|
@ -144,6 +156,8 @@ class WebSocketConnection:
|
||||||
elif message["type"] == "websocket.disconnect":
|
elif message["type"] == "websocket.disconnect":
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
receive = recv
|
receive = recv
|
||||||
|
|
||||||
async def accept(self) -> None:
|
async def accept(self) -> None:
|
||||||
|
|
|
@ -5,19 +5,19 @@ import signal
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import gunicorn.workers.base as base
|
import gunicorn.workers.base as base # type: ignore
|
||||||
|
|
||||||
from sanic.server import HttpProtocol, Signal, serve, trigger_events
|
from sanic.server import HttpProtocol, Signal, serve, trigger_events
|
||||||
from sanic.websocket import WebSocketProtocol
|
from sanic.websocket import WebSocketProtocol
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ssl
|
import ssl # type: ignore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
ssl = None
|
ssl = None # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import uvloop
|
import uvloop # type: ignore
|
||||||
|
|
||||||
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
7
tox.ini
7
tox.ini
|
@ -38,6 +38,13 @@ commands =
|
||||||
black --config ./.black.toml --check --verbose sanic/
|
black --config ./.black.toml --check --verbose sanic/
|
||||||
isort --check-only --recursive sanic
|
isort --check-only --recursive sanic
|
||||||
|
|
||||||
|
[testenv:type-checking]
|
||||||
|
deps =
|
||||||
|
mypy
|
||||||
|
|
||||||
|
commands =
|
||||||
|
mypy sanic
|
||||||
|
|
||||||
[testenv:check]
|
[testenv:check]
|
||||||
deps =
|
deps =
|
||||||
docutils
|
docutils
|
||||||
|
|
Loading…
Reference in New Issue
Block a user