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
a74ba95c
Commit
a74ba95c
authored
Oct 31, 2022
by
Jason Madden
Committed by
GitHub
Oct 31, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1922 from gevent/issue-1909
Update to greenlet 2.0
parents
a0708588
ed7c1d8b
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
165 additions
and
77 deletions
+165
-77
.github/workflows/ci.yml
.github/workflows/ci.yml
+2
-2
appveyor.yml
appveyor.yml
+20
-4
deps/greenlet/greenlet.h
deps/greenlet/greenlet.h
+45
-42
docs/changes/1909.bugfix
docs/changes/1909.bugfix
+9
-0
pyproject.toml
pyproject.toml
+4
-2
scripts/releases/make-manylinux
scripts/releases/make-manylinux
+1
-1
setup.py
setup.py
+3
-1
src/gevent/_gevent_cgreenlet.pxd
src/gevent/_gevent_cgreenlet.pxd
+22
-5
src/gevent/subprocess.py
src/gevent/subprocess.py
+1
-0
src/gevent/tests/test__memleak.py
src/gevent/tests/test__memleak.py
+10
-0
src/gevent/tests/test__socket_dns.py
src/gevent/tests/test__socket_dns.py
+46
-18
src/gevent/tests/test__socket_dns6.py
src/gevent/tests/test__socket_dns6.py
+2
-2
No files found.
.github/workflows/ci.yml
View file @
a74ba95c
...
@@ -198,7 +198,7 @@ jobs:
...
@@ -198,7 +198,7 @@ jobs:
pip install -q -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
pip install -q -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
pip install -q -U 'cffi;platform_python_implementation=="CPython"'
pip install -q -U 'cffi;platform_python_implementation=="CPython"'
pip install -q -U 'cython>=3.0a9'
pip install -q -U 'cython>=3.0a9'
pip install 'greenlet>=
1.0a1,<2
;platform_python_implementation=="CPython"'
pip install 'greenlet>=
2.0rc4
;platform_python_implementation=="CPython"'
-
name
:
Build gevent
-
name
:
Build gevent
run
:
|
run
:
|
...
@@ -393,7 +393,7 @@ jobs:
...
@@ -393,7 +393,7 @@ jobs:
pip install -q -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
pip install -q -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
pip install -q -U 'cffi;platform_python_implementation=="CPython"'
pip install -q -U 'cffi;platform_python_implementation=="CPython"'
pip install -q -U 'cython>=3.0a5'
pip install -q -U 'cython>=3.0a5'
pip install 'greenlet>=
1.0a1,<2
;platform_python_implementation=="CPython"'
pip install 'greenlet>=
2.0rc4
;platform_python_implementation=="CPython"'
-
name
:
build libs and gevent
-
name
:
build libs and gevent
env
:
env
:
...
...
appveyor.yml
View file @
a74ba95c
...
@@ -46,6 +46,12 @@ environment:
...
@@ -46,6 +46,12 @@ environment:
# a later point release.
# a later point release.
# 64-bit
# 64-bit
-
PYTHON
:
"
C:
\\
Python311-x64"
PYTHON_VERSION
:
"
3.11.0"
PYTHON_ARCH
:
"
64"
PYTHON_EXE
:
python
APPVEYOR_BUILD_WORKER_IMAGE
:
Visual Studio
2019
-
PYTHON
:
"
C:
\\
pypy3.7-v7.3.7-win64"
-
PYTHON
:
"
C:
\\
pypy3.7-v7.3.7-win64"
PYTHON_ID
:
"
pypy3"
PYTHON_ID
:
"
pypy3"
PYTHON_EXE
:
pypy3w
PYTHON_EXE
:
pypy3w
...
@@ -81,10 +87,6 @@ environment:
...
@@ -81,10 +87,6 @@ environment:
PYTHON_EXE
:
python
PYTHON_EXE
:
python
APPVEYOR_BUILD_WORKER_IMAGE
:
Visual Studio
2019
APPVEYOR_BUILD_WORKER_IMAGE
:
Visual Studio
2019
-
PYTHON
:
"
C:
\\
Python27-x64"
PYTHON_VERSION
:
"
2.7.x"
# currently 2.7.13
PYTHON_ARCH
:
"
64"
PYTHON_EXE
:
python
-
PYTHON
:
"
C:
\\
Python38-x64"
-
PYTHON
:
"
C:
\\
Python38-x64"
PYTHON_VERSION
:
"
3.8.x"
PYTHON_VERSION
:
"
3.8.x"
...
@@ -138,6 +140,20 @@ environment:
...
@@ -138,6 +140,20 @@ environment:
PYTHON_EXE
:
python
PYTHON_EXE
:
python
GWHEEL_ONLY
:
true
GWHEEL_ONLY
:
true
-
PYTHON
:
"
C:
\\
Python27-x64"
PYTHON_VERSION
:
"
2.7.x"
# currently 2.7.13
PYTHON_ARCH
:
"
64"
PYTHON_EXE
:
python
# greenlet 2.0 is evincing a warning (probably?)
# on shutdown, leading to the dreaded error:
# Fatal Python error: PyImport_GetModuleDict: no module
# dictionary!
# in some tests. This is hard to debug remotely, and as support
# for 2.7 is winding down quickly (hey, we're only two years
# late to the party) I'm not specifically going to try to debug
# it. We'll just provide a binary wheel still.
GWHEEL_ONLY
:
true
# Also test a Python version not pre-installed
# Also test a Python version not pre-installed
# See: https://github.com/ogrisel/python-appveyor-demo/issues/10
# See: https://github.com/ogrisel/python-appveyor-demo/issues/10
...
...
deps/greenlet/greenlet.h
View file @
a74ba95c
...
@@ -5,6 +5,7 @@
...
@@ -5,6 +5,7 @@
#ifndef Py_GREENLETOBJECT_H
#ifndef Py_GREENLETOBJECT_H
#define Py_GREENLETOBJECT_H
#define Py_GREENLETOBJECT_H
#include <Python.h>
#include <Python.h>
#ifdef __cplusplus
#ifdef __cplusplus
...
@@ -14,60 +15,24 @@ extern "C" {
...
@@ -14,60 +15,24 @@ extern "C" {
/* This is deprecated and undocumented. It does not change. */
/* This is deprecated and undocumented. It does not change. */
#define GREENLET_VERSION "1.0.0"
#define GREENLET_VERSION "1.0.0"
#if PY_VERSION_HEX >= 0x30B00A6
#ifndef GREENLET_MODULE
# define GREENLET_PY311 1
#define implementation_ptr_t void*
/* _PyInterpreterFrame moved to the internal C API in Python 3.11 */
# include <internal/pycore_frame.h>
#else
# define GREENLET_PY311 0
# define _PyCFrame CFrame
#endif
#endif
typedef
struct
_greenlet
{
typedef
struct
_greenlet
{
PyObject_HEAD
PyObject_HEAD
char
*
stack_start
;
char
*
stack_stop
;
char
*
stack_copy
;
intptr_t
stack_saved
;
struct
_greenlet
*
stack_prev
;
struct
_greenlet
*
parent
;
PyObject
*
run_info
;
struct
_frame
*
top_frame
;
int
recursion_depth
;
#if GREENLET_PY311
_PyInterpreterFrame
*
current_frame
;
_PyStackChunk
*
datastack_chunk
;
PyObject
**
datastack_top
;
PyObject
**
datastack_limit
;
#endif
PyObject
*
weakreflist
;
PyObject
*
weakreflist
;
#if PY_VERSION_HEX >= 0x030700A3
_PyErr_StackItem
*
exc_info
;
_PyErr_StackItem
exc_state
;
#else
PyObject
*
exc_type
;
PyObject
*
exc_value
;
PyObject
*
exc_traceback
;
#endif
PyObject
*
dict
;
PyObject
*
dict
;
#if PY_VERSION_HEX >= 0x030700A3
implementation_ptr_t
pimpl
;
PyObject
*
context
;
#endif
#if PY_VERSION_HEX >= 0x30A00B1
_PyCFrame
*
cframe
;
#endif
}
PyGreenlet
;
}
PyGreenlet
;
#define PyGreenlet_Check(op) PyObject_TypeCheck(op, &PyGreenlet_Type)
#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type))
#define PyGreenlet_MAIN(op) (((PyGreenlet*)(op))->stack_stop == (char*)-1)
#define PyGreenlet_STARTED(op) (((PyGreenlet*)(op))->stack_stop != NULL)
#define PyGreenlet_ACTIVE(op) (((PyGreenlet*)(op))->stack_start != NULL)
#define PyGreenlet_GET_PARENT(op) (((PyGreenlet*)(op))->parent)
/* C API functions */
/* C API functions */
/* Total number of symbols that are exported */
/* Total number of symbols that are exported */
#define PyGreenlet_API_pointers
8
#define PyGreenlet_API_pointers
12
#define PyGreenlet_Type_NUM 0
#define PyGreenlet_Type_NUM 0
#define PyExc_GreenletError_NUM 1
#define PyExc_GreenletError_NUM 1
...
@@ -79,6 +44,11 @@ typedef struct _greenlet {
...
@@ -79,6 +44,11 @@ typedef struct _greenlet {
#define PyGreenlet_Switch_NUM 6
#define PyGreenlet_Switch_NUM 6
#define PyGreenlet_SetParent_NUM 7
#define PyGreenlet_SetParent_NUM 7
#define PyGreenlet_MAIN_NUM 8
#define PyGreenlet_STARTED_NUM 9
#define PyGreenlet_ACTIVE_NUM 10
#define PyGreenlet_GET_PARENT_NUM 11
#ifndef GREENLET_MODULE
#ifndef GREENLET_MODULE
/* This section is used by modules that uses the greenlet C API */
/* This section is used by modules that uses the greenlet C API */
static
void
**
_PyGreenlet_API
=
NULL
;
static
void
**
_PyGreenlet_API
=
NULL
;
...
@@ -144,6 +114,39 @@ static void** _PyGreenlet_API = NULL;
...
@@ -144,6 +114,39 @@ static void** _PyGreenlet_API = NULL;
(*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \
(*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \
_PyGreenlet_API[PyGreenlet_SetParent_NUM])
_PyGreenlet_API[PyGreenlet_SetParent_NUM])
/*
* PyGreenlet_GetParent(PyObject* greenlet)
*
* return greenlet.parent;
*
* This could return NULL even if there is no exception active.
* If it does not return NULL, you are responsible for decrementing the
* reference count.
*/
# define PyGreenlet_GetParent \
(*(PyGreenlet* (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_GET_PARENT_NUM])
/*
* deprecated, undocumented alias.
*/
# define PyGreenlet_GET_PARENT PyGreenlet_GetParent
# define PyGreenlet_MAIN \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_MAIN_NUM])
# define PyGreenlet_STARTED \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_STARTED_NUM])
# define PyGreenlet_ACTIVE \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_ACTIVE_NUM])
/* Macro that imports greenlet and initializes C API */
/* Macro that imports greenlet and initializes C API */
/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we
/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we
keep the older definition to be sure older code that might have a copy of
keep the older definition to be sure older code that might have a copy of
...
...
docs/changes/1909.bugfix
0 → 100644
View file @
a74ba95c
Update to greenlet 2.0. This fixes a deallocation issue that required
a change in greenlet's ABI. The design of greenlet 2.0 is intended to
prevent future fixes and enhancements from requiring an ABI change,
making it easier to update gevent and greenlet independently.
.. caution::
greenlet 2.0 requires a modern-ish C++ compiler. This may mean
certain older platforms are no longer supported.
pyproject.toml
View file @
a74ba95c
...
@@ -23,8 +23,10 @@ requires = [
...
@@ -23,8 +23,10 @@ requires = [
# Python 3.7 requires at least 0.4.14, which is ABI incompatible with earlier
# Python 3.7 requires at least 0.4.14, which is ABI incompatible with earlier
# releases. Python 3.9 and 3.10 require 0.4.16;
# releases. Python 3.9 and 3.10 require 0.4.16;
# 0.4.17 is ABI incompatible with earlier releases, but compatible with 1.0
# 0.4.17 is ABI incompatible with earlier releases, but compatible with 1.0
# 1.1.3 is needed for CPython 3.11
# 1.1.3 is needed for CPython 3.11.
"greenlet >= 1.1.3, < 2.0 ; platform_python_implementation == 'CPython'"
,
# 2.0 is not ABI compatible with earlier releases, but with luck it won't
# have to break the ABI again.
"greenlet >= 2.0.0rc4 ; platform_python_implementation == 'CPython'"
,
]
]
[tool.towncrier]
[tool.towncrier]
...
...
scripts/releases/make-manylinux
View file @
a74ba95c
...
@@ -125,7 +125,7 @@ if [ -d /gevent -a -d /opt/python ]; then
...
@@ -125,7 +125,7 @@ if [ -d /gevent -a -d /opt/python ]; then
# The downside is that we must install dependencies manually.
# The downside is that we must install dependencies manually.
# NOTE: We can't upgrade ``wheel`` because ``auditwheel`` depends on
# NOTE: We can't upgrade ``wheel`` because ``auditwheel`` depends on
# it, and auditwheel is installed in one of these environments.
# it, and auditwheel is installed in one of these environments.
python
-mpip
install
-U
"cython >= 3.0a6"
cffi
'greenlet >=
1.0
'
setuptools
python
-mpip
install
-U
"cython >= 3.0a6"
cffi
'greenlet >=
2.0rc4
'
setuptools
time
(
python setup.py bdist_wheel
)
time
(
python setup.py bdist_wheel
)
PATH
=
"
$OPATH
"
auditwheel repair dist/gevent
*
.whl
PATH
=
"
$OPATH
"
auditwheel repair dist/gevent
*
.whl
cp
wheelhouse/gevent
*
.whl /gevent/wheelhouse
cp
wheelhouse/gevent
*
.whl /gevent/wheelhouse
...
...
setup.py
View file @
a74ba95c
...
@@ -213,7 +213,9 @@ greenlet_requires = [
...
@@ -213,7 +213,9 @@ greenlet_requires = [
# so we can add an upper bound).
# so we can add an upper bound).
# 1.1.0 is required for 3.10; it has a new ABI, but only on 1.1.0.
# 1.1.0 is required for 3.10; it has a new ABI, but only on 1.1.0.
# 1.1.3 is needed for 3.11, and supports everything 1.1.0 did.
# 1.1.3 is needed for 3.11, and supports everything 1.1.0 did.
'greenlet >= 1.1.3, < 2.0; platform_python_implementation=="CPython"'
,
# 2.0.0 supports everything 1.1.3 did, but breaks the ABI in a way that hopefully
# won't break again.
'greenlet >= 2.0.0rc4 ; platform_python_implementation=="CPython"'
,
]
]
# Note that we don't add cffi to install_requires, it's
# Note that we don't add cffi to install_requires, it's
...
...
src/gevent/_gevent_cgreenlet.pxd
View file @
a74ba95c
# cython: auto_pickle=False
# cython: auto_pickle=False
cimport
cython
cimport
cython
from
cpython.ref
cimport
Py_DECREF
from
gevent._gevent_c_ident
cimport
IdentRegistry
from
gevent._gevent_c_ident
cimport
IdentRegistry
from
gevent._gevent_c_hub_local
cimport
get_hub_noargs
as
get_hub
from
gevent._gevent_c_hub_local
cimport
get_hub_noargs
as
get_hub
from
gevent._gevent_c_waiter
cimport
Waiter
from
gevent._gevent_c_waiter
cimport
Waiter
...
@@ -21,12 +23,14 @@ cdef extern from "greenlet/greenlet.h":
...
@@ -21,12 +23,14 @@ cdef extern from "greenlet/greenlet.h":
# properly handle the case that it can be NULL. So instead we inline a getparent
# properly handle the case that it can be NULL. So instead we inline a getparent
# function that does the same thing as the green_getparent accessor but without
# function that does the same thing as the green_getparent accessor but without
# going through the overhead of generic attribute lookup.
# going through the overhead of generic attribute lookup.
cdef
void
*
parent
#cdef void* parent
pass
# These are actually macros and so must be included
# These are actually macros and so must be included
# (defined) in each .pxd, as are the two functions
# (defined) in each .pxd, as are the two functions
# that call them.
# that call them.
greenlet
PyGreenlet_GetCurrent
()
greenlet
PyGreenlet_GetCurrent
()
void
*
PyGreenlet_GetParent
(
greenlet
)
void
PyGreenlet_Import
()
void
PyGreenlet_Import
()
@
cython
.
final
@
cython
.
final
...
@@ -36,13 +40,26 @@ cdef inline greenlet getcurrent():
...
@@ -36,13 +40,26 @@ cdef inline greenlet getcurrent():
cdef
inline
object
get_generic_parent
(
greenlet
s
):
cdef
inline
object
get_generic_parent
(
greenlet
s
):
# We don't use any typed functions on the return of this,
# We don't use any typed functions on the return of this,
# so save the type check by making it just an object.
# so save the type check by making it just an object.
if
s
.
parent
!=
NULL
:
cdef
object
result
return
<
object
>
s
.
parent
cdef
void
*
parent
=
PyGreenlet_GetParent
(
s
)
if
parent
!=
NULL
:
# The cast will perform an incref; but the GetParent
# function already did an incref if we got it (and not NULL).
# Therefore, we must DECREF immediately.
result
=
<
object
>
parent
Py_DECREF
(
result
)
return
result
cdef
inline
SwitchOutGreenletWithLoop
get_my_hub
(
greenlet
s
):
cdef
inline
SwitchOutGreenletWithLoop
get_my_hub
(
greenlet
s
):
# This one we do want type checked on the return value.
# Must not be called with s = None
# Must not be called with s = None
if
s
.
parent
!=
NULL
:
cdef
object
result
return
<
object
>
s
.
parent
cdef
void
*
parent
=
PyGreenlet_GetParent
(
s
)
if
parent
!=
NULL
:
result
=
<
object
>
parent
# See above
Py_DECREF
(
result
)
return
result
cdef
bint
_greenlet_imported
cdef
bint
_greenlet_imported
...
...
src/gevent/subprocess.py
View file @
a74ba95c
...
@@ -224,6 +224,7 @@ if PY311:
...
@@ -224,6 +224,7 @@ if PY311:
_fork_exec
=
None
_fork_exec
=
None
__implements__
.
extend
([
__implements__
.
extend
([
'_fork_exec'
,
'_fork_exec'
,
]
if
sys
.
platform
!=
'win32'
else
[
])
])
actually_imported
=
copy_globals
(
__subprocess__
,
globals
(),
actually_imported
=
copy_globals
(
__subprocess__
,
globals
(),
...
...
src/gevent/tests/test__memleak.py
View file @
a74ba95c
...
@@ -26,6 +26,16 @@ class TestQueue(TestCase): # pragma: no cover
...
@@ -26,6 +26,16 @@ class TestQueue(TestCase): # pragma: no cover
refcounts
.
append
(
sys
.
gettotalrefcount
())
refcounts
.
append
(
sys
.
gettotalrefcount
())
# Refcounts may go down, but not up
# Refcounts may go down, but not up
# XXX: JAM: I think this may just be broken. Each time we add
# a new integer to our list of refcounts, we'll be
# creating a new reference. This makes sense when we see the list
# go up by one each iteration:
#
# AssertionError: 530631 not less than or equal to 530630
# : total refcount mismatch:
# [530381, 530618, 530619, 530620, 530621,
# 530622, 530623, 530624, 530625, 530626,
# 530627, 530628, 530629, 530630, 530631]
final
=
refcounts
[
-
1
]
final
=
refcounts
[
-
1
]
previous
=
refcounts
[
-
2
]
previous
=
refcounts
[
-
2
]
self
.
assertLessEqual
(
self
.
assertLessEqual
(
...
...
src/gevent/tests/test__socket_dns.py
View file @
a74ba95c
...
@@ -34,6 +34,7 @@ from gevent.testing.sysinfo import RESOLVER_DNSPYTHON
...
@@ -34,6 +34,7 @@ from gevent.testing.sysinfo import RESOLVER_DNSPYTHON
from
gevent.testing.sysinfo
import
RESOLVER_ARES
from
gevent.testing.sysinfo
import
RESOLVER_ARES
from
gevent.testing.sysinfo
import
PY2
from
gevent.testing.sysinfo
import
PY2
from
gevent.testing.sysinfo
import
PYPY
from
gevent.testing.sysinfo
import
PYPY
import
gevent.testing.timing
import
gevent.testing.timing
...
@@ -45,7 +46,8 @@ RUN_ALL_HOST_TESTS = os.getenv('GEVENTTEST_RUN_ALL_ETC_HOST_TESTS', '')
...
@@ -45,7 +46,8 @@ RUN_ALL_HOST_TESTS = os.getenv('GEVENTTEST_RUN_ALL_ETC_HOST_TESTS', '')
def
add
(
klass
,
hostname
,
name
=
None
,
def
add
(
klass
,
hostname
,
name
=
None
,
skip
=
None
,
skip_reason
=
None
):
skip
=
None
,
skip_reason
=
None
,
require_equal_errors
=
True
):
call
=
callable
(
hostname
)
call
=
callable
(
hostname
)
...
@@ -64,33 +66,39 @@ def add(klass, hostname, name=None,
...
@@ -64,33 +66,39 @@ def add(klass, hostname, name=None,
def test_getaddrinfo_http(self):
def test_getaddrinfo_http(self):
x = hostname() if call else hostname
x = hostname() if call else hostname
self._test('
getaddrinfo
', x, '
http
')
self._test('
getaddrinfo
', x, '
http
',
require_equal_errors=require_equal_errors)
test_getaddrinfo_http.__name__ = '
test_
%
s_getaddrinfo_http
' % name
test_getaddrinfo_http.__name__ = '
test_
%
s_getaddrinfo_http
' % name
_setattr(klass, test_getaddrinfo_http.__name__, test_getaddrinfo_http)
_setattr(klass, test_getaddrinfo_http.__name__, test_getaddrinfo_http)
def test_gethostbyname(self):
def test_gethostbyname(self):
x = hostname() if call else hostname
x = hostname() if call else hostname
ipaddr = self._test('
gethostbyname
', x)
ipaddr = self._test('
gethostbyname
', x,
require_equal_errors=require_equal_errors)
if not isinstance(ipaddr, Exception):
if not isinstance(ipaddr, Exception):
self._test('
gethostbyaddr
', ipaddr)
self._test('
gethostbyaddr
', ipaddr,
require_equal_errors=require_equal_errors)
test_gethostbyname.__name__ = '
test_
%
s_gethostbyname
' % name
test_gethostbyname.__name__ = '
test_
%
s_gethostbyname
' % name
_setattr(klass, test_gethostbyname.__name__, test_gethostbyname)
_setattr(klass, test_gethostbyname.__name__, test_gethostbyname)
def test
3
(self):
def test
_gethostbyname_ex
(self):
x = hostname() if call else hostname
x = hostname() if call else hostname
self._test('
gethostbyname_ex
', x)
self._test('
gethostbyname_ex
', x,
test3.__name__ = '
test_
%
s_gethostbyname_ex
' % name
require_equal_errors=require_equal_errors)
_setattr(klass, test3.__name__, test3)
test_gethostbyname_ex.__name__ = '
test_
%
s_gethostbyname_ex
' % name
_setattr(klass, test_gethostbyname_ex.__name__, test_gethostbyname_ex)
def test4(self):
def test4(self):
x = hostname() if call else hostname
x = hostname() if call else hostname
self._test('
gethostbyaddr
', x)
self._test('
gethostbyaddr
', x,
require_equal_errors=require_equal_errors)
test4.__name__ = '
test_
%
s_gethostbyaddr
' % name
test4.__name__ = '
test_
%
s_gethostbyaddr
' % name
_setattr(klass, test4.__name__, test4)
_setattr(klass, test4.__name__, test4)
def test5(self):
def test5(self):
x = hostname() if call else hostname
x = hostname() if call else hostname
self._test('
getnameinfo
', (x, 80), 0)
self._test('
getnameinfo
', (x, 80), 0,
require_equal_errors=require_equal_errors)
test5.__name__ = '
test_
%
s_getnameinfo
' % name
test5.__name__ = '
test_
%
s_getnameinfo
' % name
_setattr(klass, test5.__name__, test5)
_setattr(klass, test5.__name__, test5)
...
@@ -187,17 +195,20 @@ class TestCase(greentest.TestCase):
...
@@ -187,17 +195,20 @@ class TestCase(greentest.TestCase):
return type(result1) is not type(result2)
return type(result1) is not type(result2)
return repr(result1) != repr(result2)
return repr(result1) != repr(result2)
def _test(self, func_name, *args):
def _test(self, func_name, *args
, **kwargs
):
"""
"""
Runs the function *func_name* with *args* and compares gevent and the system.
Runs the function *func_name* with *args* and compares gevent and the system.
Keyword arguments are passed to the function itself; variable args are
used for the socket function.
Returns the gevent result.
Returns the gevent result.
"""
"""
gevent_func = getattr(gevent_socket, func_name)
gevent_func = getattr(gevent_socket, func_name)
real_func = monkey.get_original('
socket
', func_name)
real_func = monkey.get_original('
socket
', func_name)
tester = getattr(self, '
_run_test_
' + func_name, self._run_test_generic)
tester = getattr(self, '
_run_test_
' + func_name, self._run_test_generic)
result = tester(func_name, real_func, gevent_func, args)
result = tester(func_name, real_func, gevent_func, args
, **kwargs
)
_real_result, time_real, gevent_result, time_gevent = result
_real_result, time_real, gevent_result, time_gevent = result
if self.verbose_dns and time_gevent > time_real + 0.02 and time_gevent > 0.03:
if self.verbose_dns and time_gevent > time_real + 0.02 and time_gevent > 0.03:
...
@@ -213,14 +224,17 @@ class TestCase(greentest.TestCase):
...
@@ -213,14 +224,17 @@ class TestCase(greentest.TestCase):
return gevent_result
return gevent_result
def _run_test_generic(self, func_name, real_func, gevent_func, func_args):
def _run_test_generic(self, func_name, real_func, gevent_func, func_args,
require_equal_errors=True):
real_result, time_real = self.run_resolver(real_func, func_args)
real_result, time_real = self.run_resolver(real_func, func_args)
gevent_result, time_gevent = self.run_resolver(gevent_func, func_args)
gevent_result, time_gevent = self.run_resolver(gevent_func, func_args)
if util.QUIET and self.should_log_results(real_result, gevent_result):
if util.QUIET and self.should_log_results(real_result, gevent_result):
util.log('')
util.log('')
self.__trace_call(real_result, time_real, real_func, func_args)
self.__trace_call(real_result, time_real, real_func, func_args)
self.__trace_call(gevent_result, time_gevent, gevent_func, func_args)
self.__trace_call(gevent_result, time_gevent, gevent_func, func_args)
self.assertEqualResults(real_result, gevent_result, func_name)
self.assertEqualResults(real_result, gevent_result, func_name,
require_equal_errors=require_equal_errors)
return real_result, time_real, gevent_result, time_gevent
return real_result, time_real, gevent_result, time_gevent
def _normalize_result(self, result, func_name):
def _normalize_result(self, result, func_name):
...
@@ -411,7 +425,8 @@ class TestCase(greentest.TestCase):
...
@@ -411,7 +425,8 @@ class TestCase(greentest.TestCase):
# As for getaddrinfo, we'll just check the ipaddrlist has something in common.
# As for getaddrinfo, we'll just check the ipaddrlist has something in common.
return
not
set
(
real_result
[
2
]).
isdisjoint
(
set
(
gevent_result
[
2
]))
return
not
set
(
real_result
[
2
]).
isdisjoint
(
set
(
gevent_result
[
2
]))
def
assertEqualResults
(
self
,
real_result
,
gevent_result
,
func_name
):
def
assertEqualResults
(
self
,
real_result
,
gevent_result
,
func_name
,
require_equal_errors
=
True
):
errors
=
(
errors
=
(
OverflowError
,
OverflowError
,
TypeError
,
TypeError
,
...
@@ -421,7 +436,8 @@ class TestCase(greentest.TestCase):
...
@@ -421,7 +436,8 @@ class TestCase(greentest.TestCase):
socket
.
herror
,
socket
.
herror
,
)
)
if
isinstance
(
real_result
,
errors
)
and
isinstance
(
gevent_result
,
errors
):
if
isinstance
(
real_result
,
errors
)
and
isinstance
(
gevent_result
,
errors
):
self
.
_compare_exceptions
(
real_result
,
gevent_result
,
func_name
)
if
require_equal_errors
:
self
.
_compare_exceptions
(
real_result
,
gevent_result
,
func_name
)
return
return
real_result
=
self
.
_normalize_result
(
real_result
,
func_name
)
real_result
=
self
.
_normalize_result
(
real_result
,
func_name
)
...
@@ -769,10 +785,22 @@ class TestInternational(TestCase):
...
@@ -769,10 +785,22 @@ class TestInternational(TestCase):
# the 2008 version of idna encoding, whereas on Python 2,
# the 2008 version of idna encoding, whereas on Python 2,
# with the default resolver, it tries to encode to ascii and
# with the default resolver, it tries to encode to ascii and
# raises a UnicodeEncodeError. So we get different results.
# raises a UnicodeEncodeError. So we get different results.
# Starting 20221027, on GitHub Actions and *some* versions of Python,
# we started getting a different error result from our own resolver
# compared to the system. This is very weird because our own resolver
# calls the system. I can't reproduce locally. Perhaps the two
# different answers are because of caching? One from the real DNS
# server, one from the local resolver library? Hence
# require_equal_errors=False
# ('system:', "herror(2, 'Host name lookup failure')",
# 'gevent:', "herror(1, 'Unknown host')")
add
(
TestInternational
,
u'президент.рф'
,
'russian'
,
add
(
TestInternational
,
u'президент.рф'
,
'russian'
,
skip
=
(
PY2
and
RESOLVER_DNSPYTHON
),
skip
=
(
PY2
and
RESOLVER_DNSPYTHON
),
skip_reason
=
"dnspython can actually resolve these"
)
skip_reason
=
"dnspython can actually resolve these"
,
add
(
TestInternational
,
u'президент.рф'
.
encode
(
'idna'
),
'idna'
)
require_equal_errors
=
False
)
add
(
TestInternational
,
u'президент.рф'
.
encode
(
'idna'
),
'idna'
,
require_equal_errors
=
False
)
@
skipWithoutExternalNetwork
(
"Tries to resolve and compare hostnames/addrinfo"
)
@
skipWithoutExternalNetwork
(
"Tries to resolve and compare hostnames/addrinfo"
)
class
TestInterrupted_gethostbyname
(
gevent
.
testing
.
timing
.
AbstractGenericWaitTestCase
):
class
TestInterrupted_gethostbyname
(
gevent
.
testing
.
timing
.
AbstractGenericWaitTestCase
):
...
...
src/gevent/tests/test__socket_dns6.py
View file @
a74ba95c
...
@@ -61,10 +61,10 @@ class Test6(TestCase):
...
@@ -61,10 +61,10 @@ class Test6(TestCase):
if
not
OSX
and
RESOLVER_DNSPYTHON
:
if
not
OSX
and
RESOLVER_DNSPYTHON
:
# It raises gaierror instead of socket.error,
# It raises gaierror instead of socket.error,
# which is not great and leads to failures.
# which is not great and leads to failures.
def
_run_test_getnameinfo
(
self
,
*
_args
):
def
_run_test_getnameinfo
(
self
,
*
_args
,
**
_kwargs
):
return
(),
0
,
(),
0
return
(),
0
,
(),
0
def
_run_test_gethostbyname
(
self
,
*
_args
):
def
_run_test_gethostbyname
(
self
,
*
_args
,
**
_kwargs
):
raise
unittest
.
SkipTest
(
"gethostbyname[_ex] does not support IPV6"
)
raise
unittest
.
SkipTest
(
"gethostbyname[_ex] does not support IPV6"
)
_run_test_gethostbyname_ex
=
_run_test_gethostbyname
_run_test_gethostbyname_ex
=
_run_test_gethostbyname
...
...
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