Completed
Push — develop ( 680e07...e5c8fa )
by Jace
02:57
created

describe_aliases()   F

Complexity

Conditions 22

Size

Total Lines 70

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 70
rs 2.6107
cc 22

7 Methods

Rating   Name   Duplication   Size   Complexity  
A test_custom_init_is_invoked() 0 4 2
A test_alias_dict_in_list() 0 9 4
A test_alias_list() 0 13 4
A test_alias_list_in_dict() 0 9 3
A test_alias_dict() 0 14 4
A _log_ref() 0 7 3
A sample() 0 6 1

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 describe_aliases() 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
"""Integration tests for nested attributes."""
2
# pylint: disable=missing-docstring,no-self-use,attribute-defined-outside-init,no-member
3
# pylint: disable=unused-variable,misplaced-comparison-constant
0 ignored issues
show
introduced by
Bad option value 'misplaced-comparison-constant'
Loading history...
4
5
from unittest.mock import patch
6
import logging
7
8
import pytest
9
from expecter import expect
0 ignored issues
show
Configuration introduced by
The import expecter 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...
10
11
import yorm
12
13
from . import strip
14
15
16
@yorm.attr(status=yorm.types.Boolean)
17
@yorm.attr(checked=yorm.types.Integer)
18
class StatusDictionary(yorm.types.Dictionary):
19
20
    def __init__(self, status, checked):
21
        self.status = status
22
        self.checked = checked
23
        if self.checked == 42:
24
            raise RuntimeError
25
26
27
@yorm.attr(all=yorm.types.Float)
28
class NestedList3(yorm.types.List):
29
30
    def __repr__(self):
31
        return "<nested-list-3 {}>".format((id(self)))
32
33
34
@yorm.attr(nested_list_3=NestedList3)
35
@yorm.attr(number=yorm.types.Float)
36
class NestedDictionary3(yorm.types.AttributeDictionary):
37
38
    def __init__(self):
39
        super().__init__()
40
        self.number = 0
41
        self.nested_list_3 = []
42
43
    def __repr__(self):
44
        print(self.number)  # trigger a potential recursion issue
45
        return "<nested-dictionary-3 {}>".format((id(self)))
46
47
48
@yorm.attr(all=yorm.types.Float)
49
class NestedList2(yorm.types.List):
50
51
    def __repr__(self):
52
        return "<nested-list-2 {}>".format((id(self)))
53
54
55
@yorm.attr(nested_dict_3=NestedDictionary3)
56
@yorm.attr(number=yorm.types.Float)
57
class NestedDictionary2(yorm.types.AttributeDictionary):
58
59
    def __init__(self):
60
        super().__init__()
61
        self.number = 0
62
63
    def __repr__(self):
64
        print(self.number)  # trigger a potential recursion issue
65
        return "<nested-dictionary-2 {}>".format((id(self)))
66
67
68
@yorm.attr(nested_list_2=NestedList2)
69
@yorm.attr(number=yorm.types.Float)
70
class NestedDictionary(yorm.types.AttributeDictionary):
71
72
    def __init__(self):
73
        super().__init__()
74
        self.number = 0
75
        self.nested_list_2 = []
76
77
    def __repr__(self):
78
        return "<nested-dictionary {}>".format((id(self)))
79
80
81
@yorm.attr(all=NestedDictionary2)
82
class NestedList(yorm.types.List):
83
84
    def __repr__(self):
85
        return "<nested-list {}>".format((id(self)))
86
87
88
@yorm.attr(nested_dict=NestedDictionary)
89
@yorm.attr(nested_list=NestedList)
90
@yorm.sync("sample.yml")
91
class Top:
92
93
    def __init__(self):
94
        self.nested_list = []
95
        self.nested_dict = {}
96
97
    def __repr__(self):
98
        return "<top {}>".format((id(self)))
99
100
101
@patch('yorm.settings.fake', True)
102
class TestNestedOnce:
103
104
    def test_append_triggers_save(self):
105
        top = Top()
106
        logging.info("Appending dictionary to list...")
107
        top.nested_list.append({'number': 1})
