flake8-assertive 2.0.0__tar.gz → 2.2.0__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,19 @@
1
+ =======
1
2
  Changes
2
3
  =======
3
4
 
5
+ 2.2.0 (2025-10-11)
6
+ ------------------
7
+
8
+ * Drop support for Python 3.7, 3.8, and 3.9. Python 3.10+ is now required.
9
+
10
+ 2.1.0 (2022-03-15)
11
+ ------------------
12
+
13
+ * Suggest using an explicit `msg` keyword argument with ``assertTrue()`` and
14
+ ``assertFalse()`` to avoid accidental two-argument misuse. This is controlled
15
+ by a new error code: ``A504``
16
+
4
17
  2.0.0 (2021-12-30)
5
18
  ------------------
6
19
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: flake8-assertive
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Flake8 unittest assert method checker
5
5
  Home-page: https://github.com/jparise/flake8-assertive
6
6
  Author: Jon Parise
@@ -9,7 +9,6 @@ License: MIT
9
9
  Project-URL: Source Code, https://github.com/jparise/flake8-assertive
10
10
  Project-URL: Issue Tracker, https://github.com/jparise/flake8-assertive/issues
11
11
  Keywords: flake8 testing unittest assert
12
- Platform: UNKNOWN
13
12
  Classifier: Development Status :: 5 - Production/Stable
14
13
  Classifier: Environment :: Console
15
14
  Classifier: Framework :: Flake8
@@ -17,16 +16,20 @@ Classifier: Intended Audience :: Developers
17
16
  Classifier: License :: OSI Approved :: MIT License
18
17
  Classifier: Programming Language :: Python
19
18
  Classifier: Programming Language :: Python :: 3 :: Only
20
- Classifier: Programming Language :: Python :: 3.7
21
- Classifier: Programming Language :: Python :: 3.8
22
- Classifier: Programming Language :: Python :: 3.9
23
19
  Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
25
  Classifier: Topic :: Software Development :: Quality Assurance
26
26
  Classifier: Topic :: Software Development :: Testing
27
27
  Classifier: Topic :: Software Development :: Testing :: Unit
28
- Requires-Python: >=3.7
28
+ Requires-Python: >=3.10
29
29
  License-File: LICENSE
30
+ Requires-Dist: flake8>=3.0.0
31
+ Dynamic: license-file
32
+ Dynamic: requires-dist
30
33
 
31
34
  =================================
32
35
  Flake8 Unittest Assertion Checker
@@ -109,6 +112,10 @@ the generic methods.
109
112
  +------------------------------------------+-----------------------------------+------+
110
113
  | ``assertNotAlmostEquals(a, b, x)`` | ``assertNotAlmostEqual(a, b, x)`` | A503 |
111
114
  +------------------------------------------+-----------------------------------+------+
115
+ | ``assertTrue(a, b)`` | ``assertTrue(a, msg=b)`` | A504 |
116
+ +------------------------------------------+-----------------------------------+------+
117
+ | ``assertFalse(a, b)`` | ``assertFalse(a, msg=b)`` | A504 |
118
+ +------------------------------------------+-----------------------------------+------+
112
119
 
113
120
  Note that some suggestions are normalized forms of the original, such as when
114
121
  a double-negative is used (``assertFalse(a != b)`` → ``assertEqual(a, b)``).
@@ -131,7 +138,7 @@ that it has been loaded by inspecting the ``flake8 --version`` string.
131
138
  .. code-block:: sh
132
139
 
133
140
  $ flake8 --version
134
- 4.0.1 (assertive: 2.0.0, ...) CPython 3.8.6 on Darwin
141
+ 4.0.1 (assertive: 2.1.0, ...) CPython 3.9.10 on Darwin
135
142
 
136
143
 
137
144
  Error Codes
@@ -143,6 +150,7 @@ This extension adds three new `error codes`__ (using the ``A50`` prefix):
143
150
  - ``A501``: prefer *{func}* for '*{op}*' expressions
144
151
  - ``A502``: prefer *{func}* instead of comparing to *{obj}*
145
152
  - ``A503``: use *{func}* instead of the deprecated *{name}*
153
+ - ``A504``: prefer the 'msg=' kwarg for *{func}* diagnostics
146
154
 
147
155
  .. __: https://flake8.pycqa.org/en/latest/user/error-codes.html
148
156
 
@@ -190,33 +198,32 @@ values of ``a`` and ``b``.
190
198
 
191
199
  Suggested by: `Serhiy Storchaka <https://twitter.com/SerhiyStorchaka>`_
192
200
 
201
+ Alternatives
202
+ ------------
203
+
204
+ - `Teyit <https://github.com/isidentical/teyit>`_ is a Python unit test formatter that
205
+ can perform similar assertion transformations.
206
+
193
207
  .. |PyPI Version| image:: https://img.shields.io/pypi/v/flake8-assertive.svg
194
208
  :target: https://pypi.python.org/pypi/flake8-assertive
195
209
  .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/flake8-assertive.svg
196
210
  :target: https://pypi.python.org/pypi/flake8-assertive
197
211
 
198
- Copyright (c) 2018-present Jon Parise
212
+ =======
213
+ Changes
214
+ =======
199
215
 
