show_neighbor()   F
last analyzed

Complexity

Conditions 21

Size

Total Lines 63
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 53
nop 4
dl 0
loc 63
rs 0
c 0
b 0
f 0

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 exabgp.reactor.api.command.neighbor.show_neighbor() 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
# encoding: utf-8
2
"""
3
command/neighbor.py
4
5
Created by Thomas Mangin on 2017-07-01.
6
Copyright (c) 2009-2017 Exa Networks. All rights reserved.
7
License: 3-clause BSD. (See the COPYRIGHT file)
8
"""
9
10
from datetime import timedelta
11
12
from exabgp.reactor.api.command.command import Command
13
from exabgp.reactor.api.command.limit import match_neighbor
14
from exabgp.reactor.api.command.limit import extract_neighbors
15
16
17
def register_neighbor():
18
    pass
19
20
21
def _en(value):
22
    if value is None:
23
        return 'n/a'
24
    return 'enabled' if value else 'disabled'
25
26
27
def _pr(value):
28
    if value is None:
29
        return 'n/a'
30
    return '%s' % value
31
32
33
class Neighbor(object):
34
    extensive_kv = '   %-20s %15s %15s %15s'
35
    extensive_template = """\
36
Neighbor %(peer-address)s
37
38
    Session                         Local
39
%(local-address)s
40
%(state)s
41
%(duration)s
42
43
    Setup                           Local          Remote
44
%(as)s
45
%(id)s
46
%(hold)s
47
48
    Capability                      Local          Remote
49
%(capabilities)s
50
51
    Families                        Local          Remote        Add-Path
52
%(families)s
53
54
    Message Statistic                Sent        Received
55
%(messages)s
56
""".replace(
57
        '\t', '  '
58
    )
59
60
    summary_header = 'Peer            AS        up/down state       |     #sent     #recvd'
61
    summary_template = '%-15s %-7s %9s %-12s %10d %10d'
62
63
    @classmethod
64
    def extensive(cls, answer):
65
        if answer['duration']:
66
            duration = cls.extensive_kv % ('up for', timedelta(seconds=answer['duration']), '', '')
67
        else:
68
            duration = cls.extensive_kv % ('down for', timedelta(seconds=answer['down']), '', '')
69
        formated = {
70
            'peer-address': answer['peer-address'],
71
            'local-address': cls.extensive_kv % ('local', answer['local-address'], '', ''),
72
            'state': cls.extensive_kv % ('state', answer['state'], '', ''),
73
            'duration': duration,
74
            'as': cls.extensive_kv % ('AS', answer['local-as'], _pr(answer['peer-as']), ''),
75
            'id': cls.extensive_kv % ('ID', answer['local-id'], _pr(answer['peer-id']), ''),
76
            'hold': cls.extensive_kv % ('hold-time', answer['local-hold'], _pr(answer['peer-hold']), ''),
77
            'capabilities': '\n'.join(
78
                cls.extensive_kv % ('%s:' % k, _en(l), _en(p), '') for k, (l, p) in answer['capabilities'].items()
79
            ),
80
            'families': '\n'.join(
81
                cls.extensive_kv % ('%s %s:' % (a, s), _en(l), _en(r), _en(p))
82
                for (a, s), (l, r, p) in answer['families'].items()
83
            ),
84
            'messages': '\n'.join(
85
                cls.extensive_kv % ('%s:' % k, str(s), str(r), '') for k, (s, r) in answer['messages'].items()
86
            ),
87
        }
88
89
        return cls.extensive_template % formated
90
91
    @classmethod
92
    def summary(cls, answer):
93
        return cls.summary_template % (
94
            answer['peer-address'],
95
            _pr(answer['peer-as']),
96
            timedelta(seconds=answer['duration']) if answer['duration'] else 'down',
97
            answer['state'].lower(),
98
            answer['messages']['update'][0],
99
            answer['messages']['update'][1],
100
        )
101
102
103
@Command.register('text', 'teardown', True)
104
def teardown(self, reactor, service, line):
105
    try:
106
        descriptions, line = extract_neighbors(line)
107
        if ' ' not in line:
108
            reactor.processes.answer_error(service)
109
            return False
110
        _, code = line.split(' ', 1)
111
        if not code.isdigit():
112
            reactor.processes.answer_error(service)
113
            return False
114
        for key in reactor.established_peers():
115
            for description in descriptions:
116
                if match_neighbor(description, key):
117
                    reactor.teardown_peer(key, int(code))
118
                    self.log_message('teardown scheduled for %s' % ' '.join(description))
119
        reactor.processes.answer_done(service)
120
        return True
121
    except ValueError:
122
        reactor.processes.answer_error(service)
123
        return False
124
    except IndexError:
125
        reactor.processes.answer_error(service)
126
        return False
127
128
129
@Command.register('text', 'show neighbor', False, ['summary', 'extensive', 'configuration'])
130
def show_neighbor(self, reactor, service, command):
131
    words = command.split()
132
133
    extensive = 'extensive' in words
134
    configuration = 'configuration' in words
135
    summary = 'summary' in words
136
137
    if summary:
138
        words.remove('summary')
139
    if extensive:
140
        words.remove('extensive')
141
    if configuration:
142
        words.remove('configuration')
143
144
    limit = words[-1] if words[-1] != 'neighbor' else ''
145
146
    def callback_configuration():
147
        for neighbor_name in reactor.configuration.neighbors.keys():
148
            neighbor = reactor.configuration.neighbors.get(neighbor_name, None)
149
            if not neighbor:
150
                continue
151
            if limit and limit not in neighbor_name:
152
                continue
153
            for line in str(neighbor).split('\n'):
154
                reactor.processes.write(service, line)
155
                yield True
156
        reactor.processes.answer_done(service)
157
158
    def callback_extensive():
159
        for peer_name in reactor.peers():
160
            if limit and limit not in reactor.neighbor_name(peer_name):
161
                continue
162
            for line in Neighbor.extensive(reactor.neighbor_cli_data(peer_name)).split('\n'):
163
                reactor.processes.write(service, line)
164
                yield True
165
        reactor.processes.answer_done(service)
166
167
    def callback_summary():
168
        reactor.processes.write(service, Neighbor.summary_header)
169
        for peer_name in reactor.established_peers():
170
            if limit and limit != reactor.neighbor_ip(peer_name):
171
                continue
172
            for line in Neighbor.summary(reactor.neighbor_cli_data(peer_name)).split('\n'):
173
                reactor.processes.write(service, line)
174
                yield True
175
        reactor.processes.answer_done(service)
176
177
    if summary:
178
        reactor.asynchronous.schedule(service, command, callback_summary())
179
        return True
180
181
    if extensive:
182
        reactor.asynchronous.schedule(service, command, callback_extensive())
183
        return True
184
185
    if configuration:
186
        reactor.asynchronous.schedule(service, command, callback_configuration())
187
        return True
188
189
    reactor.processes.write(service, 'please specify summary, extensive or configuration')
190
    reactor.processes.write(service, 'you can filter by peer ip address adding it after the word neighbor')
191
    reactor.processes.answer_done(service)
192