Passed
Push — develop ( 3d8444...ce4f6d )
by Dean
03:03
created

ListMessages()   F

Complexity

Conditions 14

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 51
rs 2.8289
c 0
b 0
f 0
cc 14

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 ListMessages() 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
from core.helpers import pad_title, timestamp
0 ignored issues
show
Bug introduced by
The name helpers does not seem to exist in module core.
Loading history...
Configuration introduced by
The import core.helpers 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...
Unused Code introduced by
Unused timestamp imported from core.helpers
Loading history...
2
3
from plugin.core.constants import PLUGIN_PREFIX
0 ignored issues
show
Configuration introduced by
The import plugin.core.constants 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...
4
from plugin.managers.exception import ExceptionManager, MessageManager, VERSION_BASE, VERSION_BRANCH
0 ignored issues
show
Configuration introduced by
The import plugin.managers.exception 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
from plugin.models import Exception, Message
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in Exception.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
Configuration introduced by
The import plugin.models 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...
6
7
from ago import human
0 ignored issues
show
Configuration introduced by
The import ago 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...
8
from datetime import datetime, timedelta
9
10
ERROR_TYPES = [
11
    Message.Type.Exception,
12
13
    Message.Type.Warning,
14
    Message.Type.Error,
15
    Message.Type.Critical
16
]
17
18
19
@route(PLUGIN_PREFIX + '/messages/list')
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'route'
Loading history...
20
def ListMessages(viewed=None):
21
    # Cast `viewed` to boolean
22
    if type(viewed) is str:
23
        if viewed == 'None':
24
            viewed = None
25
        else:
26
            viewed = viewed == 'True'
27
28
    # Retrieve messages
29
    messages = list(List(
30
        viewed=viewed
31
    ).order_by(
32
        Message.last_logged_at.desc()
33
    ).limit(50))
34
35
    total_messages = List().count()
36
37
    # Construct container
38
    oc = ObjectContainer(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ObjectContainer'
Loading history...
39
        title2="Messages"
40
    )
41
42
    for m in messages:
43
        if m.type is None or\
44
           m.summary is None:
45
            continue
46
47
        thumb = None
48
49
        if m.type == Message.Type.Exception:
50
            thumb = R("icon-exception-viewed.png") if m.viewed else R("icon-exception.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
51
        elif m.type == Message.Type.Info:
52
            thumb = R("icon-notification-viewed.png") if m.viewed else R("icon-notification.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
53
        elif m.type in ERROR_TYPES:
54
            thumb = R("icon-error-viewed.png") if m.viewed else R("icon-error.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
55
56
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
57
            key=Callback(ViewMessage, error_id=m.id),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
58
            title=pad_title('[%s] %s' % (Message.Type.title(m.type), m.summary)),
59
            thumb=thumb
60
        ))
61
62
    # Append "View More" button
63
    if len(messages) != 50 and len(messages) < total_messages:
64
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
65
            key=Callback(ListMessages),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
66
            title=pad_title("View All")
67
        ))
68
69
    return oc
70
71
@route(PLUGIN_PREFIX + '/messages/view')
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'route'
Loading history...
72
def ViewMessage(error_id):
73
    # Retrieve message from database
74
    message = MessageManager.get.by_id(error_id)
75
76
    # Update `last_viewed_at` field
77
    message.last_viewed_at = datetime.utcnow()
78
    message.save()
79
80
    # Parse request headers
81
    web_client = Request.Headers.get('X-Plex-Product', '').lower() == 'plex web'
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Request'
Loading history...
82
83
    # Build objects
84
    oc = ObjectContainer(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ObjectContainer'
Loading history...
85
        title2='[%s] %s' % (Message.Type.title(message.type), Trim(message.summary))
86
    )
87
88
    if message.type == Message.Type.Exception:
89
        # Display exception samples
90
        for e in message.exceptions.order_by(Exception.timestamp.desc()).limit(50):
91
            since = datetime.utcnow() - e.timestamp
92
93
            callback = Callback(ViewMessage, error_id=error_id)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
94
95
            if web_client:
96
                # Display exception traceback in Plex/Web
97
                callback = Callback(ViewException, exception_id=e.id)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
98
99
            oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
100
                key=callback,
101
                title=pad_title('[%s] %s: %s' % (human(since, precision=1), e.type, e.message)),
102
                thumb=R("icon-exception.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
103
            ))
104
    elif message.type in [Message.Type.Info, Message.Type.Warning, Message.Type.Error, Message.Type.Critical]:
105
        # Display message code
106
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
107
            key='',
108
            title=pad_title('Code: %s' % hex(message.code))
109
        ))
110
111
        # Display message description
112
        if message.description:
113
            oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
114
                key='',
115
                title=pad_title('Description: %s' % message.description)
116
            ))
117
118
    return oc
119
120
@route(PLUGIN_PREFIX + '/exceptions/view')
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'route'
Loading history...
121
def ViewException(exception_id):
122
    # Retrieve exception from database
123
    exception = ExceptionManager.get.by_id(exception_id)
124
125
    # Split traceback into lines
126
    traceback = exception.traceback
127
128
    if traceback:
129
        traceback = traceback.split('\n')
130
131
    # Build exception view
132
    oc = ObjectContainer(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ObjectContainer'
Loading history...
133
        title2='%s: %s' % (exception.type, Trim(exception.message))
134
    )
135
136
    if not traceback:
137
        return oc
138
139
    for line in traceback:
140
        if not line:
141
            continue
142
143
        length = len(line)
144
145
        line = line.lstrip()
146
        spaces = length - len(line)
147
148
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
149
            key=Callback(ViewException, exception_id=exception_id),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
150
            title=pad_title(('&nbsp;' * spaces) + line)
151
        ))
152
153
    return oc
154
155
156
def Status(viewed=None):
157
    """Get the number and type of messages logged in the last week"""
158
    messages = List(viewed=viewed)
159
160
    count = 0
161
    type = 'notification'
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in type.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
162
163
    for message in messages:
164
        if message.type in ERROR_TYPES:
165
            type = 'error'
166
167
        count += 1
168
169
    return count, type
170
171
172
def List(viewed=None):
173
    """Get messages logged in the last week"""
174
    since = datetime.utcnow() - timedelta(days=7)
175
176
    where = [
177
        Message.last_logged_at > since,
178
        Message.version_base == VERSION_BASE,
179
        Message.version_branch == VERSION_BRANCH
180
    ]
181
182
    if viewed is True:
183
        where.append(
184
            ~(Message.last_viewed_at >> None),
185
            Message.last_viewed_at > Message.last_logged_at
186
        )
187
    elif viewed is False:
188
        where.append(
189
            (Message.last_viewed_at >> None) | (Message.last_viewed_at < Message.last_logged_at)
190
        )
191
192
    return MessageManager.get.where(*where)
193
194
195
def Trim(value, length=45):
196
    if value and len(value) > length:
197
        return value[:length - 3] + "..."
198
199
    return value
200