Completed
Push — master ( b9eff5...377774 )
by Björn
11s
created

Remote.__repr__()   A

Complexity

Conditions 1

Size

Total Lines 5

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 5
ccs 2
cts 2
cp 1
crap 1
rs 9.4285
1
"""Code shared between the API classes."""
2 5
import functools
3
4 5
from msgpack import unpackb
0 ignored issues
show
Configuration introduced by
The import msgpack 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...
5
6
from ..compat import unicode_errors_default
7 5
8
9
class Remote(object):
10
11
    """Base class for Nvim objects(buffer/window/tabpage).
12
13
    Each type of object has it's own specialized class with API wrappers around
14
    the msgpack-rpc session. This implements equality which takes the remote
15
    object handle into consideration.
16 5
    """
17
18
    def __init__(self, session, code_data):
19
        """Initialize from session and code_data immutable object.
20
21
        The `code_data` contains serialization information required for
22 5
        msgpack-rpc calls. It must be immutable for Buffer equality to work.
23 5
        """
24 5
        self._session = session
25 5
        self.code_data = code_data
26
        self.handle = unpackb(code_data[1])
27 5
        self.api = RemoteApi(self, self._api_prefix)
0 ignored issues
show
Bug introduced by
The Instance of Remote does not seem to have a member named _api_prefix.

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...
28
        self.vars = RemoteMap(self, self._api_prefix + 'get_var',
0 ignored issues
show
Bug introduced by
The Instance of Remote does not seem to have a member named _api_prefix.

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...
29
                              self._api_prefix + 'set_var')
0 ignored issues
show
Bug introduced by
The Instance of Remote does not seem to have a member named _api_prefix.

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...
30 5
        self.options = RemoteMap(self, self._api_prefix + 'get_option',
0 ignored issues
show
Bug introduced by
The Instance of Remote does not seem to have a member named _api_prefix.

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...
31
                                 self._api_prefix + 'set_option')
0 ignored issues
show
Bug introduced by
The Instance of Remote does not seem to have a member named _api_prefix.

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...
32 5
33
    def __repr__(self):
34
        """Get text representation of the object."""
35 5
        return '<%s(handle=%r)>' % (
36
            self.__class__.__name__,
37 5
            self.handle,
38
        )
39 5
40
    def __eq__(self, other):
41 5
        """Return True if `self` and `other` are the same object."""
42
        return (hasattr(other, 'code_data') and
43
                other.code_data == self.code_data)
44 5
45
    def __hash__(self):
46
        """Return hash based on remote object id."""
47
        return self.code_data.__hash__()
48 5
49
    def request(self, name, *args, **kwargs):
50 5
        """Wrapper for nvim.request."""
51 5
        return self._session.request(name, self, *args, **kwargs)
52
53 5
54
class RemoteApi(object):
55 5
56
    """Wrapper to allow api methods to be called like python methods."""
57
58 5
    def __init__(self, obj, api_prefix):
59
        """Initialize a RemoteApi with object and api prefix."""
60
        self._obj = obj
61
        self._api_prefix = api_prefix
62
63
    def __getattr__(self, name):
64
        """Return wrapper to named api method."""
65
        return functools.partial(self._obj.request, self._api_prefix + name)
66
67
68
class RemoteMap(object):
69 5
70
    """Represents a string->object map stored in Nvim.
71 5
72 5
    This is the dict counterpart to the `RemoteSequence` class, but it is used
73 5
    as a generic way of retrieving values from the various map-like data
74 5
    structures present in Nvim.
75
76 5
    It is used to provide a dict-like API to vim variables and options.
77
    """
78 5
79
    def __init__(self, obj, get_method, set_method=None):
80 5
        """Initialize a RemoteMap with session, getter/setter."""
81
        self._get = functools.partial(obj.request, get_method)
82 5
        self._set = None
83
        if set_method:
84 5
            self._set = functools.partial(obj.request, set_method)
85
86 5
    def __getitem__(self, key):
87
        """Return a map value by key."""
88
        return self._get(key)
89
90
    def __setitem__(self, key, value):
91
        """Set a map value by key(if the setter was provided)."""
92 5
        if not self._set:
93
            raise TypeError('This dict is read-only')
94
        self._set(key, value)
95
96
    def __delitem__(self, key):
97
        """Delete a map value by associating None with the key."""
98
        if not self._set:
99
            raise TypeError('This dict is read-only')
100 5
        return self._set(key, None)
101
102
    def __contains__(self, key):
103
        """Check if key is present in the map."""
104
        try:
105
            self._get(key)
106
            return True
107
        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...
108 5
            return False
109
110
    def get(self, key, default=None):
111
        """Return value for key if present, else a default value."""
112
        try:
113
            return self._get(key)
114
        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...
115
            return default
116
117
118
class RemoteSequence(object):
119
120
    """Represents a sequence of objects stored in Nvim.
121
122
    This class is used to wrap msgapck-rpc functions that work on Nvim
123
    sequences(of lines, buffers, windows and tabpages) with an API that
124
    is similar to the one provided by the python-vim interface.
125
126
    For example, the 'windows' property of the `Nvim` class is a RemoteSequence
127
    sequence instance, and the expression `nvim.windows[0]` is translated to
128
    session.request('nvim_list_wins')[0].
129 5
130
    One important detail about this class is that all methods will fetch the
131 5
    sequence into a list and perform the necessary manipulation
132
    locally(iteration, indexing, counting, etc).
133 5
    """
134
135 5
    def __init__(self, session, method):
136
        """Initialize a RemoteSequence with session, method."""
137 5
        self._fetch = functools.partial(session.request, method)
138
139 5
    def __len__(self):
140 5
        """Return the length of the remote sequence."""
141 4
        return len(self._fetch())
142
143 5
    def __getitem__(self, idx):
144
        """Return a sequence item by index."""
145 5
        if not isinstance(idx, slice):
146 5
            return self._fetch()[idx]
147 5
        return self._fetch()[idx.start:idx.stop]
148
149 5
    def __iter__(self):
150
        """Return an iterator for the sequence."""
151
        items = self._fetch()
152
        for item in items:
153
            yield item
154 5
155
    def __contains__(self, item):
156
        """Check if an item is present in the sequence."""
157
        return item in self._fetch()
158 5
159
160 3
def _identity(obj, session, method, kind):
0 ignored issues
show
Unused Code introduced by
The argument method seems to be unused.
Loading history...
Unused Code introduced by
The argument session seems to be unused.
Loading history...
Unused Code introduced by
The argument kind seems to be unused.
Loading history...
161 3
    return obj
162 3
163 3
164 3
def decode_if_bytes(obj, mode=True):
165
    """Decode obj if it is bytes."""
166
    if mode is True:
167 5
        mode = unicode_errors_default
168
    if isinstance(obj, bytes):
169 5
        return obj.decode("utf-8", errors=mode)
170 5
    return obj
171 5
172 5
173
def walk(fn, obj, *args, **kwargs):
174 5
    """Recursively walk an object graph applying `fn`/`args` to objects."""
175
    if type(obj) in [list, tuple]:
176
        return list(walk(fn, o, *args) for o in obj)
177
    if type(obj) is dict:
178
        return dict((walk(fn, k, *args), walk(fn, v, *args)) for k, v in
179
                    obj.items())
180
    return fn(obj, *args, **kwargs)
181