200
- Permission is hereby granted, free of charge, to any person obtaining a copy
201
- of this software and associated documentation files (the "Software"), to deal
202
- in the Software without restriction, including without limitation the rights
203
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
204
- copies of the Software, and to permit persons to whom the Software is
205
- furnished to do so, subject to the following conditions:
216
+ 2.2.0 (2025-10-11)
217
+ ------------------
206
218
 
207
- The above copyright notice and this permission notice shall be included in all
208
- copies or substantial portions of the Software.
219
+ * Drop support for Python 3.7, 3.8, and 3.9. Python 3.10+ is now required.
209
220
 
210
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
211
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
212
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
213
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
214
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
215
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
216
- SOFTWARE.
221
+ 2.1.0 (2022-03-15)
222
+ ------------------
217
223
 
218
- Changes
219
- =======
224
+ * Suggest using an explicit `msg` keyword argument with ``assertTrue()`` and
225
+ ``assertFalse()`` to avoid accidental two-argument misuse. This is controlled
226
+ by a new error code: ``A504``
220
227
 
221
228
  2.0.0 (2021-12-30)
222
229
  ------------------
@@ -267,5 +274,3 @@ Changes
267
274
  ------------------
268
275
 
269
276
  * Initial beta release
270
-
271
-
@@ -79,6 +79,10 @@ the generic methods.
79
79
  +------------------------------------------+-----------------------------------+------+
80
80
  | ``assertNotAlmostEquals(a, b, x)`` | ``assertNotAlmostEqual(a, b, x)`` | A503 |
81
81
  +------------------------------------------+-----------------------------------+------+
82
+ | ``assertTrue(a, b)`` | ``assertTrue(a, msg=b)`` | A504 |
83
+ +------------------------------------------+-----------------------------------+------+
84
+ | ``assertFalse(a, b)`` | ``assertFalse(a, msg=b)`` | A504 |
85
+ +------------------------------------------+-----------------------------------+------+
82
86
 
83
87
  Note that some suggestions are normalized forms of the original, such as when
84
88
  a double-negative is used (``assertFalse(a != b)`` → ``assertEqual(a, b)``).
@@ -101,7 +105,7 @@ that it has been loaded by inspecting the ``flake8 --version`` string.
101
105
  .. code-block:: sh
102
106
 
103
107
  $ flake8 --version
104
- 4.0.1 (assertive: 2.0.0, ...) CPython 3.8.6 on Darwin
108
+ 4.0.1 (assertive: 2.1.0, ...) CPython 3.9.10 on Darwin
105
109
 
106
110
 
107
111
  Error Codes
@@ -113,6 +117,7 @@ This extension adds three new `error codes`__ (using the ``A50`` prefix):
113
117
  - ``A501``: prefer *{func}* for '*{op}*' expressions
114
118
  - ``A502``: prefer *{func}* instead of comparing to *{obj}*
115
119
  - ``A503``: use *{func}* instead of the deprecated *{name}*
120
+ - ``A504``: prefer the 'msg=' kwarg for *{func}* diagnostics
116
121
 
117
122
  .. __: https://flake8.pycqa.org/en/latest/user/error-codes.html
118
123
 
@@ -160,6 +165,12 @@ values of ``a`` and ``b``.
160
165
 
161
166
  Suggested by: `Serhiy Storchaka <https://twitter.com/SerhiyStorchaka>`_
162
167
 
168
+ Alternatives
169
+ ------------
170
+
171
+ - `Teyit <https://github.com/isidentical/teyit>`_ is a Python unit test formatter that
172
+ can perform similar assertion transformations.
173
+
163
174
  .. |PyPI Version| image:: https://img.shields.io/pypi/v/flake8-assertive.svg
164
175
  :target: https://pypi.python.org/pypi/flake8-assertive
165
176
  .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/flake8-assertive.svg
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: flake8-assertive
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Flake8 unittest assert method checker
5
5
  Home-page: https://github.com/jparise/flake8-assertive
6
6
  Author: Jon Parise
@@ -9,7 +9,6 @@ License: MIT
9
9
  Project-URL: Source Code, https://github.com/jparise/flake8-assertive
10
10
  Project-URL: Issue Tracker, https://github.com/jparise/flake8-assertive/issues
11
11
  Keywords: flake8 testing unittest assert
12
- Platform: UNKNOWN
13
12
  Classifier: Development Status :: 5 - Production/Stable
14
13
  Classifier: Environment :: Console
15
14
  Classifier: Framework :: Flake8
@@ -17,16 +16,20 @@ Classifier: Intended Audience :: Developers
17
16
  Classifier: License :: OSI Approved :: MIT License
18
17
  Classifier: Programming Language :: Python
19
18
  Classifier: Programming Language :: Python :: 3 :: Only
20
- Classifier: Programming Language :: Python :: 3.7
21
- Classifier: Programming Language :: Python :: 3.8
22
- Classifier: Programming Language :: Python :: 3.9
23
19
  Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
25
  Classifier: Topic :: Software Development :: Quality Assurance
26
26
  Classifier: Topic :: Software Development :: Testing
27
27
  Classifier: Topic :: Software Development :: Testing :: Unit
28
- Requires-Python: >=3.7
28
+ Requires-Python: >=3.10
29
29
  License-File: LICENSE
30
+ Requires-Dist: flake8>=3.0.0
31
+ Dynamic: license-file
32
+ Dynamic: requires-dist
30
33
 
