Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
6b5a2797
Unverified
Kaydet (Commit)
6b5a2797
authored
Ock 16, 2018
tarafından
Andrew Svetlov
Kaydeden (comit)
GitHub
Ock 16, 2018
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
bpo-32410: Implement loop.sock_sendfile() (#4976)
üst
c495e799
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
609 additions
and
0 deletions
+609
-0
asyncio-eventloop.rst
Doc/library/asyncio-eventloop.rst
+30
-0
base_events.py
Lib/asyncio/base_events.py
+70
-0
events.py
Lib/asyncio/events.py
+4
-0
unix_events.py
Lib/asyncio/unix_events.py
+93
-0
test_base_events.py
Lib/test/test_asyncio/test_base_events.py
+158
-0
test_events.py
Lib/test/test_asyncio/test_events.py
+2
-0
test_unix_events.py
Lib/test/test_asyncio/test_unix_events.py
+251
-0
2017-12-22-16-05-01.bpo-32410.8JzhvH.rst
...S.d/next/Library/2017-12-22-16-05-01.bpo-32410.8JzhvH.rst
+1
-0
No files found.
Doc/library/asyncio-eventloop.rst
Dosyayı görüntüle @
6b5a2797
...
@@ -701,6 +701,36 @@ Low-level socket operations
...
@@ -701,6 +701,36 @@ Low-level socket operations
:meth:`AbstractEventLoop.create_server` and :func:`start_server`.
:meth:`AbstractEventLoop.create_server` and :func:`start_server`.
.. coroutinemethod:: AbstractEventLoop.sock_sendfile(sock, file, \
offset=0, count=None, \
*, fallback=True)
Send a file using high-performance :mod:`os.sendfile` if possible
and return the total number of bytes which were sent.
Asynchronous version of :meth:`socket.socket.sendfile`.
*sock* must be non-blocking :class:`~socket.socket` of
:const:`socket.SOCK_STREAM` type.
*file* must be a regular file object opened in binary mode.
*offset* tells from where to start reading the file. If specified,
*count* is the total number of bytes to transmit as opposed to
sending the file until EOF is reached. File position is updated on
return or also in case of error in which case :meth:`file.tell()
<io.IOBase.tell>` can be used to figure out the number of bytes
which were sent.
*fallback* set to ``True`` makes asyncio to manually read and send
the file when the platform does not support the sendfile syscall
(e.g. Windows or SSL socket on Unix).
Raise :exc:`RuntimeError` if the system does not support
*sendfile* syscall and *fallback* is ``False``.
.. versionadded:: 3.7
Resolve host name
Resolve host name
-----------------
-----------------
...
...
Lib/asyncio/base_events.py
Dosyayı görüntüle @
6b5a2797
...
@@ -154,6 +154,10 @@ def _run_until_complete_cb(fut):
...
@@ -154,6 +154,10 @@ def _run_until_complete_cb(fut):
futures
.
_get_loop
(
fut
)
.
stop
()
futures
.
_get_loop
(
fut
)
.
stop
()
class
_SendfileNotAvailable
(
RuntimeError
):
pass
class
Server
(
events
.
AbstractServer
):
class
Server
(
events
.
AbstractServer
):
def
__init__
(
self
,
loop
,
sockets
):
def
__init__
(
self
,
loop
,
sockets
):
...
@@ -647,6 +651,72 @@ class BaseEventLoop(events.AbstractEventLoop):
...
@@ -647,6 +651,72 @@ class BaseEventLoop(events.AbstractEventLoop):
return
await
self
.
run_in_executor
(
return
await
self
.
run_in_executor
(
None
,
socket
.
getnameinfo
,
sockaddr
,
flags
)
None
,
socket
.
getnameinfo
,
sockaddr
,
flags
)
async
def
sock_sendfile
(
self
,
sock
,
file
,
offset
=
0
,
count
=
None
,
*
,
fallback
=
True
):
if
self
.
_debug
and
sock
.
gettimeout
()
!=
0
:
raise
ValueError
(
"the socket must be non-blocking"
)
self
.
_check_sendfile_params
(
sock
,
file
,
offset
,
count
)
try
:
return
await
self
.
_sock_sendfile_native
(
sock
,
file
,
offset
,
count
)
except
_SendfileNotAvailable
as
exc
:
if
fallback
:
return
await
self
.
_sock_sendfile_fallback
(
sock
,
file
,
offset
,
count
)
else
:
raise
RuntimeError
(
exc
.
args
[
0
])
from
None
async
def
_sock_sendfile_native
(
self
,
sock
,
file
,
offset
,
count
):
# NB: sendfile syscall is not supported for SSL sockets and
# non-mmap files even if sendfile is supported by OS
raise
_SendfileNotAvailable
(
f
"syscall sendfile is not available for socket {sock!r} "
"and file {file!r} combination"
)
async
def
_sock_sendfile_fallback
(
self
,
sock
,
file
,
offset
,
count
):
if
offset
:
file
.
seek
(
offset
)
blocksize
=
min
(
count
,
16384
)
if
count
else
16384
buf
=
bytearray
(
blocksize
)
total_sent
=
0
try
:
while
True
:
if
count
:
blocksize
=
min
(
count
-
total_sent
,
blocksize
)
if
blocksize
<=
0
:
break
view
=
memoryview
(
buf
)[:
blocksize
]
read
=
file
.
readinto
(
view
)
if
not
read
:
break
# EOF
await
self
.
sock_sendall
(
sock
,
view
)
total_sent
+=
read
return
total_sent
finally
:
if
total_sent
>
0
and
hasattr
(
file
,
'seek'
):
file
.
seek
(
offset
+
total_sent
)
def
_check_sendfile_params
(
self
,
sock
,
file
,
offset
,
count
):
if
'b'
not
in
getattr
(
file
,
'mode'
,
'b'
):
raise
ValueError
(
"file should be opened in binary mode"
)
if
not
sock
.
type
==
socket
.
SOCK_STREAM
:
raise
ValueError
(
"only SOCK_STREAM type sockets are supported"
)
if
count
is
not
None
:
if
not
isinstance
(
count
,
int
):
raise
TypeError
(
"count must be a positive integer (got {!r})"
.
format
(
count
))
if
count
<=
0
:
raise
ValueError
(
"count must be a positive integer (got {!r})"
.
format
(
count
))
if
not
isinstance
(
offset
,
int
):
raise
TypeError
(
"offset must be a non-negative integer (got {!r})"
.
format
(
offset
))
if
offset
<
0
:
raise
ValueError
(
"offset must be a non-negative integer (got {!r})"
.
format
(
offset
))
async
def
create_connection
(
async
def
create_connection
(
self
,
protocol_factory
,
host
=
None
,
port
=
None
,
self
,
protocol_factory
,
host
=
None
,
port
=
None
,
*
,
ssl
=
None
,
family
=
0
,
*
,
ssl
=
None
,
family
=
0
,
...
...
Lib/asyncio/events.py
Dosyayı görüntüle @
6b5a2797
...
@@ -464,6 +464,10 @@ class AbstractEventLoop:
...
@@ -464,6 +464,10 @@ class AbstractEventLoop:
async
def
sock_accept
(
self
,
sock
):
async
def
sock_accept
(
self
,
sock
):
raise
NotImplementedError
raise
NotImplementedError
async
def
sock_sendfile
(
self
,
sock
,
file
,
offset
=
0
,
count
=
None
,
*
,
fallback
=
None
):
raise
NotImplementedError
# Signal handling.
# Signal handling.
def
add_signal_handler
(
self
,
sig
,
callback
,
*
args
):
def
add_signal_handler
(
self
,
sig
,
callback
,
*
args
):
...
...
Lib/asyncio/unix_events.py
Dosyayı görüntüle @
6b5a2797
"""Selector event loop for Unix with signal handling."""
"""Selector event loop for Unix with signal handling."""
import
errno
import
errno
import
io
import
os
import
os
import
selectors
import
selectors
import
signal
import
signal
...
@@ -308,6 +309,98 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop):
...
@@ -308,6 +309,98 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop):
ssl_handshake_timeout
=
ssl_handshake_timeout
)
ssl_handshake_timeout
=
ssl_handshake_timeout
)
return
server
return
server
async
def
_sock_sendfile_native
(
self
,
sock
,
file
,
offset
,
count
):
try
:
os
.
sendfile
except
AttributeError
as
exc
:
raise
base_events
.
_SendfileNotAvailable
(
"os.sendfile() is not available"
)
try
:
fileno
=
file
.
fileno
()
except
(
AttributeError
,
io
.
UnsupportedOperation
)
as
err
:
raise
base_events
.
_SendfileNotAvailable
(
"not a regular file"
)
try
:
fsize
=
os
.
fstat
(
fileno
)
.
st_size
except
OSError
as
err
:
raise
base_events
.
_SendfileNotAvailable
(
"not a regular file"
)
blocksize
=
count
if
count
else
fsize
if
not
blocksize
:
return
0
# empty file
fut
=
self
.
create_future
()
self
.
_sock_sendfile_native_impl
(
fut
,
None
,
sock
,
fileno
,
offset
,
count
,
blocksize
,
0
)
return
await
fut
def
_sock_sendfile_native_impl
(
self
,
fut
,
registered_fd
,
sock
,
fileno
,
offset
,
count
,
blocksize
,
total_sent
):
fd
=
sock
.
fileno
()
if
registered_fd
is
not
None
:
# Remove the callback early. It should be rare that the
# selector says the fd is ready but the call still returns
# EAGAIN, and I am willing to take a hit in that case in
# order to simplify the common case.
self
.
remove_writer
(
registered_fd
)
if
fut
.
cancelled
():
self
.
_sock_sendfile_update_filepos
(
fileno
,
offset
,
total_sent
)
return
if
count
:
blocksize
=
count
-
total_sent
if
blocksize
<=
0
:
self
.
_sock_sendfile_update_filepos
(
fileno
,
offset
,
total_sent
)
fut
.
set_result
(
total_sent
)
return
try
:
sent
=
os
.
sendfile
(
fd
,
fileno
,
offset
,
blocksize
)
except
(
BlockingIOError
,
InterruptedError
):
if
registered_fd
is
None
:
self
.
_sock_add_cancellation_callback
(
fut
,
sock
)
self
.
add_writer
(
fd
,
self
.
_sock_sendfile_native_impl
,
fut
,
fd
,
sock
,
fileno
,
offset
,
count
,
blocksize
,
total_sent
)
except
OSError
as
exc
:
if
total_sent
==
0
:
# We can get here for different reasons, the main
# one being 'file' is not a regular mmap(2)-like
# file, in which case we'll fall back on using
# plain send().
err
=
base_events
.
_SendfileNotAvailable
(
"os.sendfile call failed"
)
self
.
_sock_sendfile_update_filepos
(
fileno
,
offset
,
total_sent
)
fut
.
set_exception
(
err
)
else
:
self
.
_sock_sendfile_update_filepos
(
fileno
,
offset
,
total_sent
)
fut
.
set_exception
(
exc
)
except
Exception
as
exc
:
self
.
_sock_sendfile_update_filepos
(
fileno
,
offset
,
total_sent
)
fut
.
set_exception
(
exc
)
else
:
if
sent
==
0
:
# EOF
self
.
_sock_sendfile_update_filepos
(
fileno
,
offset
,
total_sent
)
fut
.
set_result
(
total_sent
)
else
:
offset
+=
sent
total_sent
+=
sent
if
registered_fd
is
None
:
self
.
_sock_add_cancellation_callback
(
fut
,
sock
)
self
.
add_writer
(
fd
,
self
.
_sock_sendfile_native_impl
,
fut
,
fd
,
sock
,
fileno
,
offset
,
count
,
blocksize
,
total_sent
)
def
_sock_sendfile_update_filepos
(
self
,
fileno
,
offset
,
total_sent
):
if
total_sent
>
0
:
os
.
lseek
(
fileno
,
offset
,
os
.
SEEK_SET
)
def
_sock_add_cancellation_callback
(
self
,
fut
,
sock
):
def
cb
(
fut
):
if
fut
.
cancelled
():
fd
=
sock
.
fileno
()
if
fd
!=
-
1
:
self
.
remove_writer
(
fd
)
fut
.
add_done_callback
(
cb
)
class
_UnixReadPipeTransport
(
transports
.
ReadTransport
):
class
_UnixReadPipeTransport
(
transports
.
ReadTransport
):
...
...
Lib/test/test_asyncio/test_base_events.py
Dosyayı görüntüle @
6b5a2797
...
@@ -1787,5 +1787,163 @@ class RunningLoopTests(unittest.TestCase):
...
@@ -1787,5 +1787,163 @@ class RunningLoopTests(unittest.TestCase):
outer_loop
.
close
()
outer_loop
.
close
()
class
BaseLoopSendfileTests
(
test_utils
.
TestCase
):
DATA
=
b
"12345abcde"
*
16
*
1024
# 160 KiB
class
MyProto
(
asyncio
.
Protocol
):
def
__init__
(
self
,
loop
):
self
.
started
=
False
self
.
closed
=
False
self
.
data
=
bytearray
()
self
.
fut
=
loop
.
create_future
()
def
connection_made
(
self
,
transport
):
self
.
started
=
True
def
data_received
(
self
,
data
):
self
.
data
.
extend
(
data
)
def
connection_lost
(
self
,
exc
):
self
.
closed
=
True
self
.
fut
.
set_result
(
None
)
async
def
wait_closed
(
self
):
await
self
.
fut
@classmethod
def
setUpClass
(
cls
):
with
open
(
support
.
TESTFN
,
'wb'
)
as
fp
:
fp
.
write
(
cls
.
DATA
)
super
()
.
setUpClass
()
@classmethod
def
tearDownClass
(
cls
):
support
.
unlink
(
support
.
TESTFN
)
super
()
.
tearDownClass
()
def
setUp
(
self
):
from
asyncio.selector_events
import
BaseSelectorEventLoop
# BaseSelectorEventLoop() has no native implementation
self
.
loop
=
BaseSelectorEventLoop
()
self
.
set_event_loop
(
self
.
loop
)
self
.
file
=
open
(
support
.
TESTFN
,
'rb'
)
self
.
addCleanup
(
self
.
file
.
close
)
super
()
.
setUp
()
def
make_socket
(
self
,
blocking
=
False
):
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
sock
.
setblocking
(
blocking
)
self
.
addCleanup
(
sock
.
close
)
return
sock
def
run_loop
(
self
,
coro
):
return
self
.
loop
.
run_until_complete
(
coro
)
def
prepare
(
self
):
sock
=
self
.
make_socket
()
proto
=
self
.
MyProto
(
self
.
loop
)
port
=
support
.
find_unused_port
()
server
=
self
.
run_loop
(
self
.
loop
.
create_server
(
lambda
:
proto
,
support
.
HOST
,
port
))
self
.
run_loop
(
self
.
loop
.
sock_connect
(
sock
,
(
support
.
HOST
,
port
)))
def
cleanup
():
server
.
close
()
self
.
run_loop
(
server
.
wait_closed
())
self
.
addCleanup
(
cleanup
)
return
sock
,
proto
def
test__sock_sendfile_native_failure
(
self
):
sock
,
proto
=
self
.
prepare
()
with
self
.
assertRaisesRegex
(
base_events
.
_SendfileNotAvailable
,
"sendfile is not available"
):
self
.
run_loop
(
self
.
loop
.
_sock_sendfile_native
(
sock
,
self
.
file
,
0
,
None
))
self
.
assertEqual
(
proto
.
data
,
b
''
)
self
.
assertEqual
(
self
.
file
.
tell
(),
0
)
def
test_sock_sendfile_no_fallback
(
self
):
sock
,
proto
=
self
.
prepare
()
with
self
.
assertRaisesRegex
(
RuntimeError
,
"sendfile is not available"
):
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
,
fallback
=
False
))
self
.
assertEqual
(
self
.
file
.
tell
(),
0
)
self
.
assertEqual
(
proto
.
data
,
b
''
)
def
test_sock_sendfile_fallback
(
self
):
sock
,
proto
=
self
.
prepare
()
ret
=
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
))
sock
.
close
()
self
.
run_loop
(
proto
.
wait_closed
())
self
.
assertEqual
(
ret
,
len
(
self
.
DATA
))
self
.
assertEqual
(
self
.
file
.
tell
(),
len
(
self
.
DATA
))
self
.
assertEqual
(
proto
.
data
,
self
.
DATA
)
def
test_sock_sendfile_fallback_offset_and_count
(
self
):
sock
,
proto
=
self
.
prepare
()
ret
=
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
,
1000
,
2000
))
sock
.
close
()
self
.
run_loop
(
proto
.
wait_closed
())
self
.
assertEqual
(
ret
,
2000
)
self
.
assertEqual
(
self
.
file
.
tell
(),
3000
)
self
.
assertEqual
(
proto
.
data
,
self
.
DATA
[
1000
:
3000
])
def
test_blocking_socket
(
self
):
self
.
loop
.
set_debug
(
True
)
sock
=
self
.
make_socket
(
blocking
=
True
)
with
self
.
assertRaisesRegex
(
ValueError
,
"must be non-blocking"
):
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
))
def
test_nonbinary_file
(
self
):
sock
=
self
.
make_socket
()
with
open
(
support
.
TESTFN
,
'r'
)
as
f
:
with
self
.
assertRaisesRegex
(
ValueError
,
"binary mode"
):
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
f
))
def
test_nonstream_socket
(
self
):
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_DGRAM
)
self
.
addCleanup
(
sock
.
close
)
with
self
.
assertRaisesRegex
(
ValueError
,
"only SOCK_STREAM type"
):
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
))
def
test_notint_count
(
self
):
sock
=
self
.
make_socket
()
with
self
.
assertRaisesRegex
(
TypeError
,
"count must be a positive integer"
):
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
,
0
,
'count'
))
def
test_negative_count
(
self
):
sock
=
self
.
make_socket
()
with
self
.
assertRaisesRegex
(
ValueError
,
"count must be a positive integer"
):
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
,
0
,
-
1
))
def
test_notint_offset
(
self
):
sock
=
self
.
make_socket
()
with
self
.
assertRaisesRegex
(
TypeError
,
"offset must be a non-negative integer"
):
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
,
'offset'
))
def
test_negative_offset
(
self
):
sock
=
self
.
make_socket
()
with
self
.
assertRaisesRegex
(
ValueError
,
"offset must be a non-negative integer"
):
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
,
-
1
))
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
unittest
.
main
()
unittest
.
main
()
Lib/test/test_asyncio/test_events.py
Dosyayı görüntüle @
6b5a2797
...
@@ -2555,6 +2555,8 @@ class AbstractEventLoopTests(unittest.TestCase):
...
@@ -2555,6 +2555,8 @@ class AbstractEventLoopTests(unittest.TestCase):
await
loop
.
sock_connect
(
f
,
f
)
await
loop
.
sock_connect
(
f
,
f
)
with
self
.
assertRaises
(
NotImplementedError
):
with
self
.
assertRaises
(
NotImplementedError
):
await
loop
.
sock_accept
(
f
)
await
loop
.
sock_accept
(
f
)
with
self
.
assertRaises
(
NotImplementedError
):
await
loop
.
sock_sendfile
(
f
,
mock
.
Mock
())
with
self
.
assertRaises
(
NotImplementedError
):
with
self
.
assertRaises
(
NotImplementedError
):
await
loop
.
connect_read_pipe
(
f
,
mock
.
sentinel
.
pipe
)
await
loop
.
connect_read_pipe
(
f
,
mock
.
sentinel
.
pipe
)
with
self
.
assertRaises
(
NotImplementedError
):
with
self
.
assertRaises
(
NotImplementedError
):
...
...
Lib/test/test_asyncio/test_unix_events.py
Dosyayı görüntüle @
6b5a2797
"""Tests for unix_events.py."""
"""Tests for unix_events.py."""
import
collections
import
collections
import
contextlib
import
errno
import
errno
import
io
import
io
import
os
import
os
...
@@ -21,6 +22,7 @@ if sys.platform == 'win32':
...
@@ -21,6 +22,7 @@ if sys.platform == 'win32':
import
asyncio
import
asyncio
from
asyncio
import
log
from
asyncio
import
log
from
asyncio
import
base_events
from
asyncio
import
unix_events
from
asyncio
import
unix_events
from
test.test_asyncio
import
utils
as
test_utils
from
test.test_asyncio
import
utils
as
test_utils
...
@@ -417,6 +419,255 @@ class SelectorEventLoopUnixSocketTests(test_utils.TestCase):
...
@@ -417,6 +419,255 @@ class SelectorEventLoopUnixSocketTests(test_utils.TestCase):
self
.
loop
.
run_until_complete
(
coro
)
self
.
loop
.
run_until_complete
(
coro
)
@unittest.skipUnless
(
hasattr
(
os
,
'sendfile'
),
'sendfile is not supported'
)
class
SelectorEventLoopUnixSockSendfileTests
(
test_utils
.
TestCase
):
DATA
=
b
"12345abcde"
*
16
*
1024
# 160 KiB
class
MyProto
(
asyncio
.
Protocol
):
def
__init__
(
self
,
loop
):
self
.
started
=
False
self
.
closed
=
False
self
.
data
=
bytearray
()
self
.
fut
=
loop
.
create_future
()
self
.
transport
=
None
def
connection_made
(
self
,
transport
):
self
.
started
=
True
self
.
transport
=
transport
def
data_received
(
self
,
data
):
self
.
data
.
extend
(
data
)
def
connection_lost
(
self
,
exc
):
self
.
closed
=
True
self
.
fut
.
set_result
(
None
)
async
def
wait_closed
(
self
):
await
self
.
fut
@classmethod
def
setUpClass
(
cls
):
with
open
(
support
.
TESTFN
,
'wb'
)
as
fp
:
fp
.
write
(
cls
.
DATA
)
super
()
.
setUpClass
()
@classmethod
def
tearDownClass
(
cls
):
support
.
unlink
(
support
.
TESTFN
)
super
()
.
tearDownClass
()
def
setUp
(
self
):
self
.
loop
=
asyncio
.
new_event_loop
()
self
.
set_event_loop
(
self
.
loop
)
self
.
file
=
open
(
support
.
TESTFN
,
'rb'
)
self
.
addCleanup
(
self
.
file
.
close
)
super
()
.
setUp
()
def
make_socket
(
self
,
blocking
=
False
):
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
sock
.
setblocking
(
blocking
)
self
.
addCleanup
(
sock
.
close
)
return
sock
def
run_loop
(
self
,
coro
):
return
self
.
loop
.
run_until_complete
(
coro
)
def
prepare
(
self
):
sock
=
self
.
make_socket
()
proto
=
self
.
MyProto
(
self
.
loop
)
port
=
support
.
find_unused_port
()
server
=
self
.
run_loop
(
self
.
loop
.
create_server
(
lambda
:
proto
,
support
.
HOST
,
port
))
self
.
run_loop
(
self
.
loop
.
sock_connect
(
sock
,
(
support
.
HOST
,
port
)))
def
cleanup
():
proto
.
transport
.
close
()
self
.
run_loop
(
proto
.
wait_closed
())
server
.
close
()
self
.
run_loop
(
server
.
wait_closed
())
self
.
addCleanup
(
cleanup
)
return
sock
,
proto
def
test_success
(
self
):
sock
,
proto
=
self
.
prepare
()
ret
=
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
))
sock
.
close
()
self
.
run_loop
(
proto
.
wait_closed
())
self
.
assertEqual
(
ret
,
len
(
self
.
DATA
))
self
.
assertEqual
(
proto
.
data
,
self
.
DATA
)
self
.
assertEqual
(
self
.
file
.
tell
(),
len
(
self
.
DATA
))
def
test_with_offset_and_count
(
self
):
sock
,
proto
=
self
.
prepare
()
ret
=
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
,
1000
,
2000
))
sock
.
close
()
self
.
run_loop
(
proto
.
wait_closed
())
self
.
assertEqual
(
proto
.
data
,
self
.
DATA
[
1000
:
3000
])
self
.
assertEqual
(
self
.
file
.
tell
(),
3000
)
self
.
assertEqual
(
ret
,
2000
)
def
test_sendfile_not_available
(
self
):
sock
,
proto
=
self
.
prepare
()
with
mock
.
patch
(
'asyncio.unix_events.os'
,
spec
=
[]):
with
self
.
assertRaisesRegex
(
base_events
.
_SendfileNotAvailable
,
"os[.]sendfile[(][)] is not available"
):
self
.
run_loop
(
self
.
loop
.
_sock_sendfile_native
(
sock
,
self
.
file
,
0
,
None
))
self
.
assertEqual
(
self
.
file
.
tell
(),
0
)
def
test_sendfile_not_a_file
(
self
):
sock
,
proto
=
self
.
prepare
()
f
=
object
()
with
self
.
assertRaisesRegex
(
base_events
.
_SendfileNotAvailable
,
"not a regular file"
):
self
.
run_loop
(
self
.
loop
.
_sock_sendfile_native
(
sock
,
f
,
0
,
None
))
self
.
assertEqual
(
self
.
file
.
tell
(),
0
)
def
test_sendfile_iobuffer
(
self
):
sock
,
proto
=
self
.
prepare
()
f
=
io
.
BytesIO
()
with
self
.
assertRaisesRegex
(
base_events
.
_SendfileNotAvailable
,
"not a regular file"
):
self
.
run_loop
(
self
.
loop
.
_sock_sendfile_native
(
sock
,
f
,
0
,
None
))
self
.
assertEqual
(
self
.
file
.
tell
(),
0
)
def
test_sendfile_not_regular_file
(
self
):
sock
,
proto
=
self
.
prepare
()
f
=
mock
.
Mock
()
f
.
fileno
.
return_value
=
-
1
with
self
.
assertRaisesRegex
(
base_events
.
_SendfileNotAvailable
,
"not a regular file"
):
self
.
run_loop
(
self
.
loop
.
_sock_sendfile_native
(
sock
,
f
,
0
,
None
))
self
.
assertEqual
(
self
.
file
.
tell
(),
0
)
def
test_sendfile_zero_size
(
self
):
sock
,
proto
=
self
.
prepare
()
fname
=
support
.
TESTFN
+
'.suffix'
with
open
(
fname
,
'wb'
)
as
f
:
pass
# make zero sized file
f
=
open
(
fname
,
'rb'
)
self
.
addCleanup
(
f
.
close
)
self
.
addCleanup
(
support
.
unlink
,
fname
)
ret
=
self
.
run_loop
(
self
.
loop
.
_sock_sendfile_native
(
sock
,
f
,
0
,
None
))
sock
.
close
()
self
.
run_loop
(
proto
.
wait_closed
())
self
.
assertEqual
(
ret
,
0
)
self
.
assertEqual
(
self
.
file
.
tell
(),
0
)
def
test_mix_sendfile_and_regular_send
(
self
):
buf
=
b
'1234567890'
*
1024
*
1024
# 10 MB
sock
,
proto
=
self
.
prepare
()
self
.
run_loop
(
self
.
loop
.
sock_sendall
(
sock
,
buf
))
ret
=
self
.
run_loop
(
self
.
loop
.
sock_sendfile
(
sock
,
self
.
file
))
self
.
run_loop
(
self
.
loop
.
sock_sendall
(
sock
,
buf
))
sock
.
close
()
self
.
run_loop
(
proto
.
wait_closed
())
self
.
assertEqual
(
ret
,
len
(
self
.
DATA
))
expected
=
buf
+
self
.
DATA
+
buf
self
.
assertEqual
(
proto
.
data
,
expected
)
self
.
assertEqual
(
self
.
file
.
tell
(),
len
(
self
.
DATA
))
def
test_cancel1
(
self
):
sock
,
proto
=
self
.
prepare
()
fut
=
self
.
loop
.
create_future
()
fileno
=
self
.
file
.
fileno
()
self
.
loop
.
_sock_sendfile_native_impl
(
fut
,
None
,
sock
,
fileno
,
0
,
None
,
len
(
self
.
DATA
),
0
)
fut
.
cancel
()
with
contextlib
.
suppress
(
asyncio
.
CancelledError
):
self
.
run_loop
(
fut
)
with
self
.
assertRaises
(
KeyError
):
self
.
loop
.
_selector
.
get_key
(
sock
)
def
test_cancel2
(
self
):
sock
,
proto
=
self
.
prepare
()
fut
=
self
.
loop
.
create_future
()
fileno
=
self
.
file
.
fileno
()
self
.
loop
.
_sock_sendfile_native_impl
(
fut
,
None
,
sock
,
fileno
,
0
,
None
,
len
(
self
.
DATA
),
0
)
fut
.
cancel
()
self
.
loop
.
_sock_sendfile_native_impl
(
fut
,
sock
.
fileno
(),
sock
,
fileno
,
0
,
None
,
len
(
self
.
DATA
),
0
)
with
self
.
assertRaises
(
KeyError
):
self
.
loop
.
_selector
.
get_key
(
sock
)
def
test_blocking_error
(
self
):
sock
,
proto
=
self
.
prepare
()
fileno
=
self
.
file
.
fileno
()
fut
=
mock
.
Mock
()
fut
.
cancelled
.
return_value
=
False
with
mock
.
patch
(
'os.sendfile'
,
side_effect
=
BlockingIOError
()):
self
.
loop
.
_sock_sendfile_native_impl
(
fut
,
None
,
sock
,
fileno
,
0
,
None
,
len
(
self
.
DATA
),
0
)
key
=
self
.
loop
.
_selector
.
get_key
(
sock
)
self
.
assertIsNotNone
(
key
)
fut
.
add_done_callback
.
assert_called_once_with
(
mock
.
ANY
)
def
test_os_error_first_call
(
self
):
sock
,
proto
=
self
.
prepare
()
fileno
=
self
.
file
.
fileno
()
fut
=
self
.
loop
.
create_future
()
with
mock
.
patch
(
'os.sendfile'
,
side_effect
=
OSError
()):
self
.
loop
.
_sock_sendfile_native_impl
(
fut
,
None
,
sock
,
fileno
,
0
,
None
,
len
(
self
.
DATA
),
0
)
with
self
.
assertRaises
(
KeyError
):
self
.
loop
.
_selector
.
get_key
(
sock
)
exc
=
fut
.
exception
()
self
.
assertIsInstance
(
exc
,
base_events
.
_SendfileNotAvailable
)
self
.
assertEqual
(
0
,
self
.
file
.
tell
())
def
test_os_error_next_call
(
self
):
sock
,
proto
=
self
.
prepare
()
fileno
=
self
.
file
.
fileno
()
fut
=
self
.
loop
.
create_future
()
err
=
OSError
()
with
mock
.
patch
(
'os.sendfile'
,
side_effect
=
err
):
self
.
loop
.
_sock_sendfile_native_impl
(
fut
,
sock
.
fileno
(),
sock
,
fileno
,
1000
,
None
,
len
(
self
.
DATA
),
1000
)
with
self
.
assertRaises
(
KeyError
):
self
.
loop
.
_selector
.
get_key
(
sock
)
exc
=
fut
.
exception
()
self
.
assertIs
(
exc
,
err
)
self
.
assertEqual
(
1000
,
self
.
file
.
tell
())
def
test_exception
(
self
):
sock
,
proto
=
self
.
prepare
()
fileno
=
self
.
file
.
fileno
()
fut
=
self
.
loop
.
create_future
()
err
=
RuntimeError
()
with
mock
.
patch
(
'os.sendfile'
,
side_effect
=
err
):
self
.
loop
.
_sock_sendfile_native_impl
(
fut
,
sock
.
fileno
(),
sock
,
fileno
,
1000
,
None
,
len
(
self
.
DATA
),
1000
)
with
self
.
assertRaises
(
KeyError
):
self
.
loop
.
_selector
.
get_key
(
sock
)
exc
=
fut
.
exception
()
self
.
assertIs
(
exc
,
err
)
self
.
assertEqual
(
1000
,
self
.
file
.
tell
())
class
UnixReadPipeTransportTests
(
test_utils
.
TestCase
):
class
UnixReadPipeTransportTests
(
test_utils
.
TestCase
):
...
...
Misc/NEWS.d/next/Library/2017-12-22-16-05-01.bpo-32410.8JzhvH.rst
0 → 100644
Dosyayı görüntüle @
6b5a2797
Implement ``loop.sock_sendfile`` for asyncio event loop.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment