Spaces:
Runtime error
Runtime error
import asyncio | |
import logging | |
import socket | |
import sys | |
from argparse import ArgumentParser | |
from collections.abc import Iterable | |
from importlib import import_module | |
from typing import ( | |
Any, | |
Awaitable, | |
Callable, | |
Iterable as TypingIterable, | |
List, | |
Optional, | |
Set, | |
Type, | |
Union, | |
cast, | |
) | |
from .abc import AbstractAccessLogger | |
from .helpers import all_tasks | |
from .log import access_logger | |
from .web_app import Application as Application, CleanupError as CleanupError | |
from .web_exceptions import ( | |
HTTPAccepted as HTTPAccepted, | |
HTTPBadGateway as HTTPBadGateway, | |
HTTPBadRequest as HTTPBadRequest, | |
HTTPClientError as HTTPClientError, | |
HTTPConflict as HTTPConflict, | |
HTTPCreated as HTTPCreated, | |
HTTPError as HTTPError, | |
HTTPException as HTTPException, | |
HTTPExpectationFailed as HTTPExpectationFailed, | |
HTTPFailedDependency as HTTPFailedDependency, | |
HTTPForbidden as HTTPForbidden, | |
HTTPFound as HTTPFound, | |
HTTPGatewayTimeout as HTTPGatewayTimeout, | |
HTTPGone as HTTPGone, | |
HTTPInsufficientStorage as HTTPInsufficientStorage, | |
HTTPInternalServerError as HTTPInternalServerError, | |
HTTPLengthRequired as HTTPLengthRequired, | |
HTTPMethodNotAllowed as HTTPMethodNotAllowed, | |
HTTPMisdirectedRequest as HTTPMisdirectedRequest, | |
HTTPMovedPermanently as HTTPMovedPermanently, | |
HTTPMultipleChoices as HTTPMultipleChoices, | |
HTTPNetworkAuthenticationRequired as HTTPNetworkAuthenticationRequired, | |
HTTPNoContent as HTTPNoContent, | |
HTTPNonAuthoritativeInformation as HTTPNonAuthoritativeInformation, | |
HTTPNotAcceptable as HTTPNotAcceptable, | |
HTTPNotExtended as HTTPNotExtended, | |
HTTPNotFound as HTTPNotFound, | |
HTTPNotImplemented as HTTPNotImplemented, | |
HTTPNotModified as HTTPNotModified, | |
HTTPOk as HTTPOk, | |
HTTPPartialContent as HTTPPartialContent, | |
HTTPPaymentRequired as HTTPPaymentRequired, | |
HTTPPermanentRedirect as HTTPPermanentRedirect, | |
HTTPPreconditionFailed as HTTPPreconditionFailed, | |
HTTPPreconditionRequired as HTTPPreconditionRequired, | |
HTTPProxyAuthenticationRequired as HTTPProxyAuthenticationRequired, | |
HTTPRedirection as HTTPRedirection, | |
HTTPRequestEntityTooLarge as HTTPRequestEntityTooLarge, | |
HTTPRequestHeaderFieldsTooLarge as HTTPRequestHeaderFieldsTooLarge, | |
HTTPRequestRangeNotSatisfiable as HTTPRequestRangeNotSatisfiable, | |
HTTPRequestTimeout as HTTPRequestTimeout, | |
HTTPRequestURITooLong as HTTPRequestURITooLong, | |
HTTPResetContent as HTTPResetContent, | |
HTTPSeeOther as HTTPSeeOther, | |
HTTPServerError as HTTPServerError, | |
HTTPServiceUnavailable as HTTPServiceUnavailable, | |
HTTPSuccessful as HTTPSuccessful, | |
HTTPTemporaryRedirect as HTTPTemporaryRedirect, | |
HTTPTooManyRequests as HTTPTooManyRequests, | |
HTTPUnauthorized as HTTPUnauthorized, | |
HTTPUnavailableForLegalReasons as HTTPUnavailableForLegalReasons, | |
HTTPUnprocessableEntity as HTTPUnprocessableEntity, | |
HTTPUnsupportedMediaType as HTTPUnsupportedMediaType, | |
HTTPUpgradeRequired as HTTPUpgradeRequired, | |
HTTPUseProxy as HTTPUseProxy, | |
HTTPVariantAlsoNegotiates as HTTPVariantAlsoNegotiates, | |
HTTPVersionNotSupported as HTTPVersionNotSupported, | |
) | |
from .web_fileresponse import FileResponse as FileResponse | |
from .web_log import AccessLogger | |
from .web_middlewares import ( | |
middleware as middleware, | |
normalize_path_middleware as normalize_path_middleware, | |
) | |
from .web_protocol import ( | |
PayloadAccessError as PayloadAccessError, | |
RequestHandler as RequestHandler, | |
RequestPayloadError as RequestPayloadError, | |
) | |
from .web_request import ( | |
BaseRequest as BaseRequest, | |
FileField as FileField, | |
Request as Request, | |
) | |
from .web_response import ( | |
ContentCoding as ContentCoding, | |
Response as Response, | |
StreamResponse as StreamResponse, | |
json_response as json_response, | |
) | |
from .web_routedef import ( | |
AbstractRouteDef as AbstractRouteDef, | |
RouteDef as RouteDef, | |
RouteTableDef as RouteTableDef, | |
StaticDef as StaticDef, | |
delete as delete, | |
get as get, | |
head as head, | |
options as options, | |
patch as patch, | |
post as post, | |
put as put, | |
route as route, | |
static as static, | |
view as view, | |
) | |
from .web_runner import ( | |
AppRunner as AppRunner, | |
BaseRunner as BaseRunner, | |
BaseSite as BaseSite, | |
GracefulExit as GracefulExit, | |
NamedPipeSite as NamedPipeSite, | |
ServerRunner as ServerRunner, | |
SockSite as SockSite, | |
TCPSite as TCPSite, | |
UnixSite as UnixSite, | |
) | |
from .web_server import Server as Server | |
from .web_urldispatcher import ( | |
AbstractResource as AbstractResource, | |
AbstractRoute as AbstractRoute, | |
DynamicResource as DynamicResource, | |
PlainResource as PlainResource, | |
PrefixedSubAppResource as PrefixedSubAppResource, | |
Resource as Resource, | |
ResourceRoute as ResourceRoute, | |
StaticResource as StaticResource, | |
UrlDispatcher as UrlDispatcher, | |
UrlMappingMatchInfo as UrlMappingMatchInfo, | |
View as View, | |
) | |
from .web_ws import ( | |
WebSocketReady as WebSocketReady, | |
WebSocketResponse as WebSocketResponse, | |
WSMsgType as WSMsgType, | |
) | |
__all__ = ( | |
# web_app | |
"Application", | |
"CleanupError", | |
# web_exceptions | |
"HTTPAccepted", | |
"HTTPBadGateway", | |
"HTTPBadRequest", | |
"HTTPClientError", | |
"HTTPConflict", | |
"HTTPCreated", | |
"HTTPError", | |
"HTTPException", | |
"HTTPExpectationFailed", | |
"HTTPFailedDependency", | |
"HTTPForbidden", | |
"HTTPFound", | |
"HTTPGatewayTimeout", | |
"HTTPGone", | |
"HTTPInsufficientStorage", | |
"HTTPInternalServerError", | |
"HTTPLengthRequired", | |
"HTTPMethodNotAllowed", | |
"HTTPMisdirectedRequest", | |
"HTTPMovedPermanently", | |
"HTTPMultipleChoices", | |
"HTTPNetworkAuthenticationRequired", | |
"HTTPNoContent", | |
"HTTPNonAuthoritativeInformation", | |
"HTTPNotAcceptable", | |
"HTTPNotExtended", | |
"HTTPNotFound", | |
"HTTPNotImplemented", | |
"HTTPNotModified", | |
"HTTPOk", | |
"HTTPPartialContent", | |
"HTTPPaymentRequired", | |
"HTTPPermanentRedirect", | |
"HTTPPreconditionFailed", | |
"HTTPPreconditionRequired", | |
"HTTPProxyAuthenticationRequired", | |
"HTTPRedirection", | |
"HTTPRequestEntityTooLarge", | |
"HTTPRequestHeaderFieldsTooLarge", | |
"HTTPRequestRangeNotSatisfiable", | |
"HTTPRequestTimeout", | |
"HTTPRequestURITooLong", | |
"HTTPResetContent", | |
"HTTPSeeOther", | |
"HTTPServerError", | |
"HTTPServiceUnavailable", | |
"HTTPSuccessful", | |
"HTTPTemporaryRedirect", | |
"HTTPTooManyRequests", | |
"HTTPUnauthorized", | |
"HTTPUnavailableForLegalReasons", | |
"HTTPUnprocessableEntity", | |
"HTTPUnsupportedMediaType", | |
"HTTPUpgradeRequired", | |
"HTTPUseProxy", | |
"HTTPVariantAlsoNegotiates", | |
"HTTPVersionNotSupported", | |
# web_fileresponse | |
"FileResponse", | |
# web_middlewares | |
"middleware", | |
"normalize_path_middleware", | |
# web_protocol | |
"PayloadAccessError", | |
"RequestHandler", | |
"RequestPayloadError", | |
# web_request | |
"BaseRequest", | |
"FileField", | |
"Request", | |
# web_response | |
"ContentCoding", | |
"Response", | |
"StreamResponse", | |
"json_response", | |
# web_routedef | |
"AbstractRouteDef", | |
"RouteDef", | |
"RouteTableDef", | |
"StaticDef", | |
"delete", | |
"get", | |
"head", | |
"options", | |
"patch", | |
"post", | |
"put", | |
"route", | |
"static", | |
"view", | |
# web_runner | |
"AppRunner", | |
"BaseRunner", | |
"BaseSite", | |
"GracefulExit", | |
"ServerRunner", | |
"SockSite", | |
"TCPSite", | |
"UnixSite", | |
"NamedPipeSite", | |
# web_server | |
"Server", | |
# web_urldispatcher | |
"AbstractResource", | |
"AbstractRoute", | |
"DynamicResource", | |
"PlainResource", | |
"PrefixedSubAppResource", | |
"Resource", | |
"ResourceRoute", | |
"StaticResource", | |
"UrlDispatcher", | |
"UrlMappingMatchInfo", | |
"View", | |
# web_ws | |
"WebSocketReady", | |
"WebSocketResponse", | |
"WSMsgType", | |
# web | |
"run_app", | |
) | |
try: | |
from ssl import SSLContext | |
except ImportError: # pragma: no cover | |
SSLContext = Any # type: ignore[misc,assignment] | |
HostSequence = TypingIterable[str] | |
async def _run_app( | |
app: Union[Application, Awaitable[Application]], | |
*, | |
host: Optional[Union[str, HostSequence]] = None, | |
port: Optional[int] = None, | |
path: Optional[str] = None, | |
sock: Optional[Union[socket.socket, TypingIterable[socket.socket]]] = None, | |
shutdown_timeout: float = 60.0, | |
keepalive_timeout: float = 75.0, | |
ssl_context: Optional[SSLContext] = None, | |
print: Callable[..., None] = print, | |
backlog: int = 128, | |
access_log_class: Type[AbstractAccessLogger] = AccessLogger, | |
access_log_format: str = AccessLogger.LOG_FORMAT, | |
access_log: Optional[logging.Logger] = access_logger, | |
handle_signals: bool = True, | |
reuse_address: Optional[bool] = None, | |
reuse_port: Optional[bool] = None, | |
) -> None: | |
# A internal functio to actually do all dirty job for application running | |
if asyncio.iscoroutine(app): | |
app = await app # type: ignore[misc] | |
app = cast(Application, app) | |
runner = AppRunner( | |
app, | |
handle_signals=handle_signals, | |
access_log_class=access_log_class, | |
access_log_format=access_log_format, | |
access_log=access_log, | |
keepalive_timeout=keepalive_timeout, | |
) | |
await runner.setup() | |
sites: List[BaseSite] = [] | |
try: | |
if host is not None: | |
if isinstance(host, (str, bytes, bytearray, memoryview)): | |
sites.append( | |
TCPSite( | |
runner, | |
host, | |
port, | |
shutdown_timeout=shutdown_timeout, | |
ssl_context=ssl_context, | |
backlog=backlog, | |
reuse_address=reuse_address, | |
reuse_port=reuse_port, | |
) | |
) | |
else: | |
for h in host: | |
sites.append( | |
TCPSite( | |
runner, | |
h, | |
port, | |
shutdown_timeout=shutdown_timeout, | |
ssl_context=ssl_context, | |
backlog=backlog, | |
reuse_address=reuse_address, | |
reuse_port=reuse_port, | |
) | |
) | |
elif path is None and sock is None or port is not None: | |
sites.append( | |
TCPSite( | |
runner, | |
port=port, | |
shutdown_timeout=shutdown_timeout, | |
ssl_context=ssl_context, | |
backlog=backlog, | |
reuse_address=reuse_address, | |
reuse_port=reuse_port, | |
) | |
) | |
if path is not None: | |
if isinstance(path, (str, bytes, bytearray, memoryview)): | |
sites.append( | |
UnixSite( | |
runner, | |
path, | |
shutdown_timeout=shutdown_timeout, | |
ssl_context=ssl_context, | |
backlog=backlog, | |
) | |
) | |
else: | |
for p in path: | |
sites.append( | |
UnixSite( | |
runner, | |
p, | |
shutdown_timeout=shutdown_timeout, | |
ssl_context=ssl_context, | |
backlog=backlog, | |
) | |
) | |
if sock is not None: | |
if not isinstance(sock, Iterable): | |
sites.append( | |
SockSite( | |
runner, | |
sock, | |
shutdown_timeout=shutdown_timeout, | |
ssl_context=ssl_context, | |
backlog=backlog, | |
) | |
) | |
else: | |
for s in sock: | |
sites.append( | |
SockSite( | |
runner, | |
s, | |
shutdown_timeout=shutdown_timeout, | |
ssl_context=ssl_context, | |
backlog=backlog, | |
) | |
) | |
for site in sites: | |
await site.start() | |
if print: # pragma: no branch | |
names = sorted(str(s.name) for s in runner.sites) | |
print( | |
"======== Running on {} ========\n" | |
"(Press CTRL+C to quit)".format(", ".join(names)) | |
) | |
# sleep forever by 1 hour intervals, | |
# on Windows before Python 3.8 wake up every 1 second to handle | |
# Ctrl+C smoothly | |
if sys.platform == "win32" and sys.version_info < (3, 8): | |
delay = 1 | |
else: | |
delay = 3600 | |
while True: | |
await asyncio.sleep(delay) | |
finally: | |
await runner.cleanup() | |
def _cancel_tasks( | |
to_cancel: Set["asyncio.Task[Any]"], loop: asyncio.AbstractEventLoop | |
) -> None: | |
if not to_cancel: | |
return | |
for task in to_cancel: | |
task.cancel() | |
loop.run_until_complete(asyncio.gather(*to_cancel, return_exceptions=True)) | |
for task in to_cancel: | |
if task.cancelled(): | |
continue | |
if task.exception() is not None: | |
loop.call_exception_handler( | |
{ | |
"message": "unhandled exception during asyncio.run() shutdown", | |
"exception": task.exception(), | |
"task": task, | |
} | |
) | |
def run_app( | |
app: Union[Application, Awaitable[Application]], | |
*, | |
host: Optional[Union[str, HostSequence]] = None, | |
port: Optional[int] = None, | |
path: Optional[str] = None, | |
sock: Optional[Union[socket.socket, TypingIterable[socket.socket]]] = None, | |
shutdown_timeout: float = 60.0, | |
keepalive_timeout: float = 75.0, | |
ssl_context: Optional[SSLContext] = None, | |
print: Callable[..., None] = print, | |
backlog: int = 128, | |
access_log_class: Type[AbstractAccessLogger] = AccessLogger, | |
access_log_format: str = AccessLogger.LOG_FORMAT, | |
access_log: Optional[logging.Logger] = access_logger, | |
handle_signals: bool = True, | |
reuse_address: Optional[bool] = None, | |
reuse_port: Optional[bool] = None, | |
loop: Optional[asyncio.AbstractEventLoop] = None, | |
) -> None: | |
"""Run an app locally""" | |
if loop is None: | |
loop = asyncio.new_event_loop() | |
# Configure if and only if in debugging mode and using the default logger | |
if loop.get_debug() and access_log and access_log.name == "aiohttp.access": | |
if access_log.level == logging.NOTSET: | |
access_log.setLevel(logging.DEBUG) | |
if not access_log.hasHandlers(): | |
access_log.addHandler(logging.StreamHandler()) | |
main_task = loop.create_task( | |
_run_app( | |
app, | |
host=host, | |
port=port, | |
path=path, | |
sock=sock, | |
shutdown_timeout=shutdown_timeout, | |
keepalive_timeout=keepalive_timeout, | |
ssl_context=ssl_context, | |
print=print, | |
backlog=backlog, | |
access_log_class=access_log_class, | |
access_log_format=access_log_format, | |
access_log=access_log, | |
handle_signals=handle_signals, | |
reuse_address=reuse_address, | |
reuse_port=reuse_port, | |
) | |
) | |
try: | |
asyncio.set_event_loop(loop) | |
loop.run_until_complete(main_task) | |
except (GracefulExit, KeyboardInterrupt): # pragma: no cover | |
pass | |
finally: | |
_cancel_tasks({main_task}, loop) | |
_cancel_tasks(all_tasks(loop), loop) | |
loop.run_until_complete(loop.shutdown_asyncgens()) | |
loop.close() | |
def main(argv: List[str]) -> None: | |
arg_parser = ArgumentParser( | |
description="aiohttp.web Application server", prog="aiohttp.web" | |
) | |
arg_parser.add_argument( | |
"entry_func", | |
help=( | |
"Callable returning the `aiohttp.web.Application` instance to " | |
"run. Should be specified in the 'module:function' syntax." | |
), | |
metavar="entry-func", | |
) | |
arg_parser.add_argument( | |
"-H", | |
"--hostname", | |
help="TCP/IP hostname to serve on (default: %(default)r)", | |
default="localhost", | |
) | |
arg_parser.add_argument( | |
"-P", | |
"--port", | |
help="TCP/IP port to serve on (default: %(default)r)", | |
type=int, | |
default="8080", | |
) | |
arg_parser.add_argument( | |
"-U", | |
"--path", | |
help="Unix file system path to serve on. Specifying a path will cause " | |
"hostname and port arguments to be ignored.", | |
) | |
args, extra_argv = arg_parser.parse_known_args(argv) | |
# Import logic | |
mod_str, _, func_str = args.entry_func.partition(":") | |
if not func_str or not mod_str: | |
arg_parser.error("'entry-func' not in 'module:function' syntax") | |
if mod_str.startswith("."): | |
arg_parser.error("relative module names not supported") | |
try: | |
module = import_module(mod_str) | |
except ImportError as ex: | |
arg_parser.error(f"unable to import {mod_str}: {ex}") | |
try: | |
func = getattr(module, func_str) | |
except AttributeError: | |
arg_parser.error(f"module {mod_str!r} has no attribute {func_str!r}") | |
# Compatibility logic | |
if args.path is not None and not hasattr(socket, "AF_UNIX"): | |
arg_parser.error( | |
"file system paths not supported by your operating" " environment" | |
) | |
logging.basicConfig(level=logging.DEBUG) | |
app = func(extra_argv) | |
run_app(app, host=args.hostname, port=args.port, path=args.path) | |
arg_parser.exit(message="Stopped\n") | |
if __name__ == "__main__": # pragma: no branch | |
main(sys.argv[1:]) # pragma: no cover | |