31
34
  =================================
32
35
  Flake8 Unittest Assertion Checker
@@ -109,6 +112,10 @@ the generic methods.
109
112
  +------------------------------------------+-----------------------------------+------+
110
113
  | ``assertNotAlmostEquals(a, b, x)`` | ``assertNotAlmostEqual(a, b, x)`` | A503 |
111
114
  +------------------------------------------+-----------------------------------+------+
115
+ | ``assertTrue(a, b)`` | ``assertTrue(a, msg=b)`` | A504 |
116
+ +------------------------------------------+-----------------------------------+------+
117
+ | ``assertFalse(a, b)`` | ``assertFalse(a, msg=b)`` | A504 |
118
+ +------------------------------------------+-----------------------------------+------+
112
119
 
113
120
  Note that some suggestions are normalized forms of the original, such as when
114
121
  a double-negative is used (``assertFalse(a != b)`` → ``assertEqual(a, b)``).
@@ -131,7 +138,7 @@ that it has been loaded by inspecting the ``flake8 --version`` string.
131
138
  .. code-block:: sh
132
139
 
133
140
  $ flake8 --version
134
- 4.0.1 (assertive: 2.0.0, ...) CPython 3.8.6 on Darwin
141
+ 4.0.1 (assertive: 2.1.0, ...) CPython 3.9.10 on Darwin
135
142
 
136
143
 
137
144
  Error Codes
@@ -143,6 +150,7 @@ This extension adds three new `error codes`__ (using the ``A50`` prefix):
143
150
  - ``A501``: prefer *{func}* for '*{op}*' expressions
144
151
  - ``A502``: prefer *{func}* instead of comparing to *{obj}*
145
152
  - ``A503``: use *{func}* instead of the deprecated *{name}*
153
+ - ``A504``: prefer the 'msg=' kwarg for *{func}* diagnostics
146
154
 
147
155
  .. __: https://flake8.pycqa.org/en/latest/user/error-codes.html
148
156
 
@@ -190,33 +198,32 @@ values of ``a`` and ``b``.
190
198
 
191
199
  Suggested by: `Serhiy Storchaka <https://twitter.com/SerhiyStorchaka>`_
192
200
 
201
+ Alternatives
202
+ ------------
203
+
204
+ - `Teyit <https://github.com/isidentical/teyit>`_ is a Python unit test formatter that
205
+ can perform similar assertion transformations.
206
+
193
207
  .. |PyPI Version| image:: https://img.shields.io/pypi/v/flake8-assertive.svg
194
208
  :target: https://pypi.python.org/pypi/flake8-assertive
195
209
  .. |Python Versions| image:: https://img.shields.io/pypi/pyversions/flake8-assertive.svg
196
210
  :target: https://pypi.python.org/pypi/flake8-assertive
197
211
 
198
- Copyright (c) 2018-present Jon Parise
212
+ =======
213
+ Changes
214
+ =======
199
215
 
200
- Permission is hereby granted, free of charge, to any person obtaining a copy
201
- of this software and associated documentation files (the "Software"), to deal
202
- in the Software without restriction, including without limitation the rights
203
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
204
- copies of the Software, and to permit persons to whom the Software is
205
- furnished to do so, subject to the following conditions:
216
+ 2.2.0 (2025-10-11)
217
+ ------------------
206
218
 
207
- The above copyright notice and this permission notice shall be included in all
208
- copies or substantial portions of the Software.
219
+ * Drop support for Python 3.7, 3.8, and 3.9. Python 3.10+ is now required.
209
220
 
210
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
211
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
212
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
213
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
214
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
215
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
216
- SOFTWARE.
221
+ 2.1.0 (2022-03-15)
222
+ ------------------
217
223
 
218
- Changes
219
- =======
224
+ * Suggest using an explicit `msg` keyword argument with ``assertTrue()`` and
225
+ ``assertFalse()`` to avoid accidental two-argument misuse. This is controlled
226
+ by a new error code: ``A504``
220
227
 
221
228
  2.0.0 (2021-12-30)
222
229
  ------------------
@@ -267,5 +274,3 @@ Changes
267
274
  ------------------
268
275
 
269
276
  * Initial beta release
270
-
271
-
@@ -11,4 +11,5 @@ flake8_assertive.egg-info/dependency_links.txt
11
11
  flake8_assertive.egg-info/entry_points.txt
12
12
  flake8_assertive.egg-info/requires.txt
13
13
  flake8_assertive.egg-info/top_level.txt
14
- flake8_assertive.egg-info/zip-safe
14
+ flake8_assertive.egg-info/zip-safe
15
+ tests/test_checker.py
@@ -1,3 +1,2 @@
1
1
  [flake8.extension]
2
2
  A50 = flake8_assertive:Checker
3
-
@@ -24,29 +24,31 @@ import ast
24
24
  import fnmatch
25
25
  import re
26
26
 
27
- __all__ = ['Checker']
28
- __version__ = '2.0.0'
27
+ __all__ = ["Checker"]
28
+ __version__ = "2.2.0"
29
29
 
30
30
 
