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())
sys.path.insert(0, root_directory)
import sanic
import sanic # noqa: E402
# -- General configuration ------------------------------------------------

View File

@ -25,5 +25,6 @@ def key_exist_handler(request):
return text("num does not exist in request")
if __name__ == "__main__":
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_stopping = True
if __name__ == "__main__":
https.run(port=HTTPS_PORT, debug=True)

View File

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

View File

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

View File

@ -1,4 +1,5 @@
import re
from pathlib import Path
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
class BaseRenderer:
def __init__(self, base_title: str):
self.base_title = base_title

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,6 @@ from mistune.core import BlockState
from mistune.directives import DirectivePlugin, RSTDirective
from mistune.markdown import Markdown
class Column(DirectivePlugin):
def parse(
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.markdown import Markdown
class Hook(DirectivePlugin):
def __call__( # type: ignore
self, directive: RSTDirective, md: Markdown

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
from pathlib import Path
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]:
loaded = yaml.decode(path.read_bytes(), type=dict[str, list[MenuItem]])

View File

@ -1,5 +1,7 @@
from pathlib import Path
from sanic import Request, Sanic, html, redirect
from webapp.display.layouts.models import MenuItem
from webapp.display.page import Page, PageRenderer
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.style import setup_style
from sanic import Request, Sanic, html, redirect
def _compile_sidebar_order(items: list[MenuItem]) -> list[str]:
order = []
for item in items:

View File

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

View File

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

View File

@ -2,6 +2,19 @@
requires = ["setuptools", "wheel"]
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]
line-length = 79

View File

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

View File

@ -14,7 +14,7 @@ class ExceptionMixin(metaclass=SanicMeta):
def exception(
self,
*exceptions: Union[Type[Exception], List[Type[Exception]]],
apply: bool = True
apply: bool = True,
) -> Callable:
"""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",
apply: bool = True,
*,
priority: int = 0
priority: int = 0,
) -> MiddlewareType:
...
@ -36,7 +36,7 @@ class MiddlewareMixin(metaclass=SanicMeta):
attach_to: str = "request",
apply: bool = True,
*,
priority: int = 0
priority: int = 0,
) -> Callable[[MiddlewareType], MiddlewareType]:
...
@ -46,7 +46,7 @@ class MiddlewareMixin(metaclass=SanicMeta):
attach_to: str = "request",
apply: bool = True,
*,
priority: int = 0
priority: int = 0,
) -> Union[MiddlewareType, Callable[[MiddlewareType], MiddlewareType]]:
"""Decorator for registering middleware.

View File

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

View File

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

View File

@ -1,7 +1,6 @@
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 ValuesView
dict

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,3 @@
import asyncio
import logging
from collections import deque, namedtuple
@ -12,7 +11,7 @@ from pytest import MonkeyPatch
from sanic import Sanic
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.request import Request
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)
assert group[0] == blueprint_1
with raises(expected_exception=IndexError) as e:
with raises(expected_exception=IndexError):
_ = group[3]

View File

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

View File

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

View File

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

View File

@ -57,7 +57,7 @@ def raised_ceiling():
# Chrome, Firefox:
# Content-Disposition: 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="😀'})
# 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.compat import use_context
from sanic.log import logger
from sanic.server.socket import configure_socket
@pytest.mark.skipif(

View File

@ -573,7 +573,7 @@ def test_streaming_echo():
async def client(app, reader, writer):
# 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(
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"
@ -581,7 +581,7 @@ def test_streaming_echo():
)
# Read response
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)
assert res.startswith(b"HTTP/1.1 200 OK\r\n")
assert res.endswith(b"\r\n\r\n")
@ -589,7 +589,7 @@ def test_streaming_echo():
async def read_chunk():
nonlocal buffer
while not b"\r\n" in buffer:
while b"\r\n" not in buffer:
data = await reader.read(4096)
assert data
buffer += data
@ -618,6 +618,6 @@ def test_streaming_echo():
assert res == b"-"
res = await read_chunk()
assert res == None
assert res is None
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
assert app.url_for("handler", _external=True) == "http://my-server/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"
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 request.url_for("handler") == url
@ -2180,7 +2180,7 @@ def test_safe_method_with_body_ignored(app):
)
assert request.body == b""
assert request.json == None
assert request.json is None
assert response.body == b"OK"

View File

@ -610,7 +610,7 @@ def test_multiple_responses(
@app.get("/4")
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"})
@app.get("/5")
@ -641,10 +641,6 @@ def test_multiple_responses(
"been responded to."
)
error_msg3 = (
"Response stream was ended, no more "
"response data is allowed to be sent."
)
with caplog.at_level(ERROR):
_, response = app.test_client.get("/1")
@ -769,7 +765,7 @@ def test_file_response_headers(
assert (
"cache-control" in headers
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 (
"expires" in headers
@ -800,14 +796,14 @@ def test_file_response_headers(
_, response = app.test_client.get(f"/files/no_cache/{file_name}")
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"
)
assert response.status == 200
_, response = app.test_client.get(f"/files/no_store/{file_name}")
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"
)
assert response.status == 200

View File

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