Completed
Pull Request — master (#232)
by Björn
22:44 queued 21:26
created

start_host()   D

Complexity

Conditions 11

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 118.5556

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 11
c 2
b 0
f 0
dl 0
loc 53
ccs 1
cts 26
cp 0.0385
crap 118.5556
rs 4.1538

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like start_host() 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
"""Python client for Nvim.
2
3
Client library for talking with Nvim processes via it's msgpack-rpc API.
4
"""
5 6
import logging
6 6
import os
7 6
import sys
8
9 6
from .api import Nvim
10 6
from .compat import IS_PYTHON3
11 6
from .msgpack_rpc import (ErrorResponse, child_session, socket_session,
12
                          stdio_session, tcp_session)
13 6
from .plugin import (Host, autocmd, command, decode, encoding, function,
14
                     plugin, rpc_export, shutdown_hook)
15 6
from .util import Version
16
17
18 6
__all__ = ('tcp_session', 'socket_session', 'stdio_session', 'child_session',
19
           'start_host', 'autocmd', 'command', 'encoding', 'decode',
20
           'function', 'plugin', 'rpc_export', 'Host', 'Nvim', 'VERSION',
21
           'shutdown_hook', 'attach', 'setup_logging', 'ErrorResponse')
22
23
24 6
VERSION = Version(major=0, minor=1, patch=11, prerelease="dev")
25
26
27 6
def start_host(session=None):
28
    """Promote the current process into python plugin host for Nvim.
29
30
    Start msgpack-rpc event loop for `session`, listening for Nvim requests
31
    and notifications. It registers Nvim commands for loading/unloading
32
    python plugins.
33
34
    The sys.stdout and sys.stderr streams are redirected to Nvim through
35
    `session`. That means print statements probably won't work as expected
36
    while this function doesn't return.
37
38
    This function is normally called at program startup and could have been
39
    defined as a separate executable. It is exposed as a library function for
40
    testing purposes only.
41
    """
42
    plugins = []
43
    for arg in sys.argv:
44
        _, ext = os.path.splitext(arg)
45
        if ext == '.py':
46
            plugins.append(arg)
47
        elif os.path.isdir(arg):
48
            init = os.path.join(arg, '__init__.py')
49
            if os.path.isfile(init):
50
                plugins.append(arg)
51
52
    # This is a special case to support the old workaround of
53
    # adding an empty .py file to make a package directory
54
    # visible, and it should be removed soon.
55
    for path in list(plugins):
56
        dup = path + ".py"
57
        if os.path.isdir(path) and dup in plugins:
58
            plugins.remove(dup)
59
60
    # Special case: the legacy scripthost receives a single relative filename
61
    # while the rplugin host will receive absolute paths.
62
    if plugins == ["script_host.py"]:
63
        name = "script"
64
    else:
65
        name = "rplugin"
66
67
    setup_logging(name)
68
69
    if not session:
70
        session = stdio_session()
71
    nvim = Nvim.from_session(session)
72
73
    if nvim.version.api_level < 1:
74
        sys.stderr.write("This version of the neovim python package "
75
                         "requires nvim 0.1.6 or later")
76
        sys.exit(1)
77
78
    host = Host(nvim)
79
    host.start(plugins)
80
81
82 6
def attach(session_type, address=None, port=None,
83
           path=None, argv=None, decode=None):
84
    """Provide a nicer interface to create python api sessions.
85
86
    Previous machinery to create python api sessions is still there. This only
87
    creates a facade function to make things easier for the most usual cases.
88
    Thus, instead of:
89
        from neovim import socket_session, Nvim
90
        session = tcp_session(address=<address>, port=<port>)
91
        nvim = Nvim.from_session(session)
92
    You can now do:
93
        from neovim import attach
94
        nvim = attach('tcp', address=<address>, port=<port>)
95
    And also:
96
        nvim = attach('socket', path=<path>)
97
        nvim = attach('child', argv=<argv>)
98
        nvim = attach('stdio')
99
    """
100 6
    session = (tcp_session(address, port) if session_type == 'tcp' else
101
               socket_session(path) if session_type == 'socket' else
102
               stdio_session() if session_type == 'stdio' else
103
               child_session(argv) if session_type == 'child' else
104
               None)
105
106 6
    if not session:
107
        raise Exception('Unknown session type "%s"' % session_type)
108
109 6
    if decode is None:
110 6
        decode = IS_PYTHON3
111
112 6
    return Nvim.from_session(session).with_decode(decode)
113
114
115 6
def setup_logging(name):
116
    """Setup logging according to environment variables."""
117 6
    logger = logging.getLogger(__name__)
118 6
    if 'NVIM_PYTHON_LOG_FILE' in os.environ:
119
        prefix = os.environ['NVIM_PYTHON_LOG_FILE'].strip()
120
        major_version = sys.version_info[0]
121
        logfile = '{0}_py{1}_{2}'.format(prefix, major_version, name)
122
        handler = logging.FileHandler(logfile, 'w')
123
        handler.formatter = logging.Formatter(
124
            '%(asctime)s [%(levelname)s @ '
125
            '%(filename)s:%(funcName)s:%(lineno)s] %(process)s - %(message)s')
126
        logging.root.addHandler(handler)
127
        level = logging.INFO
128
        if 'NVIM_PYTHON_LOG_LEVEL' in os.environ:
129
            l = getattr(logging,
130
                        os.environ['NVIM_PYTHON_LOG_LEVEL'].strip(),
131
                        level)
132
            if isinstance(l, int):
133
                level = l
134
        logger.setLevel(level)
135
136
137
# Required for python 2.6
138 6
class NullHandler(logging.Handler):
139 6
    def emit(self, record):
140 6
        pass
141
142
143 6
if not logging.root.handlers:
144
    logging.root.addHandler(NullHandler())
145