31
- # Python 3.4 introduced `ast.NameConstant` for `None`, `True`, and `False`.
32
- if hasattr(ast, 'NameConstant'):
33
- def is_constant(node, obj):
34
- return isinstance(node, ast.NameConstant) and node.value is obj
35
- else:
36
- def is_constant(node, obj):
37
- return isinstance(node, ast.Name) and node.id == str(obj)
31
+ Constant = ast.Constant if hasattr(ast, "Constant") else ast.NameConstant
32
+
33
+
34
+ def is_constant(node, obj):
35
+ return isinstance(node, Constant) and node.value is obj
38
36
 
39
37
 
40
38
  def is_function_call(node, name):
41
- return (isinstance(node, ast.Call) and
42
- isinstance(node.func, ast.Name) and
43
- node.func.id == name)
39
+ return (
40
+ isinstance(node, ast.Call)
41
+ and isinstance(node.func, ast.Name)
42
+ and node.func.id == name
43
+ )
44
44
 
45
45
 
46
46
  def is_assert_method_call(node):
47
- return (isinstance(node, ast.Call) and
48
- isinstance(node.func, ast.Attribute) and
49
- node.func.attr.startswith('assert'))
47
+ return (
48
+ isinstance(node, ast.Call)
49
+ and isinstance(node.func, ast.Attribute)
50
+ and node.func.attr.startswith("assert")
51
+ )
50
52
 
51
53
 
52
54
  def args(node):
@@ -63,18 +65,20 @@ def wrap_deprecated(func, name):
63
65
  check function doesn't yield any errors of its own, this function will
64
66
  yield an A503 error that includes the new name of the deprecated method.
