Skip to content

Commit 2d066ae

Browse files
authored
Merge pull request #143 from dflook/fix-debug
2 parents c63a92b + fe44e5f commit 2d066ae

File tree

3 files changed

+92
-8
lines changed

3 files changed

+92
-8
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ and will output source code compatible with the version of the interpreter it is
1010
This means that if you minify code written for Python 3.11 using python-minifier running with Python 3.12,
1111
the minified code may only run with Python 3.12.
1212

13+
## [3.1.1] - 2025-12-11
14+
15+
### Fixed
16+
- The remove debug transform could incorrectly remove if branches that did not test `__debug__`
17+
1318
## [3.1.0] - 2025-10-10
1419

1520
### Added
@@ -306,6 +311,7 @@ the minified code may only run with Python 3.12.
306311
- python-minifier package
307312
- pyminify command
308313

314+
[3.1.1]: https://github.com/dflook/python-minifier/compare/3.1.0...3.1.1
309315
[3.1.0]: https://github.com/dflook/python-minifier/compare/3.0.0...3.1.0
310316
[3.0.0]: https://github.com/dflook/python-minifier/compare/2.11.3...3.0.0
311317
[2.11.3]: https://github.com/dflook/python-minifier/compare/2.11.2...2.11.3

src/python_minifier/transforms/remove_debug.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,38 @@ def can_remove(self, node):
2727
if not isinstance(node, ast.If):
2828
return False
2929

30-
if isinstance(node.test, ast.Name) and node.test.id == '__debug__':
31-
return True
30+
def is_simple_debug_check():
31+
# Simple case: if __debug__:
32+
if isinstance(node.test, ast.Name) and node.test.id == '__debug__':
33+
return True
34+
return False
3235

33-
if isinstance(node.test, ast.Compare) and len(node.test.ops) == 1 and isinstance(node.test.ops[0], ast.Is) and self.constant_value(node.test.comparators[0]) is True:
34-
return True
36+
def is_truthy_debug_comparison():
37+
# Comparison case: if __debug__ is True / False / etc.
38+
if not isinstance(node.test, ast.Compare):
39+
return False
3540

36-
if isinstance(node.test, ast.Compare) and len(node.test.ops) == 1 and isinstance(node.test.ops[0], ast.IsNot) and self.constant_value(node.test.comparators[0]) is False:
37-
return True
41+
if not isinstance(node.test.left, ast.Name):
42+
return False
3843

39-
if isinstance(node.test, ast.Compare) and len(node.test.ops) == 1 and isinstance(node.test.ops[0], ast.Eq) and self.constant_value(node.test.comparators[0]) is True:
40-
return True
44+
if node.test.left.id != '__debug__':
45+
return False
4146

47+
if len(node.test.ops) == 1:
48+
op = node.test.ops[0]
49+
comparator_value = self.constant_value(node.test.comparators[0])
50+
51+
if isinstance(op, ast.Is) and comparator_value is True:
52+
return True
53+
if isinstance(op, ast.IsNot) and comparator_value is False:
54+
return True
55+
if isinstance(op, ast.Eq) and comparator_value is True:
56+
return True
57+
58+
return False
59+
60+
if is_simple_debug_check() or is_truthy_debug_comparison():
61+
return True
4262
return False
4363

4464
def suite(self, node_list, parent):

test/test_remove_debug.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,61 @@ def test_no_remove_falsy_debug(condition):
167167
expected_ast = ast.parse(expected)
168168
actual_ast = remove_debug(source)
169169
compare_ast(expected_ast, actual_ast)
170+
171+
172+
@pytest.mark.parametrize(
173+
'condition', [
174+
'__sandwich__',
175+
'__sandwich__ is True',
176+
'__sandwich__ is False',
177+
'__sandwich__ is not False',
178+
'__sandwich__ == True',
179+
'__sandwich__ == __debug__',
180+
'__sandwich() == True',
181+
'func() is True',
182+
'some_call(a, b) is True',
183+
'obj.method() is True',
184+
'obj.attr is True',
185+
'True is something',
186+
'True == something',
187+
]
188+
)
189+
def test_no_remove_not_debug(condition):
190+
source = '''
191+
value = 10
192+
193+
# Not a __debug__ test
194+
if ''' + condition + ''':
195+
value += 1
196+
197+
print(value)
198+
'''
199+
200+
expected = source
201+
202+
expected_ast = ast.parse(expected)
203+
actual_ast = remove_debug(source)
204+
compare_ast(expected_ast, actual_ast)
205+
206+
207+
def test_no_remove_is_true_in_elif_chain():
208+
"""Regression test for issue #142 - if/elif/else with 'is True' comparisons"""
209+
source = '''
210+
def check_is_internet_working(c):
211+
url, url_hostname = get_url_and_url_hostname(c)
212+
213+
if is_internet_working_socket_test(c, url_hostname) is True:
214+
c.is_internet_connected = True
215+
elif is_internet_working_urllib_open(c, url) is True:
216+
c.is_internet_connected = True
217+
else:
218+
c.is_internet_connected = False
219+
220+
return c.is_internet_connected
221+
'''
222+
223+
expected = source
224+
225+
expected_ast = ast.parse(expected)
226+
actual_ast = remove_debug(source)
227+
compare_ast(expected_ast, actual_ast)

0 commit comments

Comments
 (0)