Completed
Pull Request — master (#307)
by Björn
34:32 queued 09:33
created

AsyncioEventLoop.process_exited()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
"""Event loop implementation that uses the `asyncio` standard module.
2
3
The `asyncio` module was added to python standard library on 3.4, and it
4
provides a pure python implementation of an event loop library. It is used
5
as a fallback in case pyuv is not available(on python implementations other
6
than CPython).
7
8
Earlier python versions are supported through the `trollius` package, which
9
is a backport of `asyncio` that works on Python 2.6+.
10
"""
11 5
from __future__ import absolute_import
12
13 5
import os
14 5
import sys
15 5
from collections import deque
16
17 5
try:
18
    # For python 3.4+, use the standard library module
19 5
    import asyncio
20 3
except (ImportError, SyntaxError):
21
    # Fallback to trollius
22 3
    import trollius as asyncio
0 ignored issues
show
Configuration introduced by
The import trollius could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
23
24 5
from .base import BaseEventLoop
25
26
27 5
loop_cls = asyncio.SelectorEventLoop
28 5
if os.name == 'nt':
29
    # On windows use ProactorEventLoop which support pipes and is backed by the
30
    # more powerful IOCP facility
31
    # NOTE: we override in the stdio case, because it doesn't work.
32
    loop_cls = asyncio.ProactorEventLoop
33
34 5
    import msvcrt
0 ignored issues
show
Configuration introduced by
The import msvcrt could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
35
    from ctypes import windll, byref, wintypes, GetLastError, WinError, POINTER
0 ignored issues
show
Unused Code introduced by
Unused GetLastError imported from ctypes
Loading history...
36
    from ctypes.wintypes import HANDLE, DWORD, BOOL
37
38
    LPDWORD = POINTER(DWORD)
39 5
40
    PIPE_NOWAIT = wintypes.DWORD(0x00000001)
41 5
42 5
    ERROR_NO_DATA = 232
43 5
44
    def pipe_no_wait(pipefd):
45 5
        SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
46
        SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
47
        SetNamedPipeHandleState.restype = BOOL
48
49 5
        h = msvcrt.get_osfhandle(pipefd)
50
51
        res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
52
        if res == 0:
53
            print(WinError())
54
            return False
55
        return True
56 5
57
class AsyncioEventLoop(BaseEventLoop, asyncio.Protocol,
58 4
                       asyncio.SubprocessProtocol):
59
60 5
    """`BaseEventLoop` subclass that uses `asyncio` as a backend."""
61
62 5
    def connection_made(self, transport):
63 4
        """Used to signal `asyncio.Protocol` of a successful connection."""
64 5
        self._transport = transport
0 ignored issues
show
Coding Style introduced by
The attribute _transport was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
65 5
        self._raw_transport = transport
0 ignored issues
show
Coding Style introduced by
The attribute _raw_transport was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
66
        if isinstance(transport, asyncio.SubprocessTransport):
67
            self._transport = transport.get_pipe_transport(0)
0 ignored issues
show
Coding Style introduced by
The attribute _transport was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
68
69 5
    def connection_lost(self, exc):
70
        """Used to signal `asyncio.Protocol` of a lost connection."""
71
        self._on_error(exc.args[0] if exc else 'EOF')
72
73 5
    def data_received(self, data):
74 5
        """Used to signal `asyncio.Protocol` of incoming data."""
75 5
        if self._on_data:
76 5
            self._on_data(data)
77
            return
78 5
        self._queued_data.append(data)
79
80
    def pipe_connection_lost(self, fd, exc):
81
        """Used to signal `asyncio.SubprocessProtocol` of a lost connection."""
82 5
        self._on_error(exc.args[0] if exc else 'EOF')
83
84
    def pipe_data_received(self, fd, data):
85
        """Used to signal `asyncio.SubprocessProtocol` of incoming data."""
86
        if fd == 2:  # stderr fd number
87
            self._on_stderr(data)
0 ignored issues
show
Bug introduced by
The Instance of AsyncioEventLoop does not seem to have a member named _on_stderr.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
88
        elif self._on_data:
89 5
            self._on_data(data)
90
        else:
91
            self._queued_data.append(data)
92
93 1
    def process_exited(self):
94
        """Used to signal `asyncio.SubprocessProtocol` when the child exits."""
95 5
        self._on_error('EOF')
96 5
97 5
    def _init(self):
98
        self._queued_data = deque()
0 ignored issues
show
Coding Style introduced by
The attribute _queued_data was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
99 5
        self._fact = lambda: self
0 ignored issues
show
Coding Style introduced by
The attribute _fact was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
100 5
        self._raw_transport = None
0 ignored issues
show
Coding Style introduced by
The attribute _raw_transport was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
101
        self._raw_stdio = False
0 ignored issues
show
Coding Style introduced by
The attribute _raw_stdio was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
102 5
103 5
    def _connect_tcp(self, address, port):
104
        self._loop = loop_cls()
0 ignored issues
show
Coding Style introduced by
The attribute _loop was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
105 5
        coroutine = self._loop.create_connection(self._fact, address, port)
106 5
        self._loop.run_until_complete(coroutine)
107
108 5
    def _connect_socket(self, path):
109
        self._loop = loop_cls()
0 ignored issues
show
Coding Style introduced by
The attribute _loop was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
110 5
        if os.name == 'nt':
111 5
            coroutine = self._loop.create_pipe_connection(self._fact, path)
112
        else:
113 5
            coroutine = self._loop.create_unix_connection(self._fact, path)
114 5
        self._loop.run_until_complete(coroutine)
115
116 5
    def _on_stdin(self):
117 5
        while True:
118
            data = sys.stdin.buffer.read(1)
119
            if len(data) == 0:
120
                break
121
            self.data_received(data)
122 5
123 5
    def _stdin_reader(self):
124 5
        sys.stderr.write("a {}\n".format(os.getpid()))
125
        while True: #self._active
126 5
            data = sys.stdin.buffer.read(1)
127 5
            sys.stderr.write("b {}\n".format(len(data)))
128 5
            self._loop.call_soon_threadsafe(self.data_received, data)
129
130
    def _connect_stdio(self):
131
        self._loop = loop_cls()
0 ignored issues
show
Coding Style introduced by
The attribute _loop was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
132
        if True or os.name == "nt":
133
            if os.name == "nt":
134
                pipe_no_wait(sys.stdin.fileno())
135
            else:
136
                import fcntl
0 ignored issues
show
Unused Code introduced by
The variable fcntl seems to be unused.
Loading history...
137
                #orig_fl = fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL)
138
                #fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, orig_fl | os.O_NONBLOCK)
139
            # work around broken windows implementation
140
            #self._loop = asyncio.SelectorEventLoop()
141
            self._raw_stdio = True
0 ignored issues
show
Coding Style introduced by
The attribute _raw_stdio was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
142
            #coro = self._loop.run_in_executor(None, self._stdin_reader)
143
            #self._loop.create_task(coro)
144
            sys.stderr.write("x\n")
145
            import threading
146
            threading.Thread(target=self._stdin_reader).start()
147
        else:
148
            #self._loop = loop_cls()
149
            coroutine = self._loop.connect_read_pipe(self._fact, sys.stdin)
150
            self._loop.run_until_complete(coroutine)
151
            coroutine = self._loop.connect_write_pipe(self._fact, sys.stdout)
152
            self._loop.run_until_complete(coroutine)
153
154
    def _connect_child(self, argv):
155
        self._loop = loop_cls()
0 ignored issues
show
Coding Style introduced by
The attribute _loop was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
156
        self._child_watcher = asyncio.get_child_watcher()
0 ignored issues
show
Coding Style introduced by
The attribute _child_watcher was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
157
        self._child_watcher.attach_loop(self._loop)
158
        coroutine = self._loop.subprocess_exec(self._fact, *argv)
159
        self._loop.run_until_complete(coroutine)
160
161
    def _start_reading(self):
162
        pass
163
164
    def _send(self, data):
165
        if self._raw_stdio:
166
            sys.stdout.buffer.write(data)
0 ignored issues
show
Bug introduced by
The Instance of RedirectStream does not seem to have a member named buffer.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
167
        else:
168
            self._transport.write(data)
169
170
    def _run(self):
171
        while self._queued_data:
172
            self._on_data(self._queued_data.popleft())
173
        self._loop.run_forever()
174
175
    def _stop(self):
176
        self._loop.stop()
177
178
    def _close(self):
179
        if self._raw_transport is not None:
180
            self._raw_transport.close()
181
        self._loop.close()
182
183
    def _threadsafe_call(self, fn):
184
        self._loop.call_soon_threadsafe(fn)
185
186
    def _setup_signals(self, signals):
187
        if os.name == 'nt':
188
            # add_signal_handler is not supported in win32
189
            self._signals = []
0 ignored issues
show
Coding Style introduced by
The attribute _signals was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
190
            return
191
192
        self._signals = list(signals)
0 ignored issues
show
Coding Style introduced by
The attribute _signals was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
193
        for signum in self._signals:
194
            self._loop.add_signal_handler(signum, self._on_signal, signum)
195
196
    def _teardown_signals(self):
197
        for signum in self._signals:
198
            self._loop.remove_signal_handler(signum)
199