Completed
Push — master ( b8bb7c...e03945 )
by Björn
9s
created

start_host()   F

Complexity

Conditions 10

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 96.9616

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
c 2
b 0
f 0
dl 0
loc 46
ccs 1
cts 22
cp 0.0455
crap 96.9616
rs 3.2727

How to fix   Complexity   

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