Completed
Pull Request — master (#72)
by Björn
18:06 queued 16:50
created

AsyncioEventLoop   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Test Coverage

Coverage 61.33%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 107
ccs 46
cts 75
cp 0.6133
rs 8.8
c 2
b 0
f 0
wmc 36

20 Methods

Rating   Name   Duplication   Size   Complexity  
A _connect_socket() 0 6 2
A _init() 0 4 2
A process_exited() 0 3 1
A _stop() 0 2 1
A pipe_data_received() 0 8 3
A _connect_stdio() 0 5 1
A connection_lost() 0 3 2
A _start_reading() 0 2 1
A _connect_child() 0 3 1
A _send() 0 2 1
A _threadsafe_call() 0 2 1
A _connect_tcp() 0 3 1
A _run() 0 4 2
A connection_made() 0 5 2
A data_received() 0 6 2
A pipe_connection_lost() 0 3 2
A _setup_signals() 0 9 3
A _teardown_signals() 0 3 2
B _poll_fd() 0 11 6
A cancel() 0 5 3
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 6
from __future__ import absolute_import
12
13 6
import os
14 6
import sys
15 6
from collections import deque
16
17 6
try:
18
    # For python 3.4+, use the standard library module
19 6
    import asyncio
20 4
except (ImportError, SyntaxError):
21
    # Fallback to trollius
22 4
    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 6
from .base import BaseEventLoop
25
26
27 6
loop_cls = asyncio.SelectorEventLoop
28 6
if os.name == 'nt':
29
    # On windows use ProactorEventLoop which support pipes and is backed by the
30
    # more powerful IOCP facility
31
    loop_cls = asyncio.ProactorEventLoop
32
33
34 6
class AsyncioEventLoop(BaseEventLoop, asyncio.Protocol,
35
                       asyncio.SubprocessProtocol):
36
37
    """`BaseEventLoop` subclass that uses `asyncio` as a backend."""
38
39 6
    def connection_made(self, transport):
40
        """Used to signal `asyncio.Protocol` of a successful connection."""
41 6
        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...
42 6
        if isinstance(transport, asyncio.SubprocessTransport):
43 6
            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...
44
45 6
    def connection_lost(self, exc):
46
        """Used to signal `asyncio.Protocol` of a lost connection."""
47
        self._on_error(exc.args[0] if exc else 'EOF')
48
49 6
    def data_received(self, data):
50
        """Used to signal `asyncio.Protocol` of incoming data."""
51
        if self._on_data:
52
            self._on_data(data)
53
            return
54
        self._queued_data.append(data)
55
56 6
    def pipe_connection_lost(self, fd, exc):
57
        """Used to signal `asyncio.SubprocessProtocol` of a lost connection."""
58 5
        self._on_error(exc.args[0] if exc else 'EOF')
59
60 6
    def pipe_data_received(self, fd, data):
61
        """Used to signal `asyncio.SubprocessProtocol` of incoming data."""
62 6
        if fd == 2:  # stderr fd number
63 5
            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...
64 6
        elif self._on_data:
65 6
            self._on_data(data)
66
        else:
67
            self._queued_data.append(data)
68
69 6
    def process_exited(self):
70
        """Used to signal `asyncio.SubprocessProtocol` when the child exits."""
71
        self._on_error('EOF')
72
73 6
    def _init(self):
74 6
        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...
75 6
        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...
76 6
        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...
77
78 6
    def _connect_tcp(self, address, port):
79
        coroutine = self._loop.create_connection(self._fact, address, port)
80
        self._loop.run_until_complete(coroutine)
81
82 6
    def _connect_socket(self, path):
83
        if os.name == 'nt':
84
            coroutine = self._loop.create_pipe_connection(self._fact, path)
85
        else:
86
            coroutine = self._loop.create_unix_connection(self._fact, path)
87
        self._loop.run_until_complete(coroutine)
88
89 6
    def _connect_stdio(self):
90
        coroutine = self._loop.connect_read_pipe(self._fact, sys.stdin)
91
        self._loop.run_until_complete(coroutine)
92
        coroutine = self._loop.connect_write_pipe(self._fact, sys.stdout)
93 1
        self._loop.run_until_complete(coroutine)
94
95 6
    def _connect_child(self, argv):
96 6
        coroutine = self._loop.subprocess_exec(self._fact, *argv)
97 6
        self._loop.run_until_complete(coroutine)
98
99 6
    def _start_reading(self):
100 6
        pass
101
102 6
    def _send(self, data):
103 6
        self._transport.write(data)
104
105 6
    def _run(self):
106 6
        while self._queued_data:
107
            self._on_data(self._queued_data.popleft())
108 6
        self._loop.run_forever()
109
110 6
    def _stop(self):
111 6
        self._loop.stop()
112
113 6
    def _threadsafe_call(self, fn):
114 6
        self._loop.call_soon_threadsafe(fn)
115
116 6
    def _poll_fd(self, fd, on_readable, on_writable):
117
        if on_readable is not None:
118
            self._loop.add_reader(fd, on_readable)
119
        if on_writable is not None:
120
            self._loop.add_writer(fd, on_writable)
121
        def cancel():
122
            if on_readable is not None:
123
                self._loop.remove_reader(fd)
124
            if on_writable is not None:
125
                self._loop.remove_writer(fd)
126
        return cancel
127
128 6
    def _setup_signals(self, signals):
129 6
        if os.name == 'nt':
130
            # add_signal_handler is not supported in win32
131
            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...
132
            return
133
134 6
        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...
135 6
        for signum in self._signals:
136 6
            self._loop.add_signal_handler(signum, self._on_signal, signum)
137
138 6
    def _teardown_signals(self):
139 6
        for signum in self._signals:
140
            self._loop.remove_signal_handler(signum)
141