108
        assert strip("""
109
        nested_dict:
110
          nested_list_2: []
111
          number: 0.0
112
        nested_list:
113
        - nested_dict_3:
114
            nested_list_3: []
115
            number: 0.0
116
          number: 1.0
117
        """) == top.__mapper__.text
118
119
    def test_set_by_index_triggers_save(self):
120
        top = Top()
121
        top.nested_list = [{'number': 1.5}]
122
        assert strip("""
123
        nested_dict:
124
          nested_list_2: []
125
          number: 0.0
126
        nested_list:
127
        - nested_dict_3:
128
            nested_list_3: []
129
            number: 0.0
130
          number: 1.5
131
        """) == top.__mapper__.text
132
        top.nested_list[0] = {'number': 1.6}
133
        assert strip("""
134
        nested_dict:
135
          nested_list_2: []
136
          number: 0.0
137
        nested_list:
138
        - nested_dict_3:
139
            nested_list_3: []
140
            number: 0.0
141
          number: 1.6
142
        """) == top.__mapper__.text
143
144
    def test_get_by_index_triggers_load(self):
145
        top = Top()
146
        top.__mapper__.text = strip("""
147
        nested_list:
148
        - number: 1.7
149
        """)
150
        assert 1.7 == top.nested_list[0].number
151
152
    def test_delete_index_triggers_save(self):
153
        top = Top()
154
        top.nested_list = [{'number': 1.8}, {'number': 1.9}]
155
        assert strip("""
156
        nested_dict:
157
          nested_list_2: []
158
          number: 0.0
159
        nested_list:
160
        - nested_dict_3:
161
            nested_list_3: []
162
            number: 0.0
163
          number: 1.8
164
        - nested_dict_3:
165
            nested_list_3: []
166
            number: 0.0
167
          number: 1.9
168
        """) == top.__mapper__.text
169
        del top.nested_list[0]
170
        assert strip("""
171
        nested_dict:
172
          nested_list_2: []
173
          number: 0.0
174
        nested_list:
175
        - nested_dict_3:
176
            nested_list_3: []
177
            number: 0.0
178
          number: 1.9
179
        """) == top.__mapper__.text
180
181
    def test_set_dict_as_attribute_triggers_save(self):
182
        top = Top()
183
        top.nested_dict.number = 2
184
        assert strip("""
185
        nested_dict:
186
          nested_list_2: []
187
          number: 2.0
188
        nested_list: []
189
        """) == top.__mapper__.text
190
191
192
@patch('yorm.settings.fake', True)
193
class TestNestedTwice:
194
195
    def test_nested_list_item_value_change_triggers_save(self):
196
        top = Top()
197
        top.nested_list = [{'number': 3}]
198
        assert strip("""
199
        nested_dict:
200
          nested_list_2: []
201
          number: 0.0
202
        nested_list:
203
        - nested_dict_3:
204
            nested_list_3: []
205
            number: 0.0
206
          number: 3.0
207
        """) == top.__mapper__.text
208
        top.nested_list[0].number = 4
209
        assert strip("""
210
        nested_dict:
211
          nested_list_2: []
212
          number: 0.0
213
        nested_list:
214
        - nested_dict_3:
215
            nested_list_3: []
216
            number: 0.0
217
          number: 4.0
218
        """) == top.__mapper__.text
219
220
    def test_nested_dict_item_value_change_triggers_save(self):
221
        top = Top()
222
        top.nested_dict = {'nested_list_2': [5]}
223
        assert strip("""
224
        nested_dict:
225
          nested_list_2:
226
          - 5.0
227
          number: 0.0
228
        nested_list: []
229
        """) == top.__mapper__.text
230
        top.nested_dict.nested_list_2.append(6)
231
        assert strip("""
232
        nested_dict:
233
          nested_list_2:
234
          - 5.0
235
          - 6.0
236
          number: 0.0
237
        nested_list: []
238
        """) == top.__mapper__.text
239
240
    def test_dict_in_list_value_change_triggers_save(self):
241
        top = Top()
242
        top.nested_list.append(None)
243
        top.nested_list[0].nested_dict_3.number = 8
