Initial import from local backup (Documents-Playground/pakerpale)
This commit is contained in:
0
.env/Lib/site-packages/tornado/platform/__init__.py
Normal file
0
.env/Lib/site-packages/tornado/platform/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
337
.env/Lib/site-packages/tornado/platform/asyncio.py
Normal file
337
.env/Lib/site-packages/tornado/platform/asyncio.py
Normal file
@@ -0,0 +1,337 @@
|
||||
"""Bridges between the `asyncio` module and Tornado IOLoop.
|
||||
|
||||
.. versionadded:: 3.2
|
||||
|
||||
This module integrates Tornado with the ``asyncio`` module introduced
|
||||
in Python 3.4. This makes it possible to combine the two libraries on
|
||||
the same event loop.
|
||||
|
||||
.. deprecated:: 5.0
|
||||
|
||||
While the code in this module is still used, it is now enabled
|
||||
automatically when `asyncio` is available, so applications should
|
||||
no longer need to refer to this module directly.
|
||||
|
||||
.. note::
|
||||
|
||||
Tornado requires the `~asyncio.AbstractEventLoop.add_reader` family of
|
||||
methods, so it is not compatible with the `~asyncio.ProactorEventLoop` on
|
||||
Windows. Use the `~asyncio.SelectorEventLoop` instead.
|
||||
"""
|
||||
|
||||
import concurrent.futures
|
||||
import functools
|
||||
|
||||
from threading import get_ident
|
||||
from tornado.gen import convert_yielded
|
||||
from tornado.ioloop import IOLoop, _Selectable
|
||||
|
||||
import asyncio
|
||||
|
||||
import typing
|
||||
from typing import Any, TypeVar, Awaitable, Callable, Union, Optional
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from typing import Set, Dict, Tuple # noqa: F401
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class BaseAsyncIOLoop(IOLoop):
|
||||
def initialize( # type: ignore
|
||||
self, asyncio_loop: asyncio.AbstractEventLoop, **kwargs: Any
|
||||
) -> None:
|
||||
self.asyncio_loop = asyncio_loop
|
||||
# Maps fd to (fileobj, handler function) pair (as in IOLoop.add_handler)
|
||||
self.handlers = {} # type: Dict[int, Tuple[Union[int, _Selectable], Callable]]
|
||||
# Set of fds listening for reads/writes
|
||||
self.readers = set() # type: Set[int]
|
||||
self.writers = set() # type: Set[int]
|
||||
self.closing = False
|
||||
# If an asyncio loop was closed through an asyncio interface
|
||||
# instead of IOLoop.close(), we'd never hear about it and may
|
||||
# have left a dangling reference in our map. In case an
|
||||
# application (or, more likely, a test suite) creates and
|
||||
# destroys a lot of event loops in this way, check here to
|
||||
# ensure that we don't have a lot of dead loops building up in
|
||||
# the map.
|
||||
#
|
||||
# TODO(bdarnell): consider making self.asyncio_loop a weakref
|
||||
# for AsyncIOMainLoop and make _ioloop_for_asyncio a
|
||||
# WeakKeyDictionary.
|
||||
for loop in list(IOLoop._ioloop_for_asyncio):
|
||||
if loop.is_closed():
|
||||
del IOLoop._ioloop_for_asyncio[loop]
|
||||
IOLoop._ioloop_for_asyncio[asyncio_loop] = self
|
||||
|
||||
self._thread_identity = 0
|
||||
|
||||
super(BaseAsyncIOLoop, self).initialize(**kwargs)
|
||||
|
||||
def assign_thread_identity() -> None:
|
||||
self._thread_identity = get_ident()
|
||||
|
||||
self.add_callback(assign_thread_identity)
|
||||
|
||||
def close(self, all_fds: bool = False) -> None:
|
||||
self.closing = True
|
||||
for fd in list(self.handlers):
|
||||
fileobj, handler_func = self.handlers[fd]
|
||||
self.remove_handler(fd)
|
||||
if all_fds:
|
||||
self.close_fd(fileobj)
|
||||
# Remove the mapping before closing the asyncio loop. If this
|
||||
# happened in the other order, we could race against another
|
||||
# initialize() call which would see the closed asyncio loop,
|
||||
# assume it was closed from the asyncio side, and do this
|
||||
# cleanup for us, leading to a KeyError.
|
||||
del IOLoop._ioloop_for_asyncio[self.asyncio_loop]
|
||||
self.asyncio_loop.close()
|
||||
|
||||
def add_handler(
|
||||
self, fd: Union[int, _Selectable], handler: Callable[..., None], events: int
|
||||
) -> None:
|
||||
fd, fileobj = self.split_fd(fd)
|
||||
if fd in self.handlers:
|
||||
raise ValueError("fd %s added twice" % fd)
|
||||
self.handlers[fd] = (fileobj, handler)
|
||||
if events & IOLoop.READ:
|
||||
self.asyncio_loop.add_reader(fd, self._handle_events, fd, IOLoop.READ)
|
||||
self.readers.add(fd)
|
||||
if events & IOLoop.WRITE:
|
||||
self.asyncio_loop.add_writer(fd, self._handle_events, fd, IOLoop.WRITE)
|
||||
self.writers.add(fd)
|
||||
|
||||
def update_handler(self, fd: Union[int, _Selectable], events: int) -> None:
|
||||
fd, fileobj = self.split_fd(fd)
|
||||
if events & IOLoop.READ:
|
||||
if fd not in self.readers:
|
||||
self.asyncio_loop.add_reader(fd, self._handle_events, fd, IOLoop.READ)
|
||||
self.readers.add(fd)
|
||||
else:
|
||||
if fd in self.readers:
|
||||
self.asyncio_loop.remove_reader(fd)
|
||||
self.readers.remove(fd)
|
||||
if events & IOLoop.WRITE:
|
||||
if fd not in self.writers:
|
||||
self.asyncio_loop.add_writer(fd, self._handle_events, fd, IOLoop.WRITE)
|
||||
self.writers.add(fd)
|
||||
else:
|
||||
if fd in self.writers:
|
||||
self.asyncio_loop.remove_writer(fd)
|
||||
self.writers.remove(fd)
|
||||
|
||||
def remove_handler(self, fd: Union[int, _Selectable]) -> None:
|
||||
fd, fileobj = self.split_fd(fd)
|
||||
if fd not in self.handlers:
|
||||
return
|
||||
if fd in self.readers:
|
||||
self.asyncio_loop.remove_reader(fd)
|
||||
self.readers.remove(fd)
|
||||
if fd in self.writers:
|
||||
self.asyncio_loop.remove_writer(fd)
|
||||
self.writers.remove(fd)
|
||||
del self.handlers[fd]
|
||||
|
||||
def _handle_events(self, fd: int, events: int) -> None:
|
||||
fileobj, handler_func = self.handlers[fd]
|
||||
handler_func(fileobj, events)
|
||||
|
||||
def start(self) -> None:
|
||||
try:
|
||||
old_loop = asyncio.get_event_loop()
|
||||
except (RuntimeError, AssertionError):
|
||||
old_loop = None # type: ignore
|
||||
try:
|
||||
self._setup_logging()
|
||||
asyncio.set_event_loop(self.asyncio_loop)
|
||||
self.asyncio_loop.run_forever()
|
||||
finally:
|
||||
asyncio.set_event_loop(old_loop)
|
||||
|
||||
def stop(self) -> None:
|
||||
self.asyncio_loop.stop()
|
||||
|
||||
def call_at(
|
||||
self, when: float, callback: Callable[..., None], *args: Any, **kwargs: Any
|
||||
) -> object:
|
||||
# asyncio.call_at supports *args but not **kwargs, so bind them here.
|
||||
# We do not synchronize self.time and asyncio_loop.time, so
|
||||
# convert from absolute to relative.
|
||||
return self.asyncio_loop.call_later(
|
||||
max(0, when - self.time()),
|
||||
self._run_callback,
|
||||
functools.partial(callback, *args, **kwargs),
|
||||
)
|
||||
|
||||
def remove_timeout(self, timeout: object) -> None:
|
||||
timeout.cancel() # type: ignore
|
||||
|
||||
def add_callback(self, callback: Callable, *args: Any, **kwargs: Any) -> None:
|
||||
if get_ident() == self._thread_identity:
|
||||
call_soon = self.asyncio_loop.call_soon
|
||||
else:
|
||||
call_soon = self.asyncio_loop.call_soon_threadsafe
|
||||
try:
|
||||
call_soon(self._run_callback, functools.partial(callback, *args, **kwargs))
|
||||
except RuntimeError:
|
||||
# "Event loop is closed". Swallow the exception for
|
||||
# consistency with PollIOLoop (and logical consistency
|
||||
# with the fact that we can't guarantee that an
|
||||
# add_callback that completes without error will
|
||||
# eventually execute).
|
||||
pass
|
||||
|
||||
def add_callback_from_signal(
|
||||
self, callback: Callable, *args: Any, **kwargs: Any
|
||||
) -> None:
|
||||
try:
|
||||
self.asyncio_loop.call_soon_threadsafe(
|
||||
self._run_callback, functools.partial(callback, *args, **kwargs)
|
||||
)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
def run_in_executor(
|
||||
self,
|
||||
executor: Optional[concurrent.futures.Executor],
|
||||
func: Callable[..., _T],
|
||||
*args: Any
|
||||
) -> Awaitable[_T]:
|
||||
return self.asyncio_loop.run_in_executor(executor, func, *args)
|
||||
|
||||
def set_default_executor(self, executor: concurrent.futures.Executor) -> None:
|
||||
return self.asyncio_loop.set_default_executor(executor)
|
||||
|
||||
|
||||
class AsyncIOMainLoop(BaseAsyncIOLoop):
|
||||
"""``AsyncIOMainLoop`` creates an `.IOLoop` that corresponds to the
|
||||
current ``asyncio`` event loop (i.e. the one returned by
|
||||
``asyncio.get_event_loop()``).
|
||||
|
||||
.. deprecated:: 5.0
|
||||
|
||||
Now used automatically when appropriate; it is no longer necessary
|
||||
to refer to this class directly.
|
||||
|
||||
.. versionchanged:: 5.0
|
||||
|
||||
Closing an `AsyncIOMainLoop` now closes the underlying asyncio loop.
|
||||
"""
|
||||
|
||||
def initialize(self, **kwargs: Any) -> None: # type: ignore
|
||||
super(AsyncIOMainLoop, self).initialize(asyncio.get_event_loop(), **kwargs)
|
||||
|
||||
def make_current(self) -> None:
|
||||
# AsyncIOMainLoop already refers to the current asyncio loop so
|
||||
# nothing to do here.
|
||||
pass
|
||||
|
||||
|
||||
class AsyncIOLoop(BaseAsyncIOLoop):
|
||||
"""``AsyncIOLoop`` is an `.IOLoop` that runs on an ``asyncio`` event loop.
|
||||
This class follows the usual Tornado semantics for creating new
|
||||
``IOLoops``; these loops are not necessarily related to the
|
||||
``asyncio`` default event loop.
|
||||
|
||||
Each ``AsyncIOLoop`` creates a new ``asyncio.EventLoop``; this object
|
||||
can be accessed with the ``asyncio_loop`` attribute.
|
||||
|
||||
.. versionchanged:: 5.0
|
||||
|
||||
When an ``AsyncIOLoop`` becomes the current `.IOLoop`, it also sets
|
||||
the current `asyncio` event loop.
|
||||
|
||||
.. deprecated:: 5.0
|
||||
|
||||
Now used automatically when appropriate; it is no longer necessary
|
||||
to refer to this class directly.
|
||||
"""
|
||||
|
||||
def initialize(self, **kwargs: Any) -> None: # type: ignore
|
||||
self.is_current = False
|
||||
loop = asyncio.new_event_loop()
|
||||
try:
|
||||
super(AsyncIOLoop, self).initialize(loop, **kwargs)
|
||||
except Exception:
|
||||
# If initialize() does not succeed (taking ownership of the loop),
|
||||
# we have to close it.
|
||||
loop.close()
|
||||
raise
|
||||
|
||||
def close(self, all_fds: bool = False) -> None:
|
||||
if self.is_current:
|
||||
self.clear_current()
|
||||
super(AsyncIOLoop, self).close(all_fds=all_fds)
|
||||
|
||||
def make_current(self) -> None:
|
||||
if not self.is_current:
|
||||
try:
|
||||
self.old_asyncio = asyncio.get_event_loop()
|
||||
except (RuntimeError, AssertionError):
|
||||
self.old_asyncio = None # type: ignore
|
||||
self.is_current = True
|
||||
asyncio.set_event_loop(self.asyncio_loop)
|
||||
|
||||
def _clear_current_hook(self) -> None:
|
||||
if self.is_current:
|
||||
asyncio.set_event_loop(self.old_asyncio)
|
||||
self.is_current = False
|
||||
|
||||
|
||||
def to_tornado_future(asyncio_future: asyncio.Future) -> asyncio.Future:
|
||||
"""Convert an `asyncio.Future` to a `tornado.concurrent.Future`.
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
.. deprecated:: 5.0
|
||||
Tornado ``Futures`` have been merged with `asyncio.Future`,
|
||||
so this method is now a no-op.
|
||||
"""
|
||||
return asyncio_future
|
||||
|
||||
|
||||
def to_asyncio_future(tornado_future: asyncio.Future) -> asyncio.Future:
|
||||
"""Convert a Tornado yieldable object to an `asyncio.Future`.
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
.. versionchanged:: 4.3
|
||||
Now accepts any yieldable object, not just
|
||||
`tornado.concurrent.Future`.
|
||||
|
||||
.. deprecated:: 5.0
|
||||
Tornado ``Futures`` have been merged with `asyncio.Future`,
|
||||
so this method is now equivalent to `tornado.gen.convert_yielded`.
|
||||
"""
|
||||
return convert_yielded(tornado_future)
|
||||
|
||||
|
||||
class AnyThreadEventLoopPolicy(asyncio.DefaultEventLoopPolicy): # type: ignore
|
||||
"""Event loop policy that allows loop creation on any thread.
|
||||
|
||||
The default `asyncio` event loop policy only automatically creates
|
||||
event loops in the main threads. Other threads must create event
|
||||
loops explicitly or `asyncio.get_event_loop` (and therefore
|
||||
`.IOLoop.current`) will fail. Installing this policy allows event
|
||||
loops to be created automatically on any thread, matching the
|
||||
behavior of Tornado versions prior to 5.0 (or 5.0 on Python 2).
|
||||
|
||||
Usage::
|
||||
|
||||
asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy())
|
||||
|
||||
.. versionadded:: 5.0
|
||||
|
||||
"""
|
||||
|
||||
def get_event_loop(self) -> asyncio.AbstractEventLoop:
|
||||
try:
|
||||
return super().get_event_loop()
|
||||
except (RuntimeError, AssertionError):
|
||||
# This was an AssertionError in python 3.4.2 (which ships with debian jessie)
|
||||
# and changed to a RuntimeError in 3.4.3.
|
||||
# "There is no current event loop in thread %r"
|
||||
loop = self.new_event_loop()
|
||||
self.set_event_loop(loop)
|
||||
return loop
|
||||
32
.env/Lib/site-packages/tornado/platform/auto.py
Normal file
32
.env/Lib/site-packages/tornado/platform/auto.py
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# Copyright 2011 Facebook
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Implementation of platform-specific functionality.
|
||||
|
||||
For each function or class described in `tornado.platform.interface`,
|
||||
the appropriate platform-specific implementation exists in this module.
|
||||
Most code that needs access to this functionality should do e.g.::
|
||||
|
||||
from tornado.platform.auto import set_close_exec
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
if os.name == "nt":
|
||||
from tornado.platform.windows import set_close_exec
|
||||
else:
|
||||
from tornado.platform.posix import set_close_exec
|
||||
|
||||
__all__ = ["set_close_exec"]
|
||||
89
.env/Lib/site-packages/tornado/platform/caresresolver.py
Normal file
89
.env/Lib/site-packages/tornado/platform/caresresolver.py
Normal file
@@ -0,0 +1,89 @@
|
||||
import pycares # type: ignore
|
||||
import socket
|
||||
|
||||
from tornado.concurrent import Future
|
||||
from tornado import gen
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.netutil import Resolver, is_valid_ip
|
||||
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from typing import Generator, Any, List, Tuple, Dict # noqa: F401
|
||||
|
||||
|
||||
class CaresResolver(Resolver):
|
||||
"""Name resolver based on the c-ares library.
|
||||
|
||||
This is a non-blocking and non-threaded resolver. It may not produce
|
||||
the same results as the system resolver, but can be used for non-blocking
|
||||
resolution when threads cannot be used.
|
||||
|
||||
c-ares fails to resolve some names when ``family`` is ``AF_UNSPEC``,
|
||||
so it is only recommended for use in ``AF_INET`` (i.e. IPv4). This is
|
||||
the default for ``tornado.simple_httpclient``, but other libraries
|
||||
may default to ``AF_UNSPEC``.
|
||||
|
||||
.. versionchanged:: 5.0
|
||||
The ``io_loop`` argument (deprecated since version 4.1) has been removed.
|
||||
"""
|
||||
|
||||
def initialize(self) -> None:
|
||||
self.io_loop = IOLoop.current()
|
||||
self.channel = pycares.Channel(sock_state_cb=self._sock_state_cb)
|
||||
self.fds = {} # type: Dict[int, int]
|
||||
|
||||
def _sock_state_cb(self, fd: int, readable: bool, writable: bool) -> None:
|
||||
state = (IOLoop.READ if readable else 0) | (IOLoop.WRITE if writable else 0)
|
||||
if not state:
|
||||
self.io_loop.remove_handler(fd)
|
||||
del self.fds[fd]
|
||||
elif fd in self.fds:
|
||||
self.io_loop.update_handler(fd, state)
|
||||
self.fds[fd] = state
|
||||
else:
|
||||
self.io_loop.add_handler(fd, self._handle_events, state)
|
||||
self.fds[fd] = state
|
||||
|
||||
def _handle_events(self, fd: int, events: int) -> None:
|
||||
read_fd = pycares.ARES_SOCKET_BAD
|
||||
write_fd = pycares.ARES_SOCKET_BAD
|
||||
if events & IOLoop.READ:
|
||||
read_fd = fd
|
||||
if events & IOLoop.WRITE:
|
||||
write_fd = fd
|
||||
self.channel.process_fd(read_fd, write_fd)
|
||||
|
||||
@gen.coroutine
|
||||
def resolve(
|
||||
self, host: str, port: int, family: int = 0
|
||||
) -> "Generator[Any, Any, List[Tuple[int, Any]]]":
|
||||
if is_valid_ip(host):
|
||||
addresses = [host]
|
||||
else:
|
||||
# gethostbyname doesn't take callback as a kwarg
|
||||
fut = Future() # type: Future[Tuple[Any, Any]]
|
||||
self.channel.gethostbyname(
|
||||
host, family, lambda result, error: fut.set_result((result, error))
|
||||
)
|
||||
result, error = yield fut
|
||||
if error:
|
||||
raise IOError(
|
||||
"C-Ares returned error %s: %s while resolving %s"
|
||||
% (error, pycares.errno.strerror(error), host)
|
||||
)
|
||||
addresses = result.addresses
|
||||
addrinfo = []
|
||||
for address in addresses:
|
||||
if "." in address:
|
||||
address_family = socket.AF_INET
|
||||
elif ":" in address:
|
||||
address_family = socket.AF_INET6
|
||||
else:
|
||||
address_family = socket.AF_UNSPEC
|
||||
if family != socket.AF_UNSPEC and family != address_family:
|
||||
raise IOError(
|
||||
"Requested socket family %d but got %d" % (family, address_family)
|
||||
)
|
||||
addrinfo.append((typing.cast(int, address_family), (address, port)))
|
||||
return addrinfo
|
||||
26
.env/Lib/site-packages/tornado/platform/interface.py
Normal file
26
.env/Lib/site-packages/tornado/platform/interface.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# Copyright 2011 Facebook
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Interfaces for platform-specific functionality.
|
||||
|
||||
This module exists primarily for documentation purposes and as base classes
|
||||
for other tornado.platform modules. Most code should import the appropriate
|
||||
implementation from `tornado.platform.auto`.
|
||||
"""
|
||||
|
||||
|
||||
def set_close_exec(fd: int) -> None:
|
||||
"""Sets the close-on-exec bit (``FD_CLOEXEC``)for a file descriptor."""
|
||||
raise NotImplementedError()
|
||||
29
.env/Lib/site-packages/tornado/platform/posix.py
Normal file
29
.env/Lib/site-packages/tornado/platform/posix.py
Normal file
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# Copyright 2011 Facebook
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Posix implementations of platform-specific functionality."""
|
||||
|
||||
import fcntl
|
||||
import os
|
||||
|
||||
|
||||
def set_close_exec(fd: int) -> None:
|
||||
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)
|
||||
|
||||
|
||||
def _set_nonblocking(fd: int) -> None:
|
||||
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
||||
131
.env/Lib/site-packages/tornado/platform/twisted.py
Normal file
131
.env/Lib/site-packages/tornado/platform/twisted.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# Author: Ovidiu Predescu
|
||||
# Date: July 2011
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""Bridges between the Twisted reactor and Tornado IOLoop.
|
||||
|
||||
This module lets you run applications and libraries written for
|
||||
Twisted in a Tornado application. It can be used in two modes,
|
||||
depending on which library's underlying event loop you want to use.
|
||||
|
||||
This module has been tested with Twisted versions 11.0.0 and newer.
|
||||
"""
|
||||
|
||||
import socket
|
||||
import sys
|
||||
|
||||
import twisted.internet.abstract # type: ignore
|
||||
import twisted.internet.asyncioreactor # type: ignore
|
||||
from twisted.internet.defer import Deferred # type: ignore
|
||||
from twisted.python import failure # type: ignore
|
||||
import twisted.names.cache # type: ignore
|
||||
import twisted.names.client # type: ignore
|
||||
import twisted.names.hosts # type: ignore
|
||||
import twisted.names.resolve # type: ignore
|
||||
|
||||
|
||||
from tornado.concurrent import Future, future_set_exc_info
|
||||
from tornado.escape import utf8
|
||||
from tornado import gen
|
||||
from tornado.netutil import Resolver
|
||||
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from typing import Generator, Any, List, Tuple # noqa: F401
|
||||
|
||||
|
||||
class TwistedResolver(Resolver):
|
||||
"""Twisted-based asynchronous resolver.
|
||||
|
||||
This is a non-blocking and non-threaded resolver. It is
|
||||
recommended only when threads cannot be used, since it has
|
||||
limitations compared to the standard ``getaddrinfo``-based
|
||||
`~tornado.netutil.Resolver` and
|
||||
`~tornado.netutil.DefaultExecutorResolver`. Specifically, it returns at
|
||||
most one result, and arguments other than ``host`` and ``family``
|
||||
are ignored. It may fail to resolve when ``family`` is not
|
||||
``socket.AF_UNSPEC``.
|
||||
|
||||
Requires Twisted 12.1 or newer.
|
||||
|
||||
.. versionchanged:: 5.0
|
||||
The ``io_loop`` argument (deprecated since version 4.1) has been removed.
|
||||
"""
|
||||
|
||||
def initialize(self) -> None:
|
||||
# partial copy of twisted.names.client.createResolver, which doesn't
|
||||
# allow for a reactor to be passed in.
|
||||
self.reactor = twisted.internet.asyncioreactor.AsyncioSelectorReactor()
|
||||
|
||||
host_resolver = twisted.names.hosts.Resolver("/etc/hosts")
|
||||
cache_resolver = twisted.names.cache.CacheResolver(reactor=self.reactor)
|
||||
real_resolver = twisted.names.client.Resolver(
|
||||
"/etc/resolv.conf", reactor=self.reactor
|
||||
)
|
||||
self.resolver = twisted.names.resolve.ResolverChain(
|
||||
[host_resolver, cache_resolver, real_resolver]
|
||||
)
|
||||
|
||||
@gen.coroutine
|
||||
def resolve(
|
||||
self, host: str, port: int, family: int = 0
|
||||
) -> "Generator[Any, Any, List[Tuple[int, Any]]]":
|
||||
# getHostByName doesn't accept IP addresses, so if the input
|
||||
# looks like an IP address just return it immediately.
|
||||
if twisted.internet.abstract.isIPAddress(host):
|
||||
resolved = host
|
||||
resolved_family = socket.AF_INET
|
||||
elif twisted.internet.abstract.isIPv6Address(host):
|
||||
resolved = host
|
||||
resolved_family = socket.AF_INET6
|
||||
else:
|
||||
deferred = self.resolver.getHostByName(utf8(host))
|
||||
fut = Future() # type: Future[Any]
|
||||
deferred.addBoth(fut.set_result)
|
||||
resolved = yield fut
|
||||
if isinstance(resolved, failure.Failure):
|
||||
try:
|
||||
resolved.raiseException()
|
||||
except twisted.names.error.DomainError as e:
|
||||
raise IOError(e)
|
||||
elif twisted.internet.abstract.isIPAddress(resolved):
|
||||
resolved_family = socket.AF_INET
|
||||
elif twisted.internet.abstract.isIPv6Address(resolved):
|
||||
resolved_family = socket.AF_INET6
|
||||
else:
|
||||
resolved_family = socket.AF_UNSPEC
|
||||
if family != socket.AF_UNSPEC and family != resolved_family:
|
||||
raise Exception(
|
||||
"Requested socket family %d but got %d" % (family, resolved_family)
|
||||
)
|
||||
result = [(typing.cast(int, resolved_family), (resolved, port))]
|
||||
return result
|
||||
|
||||
|
||||
if hasattr(gen.convert_yielded, "register"):
|
||||
|
||||
@gen.convert_yielded.register(Deferred) # type: ignore
|
||||
def _(d: Deferred) -> Future:
|
||||
f = Future() # type: Future[Any]
|
||||
|
||||
def errback(failure: failure.Failure) -> None:
|
||||
try:
|
||||
failure.raiseException()
|
||||
# Should never happen, but just in case
|
||||
raise Exception("errback called without error")
|
||||
except:
|
||||
future_set_exc_info(f, sys.exc_info())
|
||||
|
||||
d.addCallbacks(f.set_result, errback)
|
||||
return f
|
||||
22
.env/Lib/site-packages/tornado/platform/windows.py
Normal file
22
.env/Lib/site-packages/tornado/platform/windows.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# NOTE: win32 support is currently experimental, and not recommended
|
||||
# for production use.
|
||||
|
||||
import ctypes
|
||||
import ctypes.wintypes
|
||||
|
||||
# See: http://msdn.microsoft.com/en-us/library/ms724935(VS.85).aspx
|
||||
SetHandleInformation = ctypes.windll.kernel32.SetHandleInformation # type: ignore
|
||||
SetHandleInformation.argtypes = (
|
||||
ctypes.wintypes.HANDLE,
|
||||
ctypes.wintypes.DWORD,
|
||||
ctypes.wintypes.DWORD,
|
||||
)
|
||||
SetHandleInformation.restype = ctypes.wintypes.BOOL
|
||||
|
||||
HANDLE_FLAG_INHERIT = 0x00000001
|
||||
|
||||
|
||||
def set_close_exec(fd: int) -> None:
|
||||
success = SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0)
|
||||
if not success:
|
||||
raise ctypes.WinError() # type: ignore
|
||||
Reference in New Issue
Block a user