Completed
Pull Request — master (#36)
by Björn
01:01
created

UIBridge.connect()   B

Complexity

Conditions 4

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 4
c 5
b 0
f 0
dl 0
loc 25
rs 8.5806
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
        debug_env = os.environ.get("NVIM_PYTHON_UI_DEBUG", "")
26
        if debug_env == "2":
27
            self.debug_events = 2
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...
28
        else:
29
            self.debug_events = len(debug_env) > 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...
30
        t = Thread(target=self._nvim_event_loop)
31
        t.daemon = True
32
        t.start()
33
        self._ui_event_loop()
34
        if self._error:
35
            print(self._error)
36
        if self._profile:
37
            print(self._profile)
38
39
    def exit(self):
40
        """Disconnect by exiting nvim."""
41
        self.detach()
42
        self._call(self._nvim.quit)
43
44
    def input(self, input_str):
45
        """Send input to nvim."""
46
        self._call(self._nvim.input, input_str)
47
48
    def resize(self, grid, columns, rows):
49
        """Send a resize request to nvim."""
50
        if 'ext_float' in self._nvim.metadata['ui_options']:
51
            self._call(self._nvim.api.ui_grid_try_resize, grid, columns, rows)
52
        else:
53
            self._call(self._nvim.api.ui_try_resize, columns, rows)
54
55
    def attach(self, columns, rows, **options):
56
        """Attach the UI to nvim."""
57
        self._call(self._nvim.api.ui_attach, columns, rows, options)
58
59
    def detach(self):
60
        """Detach the UI from nvim."""
61
        self._call(self._nvim.ui_detach)
62
63
    def _call(self, fn, *args):
64
        self._nvim.async_call(fn, *args)
65
66
    def _ui_event_loop(self):
67
        self._sem.acquire()
68
        if self._profile:
69
            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...
70
            import cProfile
71
            import pstats
72
            pr = cProfile.Profile()
73
            pr.enable()
74
        self._ui.start(self)
75
        if self._profile:
76
            pr.disable()
77
            s = StringIO.StringIO()
78
            ps = pstats.Stats(pr, stream=s)
79
            ps.strip_dirs().sort_stats(self._profile).print_stats(30)
80
            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...
81
82
    def _nvim_event_loop(self):
83
        def on_setup():
84
            self._sem.release()
85
86
        def on_request(method, args):
0 ignored issues
show
Unused Code introduced by
The argument method seems to be unused.
Loading history...
Unused Code introduced by
The argument args seems to be unused.
Loading history...
87
            raise Exception('Not implemented')
88
89
        def on_notification(method, updates):
90
            def apply_updates():
91
                if self._notify:
92
                    sys.stdout.write('attached\n')
93
                    sys.stdout.flush()
94
                    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...
95
                try:
96
                    for update in updates:
97
                        # import sys
98
                        # l = [','.join([str(a) for a in args])
99
                        #      for args in update[1:]]
100
                        # print >> sys.stderr, update[0], ' '.join(l)
101
                        try:
102
                            handler = getattr(self._ui, '_nvim_' + update[0])
103
                            nparam = len(signature(handler).parameters)
104
105
106
                        except AttributeError:
107
                            if self.debug_events:
108
                                print(self._ui._curgrid, end=' ', file=sys.stderr)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _curgrid was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
109
                                print(repr(update), file=sys.stderr)
110
                        else:
111
                            if self.debug_events == 2 or (self.debug_events and len(update[1]) > nparam):
112
                                print(repr(update), file=sys.stderr)
113
                            for args in update[1:]:
114
                                handler(*args[:nparam])
115
                    if self.debug_events == 2:
116
                        print("<flush>")
117
                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...
118
                    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...
119
                    self._call(self._nvim.quit)
120
            if method == 'redraw':
121
                self._ui.schedule_screen_update(apply_updates)
122
123
        self._nvim.run_loop(on_request, on_notification, on_setup)
124
        self._ui.quit()
125