Commit 8db2b06b authored by Piotr Ożarowski's avatar Piotr Ożarowski

Import uvloop_0.10.1+ds1.orig.tar.gz

parent 7f45b37b
.PHONY: _default clean clean-libuv distclean compile debug docs test testinstalled release setup-build
.PHONY: _default clean clean-libuv distclean compile debug docs test testinstalled release setup-build ci-clean
PYTHON ?= python
......@@ -9,12 +9,15 @@ _default: compile
clean:
rm -fr dist/ doc/_build/ *.egg-info uvloop/loop.*.pyd
rm -fr build/lib.* build/temp.* build/libuv
rm -fr uvloop/*.c uvloop/*.html uvloop/*.so
rm -fr uvloop/handles/*.html uvloop/includes/*.html
find . -name '__pycache__' | xargs rm -rf
ci-clean: clean
rm -fr build/lib.* build/temp.* build/libuv
clean-libuv:
(cd vendor/libuv; git clean -dfX)
......
Metadata-Version: 1.1
Name: uvloop
Version: 0.9.1
Version: 0.10.1
Summary: Fast implementation of asyncio event loop on top of libuv
Home-page: http://github.com/MagicStack/uvloop
Author: Yury Selivanov
Author-email: yury@magic.io
License: MIT
Description-Content-Type: UNKNOWN
Description: .. image:: https://travis-ci.org/MagicStack/uvloop.svg?branch=master
:target: https://travis-ci.org/MagicStack/uvloop
.. image:: https://ci.appveyor.com/api/projects/status/4apd79e5jqrwwe40/branch/master?svg=true
:target: https://ci.appveyor.com/project/MagicStack/uvloop
.. image:: https://img.shields.io/pypi/v/uvloop.svg
:target: https://pypi.python.org/pypi/uvloop
......@@ -43,7 +45,7 @@ Description: .. image:: https://travis-ci.org/MagicStack/uvloop.svg?branch=maste
Installation
------------
uvloop requires Python 3.5 and is available on PyPI.
uvloop requires Python 3.5 or greater and is available on PyPI.
Use pip to install it::
$ pip install uvloop
......@@ -59,31 +61,40 @@ Description: .. image:: https://travis-ci.org/MagicStack/uvloop.svg?branch=maste
import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
Alternatively, you can create an instance of the loop
manually, using:
.. code:: python
Building From Source
--------------------
To build uvloop, you'll need Python 3.5 or greater:
1. Clone the repository:
.. code::
$ git clone --recursive git@github.com:MagicStack/uvloop.git
$ cd uvloop
2. Create a virtual environment and activate it, for example:
loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop)
.. code::
$ python3.7 -m venv uvloop-dev
$ source uvloop-dev/bin/activate
Development of uvloop
---------------------
3. Install development dependencies:
To build uvloop, you'll need Cython and Python 3.5. The best way
is to create a virtual env, so that you'll have ``cython`` and
``python`` commands pointing to the correct tools.
.. code::
1. ``git clone --recursive git@github.com:MagicStack/uvloop.git``
$ pip install -r requirements.dev.txt
2. ``cd uvloop``
4. Build and run tests:
3. ``make``
.. code::
4. ``make test``
$ make && make test
License
......@@ -93,9 +104,11 @@ Description: .. image:: https://travis-ci.org/MagicStack/uvloop.svg?branch=maste
Platform: *nix
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: AsyncIO
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: License :: OSI Approved :: Apache Software License
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
......
.. image:: https://travis-ci.org/MagicStack/uvloop.svg?branch=master
:target: https://travis-ci.org/MagicStack/uvloop
.. image:: https://ci.appveyor.com/api/projects/status/4apd79e5jqrwwe40/branch/master?svg=true
:target: https://ci.appveyor.com/project/MagicStack/uvloop
.. image:: https://img.shields.io/pypi/v/uvloop.svg
:target: https://pypi.python.org/pypi/uvloop
......@@ -34,7 +37,7 @@ echo protocol. Read more about uvloop
Installation
------------
uvloop requires Python 3.5 and is available on PyPI.
uvloop requires Python 3.5 or greater and is available on PyPI.
Use pip to install it::
$ pip install uvloop
......@@ -50,31 +53,40 @@ loop policy:
import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
Alternatively, you can create an instance of the loop
manually, using:
.. code:: python
Building From Source
--------------------
To build uvloop, you'll need Python 3.5 or greater:
1. Clone the repository:
.. code::
$ git clone --recursive git@github.com:MagicStack/uvloop.git
$ cd uvloop
2. Create a virtual environment and activate it, for example:
loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop)
.. code::
$ python3.7 -m venv uvloop-dev
$ source uvloop-dev/bin/activate
Development of uvloop
---------------------
3. Install development dependencies:
To build uvloop, you'll need Cython and Python 3.5. The best way
is to create a virtual env, so that you'll have ``cython`` and
``python`` commands pointing to the correct tools.
.. code::
1. ``git clone --recursive git@github.com:MagicStack/uvloop.git``
$ pip install -r requirements.dev.txt
2. ``cd uvloop``
4. Build and run tests:
3. ``make``
.. code::
4. ``make test``
$ make && make test
License
......
......@@ -3,11 +3,11 @@
import argparse
import concurrent.futures
import socket
import ssl
import time
from concurrent.futures import ProcessPoolExecutor
from socket import *
if __name__ == '__main__':
parser = argparse.ArgumentParser()
......@@ -23,8 +23,17 @@ if __name__ == '__main__':
help='number of workers')
parser.add_argument('--addr', default='127.0.0.1:25000', type=str,
help='address:port of echoserver')
parser.add_argument('--ssl', default=False, action='store_true')
args = parser.parse_args()
client_context = None
if args.ssl:
print('with SSL')
client_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
if hasattr(client_context, 'check_hostname'):
client_context.check_hostname = False
client_context.verify_mode = ssl.CERT_NONE
unix = False
if args.addr.startswith('file:'):
unix = True
......@@ -48,16 +57,20 @@ if __name__ == '__main__':
n //= args.mpr
if unix:
sock = socket(AF_UNIX, SOCK_STREAM)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
else:
sock = socket(AF_INET, SOCK_STREAM)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
except (OSError, NameError):
pass
if client_context:
sock = client_context.wrap_socket(sock)
sock.connect(addr)
while n > 0:
sock.sendall(msg)
nrecv = 0
......@@ -73,10 +86,10 @@ if __name__ == '__main__':
NMESSAGES = args.num
start = time.time()
for _ in range(TIMES):
with ProcessPoolExecutor(max_workers=N) as e:
with concurrent.futures.ProcessPoolExecutor(max_workers=N) as e:
for _ in range(N):
e.submit(run_test, NMESSAGES)
end = time.time()
duration = end-start
print(NMESSAGES*N*TIMES,'in', duration)
print(NMESSAGES*N*TIMES/duration, 'requests/sec')
print(NMESSAGES * N * TIMES, 'in', duration)
print(NMESSAGES * N * TIMES / duration, 'requests/sec')
......@@ -2,9 +2,9 @@ import argparse
import asyncio
import gc
import os.path
import socket as socket_module
from socket import *
import pathlib
import socket
import ssl
PRINT = 0
......@@ -12,10 +12,10 @@ PRINT = 0
async def echo_server(loop, address, unix):
if unix:
sock = socket(AF_UNIX, SOCK_STREAM)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
else:
sock = socket(AF_INET, SOCK_STREAM)
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(address)
sock.listen(5)
sock.setblocking(False)
......@@ -31,7 +31,7 @@ async def echo_server(loop, address, unix):
async def echo_client(loop, client):
try:
client.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
except (OSError, NameError):
pass
......@@ -48,7 +48,7 @@ async def echo_client(loop, client):
async def echo_client_streams(reader, writer):
sock = writer.get_extra_info('socket')
try:
sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
except (OSError, NameError):
pass
if PRINT:
......@@ -88,6 +88,7 @@ if __name__ == '__main__':
parser.add_argument('--proto', default=False, action='store_true')
parser.add_argument('--addr', default='127.0.0.1:25000', type=str)
parser.add_argument('--print', default=False, action='store_true')
parser.add_argument('--ssl', default=False, action='store_true')
args = parser.parse_args()
if args.uvloop:
......@@ -121,6 +122,19 @@ if __name__ == '__main__':
print('serving on: {}'.format(addr))
server_context = None
if args.ssl:
print('with SSL')
server_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
server_context.load_cert_chain(
(pathlib.Path(__file__).parent.parent.parent /
'tests' / 'certs' / 'ssl_cert.pem'),
(pathlib.Path(__file__).parent.parent.parent /
'tests' / 'certs' / 'ssl_key.pem'))
if hasattr(server_context, 'check_hostname'):
server_context.check_hostname = False
server_context.verify_mode = ssl.CERT_NONE
if args.streams:
if args.proto:
print('cannot use --stream and --proto simultaneously')
......@@ -129,10 +143,12 @@ if __name__ == '__main__':
print('using asyncio/streams')
if unix:
coro = asyncio.start_unix_server(echo_client_streams,
addr, loop=loop)
addr, loop=loop,
ssl=server_context)
else:
coro = asyncio.start_server(echo_client_streams,
*addr, loop=loop)
*addr, loop=loop,
ssl=server_context)
srv = loop.run_until_complete(coro)
elif args.proto:
if args.streams:
......@@ -141,11 +157,17 @@ if __name__ == '__main__':
print('using simple protocol')
if unix:
coro = loop.create_unix_server(EchoProtocol, addr)
coro = loop.create_unix_server(EchoProtocol, addr,
ssl=server_context)
else:
coro = loop.create_server(EchoProtocol, *addr)
coro = loop.create_server(EchoProtocol, *addr,
ssl=server_context)
srv = loop.run_until_complete(coro)
else:
if args.ssl:
print('cannot use SSL for loop.sock_* methods')
exit(1)
print('using sock_recv/sock_sendall')
loop.create_task(echo_server(loop, addr, unix))
try:
......
......@@ -6,6 +6,11 @@ import subprocess
import sys
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext as build_ext
from setuptools.command.sdist import sdist as sdist
if sys.platform in ('win32', 'cygwin', 'cli'):
raise RuntimeError('uvloop does not support Windows at the moment')
......@@ -17,12 +22,6 @@ if vi[:2] == (3, 6):
raise RuntimeError('uvloop requires Python 3.5 or 3.6b3 or greater')
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext as build_ext
from setuptools.command.sdist import sdist as sdist
VERSION = '0.9.1'
CFLAGS = ['-O2']
LIBUV_DIR = os.path.join(os.path.dirname(__file__), 'vendor', 'libuv')
LIBUV_BUILD_DIR = os.path.join(os.path.dirname(__file__), 'build', 'libuv')
......@@ -117,9 +116,9 @@ class uvloop_build_ext(build_ext):
raise RuntimeError(
'please install Cython to compile uvloop from source')
if Cython.__version__ < '0.24':
if Cython.__version__ < '0.28':
raise RuntimeError(
'uvloop requires Cython version 0.24 or greater')
'uvloop requires Cython version 0.28 or greater')
from Cython.Build import cythonize
......@@ -139,80 +138,10 @@ class uvloop_build_ext(build_ext):
compiler_directives=directives,
annotate=self.cython_annotate)
for cfile, timestamp in cfiles.items():
if os.path.getmtime(cfile) != timestamp:
# The file was recompiled, patch
self._patch_cfile(cfile)
super().finalize_options()
self._initialized = True
def _patch_cfile(self, cfile):
# Patch Cython 'async def' coroutines to have a 'tp_iter'
# slot, which makes them compatible with 'yield from' without
# the `asyncio.coroutine` decorator.
with open(cfile, 'rt') as f:
src = f.read()
src = re.sub(
r'''
\s* offsetof\(__pyx_CoroutineObject,\s*gi_weakreflist\),
\s* 0,
\s* 0,
\s* __pyx_Coroutine_methods,
\s* __pyx_Coroutine_memberlist,
\s* __pyx_Coroutine_getsets,
''',
r'''
offsetof(__pyx_CoroutineObject, gi_weakreflist),
__Pyx_Coroutine_await, /* tp_iter */
(iternextfunc) __Pyx_Generator_Next, /* tp_iternext */
__pyx_Coroutine_methods,
__pyx_Coroutine_memberlist,
__pyx_Coroutine_getsets,
''',
src, flags=re.X)
# Fix a segfault in Cython.
src = re.sub(
r'''
\s* __Pyx_Coroutine_get_qualname\(__pyx_CoroutineObject\s+\*self\)
\s* {
\s* Py_INCREF\(self->gi_qualname\);
''',
r'''
__Pyx_Coroutine_get_qualname(__pyx_CoroutineObject *self)
{
if (self->gi_qualname == NULL) { return __pyx_empty_unicode; }
Py_INCREF(self->gi_qualname);
''',
src, flags=re.X)
src = re.sub(
r'''
\s* __Pyx_Coroutine_get_name\(__pyx_CoroutineObject\s+\*self\)
\s* {
\s* Py_INCREF\(self->gi_name\);
''',
r'''
__Pyx_Coroutine_get_name(__pyx_CoroutineObject *self)
{
if (self->gi_name == NULL) { return __pyx_empty_unicode; }
Py_INCREF(self->gi_name);
''',
src, flags=re.X)
with open(cfile, 'wt') as f:
f.write(src)
def build_libuv(self):
env = _libuv_build_env()
......@@ -281,6 +210,18 @@ with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as f:
readme = f.read()
with open(os.path.join(
os.path.dirname(__file__), 'uvloop', '__init__.py')) as f:
for line in f:
if line.startswith('__version__ ='):
_, _, version = line.partition('=')
VERSION = version.strip(" \n'\"")
break
else:
raise RuntimeError(
'unable to read the version from uvloop/__init__.py')
setup(
name='uvloop',
description='Fast implementation of asyncio event loop on top of libuv',
......@@ -307,9 +248,11 @@ setup(
],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Framework :: AsyncIO',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'License :: OSI Approved :: Apache Software License',
'License :: OSI Approved :: MIT License',
'Intended Audience :: Developers',
......
......@@ -461,56 +461,6 @@ class _TestBase:
self.mock_pattern('Unhandled error in exception handler'),
exc_info=mock.ANY)
def test_default_exc_handler_broken(self):
logger = logging.getLogger('asyncio')
_context = None
class Loop(uvloop.Loop):
_selector = mock.Mock()
_process_events = mock.Mock()
def default_exception_handler(self, context):
nonlocal _context
_context = context
# Simulates custom buggy "default_exception_handler"
raise ValueError('spam')
loop = Loop()
self.addCleanup(loop.close)
asyncio.set_event_loop(loop)
def run_loop():
def zero_error():
loop.stop()
1 / 0
loop.call_soon(zero_error)
loop.run_forever()
with mock.patch.object(logger, 'error') as log:
run_loop()
log.assert_called_with(
'Exception in default exception handler',
exc_info=True)
def custom_handler(loop, context):
raise ValueError('ham')
_context = None
loop.set_exception_handler(custom_handler)
with mock.patch.object(logger, 'error') as log:
run_loop()
log.assert_called_with(
self.mock_pattern('Exception in default exception.*'
'while handling.*in custom'),
exc_info=True)
# Check that original context was passed to default
# exception handler.
self.assertIn('context', _context)
self.assertIs(type(_context['context']['exception']),
ZeroDivisionError)
def test_set_task_factory_invalid(self):
with self.assertRaisesRegex(
TypeError,
......@@ -663,7 +613,7 @@ class TestBaseUV(_TestBase, UVTestCase):
fut.cancel()
def test_loop_call_soon_handle_cancelled(self):
cb = lambda: False
cb = lambda: False # NoQA
handle = self.loop.call_soon(cb)
self.assertFalse(handle.cancelled())
handle.cancel()
......@@ -675,7 +625,7 @@ class TestBaseUV(_TestBase, UVTestCase):
self.assertFalse(handle.cancelled())
def test_loop_call_later_handle_cancelled(self):
cb = lambda: False
cb = lambda: False # NoQA
handle = self.loop.call_later(0.01, cb)
self.assertFalse(handle.cancelled())
handle.cancel()
......@@ -692,6 +642,58 @@ class TestBaseUV(_TestBase, UVTestCase):
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
self.assertFalse(flags & fcntl.FD_CLOEXEC)
def test_default_exc_handler_broken(self):
logger = logging.getLogger('asyncio')
_context = None
class Loop(uvloop.Loop):
_selector = mock.Mock()
_process_events = mock.Mock()
def default_exception_handler(self, context):
nonlocal _context
_context = context
# Simulates custom buggy "default_exception_handler"
raise ValueError('spam')
loop = Loop()
self.addCleanup(loop.close)
self.addCleanup(lambda: asyncio.set_event_loop(None))
asyncio.set_event_loop(loop)
def run_loop():
def zero_error():
loop.stop()
1 / 0
loop.call_soon(zero_error)
loop.run_forever()
with mock.patch.object(logger, 'error') as log:
run_loop()
log.assert_called_with(
'Exception in default exception handler',
exc_info=True)
def custom_handler(loop, context):
raise ValueError('ham')
_context = None
loop.set_exception_handler(custom_handler)
with mock.patch.object(logger, 'error') as log:
run_loop()
log.assert_called_with(
self.mock_pattern('Exception in default exception.*'
'while handling.*in custom'),
exc_info=True)
# Check that original context was passed to default
# exception handler.
self.assertIn('context', _context)
self.assertIs(type(_context['context']['exception']),
ZeroDivisionError)
class TestBaseAIO(_TestBase, AIOTestCase):
pass
......
import asyncio
import decimal
import random
import sys
import unittest
from uvloop import _testbase as tb
PY37 = sys.version_info >= (3, 7, 0)
class _ContextBaseTests:
@unittest.skipUnless(PY37, 'requires Python 3.7')
def test_task_decimal_context(self):
async def fractions(t, precision, x, y):
with decimal.localcontext() as ctx:
ctx.prec = precision
a = decimal.Decimal(x) / decimal.Decimal(y)
await asyncio.sleep(t, loop=self.loop)
b = decimal.Decimal(x) / decimal.Decimal(y ** 2)
return a, b
async def main():
r1, r2 = await asyncio.gather(
fractions(0.1, 3, 1, 3), fractions(0.2, 6, 1, 3),
loop=self.loop)
return r1, r2
r1, r2 = self.loop.run_until_complete(main())
self.assertEqual(str(r1[0]), '0.333')
self.assertEqual(str(r1[1]), '0.111')
self.assertEqual(str(r2[0]), '0.333333')
self.assertEqual(str(r2[1]), '0.111111')
@unittest.skipUnless(PY37, 'requires Python 3.7')
def test_task_context_1(self):
import contextvars
cvar = contextvars.ContextVar('cvar', default='nope')
async def sub():
await asyncio.sleep(0.01, loop=self.loop)
self.assertEqual(cvar.get(), 'nope')
cvar.set('something else')
async def main():
self.assertEqual(cvar.get(), 'nope')
subtask = self.loop.create_task(sub())
cvar.set('yes')
self.assertEqual(cvar.get(), 'yes')
await subtask
self.assertEqual(cvar.get(), 'yes')
task = self.loop.create_task(main())
self.loop.run_until_complete(task)
@unittest.skipUnless(PY37, 'requires Python 3.7')
def test_task_context_2(self):
import contextvars
cvar = contextvars.ContextVar('cvar', default='nope')
async def main():
def fut_on_done(fut):
# This change must not pollute the context
# of the "main()" task.
cvar.set('something else')
self.assertEqual(cvar.get(), 'nope')
for j in range(2):
fut = self.loop.create_future()
fut.add_done_callback(fut_on_done)
cvar.set('yes{}'.format(j))
self.loop.call_soon(fut.set_result, None)
await fut
self.assertEqual(cvar.get(), 'yes{}'.format(j))
for i in range(3):
# Test that task passed its context to add_done_callback:
cvar.set('yes{}-{}'.format(i, j))
await asyncio.sleep(0.001, loop=self.loop)
self.assertEqual(cvar.get(), 'yes{}-{}'.format(i, j))
task = self.loop.create_task(main())
self.loop.run_until_complete(task)
self.assertEqual(cvar.get(), 'nope')
@unittest.skipUnless(PY37, 'requires Python 3.7')
def test_task_context_3(self):