python / asyncio

asyncio historical repository
https://docs.python.org/3/library/asyncio.html
1.04k stars 177 forks source link

NameError in _fatal_error #363

Closed rwalkerands closed 8 years ago

rwalkerands commented 8 years ago

In asyncio/sslproto.py, method _fatal_error, the use of base_events._FATAL_ERROR_IGNORE (currently at https://github.com/python/asyncio/blob/master/asyncio/sslproto.py#L658) causes a NameError.

Need to add this to the top:

from . import base_events

In my case, I'm seeing this error because of an underlying problem in my code (which I've now fixed -- I had erroneously left open a socket, and this happens when the socket is later cleaned up), but this error made it just a little harder to diagnose the cause.

See https://groups.google.com/forum/?fromgroups#!searchin/python-tulip/nameerror/python-tulip/RbZ_qWuqSZI/NfsqNvA_CwAJ and https://groups.google.com/forum/#!searchin/linux.debian.bugs.dist/827453/linux.debian.bugs.dist/6aLdMUvvSqw/YSKbGZzyEQAJ for examples of someone else getting the same symptom.

gvanrossum commented 8 years ago

Yup. Care to send us a PR with a fix? It should have a test.

rwalkerands commented 8 years ago

The first example from the forum post by Jack Bates is enough to generate the NameError:

import asyncio
asyncio.get_event_loop().run_until_complete(
    asyncio.open_connection('google.com', 'https', ssl=True))

My difficulty in writing a test based on this is how to make assertions about the presence/absence of a particular exception that seems to be generated during the cleanup (gc?) at program exit. I've been unable to force the cleanup in such a way as to trigger the exception.

rwalkerands commented 8 years ago

I guess one could just call _fatal_error() directly:

import asyncio
import unittest

class TestTransport(unittest.TestCase):

    def test_fatal_error_NameError(self):
        reader, writer = asyncio.get_event_loop().run_until_complete(
            asyncio.open_connection('google.com', 'https', ssl=True))
        writer.transport._ssl_protocol._fatal_error(None)

if __name__ == '__main__':
    unittest.main()

Output before fixing:

E
======================================================================
ERROR: test_fatal_error_NameError (__main__.TestTransport)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "script4.py", line 9, in test_fatal_error_NameError
    writer.transport._ssl_protocol._fatal_error(None)
  File "/home/users/u9002369/py352rc1/lib/python3.5/asyncio/sslproto.py", line 658, in _fatal_error
    if isinstance(exc, base_events._FATAL_ERROR_IGNORE):
NameError: name 'base_events' is not defined

----------------------------------------------------------------------
Ran 1 test in 0.048s

FAILED (errors=1)

Output after inserting the import statement:

Fatal error on transport
protocol: <asyncio.sslproto.SSLProtocol object at 0x7ff54e1f59e8>
transport: <_SelectorSocketTransport fd=7 read=polling write=<idle, bufsize=0>>
.
----------------------------------------------------------------------
Ran 1 test in 0.071s

OK  
gvanrossum commented 8 years ago

Sounds good -- can you make a PR based on that?

rwalkerands commented 8 years ago

(Oops, wrote "PR #363" instead of "Issue #363" in the commit comment.)

rwalkerands commented 8 years ago

Couldn't get the code above (using asyncio.open_connection(), etc.) to work in the context of tests/test_sslproto.py, so I adapted one of the existing tests instead, which seems to have done the trick.

1st1 commented 8 years ago

Seems a patch for this has been merged already. Closing the issue.