socket: Actually provide non-blocking DNS methods
The green socket module seemed to have only blocking DNS resolution methods even with dnspython installed which is inconsistent with the documentation. This patch has a few consequences: * an import cycle is eliminated * if an import cycle reappears here it'll be visible Note: eliminating the import cycle revealed an issue related to monkey patching and the way we perform greendns tests (the test failures were already present on Python 3.5[1] as that version has some import cycle handling changes). The failures look like this: ====================================================================== FAIL: test_query_ans_types (tests.greendns_test.TestHostsResolver) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/kuba/projects/eventlet/tests/greendns_test.py", line 97, in test_query_ans_types assert isinstance(ans, greendns.dns.resolver.Answer) AssertionError ====================================================================== FAIL: test_query_unknown_no_raise (tests.greendns_test.TestHostsResolver) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/kuba/projects/eventlet/tests/greendns_test.py", line 129, in test_query_unknown_no_raise assert isinstance(ans, greendns.dns.resolver.Answer) AssertionError This issue will be addressed in a separate commit. This patch is contributed by Smarkets Limited. [1] https://github.com/eventlet/eventlet/issues/267
This commit is contained in:
@@ -16,7 +16,16 @@ if os.environ.get("EVENTLET_NO_GREENDNS", '').lower() != "yes":
|
||||
try:
|
||||
from eventlet.support import greendns
|
||||
except ImportError as ex:
|
||||
pass
|
||||
try:
|
||||
import dns
|
||||
except ImportError:
|
||||
# greendns import failed because we don't have dnspython - all is well,
|
||||
# that's why we have the conditional import
|
||||
pass
|
||||
else:
|
||||
# If, however, dnspython is importable yet greendns can't be imported
|
||||
# this suggests there's another issue (like an import cycle)
|
||||
raise
|
||||
|
||||
if greendns:
|
||||
gethostbyname = greendns.gethostbyname
|
||||
|
@@ -43,6 +43,10 @@ from eventlet.support import six
|
||||
|
||||
|
||||
def import_patched(module_name):
|
||||
# Import cycle note: it's crucial to use _socket_nodns here because
|
||||
# regular evenlet.green.socket imports *this* module and if we imported
|
||||
# it back we'd end with an import cycle (socket -> greendns -> socket).
|
||||
# We break this import cycle by providing a restricted socket module.
|
||||
return patcher.import_patched(module_name,
|
||||
select=select,
|
||||
time=time,
|
||||
@@ -55,15 +59,15 @@ dns.resolver = import_patched('dns.resolver')
|
||||
|
||||
for pkg in ('dns.entropy', 'dns.inet', 'dns.query'):
|
||||
setattr(dns, pkg.split('.')[1], import_patched(pkg))
|
||||
del import_patched
|
||||
|
||||
import dns.rdtypes
|
||||
for pkg in ['dns.rdtypes.IN', 'dns.rdtypes.ANY']:
|
||||
setattr(dns.rdtypes, pkg.split('.')[-1], patcher.import_patched(pkg))
|
||||
setattr(dns.rdtypes, pkg.split('.')[-1], import_patched(pkg))
|
||||
for pkg in ['dns.rdtypes.IN.A', 'dns.rdtypes.IN.AAAA']:
|
||||
setattr(dns.rdtypes.IN, pkg.split('.')[-1], patcher.import_patched(pkg))
|
||||
setattr(dns.rdtypes.IN, pkg.split('.')[-1], import_patched(pkg))
|
||||
for pkg in ['dns.rdtypes.ANY.CNAME']:
|
||||
setattr(dns.rdtypes.ANY, pkg.split('.')[-1], patcher.import_patched(pkg))
|
||||
setattr(dns.rdtypes.ANY, pkg.split('.')[-1], import_patched(pkg))
|
||||
del import_patched
|
||||
|
||||
|
||||
socket = _socket_nodns
|
||||
|
@@ -1,5 +1,11 @@
|
||||
import eventlet
|
||||
from eventlet.green import socket
|
||||
try:
|
||||
from eventlet.support import greendns
|
||||
has_greendns = True
|
||||
except ImportError:
|
||||
has_greendns = False
|
||||
from tests import skip_if
|
||||
|
||||
|
||||
def test_create_connection_error():
|
||||
@@ -29,3 +35,11 @@ def test_recv_type():
|
||||
sock = eventlet.connect(tuple(addr))
|
||||
s = sock.recv(1)
|
||||
assert isinstance(s, bytes)
|
||||
|
||||
|
||||
@skip_if(not has_greendns)
|
||||
def test_dns_methods_are_green():
|
||||
assert socket.gethostbyname is greendns.gethostbyname
|
||||
assert socket.gethostbyname_ex is greendns.gethostbyname_ex
|
||||
assert socket.getaddrinfo is greendns.getaddrinfo
|
||||
assert socket.getnameinfo is greendns.getnameinfo
|
||||
|
Reference in New Issue
Block a user