65
67
  """
68
+
66
69
  def wrapper(self, node):
67
70
  for error in func(self, node):
68
71
  yield error
69
72
  else:
70
- yield self.error(node, 'A503', func=name, name=node.func.attr)
73
+ yield self.error(node, "A503", func=name, name=node.func.attr)
74
+
71
75
  return wrapper
72
76
 
73
77
 
74
- class Checker(object):
78
+ class Checker:
75
79
  """Unittest assert method checker"""
76
80
 
77
- name = 'assertive'
81
+ name = "assertive"
78
82
  version = __version__
79
83
  pattern = None
80
84
  snakecase = False
@@ -83,6 +87,7 @@ class Checker(object):
83
87
  A501 = "prefer {func}() for '{op}' expressions"
84
88
  A502 = "prefer {func}() instead of comparing to {obj}"
85
89
  A503 = "use {func}() instead of the deprecated {name}()"
90
+ A504 = "prefer the 'msg=' kwarg for {func}() diagnostics"
86
91
 
87
92
  def __init__(self, tree, filename):
88
93
  self.tree = tree
@@ -91,16 +96,18 @@ class Checker(object):
91
96
  @classmethod
92
97
  def add_options(cls, parser):
93
98
  parser.add_option(
94
- '--assertive-snakecase',
99
+ "--assertive-snakecase",
95
100
  help="Use snake_case assert method names ('assert_true()')",
96
- action='store_true',
101
+ action="store_true",
97
102
  default=False,
98
- parse_from_config=True)
103
+ parse_from_config=True,
104
+ )
99
105
  parser.add_option(
100
- '--assertive-test-pattern',
106
+ "--assertive-test-pattern",
101
107
  help="fnmatch() pattern for identifying unittest test files",
102
108
  default=None,
103
- parse_from_config=True)
109
+ parse_from_config=True,
110
+ )
104
111
 
105
112
  @classmethod
106
113
  def parse_options(cls, options):
@@ -109,8 +116,8 @@ class Checker(object):
109
116
 
110
117
  def error(self, node, code, func, **kwargs):
111
118
  if self.snakecase:
112
- func = re.sub(r'([A-Z])', r'_\1', func).lower()
113
- message = code + ' ' + getattr(self, code).format(func=func, **kwargs)
119
+ func = re.sub(r"([A-Z])", r"_\1", func).lower()
120
+ message = code + " " + getattr(self, code).format(func=func, **kwargs)
114
121
  return (node.lineno, node.col_offset, message, self)
115
122
 
116
123
  def run(self):
@@ -121,120 +128,118 @@ class Checker(object):
121
128
  # Visit all of the assert method calls in the tree.
122
129
  for node in ast.walk(self.tree):
123
130
  if is_assert_method_call(node):
124
- name = node.func.attr.lower().replace('_', '')
125
- func = getattr(self, 'check_' + name, None)
131
+ name = node.func.attr.lower().replace("_", "")
132
+ func = getattr(self, "check_" + name, None)
126
133
  if func is not None:
127
134
  for error in func(node):
128
135
  yield error
129
136
 
130
137
  def check_assertequal(self, node):
131
138
  if any(arg for arg in args(node) if is_constant(arg, None)):
132
- yield self.error(node, 'A502', 'assertIsNone', obj=None)
139
+ yield self.error(node, "A502", "assertIsNone", obj=None)
133
140
  elif any(arg for arg in args(node) if is_constant(arg, True)):
134
- yield self.error(node, 'A502', 'assertTrue', obj=True)
141
+ yield self.error(node, "A502", "assertTrue", obj=True)
135
142
  elif any(arg for arg in args(node) if is_constant(arg, False)):
136
- yield self.error(node, 'A502', 'assertFalse', obj=False)
137
- elif any(arg for arg in args(node) if is_function_call(arg, 'round')):
138
- yield self.error(node, 'A501',
139
- 'built-in rounding of assertAlmostEqual',
140
- op='round')
143
+ yield self.error(node, "A502", "assertFalse", obj=False)
144
+ elif any(arg for arg in args(node) if is_function_call(arg, "round")):
145
+ yield self.error(
146
+ node, "A501", "built-in rounding of assertAlmostEqual", op="round"
147
+ )
141
148
 
142
149
  def check_assertalmostequal(self, node):
143
- if any(arg for arg in args(node) if is_function_call(arg, 'round')):
144
- yield self.error(node, 'A501',
145
- 'built-in rounding of assertAlmostEqual',
146
- op='round')
150
+ if any(arg for arg in args(node) if is_function_call(arg, "round")):
151
+ yield self.error(
152
+ node, "A501", "built-in rounding of assertAlmostEqual", op="round"
153
+ )
147
154
 
148
155
  def check_assertnotequal(self, node):
149
156
  if any(arg for arg in args(node) if is_constant(arg, None)):
150
- yield self.error(node, 'A502', 'assertIsNotNone', obj=None)
157
+ yield self.error(node, "A502", "assertIsNotNone", obj=None)
151
158
  elif any(arg for arg in args(node) if is_constant(arg, True)):
152
- yield self.error(node, 'A502', 'assertFalse', obj=True)
159
+ yield self.error(node, "A502", "assertFalse", obj=True)
153
160
  elif any(arg for arg in args(node) if is_constant(arg, False)):
154
- yield self.error(node, 'A502', 'assertTrue', obj=False)
155
- elif any(arg for arg in args(node) if is_function_call(arg, 'round')):
156
- yield self.error(node, 'A501',
157
- 'built-in rounding of assertNotAlmostEqual',
158
- op='round')
161
+ yield self.error(node, "A502", "assertTrue", obj=False)
162
+ elif any(arg for arg in args(node) if is_function_call(arg, "round")):
163
+ yield self.error(
164
+ node, "A501", "built-in rounding of assertNotAlmostEqual", op="round"
165
+ )
159
166
 
160
167
  def check_assertnotalmostequal(self, node):
161
- if any(arg for arg in args(node) if is_function_call(arg, 'round')):
162
- yield self.error(node, 'A501',
163
- 'built-in rounding of assertNotAlmostEqual',
164
- op='round')
168
+ if any(arg for arg in args(node) if is_function_call(arg, "round")):
169
+ yield self.error(
170
+ node, "A501", "built-in rounding of assertNotAlmostEqual", op="round"
171
+ )
165
172
 
166
173
  def check_asserttrue(self, node):
174
+ if len(node.args) > 1:
175
+ yield self.error(node, "A504", "assertTrue")
167
176
  arg = next(args(node), None)
168
177
  if arg and isinstance(arg, ast.Compare) and len(arg.ops) == 1:
169
178
  op = arg.ops[0]
170
179
  if isinstance(op, ast.In):
171
- yield self.error(node, 'A501', 'assertIn', op='in')
180
+ yield self.error(node, "A501", "assertIn", op="in")
172
181
  elif isinstance(op, ast.NotIn):
173
- yield self.error(node, 'A501', 'assertNotIn', op='in')
182
+ yield self.error(node, "A501", "assertNotIn", op="in")
174
183
  elif isinstance(op, ast.Is):
175
184
  if is_constant(arg.comparators[0], None):
176
- yield self.error(node, 'A502', 'assertIsNone', obj=None)
185
+ yield self.error(node, "A502", "assertIsNone", obj=None)
177
186
  else:
178
- yield self.error(node, 'A501', 'assertIs', op='is')
187
+ yield self.error(node, "A501", "assertIs", op="is")
179
188
  elif isinstance(op, ast.IsNot):
180
189
  if is_constant(arg.comparators[0], None):
181
- yield self.error(node, 'A502', 'assertIsNotNone', obj=None)
190
+ yield self.error(node, "A502", "assertIsNotNone", obj=None)
182
191
  else:
183
- yield self.error(node, 'A501', 'assertIsNot', op='is')
192
+ yield self.error(node, "A501", "assertIsNot", op="is")
184
193
  elif isinstance(op, ast.Eq):
185
- yield self.error(node, 'A500', 'assertEqual', op='==')
194
+ yield self.error(node, "A500", "assertEqual", op="==")
186
195
  elif isinstance(op, ast.NotEq):
187
- yield self.error(node, 'A500', 'assertNotEqual', op='!=')
196
+ yield self.error(node, "A500", "assertNotEqual", op="!=")
188
197
  elif isinstance(op, ast.Lt):
189
- yield self.error(node, 'A500', 'assertLess', op='<')
198
+ yield self.error(node, "A500", "assertLess", op="<")
190
199
  elif isinstance(op, ast.LtE):
191
- yield self.error(node, 'A500', 'assertLessEqual', op='<=')
200
+ yield self.error(node, "A500", "assertLessEqual", op="<=")
192
201
  elif isinstance(op, ast.Gt):
193
- yield self.error(node, 'A500', 'assertGreater', op='>')
202
+ yield self.error(node, "A500", "assertGreater", op=">")
194
203
  elif isinstance(op, ast.GtE):
195
- yield self.error(node, 'A500', 'assertGreaterEqual', op='>=')
196
- elif is_function_call(arg, 'isinstance'):
197
- yield self.error(
198
- node, 'A501', 'assertIsInstance', op='isinstance()')
204
+ yield self.error(node, "A500", "assertGreaterEqual", op=">=")
205
+ elif is_function_call(arg, "isinstance"):
206
+ yield self.error(node, "A501", "assertIsInstance", op="isinstance()")
199
207
 
200
208
  def check_assertfalse(self, node):
209
+ if len(node.args) > 1:
210
+ yield self.error(node, "A504", "assertFalse")
201
211
  arg = next(args(node), None)
202
212
  if arg and isinstance(arg, ast.Compare) and len(arg.ops) == 1:
203
213
  op = arg.ops[0]
204
214
  if isinstance(op, ast.In):
205
- yield self.error(node, 'A501', 'assertNotIn', op='in')
215
+ yield self.error(node, "A501", "assertNotIn", op="in")
206
216
  elif isinstance(op, ast.NotIn):
207
- yield self.error(node, 'A501', 'assertIn', op='in')
217
+ yield self.error(node, "A501", "assertIn", op="in")
208
218
  elif isinstance(op, ast.Is):
209
219
  if is_constant(arg.comparators[0], None):
210
- yield self.error(node, 'A502', 'assertIsNotNone', obj=None)
220
+ yield self.error(node, "A502", "assertIsNotNone", obj=None)
211
221
  else:
212
- yield self.error(node, 'A501', 'assertIsNot', op='is')
222
+ yield self.error(node, "A501", "assertIsNot", op="is")
213
223
  elif isinstance(op, ast.IsNot):
214
224
  if is_constant(arg.comparators[0], None):
215
- yield self.error(node, 'A502', 'assertIsNone', obj=None)
225
+ yield self.error(node, "A502", "assertIsNone", obj=None)
216
226
  else:
217
- yield self.error(node, 'A501', 'assertIs', op='is')
227
+ yield self.error(node, "A501", "assertIs", op="is")
218
228
  elif isinstance(op, ast.Eq):
219
- yield self.error(node, 'A500', 'assertNotEqual', op='==')
229
+ yield self.error(node, "A500", "assertNotEqual", op="==")
220
230
  elif isinstance(op, ast.NotEq):
221
- yield self.error(node, 'A500', 'assertEqual', op='!=')
222
- elif is_function_call(arg, 'isinstance'):
223
- yield self.error(
224
- node, 'A501', 'assertNotIsInstance', op='isinstance()')
231
+ yield self.error(node, "A500", "assertEqual", op="!=")
232
+ elif is_function_call(arg, "isinstance"):
233
+ yield self.error(node, "A501", "assertNotIsInstance", op="isinstance()")
225
234
 
226
- check_assertequals = wrap_deprecated(
227
- check_assertequal,
228
- 'assertEqual')
235
+ check_assertequals = wrap_deprecated(check_assertequal, "assertEqual")
229
236
 
230
- check_assertnotequals = wrap_deprecated(
231
- check_assertnotequal,
232
- 'assertNotEqual')
237
+ check_assertnotequals = wrap_deprecated(check_assertnotequal, "assertNotEqual")
233
238
 
234
239
  check_assertalmostequals = wrap_deprecated(
235
- check_assertalmostequal,
236
- 'assertAlmostEqual')
240
+ check_assertalmostequal, "assertAlmostEqual"
241
+ )
237
242
 
238
243
  check_assertnotalmostequals = wrap_deprecated(
239
- check_assertnotalmostequal,
240
- 'assertNotAlmostEqual')
244
+ check_assertnotalmostequal, "assertNotAlmostEqual"
245
+ )
@@ -4,7 +4,7 @@ version = attr: flake8_assertive.__version__
4
4
  author = Jon Parise
5
5
  author_email = jon@indelible.org
6
6
  description = Flake8 unittest assert method checker
7
- long_description = file: README.rst, LICENSE, CHANGELOG.rst
7
+ long_description = file: README.rst, CHANGELOG.rst
8
8
  license = MIT
9
9
  url = https://github.com/jparise/flake8-assertive
10
10
  project_urls =
@@ -19,10 +19,11 @@ classifiers =
19
19
  License :: OSI Approved :: MIT License
20
20
  Programming Language :: Python
21
21
  Programming Language :: Python :: 3 :: Only
22
- Programming Language :: Python :: 3.7
23
- Programming Language :: Python :: 3.8
24
- Programming Language :: Python :: 3.9
25
22
  Programming Language :: Python :: 3.10
23
+ Programming Language :: Python :: 3.11
24
+ Programming Language :: Python :: 3.12
25
+ Programming Language :: Python :: 3.13
26
+ Programming Language :: Python :: 3.14
26
27
  Topic :: Software Development :: Libraries :: Python Modules
27
28
  Topic :: Software Development :: Quality Assurance
28
29
  Topic :: Software Development :: Testing
@@ -30,7 +31,7 @@ classifiers =
30
31
 
31
32
  [options]
32
33
  py_modules = flake8_assertive
33
- python_requires = >= 3.7
34
+ python_requires = >= 3.10
34
35
  zip_safe = True
35
36
 
36
37
  [options.entry_points]
@@ -39,6 +40,8 @@ flake8.extension =
39
40
 
40
41
  [flake8]
41
42
  exclude = .eggs/,.git/,.venv/,build/,dist/
43
+ extend-ignore = E203
44
+ max-line-length = 88
42
45
 
43
46
  [egg_info]
44
47
  tag_build =
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env python
2
+
3
+ from setuptools import setup
4
+
5
+ setup(
6
+ name="flake8-assertive",
7
+ install_requires=["flake8>=3.0.0"],
8
+ tests_require=["flake8>=3.0.0"],
9
+ test_suite="tests",
10
+ )
@@ -0,0 +1,204 @@
1
+ import ast
2
+ import re
3
+ import unittest
4
+
5
+ from flake8_assertive import Checker
6
+
7
+
8
+ class TestChecks(unittest.TestCase):
9
+ def tearDown(self):
10
+ Checker.pattern = None
11
+ Checker.snakecase = False
12
+
13
+ def check(self, code, expected=None, pattern=None, filename="test.py"):
14
+ tree = ast.parse(code, filename)
15
+ checker = Checker(tree, filename)
16
+ error = next(checker.run(), None)
17
+
18
+ if expected is None:
19
+ return self.assertIsNone(error)
20
+
21
+ self.assertIsNotNone(error, "expected {0} error".format(expected))
22
+ self.assertEqual(expected, error[2].split(" ")[0])
23
+ if pattern is not None:
24
+ self.assertRegex(error[2], re.escape(pattern))
25
+
26
+ def test_assertequal_none(self):
27
+ self.check("self.assertEqual(None, 1)", "A502", "assertIsNone()")
28
+ self.check("self.assertEqual(1, None)", "A502", "assertIsNone()")
29
+
30
+ def test_assertequal_true(self):
31
+ self.check("self.assertEqual(True, a)", "A502", "assertTrue()")
32
+ self.check("self.assertEqual(a, True)", "A502", "assertTrue()")
33
+
34
+ def test_assertequal_false(self):
35
+ self.check("self.assertEqual(False, a)", "A502", "assertFalse()")
36
+ self.check("self.assertEqual(a, False)", "A502", "assertFalse()")
37
+
38
+ def test_assertequal_round(self):
39
+ self.check(
40
+ "self.assertEqual(1.01, round(a, 2))",
41
+ "A501",
42
+ "built-in rounding of assertAlmostEqual()",
43
+ )
44
+ self.check(
45
+ "self.assertEqual(round(a, 2), 1.01)",
46
+ "A501",
47
+ "built-in rounding of assertAlmostEqual()",
48
+ )
49
+
50
+ def test_assertnotequal_none(self):
51
+ self.check("self.assertNotEqual(None, 1)", "A502", "assertIsNotNone()")
52
+ self.check("self.assertNotEqual(1, None)", "A502", "assertIsNotNone()")
53
+
54
+ def test_assertnotequal_true(self):
55
+ self.check("self.assertNotEqual(True, a)", "A502", "assertFalse()")
56
+ self.check("self.assertNotEqual(a, True)", "A502", "assertFalse()")
57
+
58
+ def test_assertnotequal_false(self):
59
+ self.check("self.assertNotEqual(False, a)", "A502", "assertTrue()")
60
+ self.check("self.assertNotEqual(a, False)", "A502", "assertTrue()")
61
+
62
+ def test_assertnotequal_round(self):
63
+ self.check(
64
+ "self.assertNotEqual(1.01, round(a, 2))",
65
+ "A501",
66
+ "built-in rounding of assertNotAlmostEqual()",
67
+ )
68
+ self.check(
69
+ "self.assertNotEqual(round(a, 2), 1.01)",
70
+ "A501",
71
+ "built-in rounding of assertNotAlmostEqual()",
72
+ )
73
+
74
+ def test_assertequals(self):
75
+ self.check("self.assertEquals(True, a)", "A502", "assertTrue()")
76
+
77
+ def test_assertnotequals(self):
78
+ self.check("self.assertNotEquals(True, a)", "A502", "assertFalse()")
79
+
80
+ def test_assertalmostequal_round(self):
81
+ self.check(
82
+ "self.assertAlmostEqual(1.01, round(a, 2))",
83
+ "A501",
84
+ "built-in rounding of assertAlmostEqual()",
85
+ )
86
+ self.check(
87
+ "self.assertAlmostEqual(round(a, 2), 1.01)",
88
+ "A501",
89
+ "built-in rounding of assertAlmostEqual()",
90
+ )
91
+
92
+ def test_assertalmostequals(self):
93
+ self.check(
94
+ "self.assertEquals(1.01, round(a, 2))",
95
+ "A501",
96
+ "built-in rounding of assertAlmostEqual()",
97
+ )
98
+
99
+ def test_assertnotalmostequal_round(self):
100
+ self.check(
101
+ "self.assertNotAlmostEqual(1.01, round(a, 2))",
102
+ "A501",
103
+ "built-in rounding of assertNotAlmostEqual()",
104
+ )
105
+ self.check(
106
+ "self.assertNotAlmostEqual(round(a, 2), 1.01)",
107
+ "A501",
108
+ "built-in rounding of assertNotAlmostEqual()",
109
+ )
110
+
111
+ def test_assertnotalmostequals(self):
112
+ self.check(
113
+ "self.assertNotAlmostEquals(1.01, round(a, 2))",
114
+ "A501",
115
+ "built-in rounding of assertNotAlmostEqual()",
116
+ )
117
+
118
+ def test_asserttrue_is(self):
119
+ self.check("self.assertTrue(True is True)", "A501", "assertIs()")
120
+ self.check("self.assertTrue(True is not False)", "A501", "assertIsNot()")
121
+
122
+ def test_asserttrue_is_none(self):
123
+ self.check("self.assertTrue(a is None)", "A502", "assertIsNone()")
124
+ self.check("self.assertTrue(a is not None)", "A502", "assertIsNotNone()")
125
+
126
+ def test_assertfalse_is(self):
127
+ self.check("self.assertFalse(True is False)", "A501", "assertIsNot()")
128
+ self.check("self.assertFalse(True is not True)", "A501", "assertIs()")
129
+
130
+ def test_assertfalse_is_none(self):
131
+ self.check("self.assertFalse(a is None)", "A502", "assertIsNotNone()")
132
+ self.check("self.assertFalse(a is not None)", "A502", "assertIsNone()")
133
+
134
+ def test_asserttrue_in(self):
135
+ self.check("self.assertTrue(1 in [1])", "A501", "assertIn()")
136
+ self.check("self.assertTrue(1 not in [2])", "A501", "assertNotIn()")
137
+
138
+ def test_assertfalse_in(self):
139
+ self.check("self.assertFalse(1 in [2])", "A501", "assertNotIn()")
140
+ self.check("self.assertFalse(1 not in [1])", "A501", "assertIn()")
141
+
142
+ def test_asserttrue_equal(self):
143
+ self.check("self.assertTrue(1 == 1)", "A500", "assertEqual() for '=='")
144
+ self.check("self.assertTrue(1 != 1)", "A500", "assertNotEqual() for '!='")
145
+
146
+ def test_asserttrue_less(self):
147
+ self.check("self.assertTrue(0 < 1)", "A500", "assertLess() for '<'")
148
+ self.check("self.assertTrue(0 <= 1)", "A500", "assertLessEqual() for '<='")
149
+
150
+ def test_asserttrue_greater(self):
151
+ self.check("self.assertTrue(1 > 0)", "A500", "assertGreater() for '>'")
152
+ self.check("self.assertTrue(1 >= 0)", "A500", "assertGreaterEqual() for '>='")
153
+
154
+ def test_asserttrue_isinstance(self):
155
+ self.check(
156
+ "self.assertTrue(isinstance(True, bool))",
157
+ "A501",
158
+ "assertIsInstance() for 'isinstance()'",
159
+ )
160
+
161
+ def test_assertfalse_isinstance(self):
162
+ self.check(
163
+ "self.assertFalse(isinstance(True, bool))",
164
+ "A501",
165
+ "assertNotIsInstance() for 'isinstance()'",
166
+ )
167
+
168
+ def test_assertfalse_equal(self):
169
+ self.check("self.assertFalse(1 == 1)", "A500", "assertNotEqual() for '=='")
170
+ self.check("self.assertFalse(1 != 0)", "A500", "assertEqual() for '!='")
171
+
172
+ def test_keyword_args(self):
173
+ self.check("self.assertTrue(expr=1)", expected=None)
174
+ self.check("self.assertTrue(expr=(True is True))", expected="A501")
175
+ self.check("self.assertEqual(first=1, second=1)", expected=None)
176
+ self.check("self.assertEqual(first=1, second=None)", "A502")
177
+ self.check("self.assertEqual(first=None, second=1)", "A502")
178
+ self.check("self.assertEqual(1, second=1)", expected=None)
179
+ self.check("self.assertEqual(None, second=1)", "A502")
180
+
181
+ def test_multiple_comparison_ops(self):
182
+ self.check("self.assertTrue(1 == 1 == 1)", expected=None)
183
+ self.check("self.assertFalse(1 == 1 == 1)", expected=None)
184
+
185
+ def test_pattern(self):
186
+ Checker.pattern = "[a-m]*.py"
187
+ self.check("self.assertTrue(1 == 1)", expected="A500", filename="a.py")
188
+ self.check("self.assertTrue(1 == 1)", expected=None, filename="z.py")
189
+
190
+ def test_snakecase(self):
191
+ Checker.snakecase = True
192
+ self.check("self.assert_equal(True, a)", "A502", "assert_true()")
193
+
194
+ def test_deprecated(self):
195
+ self.check("self.assertEquals(True, a)", "A502", "assertTrue()")
196
+ self.check("self.assertEquals(a, b)", "A503", "assertEqual()")
197
+
198
+ def test_asserttrue_misuse(self):
199
+ self.check("self.assertTrue(a, 'foo')", expected="A504")
200
+ self.check("self.assertTrue(a, msg='foo')", expected=None)
201
+
202
+ def test_assertfalse_misuse(self):
203
+ self.check("self.assertFalse(a, 'foo')", expected="A504")
204
+ self.check("self.assertFalse(a, msg='foo')", expected=None)
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- from setuptools import setup
4
-
5
-
6
- setup(
7
- name='flake8-assertive',
8
- install_requires=['flake8>=3.0.0'],
9
- tests_require=['flake8>=3.0.0'],
10
- test_suite='tests',
11
- )