244
        assert strip("""
245
        nested_dict:
246
          nested_list_2: []
247
          number: 0.0
248
        nested_list:
249
        - nested_dict_3:
250
            nested_list_3: []
251
            number: 8.0
252
          number: 0.0
253
        """) == top.__mapper__.text
254
255
    def test_list_in_dict_append_triggers_save(self):
256
        top = Top()
257
        top.nested_list.append(None)
258
        top.nested_list.append(None)
259
        for nested_dict_2 in top.nested_list:
260
            nested_dict_2.number = 9
261
            nested_dict_2.nested_dict_3.nested_list_3.append(10)
262
        assert strip("""
263
        nested_dict:
264
          nested_list_2: []
265
          number: 0.0
266
        nested_list:
267
        - nested_dict_3:
268
            nested_list_3:
269
            - 10.0
270
            number: 0.0
271
          number: 9.0
272
        - nested_dict_3:
273
            nested_list_3:
274
            - 10.0
275
            number: 0.0
276
          number: 9.0
277
        """) == top.__mapper__.text
278
279
280
def describe_aliases():
281
282
    @pytest.fixture
283
    def sample(tmpdir):
284
        cls = type('Sample', (), {})
285
        path = str(tmpdir.join("sample.yml"))
286
        attrs = dict(var4=NestedList3, var5=StatusDictionary)
287
        return yorm.sync(cls(), path, attrs)
288
289
    def _log_ref(name, var, ref):
290
        logging.info("%s: %r", name, var)
291
        logging.info("%s_ref: %r", name, ref)
292
        logging.info("%s ID: %s", name, id(var))
293
        logging.info("%s_ref ID: %s", name, id(ref))
294
        assert id(ref) == id(var)
295
        assert ref == var
296
297
    def test_alias_list(sample):
298
        var4_ref = sample.var4
299
        _log_ref('var4', sample.var4, var4_ref)
300
        assert [] == sample.var4
301
302
        logging.info("Appending 42 to var4_ref...")
303
        var4_ref.append(42)
304
        _log_ref('var4', sample.var4, var4_ref)
305
        assert [42] == sample.var4
306
307
        logging.info("Appending 2015 to var4_ref...")
308
        var4_ref.append(2015)
309
        assert [42, 2015] == sample.var4
310
311
    def test_alias_dict(sample):
312
        var5_ref = sample.var5
313
        _log_ref('var5', sample.var5, var5_ref)
314
        assert {'status': False, 'checked': 0} == sample.var5
315
316
        logging.info("Setting status=True in var5_ref...")
317
        var5_ref['status'] = True
318
        _log_ref('var5', sample.var5, var5_ref)
319
        assert {'status': True, 'checked': 0} == sample.var5
320
321
        logging.info("Setting status=False in var5_ref...")
322
        var5_ref['status'] = False
323
        _log_ref('var5', sample.var5, var5_ref)
324
        assert {'status': False, 'checked': 0} == sample.var5
325
326
    def test_alias_dict_in_list():
327
        top = Top()
328
        top.nested_list.append(None)
329
        ref1 = top.nested_list[0]
330
        ref2 = top.nested_list[0].nested_dict_3
331
        ref3 = top.nested_list[0].nested_dict_3.nested_list_3
332
        assert id(ref1) == id(top.nested_list[0])
333
        assert id(ref2) == id(top.nested_list[0].nested_dict_3)
334
        assert id(ref3) == id(top.nested_list[0].nested_dict_3.nested_list_3)
335
336
    def test_alias_list_in_dict():
337
        top = Top()
338
        logging.info("Updating nested attribute...")
339
        top.nested_dict.number = 1
340
        logging.info("Grabbing refs...")
341
        ref1 = top.nested_dict
342
        ref2 = top.nested_dict.nested_list_2
343
        assert id(ref1) == id(top.nested_dict)
344
        assert id(ref2) == id(top.nested_dict.nested_list_2)
345
346
    def test_custom_init_is_invoked(sample):
347
        sample.__mapper__.text = "var5:\n  checked: 42"
348
        with expect.raises(RuntimeError):
349
            print(sample.var5)
350