Completed
Push — master ( 64a5f3...843c4c )
by Björn
35s
created

UIBridge.apply_updates()   F

Complexity

Conditions 10

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 10
c 5
b 0
f 0
dl 0
loc 26
rs 3.1304

How to fix   Complexity   

Complexity

Complex classes like UIBridge.apply_updates() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""Bridge for connecting a UI instance to nvim."""
2
import sys
3
import os
4
from threading import Semaphore, Thread
5
from traceback import format_exc
6
from inspect import signature
7
8
9
class UIBridge(object):
10
11
    """UIBridge class. Connects a Nvim instance to a UI class."""
12
13
    def connect(self, nvim, ui, profile=None, notify=False):
14
        """Connect nvim and the ui.
15
16
        This will start loops for handling the UI and nvim events while
17
        also synchronizing both.
18
        """
19
        self._notify = notify
0 ignored issues
show
Coding Style introduced by
The attribute _notify 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...
20
        self._error = None
0 ignored issues
show
Coding Style introduced by
The attribute _error 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...
21
        self._nvim = nvim
0 ignored issues
show
Coding Style introduced by
The attribute _nvim 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...
22
        self._ui = ui
0 ignored issues
show
Coding Style introduced by
The attribute _ui 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...
23
        self._profile = profile
0 ignored issues
show
Coding Style introduced by
The attribute _profile 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...
24
        self._sem = Semaphore(0)
0 ignored issues
show
Coding Style introduced by
The attribute _sem 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...
25
        self.debug_events = len(os.environ.get("NVIM_PYTHON_UI_DEBUG", "")) > 0
0 ignored issues
show
Coding Style introduced by
The attribute debug_events 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...
26
        t = Thread(target=self._nvim_event_loop)
27
        t.daemon = True
28
        t.start()
29
        self._ui_event_loop()
30
        if self._error:
31
            print(self._error)
32
        if self._profile:
33
            print(self._profile)
34
35
    def exit(self):
36
        """Disconnect by exiting nvim."""
37
        self.detach()
38
        self._call(self._nvim.quit)
39
40
    def input(self, input_str):
41
        """Send input to nvim."""
42
        self._call(self._nvim.input, input_str)
43
44
    def resize(self, columns, rows):
45
        """Send a resize request to nvim."""
46
        self._call(self._nvim.ui_try_resize, columns, rows)
47
48
    def attach(self, columns, rows, **options):
49
        """Attach the UI to nvim."""
50
        self._call(self._nvim.api.ui_attach, columns, rows, options)
51
52
    def detach(self):
53
        """Detach the UI from nvim."""
54
        self._call(self._nvim.ui_detach)
55
56
    def _call(self, fn, *args):
57
        self._nvim.async_call(fn, *args)
58
59
    def _ui_event_loop(self):
60
        self._sem.acquire()
61
        if self._profile:
62
            import StringIO
0 ignored issues
show
Configuration introduced by
The import StringIO 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...
63
            import cProfile
64
            import pstats
65
            pr = cProfile.Profile()
66
            pr.enable()
67
        self._ui.start(self)
68
        if self._profile:
69
            pr.disable()
70
            s = StringIO.StringIO()
71
            ps = pstats.Stats(pr, stream=s)
72
            ps.strip_dirs().sort_stats(self._profile).print_stats(30)
73
            self._profile = s.getvalue()
0 ignored issues
show
Coding Style introduced by
The attribute _profile 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...
74
75
    def _nvim_event_loop(self):
76
        def on_setup():
77
            self._sem.release()
78
79
        def on_request(method, args):
0 ignored issues
show
Unused Code introduced by
The argument args seems to be unused.
Loading history...
Unused Code introduced by
The argument method seems to be unused.
Loading history...
80
            raise Exception('Not implemented')
81
82
        def on_notification(method, updates):
83
            def apply_updates():
84
                if self._notify:
85
                    sys.stdout.write('attached\n')
86
                    sys.stdout.flush()
87
                    self._notify = False
0 ignored issues
show
Coding Style introduced by
The attribute _notify 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...
88
                try:
89
                    for update in updates:
90
                        # import sys
91
                        # l = [','.join([str(a) for a in args])
92
                        #      for args in update[1:]]
93
                        # print >> sys.stderr, update[0], ' '.join(l)
94
                        try:
95
                            handler = getattr(self._ui, '_nvim_' + update[0])
96
                            nparam = len(signature(handler).parameters)
97
98
                        except AttributeError:
99
                            if self.debug_events:
100
                                print(repr(update), file=sys.stderr)
101
                        else:
102
                            if self.debug_events and len(update[1]) > nparam:
103
                                print(repr(update), file=sys.stderr)
104
                            for args in update[1:]:
105
                                handler(*args[:nparam])
106
                except Exception:
0 ignored issues
show
Best Practice introduced by
Catching very general exceptions such as Exception is usually not recommended.

Generally, you would want to handle very specific errors in the exception handler. This ensure that you do not hide other types of errors which should be fixed.

So, unless you specifically plan to handle any error, consider adding a more specific exception.

Loading history...
107
                    self._error = format_exc()
0 ignored issues
show
Coding Style introduced by
The attribute _error 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...
108
                    self._call(self._nvim.quit)
109
            if method == 'redraw':
110
                self._ui.schedule_screen_update(apply_updates)
111
112
        self._nvim.run_loop(on_request, on_notification, on_setup)
113
        self._ui.quit()
114