Sanic on pypy (#2682)
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>
This commit is contained in:
parent
9a7dafd531
commit
273825dab6
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -21,4 +21,5 @@ dist/*
|
|||
pip-wheel-metadata/
|
||||
.pytest_cache/*
|
||||
.venv/*
|
||||
venv/*
|
||||
.vscode/*
|
||||
|
|
|
@ -3,7 +3,7 @@ import sys
|
|||
|
||||
from os import environ
|
||||
|
||||
from sanic.compat import is_atty
|
||||
from sanic.helpers import is_atty
|
||||
|
||||
|
||||
BASE_LOGO = """
|
||||
|
|
|
@ -4,7 +4,7 @@ from textwrap import indent, wrap
|
|||
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
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import asyncio
|
||||
import os
|
||||
import platform
|
||||
import signal
|
||||
import sys
|
||||
|
||||
|
@ -10,6 +11,7 @@ from typing import Awaitable, Union
|
|||
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
|
||||
|
@ -22,6 +24,7 @@ else: # no cov
|
|||
]
|
||||
|
||||
OS_IS_WINDOWS = os.name == "nt"
|
||||
PYPY_IMPLEMENTATION = platform.python_implementation() == "PyPy"
|
||||
UVLOOP_INSTALLED = False
|
||||
|
||||
try:
|
||||
|
@ -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
|
||||
|
@ -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("_"):
|
||||
|
@ -112,6 +147,12 @@ if use_trio: # pragma: no cover
|
|||
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
|
||||
|
||||
|
@ -143,7 +184,3 @@ def ctrlc_workaround_for_windows(app):
|
|||
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())
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Defines basics of HTTP standard."""
|
||||
|
||||
import sys
|
||||
|
||||
from importlib import import_module
|
||||
from inspect import ismodule
|
||||
from typing import Dict
|
||||
|
@ -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
|
||||
|
|
|
@ -5,7 +5,7 @@ from enum import Enum
|
|||
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.
|
||||
|
|
|
@ -41,9 +41,9 @@ from sanic.application.logo import get_logo
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue
Block a user