Compare commits

..

6 Commits
main ... ruff

Author SHA1 Message Date
L. Kärkkäinen
ec35f5f2c8 Fix/ignore all remaining errors. 2023-10-25 02:03:44 +01:00
L. Kärkkäinen
9ae25e6744 ruff --fix # also import sorting 2023-10-25 01:03:35 +01:00
L. Kärkkäinen
758f10c513 ruff --fix --unsafe-fixes # Tests still A-OK! 2023-10-25 00:32:27 +01:00
L. Kärkkäinen
140d27ef96 ruff format 2023-10-25 00:22:00 +01:00
L. Kärkkäinen
209840b771 ruff --fix 2023-10-25 00:21:29 +01:00
L. Kärkkäinen
20fd58b8d7 Add config for Ruff 2023-10-25 00:21:09 +01:00
56 changed files with 89 additions and 109 deletions

View File

@ -19,7 +19,7 @@ import sys
root_directory = os.path.dirname(os.getcwd()) root_directory = os.path.dirname(os.getcwd())
sys.path.insert(0, root_directory) sys.path.insert(0, root_directory)
import sanic import sanic # noqa: E402
# -- General configuration ------------------------------------------------ # -- General configuration ------------------------------------------------

View File

@ -25,5 +25,6 @@ def key_exist_handler(request):
return text("num does not exist in request") return text("num does not exist in request")
if __name__ == "__main__": if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True) app.run(host="0.0.0.0", port=8000, debug=True)

View File

@ -69,5 +69,6 @@ async def runner(app: Sanic, app_server: AsyncioServer):
app.is_running = False app.is_running = False
app.is_stopping = True app.is_stopping = True
if __name__ == "__main__": if __name__ == "__main__":
https.run(port=HTTPS_PORT, debug=True) https.run(port=HTTPS_PORT, debug=True)

View File

@ -1,5 +1,6 @@
import requests import requests
# Warning: This is a heavy process. # Warning: This is a heavy process.
data = "" data = ""

View File

