Skip to content

Commit

Permalink
Sanic on pypy (#2682)
Browse files Browse the repository at this point in the history
Co-authored-by: L. Kärkkäinen <98187+Tronic@users.noreply.github.com>
Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
  • Loading branch information
4 people committed Jul 5, 2023
1 parent 9a7dafd commit 273825d
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ dist/*
pip-wheel-metadata/
.pytest_cache/*
.venv/*
venv/*
.vscode/*
2 changes: 1 addition & 1 deletion sanic/application/logo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from os import environ

from sanic.compat import is_atty
from sanic.helpers import is_atty


BASE_LOGO = """
Expand Down
2 changes: 1 addition & 1 deletion sanic/application/motd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Dict, Optional

from sanic import __version__
from sanic.compat import is_atty
from sanic.helpers import is_atty
from sanic.log import logger


Expand Down
47 changes: 42 additions & 5 deletions sanic/compat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import os
import platform
import signal
import sys

Expand All @@ -10,6 +11,7 @@
from multidict import CIMultiDict # type: ignore

from sanic.helpers import Default
from sanic.log import error_logger


if sys.version_info < (3, 8): # no cov
Expand All @@ -22,6 +24,7 @@
]

OS_IS_WINDOWS = os.name == "nt"
PYPY_IMPLEMENTATION = platform.python_implementation() == "PyPy"
UVLOOP_INSTALLED = False

try:
Expand Down Expand Up @@ -73,6 +76,38 @@ def enable_windows_color_support():
kernel.SetConsoleMode(kernel.GetStdHandle(-11), 7)


def pypy_os_module_patch() -> None:
"""
The PyPy os module is missing the 'readlink' function, which causes issues
withaiofiles. This workaround replaces the missing 'readlink' function
with 'os.path.realpath', which serves the same purpose.
"""
if hasattr(os, "readlink"):
error_logger.warning(
"PyPy: Skipping patching of the os module as it appears the "
"'readlink' function has been added."
)
return

module = sys.modules["os"]
module.readlink = os.path.realpath # type: ignore


def pypy_windows_set_console_cp_patch() -> None:
"""
A patch function for PyPy on Windows that sets the console code page to
UTF-8 encodingto allow for proper handling of non-ASCII characters. This
function uses ctypes to call the Windows API functions SetConsoleCP and
SetConsoleOutputCP to set the code page.
"""
from ctypes import windll # type: ignore

code: int = windll.kernel32.GetConsoleOutputCP()
if code != 65001:
windll.kernel32.SetConsoleCP(65001)
windll.kernel32.SetConsoleOutputCP(65001)


class Header(CIMultiDict):
"""
Container used for both request and response headers. It is a subclass of
Expand All @@ -86,7 +121,7 @@ class Header(CIMultiDict):
<https://multidict.readthedocs.io/en/stable/multidict.html#multidict>`_
for more details about how to use the object. In general, it should work
very similar to a regular dictionary.
"""
""" # noqa: E501

def __getattr__(self, key: str) -> str:
if key.startswith("_"):
Expand All @@ -112,6 +147,12 @@ def stat_async(path) -> Awaitable[os.stat_result]:
open_async = trio.open_file
CancelledErrors = tuple([asyncio.CancelledError, trio.Cancelled])
else:
if PYPY_IMPLEMENTATION:
pypy_os_module_patch()

if OS_IS_WINDOWS:
pypy_windows_set_console_cp_patch()

from aiofiles import open as aio_open # type: ignore
from aiofiles.os import stat as stat_async # type: ignore # noqa: F401

Expand Down Expand Up @@ -143,7 +184,3 @@ def ctrlc_handler(sig, frame):
die = False
signal.signal(signal.SIGINT, ctrlc_handler)
app.add_task(stay_active)


def is_atty() -> bool:
return bool(sys.stdout and sys.stdout.isatty())
6 changes: 6 additions & 0 deletions sanic/helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Defines basics of HTTP standard."""

import sys

from importlib import import_module
from inspect import ismodule
from typing import Dict
Expand Down Expand Up @@ -157,6 +159,10 @@ def import_string(module_name, package=None):
return obj()


def is_atty() -> bool:
return bool(sys.stdout and sys.stdout.isatty())


class Default:
"""
It is used to replace `None` or `object()` as a sentinel
Expand Down
2 changes: 1 addition & 1 deletion sanic/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import TYPE_CHECKING, Any, Dict
from warnings import warn

from sanic.compat import is_atty
from sanic.helpers import is_atty


# Python 3.11 changed the way Enum formatting works for mixed-in types.
Expand Down
4 changes: 2 additions & 2 deletions sanic/mixins/startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@
from sanic.application.motd import MOTD
from sanic.application.state import ApplicationServerInfo, Mode, ServerStage
from sanic.base.meta import SanicMeta
from sanic.compat import OS_IS_WINDOWS, StartMethod, is_atty
from sanic.compat import OS_IS_WINDOWS, StartMethod
from sanic.exceptions import ServerKilled
from sanic.helpers import Default, _default
from sanic.helpers import Default, _default, is_atty
from sanic.http.constants import HTTP
from sanic.http.tls import get_ssl_context, process_to_context
from sanic.http.tls.context import SanicSSLContext
Expand Down

0 comments on commit 273825d

Please sign in to comment.