Completed
Push — master ( f427d0...2d9fb2 )
by Björn
13s
created

neovim.start_host()   F

Complexity

Conditions 10

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 72.9643
Metric Value
cc 10
dl 0
loc 42
ccs 2
cts 14
cp 0.1429
crap 72.9643
rs 3.1304

How to fix   Complexity   

Complexity

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