@ -35,6 +35,7 @@ async def after_server_stop(app, loop):
async def test(request): async def test(request):
return response.json({"answer": "42"}) return response.json({"answer": "42"})
if __name__ == "__main__": if __name__ == "__main__":
asyncio.set_event_loop(uvloop.new_event_loop()) asyncio.set_event_loop(uvloop.new_event_loop())
serv_coro = app.create_server( serv_coro = app.create_server(

View File

@ -1,4 +1,5 @@
import re import re
from pathlib import Path from pathlib import Path
from textwrap import indent from textwrap import indent

7
guide/pyproject.toml Normal file
View File

@ -0,0 +1,7 @@
[tool.ruff]
extend = "../pyproject.toml"
[tool.ruff.isort]
known-first-party = ["webapp"]
lines-after-imports = 1
lines-between-types = 1

View File

@ -2,7 +2,6 @@ from __future__ import annotations
from html5tagger import Builder, Document # type: ignore from html5tagger import Builder, Document # type: ignore
class BaseRenderer: class BaseRenderer:
def __init__(self, base_title: str): def __init__(self, base_title: str):
self.base_title = base_title self.base_title = base_title

View File

@ -7,7 +7,6 @@ from pygments.token import ( # Error,; Generic,; Number,; Operator,
Token, Token,
) )
class SanicCodeStyle(Style): class SanicCodeStyle(Style):
styles = { styles = {
Token: "#777", Token: "#777",

View File

@ -6,7 +6,6 @@ from typing import Generator
from html5tagger import Builder from html5tagger import Builder
from sanic import Request from sanic import Request
class BaseLayout: class BaseLayout:
def __init__(self, builder: Builder): def __init__(self, builder: Builder):
self.builder = builder self.builder = builder

View File

@ -3,7 +3,6 @@ from datetime import datetime
from html5tagger import Builder, E # type: ignore from html5tagger import Builder, E # type: ignore
from sanic import Request from sanic import Request
def do_footer(builder: Builder, request: Request) -> None: def do_footer(builder: Builder, request: Request) -> None:
builder.footer( builder.footer(
_pagination(request), _pagination(request),

View File

@ -1,8 +1,7 @@
from webapp.display.layouts.models import MenuItem
from html5tagger import Builder, E # type: ignore from html5tagger import Builder, E # type: ignore
from sanic import Request from sanic import Request
from webapp.display.layouts.models import MenuItem
def do_navbar(builder: Builder, request: Request) -> None: def do_navbar(builder: Builder, request: Request) -> None:
navbar_items = [ navbar_items = [

View File

@ -1,9 +1,8 @@
from webapp.display.layouts.models import MenuItem
from webapp.display.text import slugify
from html5tagger import Builder, E # type: ignore from html5tagger import Builder, E # type: ignore
from sanic import Request from sanic import Request
from webapp.display.layouts.models import MenuItem
from webapp.display.text import slugify
def do_sidebar(builder: Builder, request: Request) -> None: def do_sidebar(builder: Builder, request: Request) -> None:
builder.a(class_="burger")(E.span().span().span().span()) builder.a(class_="burger")(E.span().span().span().span())

View File

@ -8,7 +8,6 @@ from sanic import Request
from .base import BaseLayout from .base import BaseLayout
class HomeLayout(BaseLayout): class HomeLayout(BaseLayout):
@contextmanager @contextmanager
def layout( def layout(

View File

@ -1,15 +1,14 @@
from contextlib import contextmanager from contextlib import contextmanager
from typing import Generator from typing import Generator
from sanic import Request
from webapp.display.layouts.elements.footer import do_footer from webapp.display.layouts.elements.footer import do_footer
from webapp.display.layouts.elements.navbar import do_navbar from webapp.display.layouts.elements.navbar import do_navbar
from webapp.display.layouts.elements.sidebar import do_sidebar from webapp.display.layouts.elements.sidebar import do_sidebar
from sanic import Request
from .base import BaseLayout from .base import BaseLayout
class MainLayout(BaseLayout): class MainLayout(BaseLayout):
@contextmanager @contextmanager
def layout( def layout(

View File

@ -2,7 +2,6 @@ from __future__ import annotations
from msgspec import Struct, field from msgspec import Struct, field
class MenuItem(Struct, kw_only=False, omit_defaults=True): class MenuItem(Struct, kw_only=False, omit_defaults=True):
label: str label: str
path: str | None = None path: str | None = None

View File

@ -1,6 +1,8 @@
import re import re
from textwrap import dedent from textwrap import dedent
from html5tagger import HTML, Builder, E # type: ignore
from mistune import HTMLRenderer, create_markdown, escape from mistune import HTMLRenderer, create_markdown, escape
from mistune.directives import RSTDirective, TableOfContents from mistune.directives import RSTDirective, TableOfContents
from mistune.util import safe_entity from mistune.util import safe_entity
@ -8,8 +10,6 @@ from pygments import highlight
from pygments.formatters import html from pygments.formatters import html
from pygments.lexers import get_lexer_by_name from pygments.lexers import get_lexer_by_name
from html5tagger import HTML, Builder, E # type: ignore
from .code_style import SanicCodeStyle from .code_style import SanicCodeStyle
from .plugins.attrs import Attributes from .plugins.attrs import Attributes
from .plugins.columns import Column from .plugins.columns import Column
@ -20,7 +20,6 @@ from .plugins.span import span
from .plugins.tabs import Tabs from .plugins.tabs import Tabs
from .text import slugify from .text import slugify
class DocsRenderer(HTMLRenderer): class DocsRenderer(HTMLRenderer):
def block_code(self, code: str, info: str | None = None): def block_code(self, code: str, info: str | None = None):
builder = Builder("Block") builder = Builder("Block")

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import importlib import importlib
import inspect import inspect
import pkgutil import pkgutil
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass, field from dataclasses import dataclass, field
from html import escape from html import escape
@ -10,12 +11,10 @@ from html import escape
from docstring_parser import Docstring, DocstringParam, DocstringRaises from docstring_parser import Docstring, DocstringParam, DocstringRaises
from docstring_parser import parse as parse_docstring from docstring_parser import parse as parse_docstring
from docstring_parser.common import DocstringExample from docstring_parser.common import DocstringExample
from html5tagger import HTML, Builder, E # type: ignore from html5tagger import HTML, Builder, E # type: ignore
from ..markdown import render_markdown, slugify from ..markdown import render_markdown, slugify
@dataclass @dataclass
class DocObject: class DocObject:
name: str name: str

View File

@ -3,15 +3,14 @@ from __future__ import annotations
from contextlib import contextmanager from contextlib import contextmanager
from typing import Type from typing import Type
from webapp.display.base import BaseRenderer
from html5tagger import HTML, Builder # type: ignore from html5tagger import HTML, Builder # type: ignore
from sanic import Request from sanic import Request
from webapp.display.base import BaseRenderer
from ..layouts.base import BaseLayout from ..layouts.base import BaseLayout
from .page import Page from .page import Page
class PageRenderer(BaseRenderer): class PageRenderer(BaseRenderer):
def render(self, request: Request, language: str, path: str) -> Builder: def render(self, request: Request, language: str, path: str) -> Builder:
builder = self.get_builder( builder = self.get_builder(

View File

@ -2,13 +2,11 @@ from re import Match
from textwrap import dedent from textwrap import dedent
from typing import Any from typing import Any
from html5tagger import HTML, E
from mistune.block_parser import BlockParser from mistune.block_parser import BlockParser
from mistune.core import BlockState from mistune.core import BlockState
from mistune.directives import DirectivePlugin from mistune.directives import DirectivePlugin
from html5tagger import HTML, E
class Attributes(DirectivePlugin): class Attributes(DirectivePlugin):
def __call__(self, directive, md): def __call__(self, directive, md):
directive.register("attrs", self.parse) directive.register("attrs", self.parse)

View File

@ -8,7 +8,6 @@ from mistune.core import BlockState
from mistune.directives import DirectivePlugin, RSTDirective from mistune.directives import DirectivePlugin, RSTDirective
from mistune.markdown import Markdown from mistune.markdown import Markdown
class Column(DirectivePlugin): class Column(DirectivePlugin):
def parse( def parse(
self, block: BlockParser, m: Match, state: BlockState self, block: BlockParser, m: Match, state: BlockState

View File

@ -2,7 +2,6 @@ from mistune.core import BlockState
from mistune.directives import DirectivePlugin, RSTDirective from mistune.directives import DirectivePlugin, RSTDirective
from mistune.markdown import Markdown from mistune.markdown import Markdown
class Hook(DirectivePlugin): class Hook(DirectivePlugin):
def __call__( # type: ignore def __call__( # type: ignore
self, directive: RSTDirective, md: Markdown self, directive: RSTDirective, md: Markdown

View File

@ -3,15 +3,13 @@ from re import Match
from textwrap import dedent from textwrap import dedent
from typing import Any from typing import Any
from html5tagger import HTML, E
from mistune import HTMLRenderer from mistune import HTMLRenderer
from mistune.block_parser import BlockParser from mistune.block_parser import BlockParser
from mistune.core import BlockState from mistune.core import BlockState
from mistune.directives import DirectivePlugin, RSTDirective from mistune.directives import DirectivePlugin, RSTDirective
from mistune.markdown import Markdown from mistune.markdown import Markdown
from html5tagger import HTML, E
class Mermaid(DirectivePlugin): class Mermaid(DirectivePlugin):
def parse( def parse(
self, block: BlockParser, m: Match, state: BlockState self, block: BlockParser, m: Match, state: BlockState

View File

@ -1,7 +1,5 @@
from mistune.directives import Admonition
from html5tagger import HTML, E from html5tagger import HTML, E
from mistune.directives import Admonition
class Notification(Admonition): class Notification(Admonition):
SUPPORTED_NAMES = { SUPPORTED_NAMES = {

View File

@ -2,7 +2,6 @@ import re
from mistune.markdown import Markdown from mistune.markdown import Markdown
def parse_inline_span(inline, m: re.Match, state): def parse_inline_span(inline, m: re.Match, state):
state.append_token( state.append_token(
{ {

View File

@ -8,7 +8,6 @@ from mistune.core import BlockState
from mistune.directives import DirectivePlugin, RSTDirective from mistune.directives import DirectivePlugin, RSTDirective
from mistune.markdown import Markdown from mistune.markdown import Markdown
class Tabs(DirectivePlugin): class Tabs(DirectivePlugin):
def parse( def parse(
self, block: BlockParser, m: Match, state: BlockState self, block: BlockParser, m: Match, state: BlockState

View File

@ -1,15 +1,14 @@
from contextlib import contextmanager from contextlib import contextmanager
from urllib.parse import unquote from urllib.parse import unquote
from webapp.display.search.search import Searcher
from html5tagger import Builder, E # type: ignore from html5tagger import Builder, E # type: ignore
from sanic import Request from sanic import Request
from webapp.display.search.search import Searcher
from ..base import BaseRenderer from ..base import BaseRenderer
from ..layouts.main import MainLayout from ..layouts.main import MainLayout
class SearchRenderer(BaseRenderer): class SearchRenderer(BaseRenderer):
def render( def render(
self, request: Request, language: str, searcher: Searcher, full: bool self, request: Request, language: str, searcher: Searcher, full: bool

View File

@ -5,8 +5,8 @@ from pathlib import Path
from typing import ClassVar from typing import ClassVar
from msgspec import Struct from msgspec import Struct
from webapp.display.page import Page
from webapp.display.page import Page
class Stemmer: class Stemmer:
STOP_WORDS: ClassVar[set[str]] = set( STOP_WORDS: ClassVar[set[str]] = set(

View File

@ -1,11 +1,11 @@
# from urllib.parse import unquote # from urllib.parse import unquote
from sanic import Blueprint, Request, Sanic, html
from webapp.display.page import Page from webapp.display.page import Page
from webapp.display.search.renderer import SearchRenderer from webapp.display.search.renderer import SearchRenderer
from webapp.display.search.search import Document, Searcher, Stemmer from webapp.display.search.search import Document, Searcher, Stemmer
from sanic import Blueprint, Request, Sanic, html
bp = Blueprint("search", url_prefix="/<language>/search") bp = Blueprint("search", url_prefix="/<language>/search")

View File

@ -1,8 +1,8 @@
from pathlib import Path from pathlib import Path
from msgspec import yaml from msgspec import yaml
from webapp.display.layouts.models import GeneralConfig, MenuItem
from webapp.display.layouts.models import GeneralConfig, MenuItem
def load_menu(path: Path) -> list[MenuItem]: def load_menu(path: Path) -> list[MenuItem]:
loaded = yaml.decode(path.read_bytes(), type=dict[str, list[MenuItem]]) loaded = yaml.decode(path.read_bytes(), type=dict[str, list[MenuItem]])

View File

@ -1,5 +1,7 @@
from pathlib import Path from pathlib import Path
from sanic import Request, Sanic, html, redirect
from webapp.display.layouts.models import MenuItem from webapp.display.layouts.models import MenuItem
from webapp.display.page import Page, PageRenderer from webapp.display.page import Page, PageRenderer
from webapp.endpoint.view import bp from webapp.endpoint.view import bp
@ -7,9 +9,6 @@ from webapp.worker.config import load_config, load_menu
from webapp.worker.reload import setup_livereload from webapp.worker.reload import setup_livereload
from webapp.worker.style import setup_style from webapp.worker.style import setup_style
from sanic import Request, Sanic, html, redirect
def _compile_sidebar_order(items: list[MenuItem]) -> list[str]: def _compile_sidebar_order(items: list[MenuItem]) -> list[str]:
order = [] order = []
for item in items: for item in items:

View File

@ -8,7 +8,6 @@ import ujson
from sanic import Request, Sanic, Websocket from sanic import Request, Sanic, Websocket
def setup_livereload(app: Sanic) -> None: def setup_livereload(app: Sanic) -> None:
@app.main_process_start @app.main_process_start
async def main_process_start(app: Sanic): async def main_process_start(app: Sanic):

View File

@ -1,11 +1,10 @@
# from scss.compiler import compile_string # from scss.compiler import compile_string
from pygments.formatters import html from pygments.formatters import html
from sass import compile as compile_scss
from webapp.display.code_style import SanicCodeStyle
from sanic import Sanic from sanic import Sanic
from sass import compile as compile_scss
from webapp.display.code_style import SanicCodeStyle
def setup_style(app: Sanic) -> None: def setup_style(app: Sanic) -> None:
index = app.config.STYLE_DIR / "index.scss" index = app.config.STYLE_DIR / "index.scss"

View File

@ -2,6 +2,19 @@
requires = ["setuptools", "wheel"] requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta" build-backend = "setuptools.build_meta"
[tool.ruff]
extend-select = ["I"]
ignore = ["D100", "D101", "D102", "D103", "E402", "E741", "F811", "F821"]
line-length = 79
show-source = true
show-fixes = true
[tool.ruff.isort]
known-first-party = ["sanic"]
known-third-party = ["pytest"]
lines-after-imports = 2
lines-between-types = 1
[tool.black] [tool.black]
line-length = 79 line-length = 79

View File

@ -349,8 +349,7 @@ def parse_content_header(value: str) -> Tuple[str, Options]:
options: Dict[str, Union[int, str]] = {} options: Dict[str, Union[int, str]] = {}
else: else:
options = { options = {
m.group(1) m.group(1).lower(): (m.group(2) or m.group(3))
.lower(): (m.group(2) or m.group(3))
.replace("%22", '"') .replace("%22", '"')
.replace("%0D%0A", "\n") .replace("%0D%0A", "\n")
for m in _param.finditer(value[pos:]) for m in _param.finditer(value[pos:])

View File

@ -14,7 +14,7 @@ class ExceptionMixin(metaclass=SanicMeta):
def exception( def exception(
self, self,
*exceptions: Union[Type[Exception], List[Type[Exception]]], *exceptions: Union[Type[Exception], List[Type[Exception]]],
apply: bool = True apply: bool = True,
) -> Callable: ) -> Callable:
"""Decorator used to register an exception handler for the current application or blueprint instance. """Decorator used to register an exception handler for the current application or blueprint instance.

View File

@ -25,7 +25,7 @@ class MiddlewareMixin(metaclass=SanicMeta):
attach_to: str = "request", attach_to: str = "request",
apply: bool = True, apply: bool = True,
*, *,
priority: int = 0 priority: int = 0,
) -> MiddlewareType: ) -> MiddlewareType:
... ...
@ -36,7 +36,7 @@ class MiddlewareMixin(metaclass=SanicMeta):
attach_to: str = "request", attach_to: str = "request",
apply: bool = True, apply: bool = True,
*, *,
priority: int = 0 priority: int = 0,
) -> Callable[[MiddlewareType], MiddlewareType]: ) -> Callable[[MiddlewareType], MiddlewareType]:
... ...
@ -46,7 +46,7 @@ class MiddlewareMixin(metaclass=SanicMeta):
attach_to: str = "request", attach_to: str = "request",
apply: bool = True, apply: bool = True,
*, *,
priority: int = 0 priority: int = 0,
) -> Union[MiddlewareType, Callable[[MiddlewareType], MiddlewareType]]: ) -> Union[MiddlewareType, Callable[[MiddlewareType], MiddlewareType]]:
"""Decorator for registering middleware. """Decorator for registering middleware.

View File

@ -44,12 +44,8 @@ class ConnInfo:
self.server_name = "" self.server_name = ""
self.cert: Dict[str, Any] = {} self.cert: Dict[str, Any] = {}
self.network_paths: List[Any] = [] self.network_paths: List[Any] = []
sslobj: Optional[SSLObject] = transport.get_extra_info( sslobj: Optional[SSLObject] = transport.get_extra_info("ssl_object") # type: ignore
"ssl_object" sslctx: Optional[SSLContext] = transport.get_extra_info("ssl_context") # type: ignore
) # type: ignore
sslctx: Optional[SSLContext] = transport.get_extra_info(
"ssl_context"
) # type: ignore
if sslobj: if sslobj:
self.ssl = True self.ssl = True
self.server_name = getattr(sslobj, "sanic_server_name", None) or "" self.server_name = getattr(sslobj, "sanic_server_name", None) or ""

View File

@ -57,9 +57,7 @@ class WebsocketFrameAssembler:
self.read_mutex = asyncio.Lock() self.read_mutex = asyncio.Lock()
self.write_mutex = asyncio.Lock() self.write_mutex = asyncio.Lock()
self.completed_queue = asyncio.Queue( self.completed_queue = asyncio.Queue(maxsize=1) # type: asyncio.Queue[Data]
maxsize=1
) # type: asyncio.Queue[Data]
# put() sets this event to tell get() that a message can be fetched. # put() sets this event to tell get() that a message can be fetched.
self.message_complete = asyncio.Event() self.message_complete = asyncio.Event()

View File

@ -1,7 +1,6 @@
from collections.abc import Mapping from collections.abc import Mapping
from typing import Any, Dict, ItemsView, Iterator, KeysView, List from typing import Any, Dict, ItemsView, Iterator, KeysView, List, ValuesView
from typing import Mapping as MappingType from typing import Mapping as MappingType
from typing import ValuesView
dict dict

View File

@ -1,12 +1,14 @@
#!/usr/bin/env python #!/usr/bin/env python
from os import path
import sys import sys
from os import path
if __name__ == "__main__": if __name__ == "__main__":
try: try:
import towncrier
import click import click
import towncrier
except ImportError: except ImportError:
print( print(
"Please make sure you have a installed towncrier and click before using this tool" "Please make sure you have a installed towncrier and click before using this tool"

View File

@ -1,18 +1,21 @@
#!/usr/bin/env python #!/usr/bin/env python
import sys
from argparse import ArgumentParser, Namespace from argparse import ArgumentParser, Namespace
from collections import OrderedDict from collections import OrderedDict
from configparser import RawConfigParser from configparser import RawConfigParser
from datetime import datetime from datetime import datetime
from json import dumps from json import dumps
from os import path, chdir from os import chdir, path
from subprocess import Popen, PIPE from subprocess import PIPE, Popen
from jinja2 import Environment, BaseLoader
from requests import patch
import sys
import towncrier import towncrier
from jinja2 import BaseLoader, Environment
from requests import patch
GIT_COMMANDS = { GIT_COMMANDS = {
"get_tag": ["git describe --tags --abbrev=0"], "get_tag": ["git describe --tags --abbrev=0"],
"commit_version_change": [ "commit_version_change": [
@ -78,7 +81,7 @@ def _run_shell_command(command: list):
output, error = process.communicate() output, error = process.communicate()
return_code = process.returncode return_code = process.returncode
return output.decode("utf-8"), error, return_code return output.decode("utf-8"), error, return_code
except: except Exception:
return None, None, -1 return None, None, -1

View File

@ -2,7 +2,7 @@
import bottle import bottle
import ujson import ujson
from bottle import route, run from bottle import route
@route("/") @route("/")

View File

@ -3,8 +3,6 @@ import os
import sys import sys
import timeit import timeit
import asyncpg
from sanic.response import json from sanic.response import json

View File

@ -4,7 +4,6 @@
import ujson import ujson
from wheezy.http import HTTPResponse, WSGIApplication from wheezy.http import HTTPResponse, WSGIApplication
from wheezy.http.response import json_response
from wheezy.routing import url from wheezy.routing import url
from wheezy.web.handlers import BaseHandler from wheezy.web.handlers import BaseHandler
from wheezy.web.middleware import ( from wheezy.web.middleware import (

View File

@ -1,4 +1,3 @@
import asyncio
import logging import logging
from collections import deque, namedtuple from collections import deque, namedtuple
@ -12,7 +11,7 @@ from pytest import MonkeyPatch
from sanic import Sanic from sanic import Sanic
from sanic.application.state import Mode from sanic.application.state import Mode
from sanic.asgi import ASGIApp, Lifespan, MockTransport from sanic.asgi import Lifespan, MockTransport
from sanic.exceptions import BadRequest, Forbidden, ServiceUnavailable from sanic.exceptions import BadRequest, Forbidden, ServiceUnavailable
from sanic.request import Request from sanic.request import Request
from sanic.response import json, text from sanic.response import json, text

View File

@ -22,7 +22,7 @@ def test_bp_group_indexing(app: Sanic):
group = Blueprint.group(blueprint_1, blueprint_2) group = Blueprint.group(blueprint_1, blueprint_2)
assert group[0] == blueprint_1 assert group[0] == blueprint_1
with raises(expected_exception=IndexError) as e: with raises(expected_exception=IndexError):
_ = group[3] _ = group[3]

View File

@ -1,9 +1,5 @@
import asyncio
from asyncio import CancelledError from asyncio import CancelledError
import pytest
from sanic import Request, Sanic, json from sanic import Request, Sanic, json

View File

@ -7,7 +7,7 @@ from unittest.mock import Mock
import pytest import pytest
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from pytest import LogCaptureFixture, MonkeyPatch, WarningsRecorder from pytest import LogCaptureFixture, MonkeyPatch
from sanic import Sanic, handlers from sanic import Sanic, handlers
from sanic.exceptions import BadRequest, Forbidden, NotFound, ServerError from sanic.exceptions import BadRequest, Forbidden, NotFound, ServerError
@ -169,7 +169,7 @@ def test_exception_handler_lookup(exception_handler_app: Sanic):
pass pass
try: try:
ModuleNotFoundError ModuleNotFoundError # noqa: F823
except Exception: except Exception:
class ModuleNotFoundError(ImportError): class ModuleNotFoundError(ImportError):

View File

@ -1,14 +1,12 @@
import sys import sys
from unittest.mock import MagicMock
import pytest import pytest
from sanic import Sanic from sanic import Sanic
try: try:
import sanic_ext import sanic_ext # noqa: F401
SANIC_EXT_IN_ENV = True SANIC_EXT_IN_ENV = True
except ImportError: except ImportError:

View File

@ -57,7 +57,7 @@ def raised_ceiling():
# Chrome, Firefox: # Chrome, Firefox:
# Content-Disposition: form-data; name="foo%22;bar\"; filename="😀" # Content-Disposition: form-data; name="foo%22;bar\"; filename="😀"
'form-data; name="foo%22;bar\\"; filename="😀"', 'form-data; name="foo%22;bar\\"; filename="😀"',
("form-data", {"name": 'foo";bar\\', "filename": "😀"}) ("form-data", {"name": 'foo";bar\\', "filename": "😀"}),
# cgi: ('form-data', {'name': 'foo%22;bar"; filename="😀'}) # cgi: ('form-data', {'name': 'foo%22;bar"; filename="😀'})
# werkzeug (pre 2.3.0): ('form-data', {'name': 'foo%22;bar"; filename='}) # werkzeug (pre 2.3.0): ('form-data', {'name': 'foo%22;bar"; filename='})
), ),

View File

@ -14,7 +14,6 @@ from sanic_testing.testing import HOST, PORT
from sanic import Blueprint, text from sanic import Blueprint, text
from sanic.compat import use_context from sanic.compat import use_context
from sanic.log import logger from sanic.log import logger
from sanic.server.socket import configure_socket
@pytest.mark.skipif( @pytest.mark.skipif(

View File

@ -573,7 +573,7 @@ def test_streaming_echo():
async def client(app, reader, writer): async def client(app, reader, writer):
# Unfortunately httpx does not support 2-way streaming, so do it by hand. # Unfortunately httpx does not support 2-way streaming, so do it by hand.
host = f"host: localhost:8000\r\n".encode() host = "host: localhost:8000\r\n".encode()
writer.write( writer.write(
b"POST /echo HTTP/1.1\r\n" + host + b"content-length: 2\r\n" b"POST /echo HTTP/1.1\r\n" + host + b"content-length: 2\r\n"
b"content-type: text/plain; charset=utf-8\r\n" b"content-type: text/plain; charset=utf-8\r\n"
@ -581,7 +581,7 @@ def test_streaming_echo():
) )
# Read response # Read response
res = b"" res = b""
while not b"\r\n\r\n" in res: while b"\r\n\r\n" not in res:
res += await reader.read(4096) res += await reader.read(4096)
assert res.startswith(b"HTTP/1.1 200 OK\r\n") assert res.startswith(b"HTTP/1.1 200 OK\r\n")
assert res.endswith(b"\r\n\r\n") assert res.endswith(b"\r\n\r\n")
@ -589,7 +589,7 @@ def test_streaming_echo():
async def read_chunk(): async def read_chunk():
nonlocal buffer nonlocal buffer
while not b"\r\n" in buffer: while b"\r\n" not in buffer:
data = await reader.read(4096) data = await reader.read(4096)
assert data assert data
buffer += data buffer += data
@ -618,6 +618,6 @@ def test_streaming_echo():
assert res == b"-" assert res == b"-"
res = await read_chunk() res = await read_chunk()
assert res == None assert res is None
app.run(access_log=False, single_process=True) app.run(access_log=False, single_process=True)

View File

@ -2011,11 +2011,11 @@ def test_server_name_and_url_for(app):
app.config.SERVER_NAME = "my-server" # This means default port app.config.SERVER_NAME = "my-server" # This means default port
assert app.url_for("handler", _external=True) == "http://my-server/foo" assert app.url_for("handler", _external=True) == "http://my-server/foo"
request, response = app.test_client.get("/foo") request, response = app.test_client.get("/foo")
assert request.url_for("handler") == f"http://my-server/foo" assert request.url_for("handler") == "http://my-server/foo"
app.config.SERVER_NAME = "https://my-server/path" app.config.SERVER_NAME = "https://my-server/path"
request, response = app.test_client.get("/foo") request, response = app.test_client.get("/foo")
url = f"https://my-server/path/foo" url = "https://my-server/path/foo"
assert app.url_for("handler", _external=True) == url assert app.url_for("handler", _external=True) == url
assert request.url_for("handler") == url assert request.url_for("handler") == url
@ -2180,7 +2180,7 @@ def test_safe_method_with_body_ignored(app):
) )
assert request.body == b"" assert request.body == b""
assert request.json == None assert request.json is None
assert response.body == b"OK" assert response.body == b"OK"

View File

@ -610,7 +610,7 @@ def test_multiple_responses(
@app.get("/4") @app.get("/4")
async def handler4(request: Request): async def handler4(request: Request):
response = await request.respond(headers={"one": "one"}) await request.respond(headers={"one": "one"})
return json({"foo": "bar"}, headers={"one": "two"}) return json({"foo": "bar"}, headers={"one": "two"})
@app.get("/5") @app.get("/5")
@ -641,10 +641,6 @@ def test_multiple_responses(
"been responded to." "been responded to."
) )
error_msg3 = (
"Response stream was ended, no more "
"response data is allowed to be sent."
)
with caplog.at_level(ERROR): with caplog.at_level(ERROR):
_, response = app.test_client.get("/1") _, response = app.test_client.get("/1")
@ -769,7 +765,7 @@ def test_file_response_headers(
assert ( assert (
"cache-control" in headers "cache-control" in headers
and f"max-age={test_max_age}" in headers.get("cache-control") and f"max-age={test_max_age}" in headers.get("cache-control")
and f"public" in headers.get("cache-control") and "public" in headers.get("cache-control")
) )
assert ( assert (
"expires" in headers "expires" in headers
@ -800,14 +796,14 @@ def test_file_response_headers(
_, response = app.test_client.get(f"/files/no_cache/{file_name}") _, response = app.test_client.get(f"/files/no_cache/{file_name}")
headers = response.headers headers = response.headers
assert "cache-control" in headers and f"no-cache" == headers.get( assert "cache-control" in headers and "no-cache" == headers.get(
"cache-control" "cache-control"
) )
assert response.status == 200 assert response.status == 200
_, response = app.test_client.get(f"/files/no_store/{file_name}") _, response = app.test_client.get(f"/files/no_store/{file_name}")
headers = response.headers headers = response.headers
assert "cache-control" in headers and f"no-store" == headers.get( assert "cache-control" in headers and "no-store" == headers.get(
"cache-control" "cache-control"
) )
assert response.status == 200 assert response.status == 200

View File

@ -1,7 +1,6 @@
# flake8: noqa: E501 # flake8: noqa: E501
import subprocess import subprocess
import sys
from pathlib import Path from pathlib import Path
from typing import List, Tuple from typing import List, Tuple