Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gevent
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
gevent
Commits
0838e93d
Commit
0838e93d
authored
Jan 15, 2021
by
Jason Madden
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Handle .name on FileObject more like the stdlib.
Fixes #1745
parent
eacc8d33
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
145 additions
and
36 deletions
+145
-36
docs/changes/1745.bugfix
docs/changes/1745.bugfix
+10
-0
src/gevent/_ffi/loop.py
src/gevent/_ffi/loop.py
+2
-0
src/gevent/_fileobjectcommon.py
src/gevent/_fileobjectcommon.py
+28
-9
src/gevent/_fileobjectposix.py
src/gevent/_fileobjectposix.py
+6
-0
src/gevent/tests/test__fileobject.py
src/gevent/tests/test__fileobject.py
+99
-27
No files found.
docs/changes/1745.bugfix
0 → 100644
View file @
0838e93d
Make gevent ``FileObjects`` more closely match the semantics of native
file objects for the ``name`` attribute:
- Objects opened from a file descriptor integer have that integer as
their ``name.`` (Note that this is the Python 3 semantics; Python 2
native file objects returned from ``os.fdopen()`` have the string
"<fdopen>" as their name , but here gevent always follows Python 3.)
- The ``name`` remains accessible after the file object is closed.
Thanks to Dan Milon.
src/gevent/_ffi/loop.py
View file @
0838e93d
...
@@ -437,6 +437,8 @@ class AbstractLoop(object):
...
@@ -437,6 +437,8 @@ class AbstractLoop(object):
self
.
_init_callback_timer
()
self
.
_init_callback_timer
()
self
.
_threadsafe_async
=
self
.
async_
(
ref
=
False
)
self
.
_threadsafe_async
=
self
.
async_
(
ref
=
False
)
# No need to do anything with this on ``fork()``, both libev and libuv
# take care of creating a new pipe in their respective ``loop_fork()`` methods.
self
.
_threadsafe_async
.
start
(
lambda
:
None
)
self
.
_threadsafe_async
.
start
(
lambda
:
None
)
# TODO: We may be able to do something nicer and use the existing python_callback
# TODO: We may be able to do something nicer and use the existing python_callback
# combined with onerror and the class check/timer/prepare to simplify things
# combined with onerror and the class check/timer/prepare to simplify things
...
...
src/gevent/_fileobjectcommon.py
View file @
0838e93d
...
@@ -428,6 +428,30 @@ class OpenDescriptor(object): # pylint:disable=too-many-instance-attributes
...
@@ -428,6 +428,30 @@ class OpenDescriptor(object): # pylint:disable=too-many-instance-attributes
return
result
return
result
class
_ClosedIO
(
object
):
# Used for FileObjectBase._io when FOB.close()
# is called. Lets us drop references to ``_io``
# for GC/resource cleanup reasons, but keeps some useful
# information around.
__slots__
=
(
'name'
,)
def
__init__
(
self
,
io_obj
):
try
:
self
.
name
=
io_obj
.
name
except
AttributeError
:
pass
def
__getattr__
(
self
,
name
):
if
name
==
'name'
:
# We didn't set it in __init__ because there wasn't one
raise
AttributeError
raise
FileObjectClosed
def
__bool__
(
self
):
return
False
__nonzero__
=
__bool__
class
FileObjectBase
(
object
):
class
FileObjectBase
(
object
):
"""
"""
Internal base class to ensure a level of consistency
Internal base class to ensure a level of consistency
...
@@ -472,7 +496,6 @@ class FileObjectBase(object):
...
@@ -472,7 +496,6 @@ class FileObjectBase(object):
# We don't actually use this property ourself, but we save it (and
# We don't actually use this property ourself, but we save it (and
# pass it along) for compatibility.
# pass it along) for compatibility.
self
.
_close
=
descriptor
.
closefd
self
.
_close
=
descriptor
.
closefd
self
.
_do_delegate_methods
()
self
.
_do_delegate_methods
()
...
@@ -503,14 +526,14 @@ class FileObjectBase(object):
...
@@ -503,14 +526,14 @@ class FileObjectBase(object):
@
property
@
property
def
closed
(
self
):
def
closed
(
self
):
"""True if the file is closed"""
"""True if the file is closed"""
return
self
.
_io
is
None
return
isinstance
(
self
.
_io
,
_ClosedIO
)
def
close
(
self
):
def
close
(
self
):
if
self
.
_io
is
None
:
if
isinstance
(
self
.
_io
,
_ClosedIO
)
:
return
return
fobj
=
self
.
_io
fobj
=
self
.
_io
self
.
_io
=
None
self
.
_io
=
_ClosedIO
(
self
.
_io
)
try
:
try
:
self
.
_do_close
(
fobj
,
self
.
_close
)
self
.
_do_close
(
fobj
,
self
.
_close
)
finally
:
finally
:
...
@@ -525,8 +548,6 @@ class FileObjectBase(object):
...
@@ -525,8 +548,6 @@ class FileObjectBase(object):
raise
NotImplementedError
()
raise
NotImplementedError
()
def
__getattr__
(
self
,
name
):
def
__getattr__
(
self
,
name
):
if
self
.
_io
is
None
:
raise
FileObjectClosed
()
return
getattr
(
self
.
_io
,
name
)
return
getattr
(
self
.
_io
,
name
)
def
__repr__
(
self
):
def
__repr__
(
self
):
...
@@ -656,8 +677,6 @@ class FileObjectThread(FileObjectBase):
...
@@ -656,8 +677,6 @@ class FileObjectThread(FileObjectBase):
def
_do_delegate_methods
(
self
):
def
_do_delegate_methods
(
self
):
FileObjectBase
.
_do_delegate_methods
(
self
)
FileObjectBase
.
_do_delegate_methods
(
self
)
# if not hasattr(self, 'read1') and 'r' in getattr(self._io, 'mode', ''):
# self.read1 = self.read
self
.
__io_holder
[
0
]
=
self
.
_io
self
.
__io_holder
[
0
]
=
self
.
_io
def
_extra_repr
(
self
):
def
_extra_repr
(
self
):
...
@@ -676,7 +695,7 @@ class FileObjectThread(FileObjectBase):
...
@@ -676,7 +695,7 @@ class FileObjectThread(FileObjectBase):
# This is different than FileObjectPosix, etc,
# This is different than FileObjectPosix, etc,
# because we want to save the expensive trip through
# because we want to save the expensive trip through
# the threadpool.
# the threadpool.
raise
FileObjectClosed
()
raise
FileObjectClosed
with
lock
:
with
lock
:
return
threadpool
.
apply
(
method
,
args
,
kwargs
)
return
threadpool
.
apply
(
method
,
args
,
kwargs
)
...
...
src/gevent/_fileobjectposix.py
View file @
0838e93d
...
@@ -43,6 +43,7 @@ class GreenFileDescriptorIO(RawIOBase):
...
@@ -43,6 +43,7 @@ class GreenFileDescriptorIO(RawIOBase):
self
.
_closefd
=
closefd
self
.
_closefd
=
closefd
self
.
_fileno
=
fileno
self
.
_fileno
=
fileno
self
.
name
=
fileno
self
.
mode
=
open_descriptor
.
fileio_mode
self
.
mode
=
open_descriptor
.
fileio_mode
make_nonblocking
(
fileno
)
make_nonblocking
(
fileno
)
readable
=
open_descriptor
.
can_read
readable
=
open_descriptor
.
can_read
...
@@ -235,6 +236,11 @@ class GreenOpenDescriptor(OpenDescriptor):
...
@@ -235,6 +236,11 @@ class GreenOpenDescriptor(OpenDescriptor):
fileno
=
raw
.
fileno
()
fileno
=
raw
.
fileno
()
fileio
=
GreenFileDescriptorIO
(
fileno
,
self
,
closefd
=
closefd
)
fileio
=
GreenFileDescriptorIO
(
fileno
,
self
,
closefd
=
closefd
)
fileio
.
_keep_alive
=
raw
fileio
.
_keep_alive
=
raw
# We can usually do better for a name, though.
try
:
fileio
.
name
=
raw
.
name
except
AttributeError
:
del
fileio
.
name
return
fileio
return
fileio
def
_make_atomic_write
(
self
,
result
,
raw
):
def
_make_atomic_write
(
self
,
result
,
raw
):
...
...
src/gevent/tests/test__fileobject.py
View file @
0838e93d
from
__future__
import
print_function
,
absolute_import
from
__future__
import
print_function
from
__future__
import
absolute_import
import
functools
import
functools
import
gc
import
gc
...
@@ -51,7 +52,24 @@ def skipUnlessWorksWithRegularFiles(func):
...
@@ -51,7 +52,24 @@ def skipUnlessWorksWithRegularFiles(func):
func
(
self
)
func
(
self
)
return
f
return
f
class
TestFileObjectBlock
(
greentest
.
TestCase
):
# serves as a base for the concurrent tests too
class
CleanupMixin
(
object
):
def
_mkstemp
(
self
,
suffix
):
fileno
,
path
=
tempfile
.
mkstemp
(
suffix
)
self
.
addCleanup
(
os
.
remove
,
path
)
self
.
addCleanup
(
close_fd_quietly
,
fileno
)
return
fileno
,
path
def
_pipe
(
self
):
r
,
w
=
os
.
pipe
()
self
.
addCleanup
(
close_fd_quietly
,
r
)
self
.
addCleanup
(
close_fd_quietly
,
w
)
return
r
,
w
class
TestFileObjectBlock
(
CleanupMixin
,
greentest
.
TestCase
):
# serves as a base for the concurrent tests too
WORKS_WITH_REGULAR_FILES
=
True
WORKS_WITH_REGULAR_FILES
=
True
...
@@ -62,10 +80,7 @@ class TestFileObjectBlock(greentest.TestCase): # serves as a base for the concur
...
@@ -62,10 +80,7 @@ class TestFileObjectBlock(greentest.TestCase): # serves as a base for the concur
return
self
.
_getTargetClass
()(
*
args
,
**
kwargs
)
return
self
.
_getTargetClass
()(
*
args
,
**
kwargs
)
def
_test_del
(
self
,
**
kwargs
):
def
_test_del
(
self
,
**
kwargs
):
r
,
w
=
os
.
pipe
()
r
,
w
=
self
.
_pipe
()
self
.
addCleanup
(
close_fd_quietly
,
r
)
self
.
addCleanup
(
close_fd_quietly
,
w
)
self
.
_do_test_del
((
r
,
w
),
**
kwargs
)
self
.
_do_test_del
((
r
,
w
),
**
kwargs
)
def
_do_test_del
(
self
,
pipe
,
**
kwargs
):
def
_do_test_del
(
self
,
pipe
,
**
kwargs
):
...
@@ -104,10 +119,10 @@ class TestFileObjectBlock(greentest.TestCase): # serves as a base for the concur
...
@@ -104,10 +119,10 @@ class TestFileObjectBlock(greentest.TestCase): # serves as a base for the concur
def
test_del_close
(
self
):
def
test_del_close
(
self
):
self
.
_test_del
(
close
=
True
)
self
.
_test_del
(
close
=
True
)
@
skipUnlessWorksWithRegularFiles
@
skipUnlessWorksWithRegularFiles
def
test_seek
(
self
):
def
test_seek
(
self
):
fileno
,
path
=
tempfile
.
mkstemp
(
'.gevent.test__fileobject.test_seek'
)
fileno
,
path
=
self
.
_mkstemp
(
'.gevent.test__fileobject.test_seek'
)
self
.
addCleanup
(
os
.
remove
,
path
)
s
=
b'a'
*
1024
s
=
b'a'
*
1024
os
.
write
(
fileno
,
b'B'
*
15
)
os
.
write
(
fileno
,
b'B'
*
15
)
...
@@ -139,8 +154,7 @@ class TestFileObjectBlock(greentest.TestCase): # serves as a base for the concur
...
@@ -139,8 +154,7 @@ class TestFileObjectBlock(greentest.TestCase): # serves as a base for the concur
def
__check_native_matches
(
self
,
byte_data
,
open_mode
,
def
__check_native_matches
(
self
,
byte_data
,
open_mode
,
meth
=
'read'
,
open_path
=
True
,
meth
=
'read'
,
open_path
=
True
,
**
open_kwargs
):
**
open_kwargs
):
fileno
,
path
=
tempfile
.
mkstemp
(
'.gevent_test_'
+
open_mode
)
fileno
,
path
=
self
.
_mkstemp
(
'.gevent_test_'
+
open_mode
)
self
.
addCleanup
(
os
.
remove
,
path
)
os
.
write
(
fileno
,
byte_data
)
os
.
write
(
fileno
,
byte_data
)
os
.
close
(
fileno
)
os
.
close
(
fileno
)
...
@@ -232,6 +246,67 @@ class TestFileObjectBlock(greentest.TestCase): # serves as a base for the concur
...
@@ -232,6 +246,67 @@ class TestFileObjectBlock(greentest.TestCase): # serves as a base for the concur
x
.
close
()
x
.
close
()
y
.
close
()
y
.
close
()
@
skipUnlessWorksWithRegularFiles
@
greentest
.
ignores_leakcheck
def
test_name_after_close
(
self
):
fileno
,
path
=
self
.
_mkstemp
(
'.gevent_test_named_path_after_close'
)
# Passing the fileno; the name is the same as the fileno, and
# doesn't change when closed.
f
=
self
.
_makeOne
(
fileno
)
nf
=
os
.
fdopen
(
fileno
)
# On Python 2, os.fdopen() produces a name of <fdopen>;
# we follow the Python 3 semantics everywhere.
nf_name
=
'<fdopen>'
if
greentest
.
PY2
else
fileno
self
.
assertEqual
(
f
.
name
,
fileno
)
self
.
assertEqual
(
nf
.
name
,
nf_name
)
# A file-like object that has no name; we'll close the
# `f` after this because we reuse the fileno, which
# gets passed to fcntl and so must still be valid
class
Nameless
(
object
):
def
fileno
(
self
):
return
fileno
close
=
flush
=
isatty
=
closed
=
writable
=
lambda
self
:
False
seekable
=
readable
=
lambda
self
:
True
nameless
=
self
.
_makeOne
(
Nameless
(),
'rb'
)
with
self
.
assertRaises
(
AttributeError
):
getattr
(
nameless
,
'name'
)
nameless
.
close
()
with
self
.
assertRaises
(
AttributeError
):
getattr
(
nameless
,
'name'
)
f
.
close
()
try
:
nf
.
close
()
except
(
OSError
,
IOError
):
# OSError: Py3, IOError: Py2
pass
self
.
assertEqual
(
f
.
name
,
fileno
)
self
.
assertEqual
(
nf
.
name
,
nf_name
)
def
check
(
arg
):
f
=
self
.
_makeOne
(
arg
)
self
.
assertEqual
(
f
.
name
,
path
)
f
.
close
()
# Doesn't change after closed.
self
.
assertEqual
(
f
.
name
,
path
)
# Passing the string
check
(
path
)
# Passing an opened native object
with
open
(
path
)
as
nf
:
check
(
nf
)
# An io object
with
io
.
open
(
path
)
as
nf
:
check
(
nf
)
class
ConcurrentFileObjectMixin
(
object
):
class
ConcurrentFileObjectMixin
(
object
):
# Additional tests for fileobjects that cooperate
# Additional tests for fileobjects that cooperate
...
@@ -239,7 +314,7 @@ class ConcurrentFileObjectMixin(object):
...
@@ -239,7 +314,7 @@ class ConcurrentFileObjectMixin(object):
def
test_read1_binary_present
(
self
):
def
test_read1_binary_present
(
self
):
# Issue #840
# Issue #840
r
,
w
=
os
.
pipe
()
r
,
w
=
self
.
_
pipe
()
reader
=
self
.
_makeOne
(
r
,
'rb'
)
reader
=
self
.
_makeOne
(
r
,
'rb'
)
self
.
_close_on_teardown
(
reader
)
self
.
_close_on_teardown
(
reader
)
writer
=
self
.
_makeOne
(
w
,
'w'
)
writer
=
self
.
_makeOne
(
w
,
'w'
)
...
@@ -248,7 +323,7 @@ class ConcurrentFileObjectMixin(object):
...
@@ -248,7 +323,7 @@ class ConcurrentFileObjectMixin(object):
def
test_read1_text_not_present
(
self
):
def
test_read1_text_not_present
(
self
):
# Only defined for binary.
# Only defined for binary.
r
,
w
=
os
.
pipe
()
r
,
w
=
self
.
_
pipe
()
reader
=
self
.
_makeOne
(
r
,
'rt'
)
reader
=
self
.
_makeOne
(
r
,
'rt'
)
self
.
_close_on_teardown
(
reader
)
self
.
_close_on_teardown
(
reader
)
self
.
addCleanup
(
os
.
close
,
w
)
self
.
addCleanup
(
os
.
close
,
w
)
...
@@ -257,7 +332,7 @@ class ConcurrentFileObjectMixin(object):
...
@@ -257,7 +332,7 @@ class ConcurrentFileObjectMixin(object):
def
test_read1_default
(
self
):
def
test_read1_default
(
self
):
# If just 'r' is given, whether it has one or not
# If just 'r' is given, whether it has one or not
# depends on if we're Python 2 or 3.
# depends on if we're Python 2 or 3.
r
,
w
=
os
.
pipe
()
r
,
w
=
self
.
_
pipe
()
self
.
addCleanup
(
os
.
close
,
w
)
self
.
addCleanup
(
os
.
close
,
w
)
reader
=
self
.
_makeOne
(
r
)
reader
=
self
.
_makeOne
(
r
)
self
.
_close_on_teardown
(
reader
)
self
.
_close_on_teardown
(
reader
)
...
@@ -265,7 +340,7 @@ class ConcurrentFileObjectMixin(object):
...
@@ -265,7 +340,7 @@ class ConcurrentFileObjectMixin(object):
def
test_bufsize_0
(
self
):
def
test_bufsize_0
(
self
):
# Issue #840
# Issue #840
r
,
w
=
os
.
pipe
()
r
,
w
=
self
.
_
pipe
()
x
=
self
.
_makeOne
(
r
,
'rb'
,
bufsize
=
0
)
x
=
self
.
_makeOne
(
r
,
'rb'
,
bufsize
=
0
)
y
=
self
.
_makeOne
(
w
,
'wb'
,
bufsize
=
0
)
y
=
self
.
_makeOne
(
w
,
'wb'
,
bufsize
=
0
)
self
.
_close_on_teardown
(
x
)
self
.
_close_on_teardown
(
x
)
...
@@ -280,7 +355,7 @@ class ConcurrentFileObjectMixin(object):
...
@@ -280,7 +355,7 @@ class ConcurrentFileObjectMixin(object):
def
test_newlines
(
self
):
def
test_newlines
(
self
):
import
warnings
import
warnings
r
,
w
=
os
.
pipe
()
r
,
w
=
self
.
_
pipe
()
lines
=
[
b'line1
\
n
'
,
b'line2
\
r
'
,
b'line3
\
r
\
n
'
,
b'line4
\
r
\
n
line5'
,
b'
\
n
line6'
]
lines
=
[
b'line1
\
n
'
,
b'line2
\
r
'
,
b'line3
\
r
\
n
'
,
b'line4
\
r
\
n
line5'
,
b'
\
n
line6'
]
g
=
gevent
.
spawn
(
Writer
,
self
.
_makeOne
(
w
,
'wb'
),
lines
)
g
=
gevent
.
spawn
(
Writer
,
self
.
_makeOne
(
w
,
'wb'
),
lines
)
...
@@ -296,7 +371,7 @@ class ConcurrentFileObjectMixin(object):
...
@@ -296,7 +371,7 @@ class ConcurrentFileObjectMixin(object):
g
.
kill
()
g
.
kill
()
class
TestFileObjectThread
(
ConcurrentFileObjectMixin
,
class
TestFileObjectThread
(
ConcurrentFileObjectMixin
,
# pylint:disable=too-many-ancestors
TestFileObjectBlock
):
TestFileObjectBlock
):
def
_getTargetClass
(
self
):
def
_getTargetClass
(
self
):
...
@@ -329,7 +404,7 @@ class TestFileObjectThread(ConcurrentFileObjectMixin,
...
@@ -329,7 +404,7 @@ class TestFileObjectThread(ConcurrentFileObjectMixin,
hasattr
(
fileobject
,
'FileObjectPosix'
),
hasattr
(
fileobject
,
'FileObjectPosix'
),
"Needs FileObjectPosix"
"Needs FileObjectPosix"
)
)
class
TestFileObjectPosix
(
ConcurrentFileObjectMixin
,
class
TestFileObjectPosix
(
ConcurrentFileObjectMixin
,
# pylint:disable=too-many-ancestors
TestFileObjectBlock
):
TestFileObjectBlock
):
if
sysinfo
.
LIBUV
and
sysinfo
.
LINUX
:
if
sysinfo
.
LIBUV
and
sysinfo
.
LINUX
:
...
@@ -345,10 +420,7 @@ class TestFileObjectPosix(ConcurrentFileObjectMixin,
...
@@ -345,10 +420,7 @@ class TestFileObjectPosix(ConcurrentFileObjectMixin,
# https://github.com/gevent/gevent/issues/1323
# https://github.com/gevent/gevent/issues/1323
# Get a non-seekable file descriptor
# Get a non-seekable file descriptor
r
,
w
=
os
.
pipe
()
r
,
_w
=
self
.
_pipe
()
self
.
addCleanup
(
close_fd_quietly
,
r
)
self
.
addCleanup
(
close_fd_quietly
,
w
)
with
self
.
assertRaises
(
OSError
)
as
ctx
:
with
self
.
assertRaises
(
OSError
)
as
ctx
:
os
.
lseek
(
r
,
0
,
os
.
SEEK_SET
)
os
.
lseek
(
r
,
0
,
os
.
SEEK_SET
)
...
@@ -367,7 +439,7 @@ class TestFileObjectPosix(ConcurrentFileObjectMixin,
...
@@ -367,7 +439,7 @@ class TestFileObjectPosix(ConcurrentFileObjectMixin,
self
.
assertEqual
(
io_ex
.
args
,
os_ex
.
args
)
self
.
assertEqual
(
io_ex
.
args
,
os_ex
.
args
)
self
.
assertEqual
(
str
(
io_ex
),
str
(
os_ex
))
self
.
assertEqual
(
str
(
io_ex
),
str
(
os_ex
))
class
TestTextMode
(
unittest
.
TestCase
):
class
TestTextMode
(
CleanupMixin
,
unittest
.
TestCase
):
def
test_default_mode_writes_linesep
(
self
):
def
test_default_mode_writes_linesep
(
self
):
# See https://github.com/gevent/gevent/issues/1282
# See https://github.com/gevent/gevent/issues/1282
...
@@ -376,9 +448,7 @@ class TestTextMode(unittest.TestCase):
...
@@ -376,9 +448,7 @@ class TestTextMode(unittest.TestCase):
# First, make sure we initialize gevent
# First, make sure we initialize gevent
gevent
.
get_hub
()
gevent
.
get_hub
()
fileno
,
path
=
tempfile
.
mkstemp
(
'.gevent.test__fileobject.test_default'
)
fileno
,
path
=
self
.
_mkstemp
(
'.gevent.test__fileobject.test_default'
)
self
.
addCleanup
(
os
.
remove
,
path
)
os
.
close
(
fileno
)
os
.
close
(
fileno
)
with
open
(
path
,
"w"
)
as
f
:
with
open
(
path
,
"w"
)
as
f
:
...
@@ -389,7 +459,7 @@ class TestTextMode(unittest.TestCase):
...
@@ -389,7 +459,7 @@ class TestTextMode(unittest.TestCase):
self
.
assertEqual
(
data
,
os
.
linesep
.
encode
(
'ascii'
))
self
.
assertEqual
(
data
,
os
.
linesep
.
encode
(
'ascii'
))
class
TestOpenDescriptor
(
greentest
.
TestCase
):
class
TestOpenDescriptor
(
CleanupMixin
,
greentest
.
TestCase
):
def
_getTargetClass
(
self
):
def
_getTargetClass
(
self
):
return
OpenDescriptor
return
OpenDescriptor
...
@@ -421,7 +491,8 @@ class TestOpenDescriptor(greentest.TestCase):
...
@@ -421,7 +491,8 @@ class TestOpenDescriptor(greentest.TestCase):
def
test_atomicwrite_fd
(
self
):
def
test_atomicwrite_fd
(
self
):
from
gevent._fileobjectcommon
import
WriteallMixin
from
gevent._fileobjectcommon
import
WriteallMixin
# It basically only does something when buffering is otherwise disabled
# It basically only does something when buffering is otherwise disabled
desc
=
self
.
_makeOne
(
1
,
'wb'
,
fileno
,
_path
=
self
.
_mkstemp
(
'.gevent_test_atomicwrite_fd'
)
desc
=
self
.
_makeOne
(
fileno
,
'wb'
,
buffering
=
0
,
buffering
=
0
,
closefd
=
False
,
closefd
=
False
,
atomic_write
=
True
)
atomic_write
=
True
)
...
@@ -429,6 +500,7 @@ class TestOpenDescriptor(greentest.TestCase):
...
@@ -429,6 +500,7 @@ class TestOpenDescriptor(greentest.TestCase):
fobj
=
desc
.
opened
()
fobj
=
desc
.
opened
()
self
.
assertIsInstance
(
fobj
,
WriteallMixin
)
self
.
assertIsInstance
(
fobj
,
WriteallMixin
)
os
.
close
(
fileno
)
def
pop
():
def
pop
():
for
regex
,
kind
,
kwargs
in
TestOpenDescriptor
.
CASES
:
for
regex
,
kind
,
kwargs
in
TestOpenDescriptor
.
CASES
:
...
...
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