mutmut 3.0.2__tar.gz → 3.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,13 @@
1
1
  Changelog
2
2
  ---------
3
3
 
4
+ 3.0.3
5
+ ~~~~~
6
+
7
+ * Fixed missing requirement in install package
8
+
9
+ * Fixed missing file from the install package
10
+
4
11
  3.0.2
5
12
  ~~~~~
6
13
 
@@ -2,5 +2,5 @@ include HISTORY.rst
2
2
  include LICENSE
3
3
  include README.rst
4
4
  include requirements.txt
5
- include test_requirements.txt
6
- include mutmut/result_browser_layout.tcss
5
+ recursive-include mutmut *.tcss
6
+ exclude tests/*.*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mutmut
3
- Version: 3.0.2
3
+ Version: 3.0.3
4
4
  Summary: mutation testing for Python 3
5
5
  Home-page: https://github.com/boxed/mutmut
6
6
  Author: Anders Hovmöller
@@ -19,6 +19,7 @@ Requires-Dist: parso
19
19
  Requires-Dist: click
20
20
  Requires-Dist: junit-xml==1.8
21
21
  Requires-Dist: setproctitle
22
+ Requires-Dist: textual
22
23
  Provides-Extra: pytest
23
24
  Requires-Dist: pytest; extra == "pytest"
24
25
  Provides-Extra: coverage
@@ -4,7 +4,7 @@ from parso.python.tree import (
4
4
  Number,
5
5
  )
6
6
 
7
- __version__ = '3.0.2'
7
+ __version__ = '3.0.3'
8
8
 
9
9
 
10
10
  # We have a global whitelist for constants of the pattern __all__, __version__, etc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mutmut
3
- Version: 3.0.2
3
+ Version: 3.0.3
4
4
  Summary: mutation testing for Python 3
5
5
  Home-page: https://github.com/boxed/mutmut
6
6
  Author: Anders Hovmöller
@@ -19,6 +19,7 @@ Requires-Dist: parso
19
19
  Requires-Dist: click
20
20
  Requires-Dist: junit-xml==1.8
21
21
  Requires-Dist: setproctitle
22
+ Requires-Dist: textual
22
23
  Provides-Extra: pytest
23
24
  Requires-Dist: pytest; extra == "pytest"
24
25
  Provides-Extra: coverage
@@ -6,11 +6,8 @@ README.rst
6
6
  requirements.txt
7
7
  setup.cfg
8
8
  setup.py
9
- test_requirements.txt
10
9
  ./mutmut/__init__.py
11
10
  ./mutmut/__main__.py
12
- mutmut/__init__.py
13
- mutmut/__main__.py
14
11
  mutmut/result_browser_layout.tcss
15
12
  mutmut.egg-info/PKG-INFO
16
13
  mutmut.egg-info/SOURCES.txt
@@ -18,6 +15,4 @@ mutmut.egg-info/dependency_links.txt
18
15
  mutmut.egg-info/entry_points.txt
19
16
  mutmut.egg-info/not-zip-safe
20
17
  mutmut.egg-info/requires.txt
21
- mutmut.egg-info/top_level.txt
22
- tests/test_mutation.py
23
- tests/test_mutmut3.py
18
+ mutmut.egg-info/top_level.txt
@@ -2,6 +2,7 @@ parso
2
2
  click
3
3
  junit-xml==1.8
4
4
  setproctitle
5
+ textual
5
6
 
6
7
  [coverage]
7
8
  coverage
@@ -2,3 +2,4 @@ parso
2
2
  click
3
3
  junit-xml==1.8
4
4
  setproctitle
5
+ textual
@@ -1,4 +0,0 @@
1
- pytest
2
- mock>=2.0.0
3
- coverage
4
- whatthepatch==0.0.6
@@ -1,339 +0,0 @@
1
- from io import StringIO
2
-
3
- import pytest
4
- from parso import parse
5
-
6
- from mutmut.__main__ import (
7
- CLASS_NAME_SEPARATOR,
8
- FuncContext,
9
- get_diff_for_mutant,
10
- mangle_function_name,
11
- orig_function_and_class_names_from_key,
12
- pragma_no_mutate_lines,
13
- write_all_mutants_to_file,
14
- yield_mutants_for_module,
15
- yield_mutants_for_node,
16
- )
17
-
18
-
19
- @pytest.mark.parametrize(
20
- 'original, expected', [
21
- ('foo(a, *args, **kwargs)', [
22
- 'foo( *args, **kwargs)',
23
- 'foo(None, *args, **kwargs)',
24
- 'foo(a, **kwargs)',
25
- 'foo(a, *args,)',
26
- ]),
27
- # TODO: Fix these
28
- # ('break', 'continue'), # probably a bad idea. Can introduce infinite loops.
29
- ('a(b)', 'a(None)'),
30
- # ("x if a else b", "x if a else b"),
31
- ("dict(a=None)", ["dict(aXX=None)"]),
32
- ("dict(a=b)", ["dict(aXX=b)", 'dict(a=None)']),
33
- ('lambda **kwargs: Variable.integer(**setdefaults(kwargs, dict(show=False)))', [
34
- 'lambda **kwargs: Variable.integer(**setdefaults(kwargs, dict(show=True)))',
35
- 'lambda **kwargs: Variable.integer(**setdefaults(kwargs, dict(showXX=False)))',
36
- 'lambda **kwargs: Variable.integer(**setdefaults(None, dict(show=False)))',
37
- 'lambda **kwargs: Variable.integer(**setdefaults( dict(show=False)))',
38
- # TODO: this mutant should exist... I guess we need to handle method calls separately from function calls?
39
- # 'lambda **kwargs: Variable.integer()',
40
- 'lambda **kwargs: None',
41
- ]),
42
- ('a: Optional[int] = None', 'a: Optional[int] = ""'),
43
- ('a: int = 1', ['a: int = 2', 'a: int = None']),
44
- ('lambda: 0', ['lambda: 1', 'lambda: None']),
45
- ("1 in (1, 2)", ['2 in (1, 2)', '1 not in (1, 2)', '1 in (2, 2)', '1 in (1, 3)']),
46
- ('1+1', ['2+1', '1-1', '1+2']),
47
- ('1', '2'),
48
- ('1-1', ['2-1', '1+1', '1-2']),
49
- ('1*1', ['2*1', '1/1', '1*2']),
50
- ('1/1', ['2/1', '1*1', '1/2']),
51
- # ('1.0', '1.0000000000000002'), # using numpy features
52
- ('1.0', '2.0'),
53
- ('0.1', '1.1'),
54
- ('1e-3', '1.001'),
55
- ('True', 'False'),
56
- ('False', 'True'),
57
- ('"foo"', '"XXfooXX"'),
58
- ("'foo'", "'XXfooXX'"),
59
- ("u'foo'", "u'XXfooXX'"),
60
- ("0", "1"),
61
- ("0o0", "1"),
62
- ("0.", "1.0"),
63
- ("0x0", "1"),
64
- ("0b0", "1"),
65
- ("1<2", ['2<2', '1<=2', '1<3']),
66
- ('(1, 2)', ['(2, 2)', '(1, 3)']),
67
- ("1 not in (1, 2)", ['2 not in (1, 2)', '1 in (1, 2)', '1 not in (2, 2)', '1 not in (1, 3)']), # two spaces here because "not in" is two words
68
- ("foo is foo", "foo is not foo"),
69
- ("foo is not foo", "foo is foo"),
70
- ('a or b', 'a and b'),
71
- ('a and b', 'a or b'),
72
- ('a = b', 'a = None'),
73
- ('a = b = c = x', 'a = b = c = None'),
74
-
75
- # subscript
76
- ('a[None]', []),
77
- ('a[b]', 'a[None]'),
78
- ('s[0]', ['s[1]', 's[None]']),
79
- ('s[0] = a', ['s[1] = a', 's[None] = a', 's[0] = None']),
80
- ('s[1:]', ['s[2:]', 's[None]']),
81
-
82
- ('1j', '2j'),
83
- ('1.0j', '2.0j'),
84
- ('0o1', '2'),
85
- ('1.0e10', '10000000001.0'),
86
- ('a = {x for x in y}', 'a = None'),
87
- ('x+=1', ['x=1', 'x-=1', 'x+=2']),
88
- ('x-=1', ['x=1', 'x+=1', 'x-=2']),
89
- ('x*=1', ['x=1', 'x/=1', 'x*=2']),
90
- ('x/=1', ['x=1', 'x*=1', 'x/=2']),
91
- ('x//=1', ['x=1', 'x/=1', 'x//=2']),
92
- ('x%=1', ['x=1', 'x/=1', 'x%=2']),
93
- ('x<<=1', ['x=1', 'x>>=1', 'x<<=2']),
94
- ('x>>=1', ['x=1', 'x<<=1', 'x>>=2']),
95
- ('x&=1', ['x=1', 'x|=1', 'x&=2']),
96
- ('x|=1', ['x=1', 'x&=1', 'x|=2']),
97
- ('x^=1', ['x=1', 'x&=1', 'x^=2']),
98
- ('x**=1', ['x=1', 'x*=1', 'x**=2']),
99
- ('def foo(s: Int = 1): pass', 'def foo(s: Int = 2): pass'),
100
- ('a = None', 'a = ""'),
101
- ('lambda **kwargs: None', 'lambda **kwargs: 0'),
102
- ('lambda: None', 'lambda: 0'),
103
- ('def foo(s: str): pass', []),
104
- ('def foo(a, *, b): pass', []),
105
- ('a(None)', []),
106
- ("'''foo'''", []), # don't mutate things we assume to be docstrings
107
- ("r'''foo'''", []), # don't mutate things we assume to be docstrings
108
- ('(x for x in [])', []), # don't mutate 'in' in generators
109
- ("DictSynonym(a=b)", ["DictSynonym(aXX=b)", 'DictSynonym(a=None)']),
110
- ("NotADictSynonym(a=b)", "NotADictSynonym(a=None)"),
111
- ('from foo import *', []),
112
- ('from .foo import *', []),
113
- ('import foo', []),
114
- ('import foo as bar', []),
115
- ('foo.bar', []),
116
- ('for x in y: pass', []),
117
- ('def foo(a, *args, **kwargs): pass', []),
118
- ('import foo', []),
119
- ('isinstance(a, b)', []),
120
- ('len(a)', []),
121
- ]
122
- )
123
- def test_basic_mutations(original, expected):
124
- if isinstance(expected, str):
125
- expected = [expected]
126
- func_node = parse(f'def fake():\n {original}').children[0]
127
- node = func_node.children[-1]
128
- assert node.get_code().strip() == original.strip()
129
- mutants = list(yield_mutants_for_node(func_node=func_node, context=FuncContext(dict_synonyms={'DictSynonym'}), node=node))
130
- actual = sorted([
131
- parse(mutant).children[0].children[-1].get_code().strip()
132
- for (type_, mutant, _, _) in mutants
133
- if type_ == 'mutant'
134
- ])
135
- expected = sorted(expected)
136
- assert actual == expected
137
-
138
-
139
- def test_do_not_mutate_annotations():
140
- source = """
141
- def foo() -> int:
142
- bar: Optional[int]
143
- return
144
- """.strip()
145
-
146
- mutants = [
147
- mutant
148
- for type_, mutant, _, _ in yield_mutants_for_module(parse(source), {})
149
- if type_ == 'mutant'
150
- ]
151
- for m in mutants:
152
- print(m) # pragma: no cover
153
-
154
- assert not mutants
155
-
156
-
157
- def test_basic_class():
158
- source = """
159
- class Foo:
160
- def member(self):
161
- return 1
162
- """.strip()
163
-
164
- mutants = [
165
- mutant
166
- for type_, mutant, _, _ in yield_mutants_for_module(parse(source), {})
167
- if type_ == 'mutant'
168
- ]
169
- for m in mutants:
170
- print(m)
171
-
172
- assert len(mutants) == 1
173
- assert mutants[0] == f' def x{CLASS_NAME_SEPARATOR}Foo{CLASS_NAME_SEPARATOR}member__mutmut_1(self): \n return 2'
174
-
175
-
176
- def mutants_for_source(source):
177
- no_mutate_lines = pragma_no_mutate_lines(source)
178
- r = []
179
- for type_, x, name_and_hash, mutant_name in yield_mutants_for_module(parse(source, error_recovery=False), no_mutate_lines):
180
- if type_ == 'mutant':
181
- r.append(x)
182
- return r
183
-
184
-
185
- def test_function_with_annotation():
186
- source = "def capitalize(s : str):\n return s[0].upper() + s[1:] if s else s\n".strip()
187
- mutants = mutants_for_source(source)
188
- assert mutants == [
189
- 'def capitalize__mutmut_1(s : str):\n return s[1].upper() + s[1:] if s else s',
190
- 'def capitalize__mutmut_2(s : str):\n return s[None].upper() + s[1:] if s else s',
191
- 'def capitalize__mutmut_3(s : str):\n return s[0].upper() - s[1:] if s else s',
192
- 'def capitalize__mutmut_4(s : str):\n return s[0].upper() + s[2:] if s else s',
193
- 'def capitalize__mutmut_5(s : str):\n return s[0].upper() + s[None] if s else s'
194
- ]
195
-
196
-
197
- def test_pragma_no_mutate():
198
- source = """def foo():\n return 1+1 # pragma: no mutate\n""".strip()
199
- mutants = mutants_for_source(source)
200
- assert not mutants
201
-
202
-
203
- def test_pragma_no_mutate_and_no_cover():
204
- source = """def foo():\n return 1+1 # pragma: no cover, no mutate\n""".strip()
205
- mutants = mutants_for_source(source)
206
- assert not mutants
207
-
208
-
209
- def test_mutate_dict():
210
- source = '''
211
- def foo():
212
- dict(a=b, c=d)
213
- '''
214
- mutants = mutants_for_source(source)
215
- assert mutants == [
216
- '\ndef foo__mutmut_1(): \n dict(a=None, c=d)\n',
217
- '\ndef foo__mutmut_2(): \n dict(aXX=b, c=d)\n',
218
- '\ndef foo__mutmut_3(): \n dict(a=b, c=None)\n',
219
- '\ndef foo__mutmut_4(): \n dict(a=b, cXX=d)\n',
220
- '\ndef foo__mutmut_5(): \n dict( c=d)\n',
221
- '\ndef foo__mutmut_6(): \n dict(a=b,)\n',
222
- ]
223
-
224
-
225
- def test_syntax_error():
226
- with pytest.raises(Exception):
227
- mutants_for_source(':!')
228
-
229
-
230
- def test_bug_github_issue_18():
231
- source = """
232
- @register.simple_tag(name='icon')
233
- def icon(name):
234
- if name is None:
235
- return ''
236
- tpl = '<span class="glyphicon glyphicon-{}"></span>'
237
- return format_html(tpl, name)
238
- """.strip()
239
- mutants_for_source(source)
240
-
241
-
242
- def test_bug_github_issue_19_argument_mutation_crash():
243
- source = """key = lambda a: "foo"
244
- filters = dict((key(field), False) for field in fields)"""
245
- mutants_for_source(source)
246
-
247
-
248
- def test_bug_github_issue_26():
249
- source = """
250
- def wrapper():
251
- class ConfigurationOptions(Protocol):
252
- min_name_length: int
253
- """.strip()
254
- assert mutants_for_source(source) == []
255
-
256
-
257
- def test_bug_github_issue_30():
258
- source = """
259
- def wrapper():
260
- def from_checker(cls: Type['BaseVisitor'], checker) -> 'BaseVisitor':
261
- pass
262
- """.strip()
263
- assert mutants_for_source(source) == []
264
-
265
-
266
- def test_bug_github_issue_77():
267
- # Don't crash on this
268
- assert mutants_for_source('') == []
269
-
270
-
271
- def test_multiline_dunder_whitelist():
272
- source = """
273
- __all__ = [
274
- 1,
275
- 2,
276
- 'foo',
277
- 'bar',
278
- ]
279
- """.strip()
280
- mutants = mutants_for_source(source)
281
- assert not mutants
282
-
283
-
284
- def test_bad_mutation_str_type_definition():
285
- source = """
286
- def foo():
287
- foo: 'SomeType'
288
- """.strip()
289
- mutants = mutants_for_source(source)
290
- assert not mutants
291
-
292
-
293
- def test_orig_function_name_from_key():
294
- assert orig_function_and_class_names_from_key(f'_{CLASS_NAME_SEPARATOR}Foo{CLASS_NAME_SEPARATOR}bar__mutmut_1') == ('bar', 'Foo')
295
- assert orig_function_and_class_names_from_key('bar__mutmut_1') == ('bar', None)
296
-
297
-
298
- def test_mangle_function_name():
299
- assert mangle_function_name(name='bar', class_name=None) == 'bar'
300
- assert mangle_function_name(name='bar', class_name='Foo') == f'x{CLASS_NAME_SEPARATOR}Foo{CLASS_NAME_SEPARATOR}bar'
301
-
302
-
303
- def test_diff_ops():
304
- source = """
305
- def foo():
306
- return 1
307
-
308
-
309
- class Foo:
310
- def member(self):
311
- return 3
312
-
313
- """.strip()
314
-
315
- out = StringIO()
316
- mutant_names, hash_by_function_name = write_all_mutants_to_file(out=out, source=source, filename='filename')
317
- assert len(mutant_names) == 2
318
- mutants_source = out.getvalue()
319
-
320
- diff1 = get_diff_for_mutant(mutant_name=mutant_names[0], source=mutants_source, path='test.py').strip()
321
- diff2 = get_diff_for_mutant(mutant_name=mutant_names[1], source=mutants_source, path='test.py').strip()
322
-
323
- assert diff1 == '''
324
- --- test.py
325
- +++ test.py
326
- @@ -1,2 +1,2 @@
327
- def foo():
328
- - return 1
329
- + return 2
330
- '''.strip()
331
-
332
- assert diff2 == '''
333
- --- test.py
334
- +++ test.py
335
- @@ -1,2 +1,2 @@
336
- def member(self):
337
- - return 3
338
- + return 4
339
- '''.strip()
@@ -1,80 +0,0 @@
1
- from parso import parse
2
-
3
- from mutmut.__main__ import (
4
- trampoline_impl,
5
- yield_mutants_for_module,
6
- )
7
-
8
-
9
- def test_yield_mutants_for_module():
10
- source = """
11
- a + 1
12
-
13
- def foo(a, b, c):
14
- return a + b * c
15
- """
16
-
17
- expected = trampoline_impl + """
18
-
19
- a + 1
20
-
21
- def foo__mutmut_orig(a, b, c):
22
- return a + b * c
23
-
24
- def foo__mutmut_1(a, b, c):
25
- return a - b * c
26
-
27
- def foo__mutmut_2(a, b, c):
28
- return a + b / c
29
-
30
- foo__mutmut_mutants = {
31
- 'foo__mutmut_1': foo__mutmut_1,
32
- 'foo__mutmut_2': foo__mutmut_2
33
- }
34
-
35
- def foo(*args, **kwargs):
36
- return _mutmut_trampoline(foo__mutmut_orig, foo__mutmut_mutants, *args, **kwargs)
37
-
38
- foo.__signature__ = _mutmut_signature(foo__mutmut_orig)
39
- foo__mutmut_orig.__name__ = 'foo'
40
-
41
-
42
- """
43
-
44
- node = parse(source)
45
- result = ''.join([x[1] for x in yield_mutants_for_module(node, no_mutate_lines=[])])
46
-
47
- assert result == expected
48
-
49
-
50
- def test_avoid_annotations():
51
- source = """
52
- def foo(a: List[int]) -> int:
53
- return 1
54
- """
55
-
56
- expected = trampoline_impl + """
57
-
58
- def foo__mutmut_orig(a: List[int]) -> int:
59
- return 1
60
-
61
- def foo__mutmut_1(a: List[int]) -> int:
62
- return 2
63
-
64
- foo__mutmut_mutants = {
65
- 'foo__mutmut_1': foo__mutmut_1
66
- }
67
-
68
- def foo(*args, **kwargs):
69
- return _mutmut_trampoline(foo__mutmut_orig, foo__mutmut_mutants, *args, **kwargs)
70
-
71
- foo.__signature__ = _mutmut_signature(foo__mutmut_orig)
72
- foo__mutmut_orig.__name__ = 'foo'
73
-
74
-
75
- """
76
-
77
- node = parse(source)
78
- result = ''.join([x[1] for x in yield_mutants_for_module(node, no_mutate_lines=[])])
79
-
80
- assert result == expected
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes