Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-eradicate for
openSUSE:Factory checked in at 2022-08-26 09:08:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-eradicate (Old)
and /work/SRC/openSUSE:Factory/.python-eradicate.new.2083 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-eradicate"
Fri Aug 26 09:08:16 2022 rev:3 rq:999344 version:2.1.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-eradicate/python-eradicate.changes
2019-02-26 22:22:14.826069436 +0100
+++
/work/SRC/openSUSE:Factory/.python-eradicate.new.2083/python-eradicate.changes
2022-08-26 09:08:17.941385049 +0200
@@ -1,0 +2,7 @@
+Thu Aug 25 09:45:28 UTC 2022 - Ben Greiner <[email protected]>
+
+- Update to 2.1.0
+ * New class-based API.
+- No further release notes
+
+-------------------------------------------------------------------
Old:
----
eradicate-1.0.tar.gz
New:
----
eradicate-2.1.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-eradicate.spec ++++++
--- /var/tmp/diff_new_pack.3cSWcJ/_old 2022-08-26 09:08:18.349385467 +0200
+++ /var/tmp/diff_new_pack.3cSWcJ/_new 2022-08-26 09:08:18.353385470 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-eradicate
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2022 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-eradicate
-Version: 1.0
+Version: 2.1.0
Release: 0
Summary: Python utility for removing commented-out code
License: MIT
@@ -30,7 +30,7 @@
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires(post): update-alternatives
-Requires(postun): update-alternatives
+Requires(postun):update-alternatives
BuildArch: noarch
%python_subpackages
@@ -62,12 +62,13 @@
%python_uninstall_alternative eradicate
%check
-export PYTHONPATH=.
-%python_exec %{SOURCE1}
+%pyunittest -v
%files %{python_files}
%doc README.rst
%python_alternative %{_bindir}/eradicate
-%{python_sitelib}/*
+%{python_sitelib}/eradicate.py*
+%pycache_only %{python_sitelib}/__pycache__/eradicate*.pyc
+%{python_sitelib}/eradicate-%{version}*-info
%changelog
++++++ eradicate-1.0.tar.gz -> eradicate-2.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/MANIFEST.in
new/eradicate-2.1.0/MANIFEST.in
--- old/eradicate-1.0/MANIFEST.in 2015-03-14 03:22:41.000000000 +0100
+++ new/eradicate-2.1.0/MANIFEST.in 2022-04-06 11:43:12.000000000 +0200
@@ -1,4 +1,3 @@
include MANIFEST.in
include README.rst
exclude Makefile
-exclude test_eradicate.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/PKG-INFO new/eradicate-2.1.0/PKG-INFO
--- old/eradicate-1.0/PKG-INFO 2018-12-23 19:30:37.000000000 +0100
+++ new/eradicate-2.1.0/PKG-INFO 2022-04-06 11:46:41.558620200 +0200
@@ -1,70 +1,10 @@
-Metadata-Version: 1.1
+Metadata-Version: 2.1
Name: eradicate
-Version: 1.0
+Version: 2.1.0
Summary: Removes commented-out code.
Home-page: https://github.com/myint/eradicate
Author: Steven Myint
-Author-email: UNKNOWN
License: Expat License
-Description: =========
- eradicate
- =========
-
- .. image:: https://travis-ci.org/myint/eradicate.svg?branch=master
- :target: https://travis-ci.org/myint/eradicate
- :alt: Build status
-
- ``eradicate`` removes commented-out code from Python files.
-
-
- Introduction
- ============
-
- With modern revision control available, there is no reason to save
- commented-out code to your repository. ``eradicate`` helps cleans up
- existing junk comments. It does this by detecting block comments that
- contain valid Python syntax that are likely to be commented out code.
- (It avoids false positives like the sentence ``this is not good``,
- which is valid Python syntax, but is probably not code.)
-
-
- Example
- =======
-
- ::
-
- $ eradicate --in-place example.py
-
- Before running ``eradicate``.
-
- .. code-block:: python
-
- #import os
- # from foo import junk
- #a = 3
- a = 4
- #foo(1, 2, 3)
-
- def foo(x, y, z):
- # print('hello')
- print(x, y, z)
-
- # This is a real comment.
- #return True
- return False
-
- After running ``eradicate``.
-
- .. code-block:: python
-
- a = 4
-
- def foo(x, y, z):
- print(x, y, z)
-
- # This is a real comment.
- return False
-
Keywords: clean,format,commented-out code
Platform: UNKNOWN
Classifier: Environment :: Console
@@ -73,3 +13,85 @@
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Quality Assurance
+
+=========
+eradicate
+=========
+
+.. image::
https://github.com/myint/eradicate/actions/workflows/test.yml/badge.svg
+ :target: https://github.com/myint/eradicate/actions/workflows/test.yml
+ :alt: Build status
+
+----
+
+``eradicate`` removes commented-out code from Python files.
+
+
+Introduction
+============
+
+With modern revision control available, there is no reason to save
+commented-out code to your repository. ``eradicate`` helps cleans up
+existing junk comments. It does this by detecting block comments that
+contain valid Python syntax that are likely to be commented out code.
+(It avoids false positives like the sentence ``this is not good``,
+which is valid Python syntax, but is probably not code.)
+
+
+Example
+=======
+
+.. code-block:: bash
+
+ $ eradicate --in-place example.py
+
+Before running ``eradicate``.
+
+.. code-block:: python
+
+ #import os
+ # from foo import junk
+ #a = 3
+ a = 4
+ #foo(1, 2, 3)
+
+ def foo(x, y, z):
+ # print('hello')
+ print(x, y, z)
+
+ # This is a real comment.
+ #return True
+ return False
+
+After running ``eradicate``.
+
+.. code-block:: python
+
+ a = 4
+
+ def foo(x, y, z):
+ print(x, y, z)
+
+ # This is a real comment.
+ return False
+
+
+Whitelisting
+============
+
+False positives can happen so there is a whitelist feature to fix them
shorthand.
+You can either add entries to the default whitelist with
``--whitelist-extend`` or overwrite the default with ``--whitelist``.
+Both arguments expect a string of ``#`` separated regex strings (whitespaces
are preserved). E.g. ``eradicate --whitelist "foo#b a r" filename``
+Those regex strings are matched case insensitive against the start of the
comment itself.
+
+For the default whitelist please see ``eradicate.py``.
+
+
+Related
+=======
+
+There are different tools, plugins, and integrations for ``eradicate`` users:
+
+- `flake8-eradicate <https://github.com/sobolevn/flake8-eradicate>`_ - Flake8
plugin to find commented out or dead code.
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/README.rst
new/eradicate-2.1.0/README.rst
--- old/eradicate-1.0/README.rst 2014-05-11 16:49:33.000000000 +0200
+++ new/eradicate-2.1.0/README.rst 2022-04-06 11:43:12.000000000 +0200
@@ -2,10 +2,12 @@
eradicate
=========
-.. image:: https://travis-ci.org/myint/eradicate.svg?branch=master
- :target: https://travis-ci.org/myint/eradicate
+.. image::
https://github.com/myint/eradicate/actions/workflows/test.yml/badge.svg
+ :target: https://github.com/myint/eradicate/actions/workflows/test.yml
:alt: Build status
+----
+
``eradicate`` removes commented-out code from Python files.
@@ -23,7 +25,7 @@
Example
=======
-::
+.. code-block:: bash
$ eradicate --in-place example.py
@@ -56,3 +58,22 @@
# This is a real comment.
return False
+
+
+Whitelisting
+============
+
+False positives can happen so there is a whitelist feature to fix them
shorthand.
+You can either add entries to the default whitelist with
``--whitelist-extend`` or overwrite the default with ``--whitelist``.
+Both arguments expect a string of ``#`` separated regex strings (whitespaces
are preserved). E.g. ``eradicate --whitelist "foo#b a r" filename``
+Those regex strings are matched case insensitive against the start of the
comment itself.
+
+For the default whitelist please see ``eradicate.py``.
+
+
+Related
+=======
+
+There are different tools, plugins, and integrations for ``eradicate`` users:
+
+- `flake8-eradicate <https://github.com/sobolevn/flake8-eradicate>`_ - Flake8
plugin to find commented out or dead code.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/eradicate new/eradicate-2.1.0/eradicate
--- old/eradicate-1.0/eradicate 2014-12-31 17:03:15.000000000 +0100
+++ new/eradicate-2.1.0/eradicate 2022-04-06 11:43:12.000000000 +0200
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-# Copyright (C) 2012-2015 Steven Myint
+# Copyright (C) 2012-2018 Steven Myint
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/eradicate.egg-info/PKG-INFO
new/eradicate-2.1.0/eradicate.egg-info/PKG-INFO
--- old/eradicate-1.0/eradicate.egg-info/PKG-INFO 1970-01-01
01:00:00.000000000 +0100
+++ new/eradicate-2.1.0/eradicate.egg-info/PKG-INFO 2022-04-06
11:46:41.000000000 +0200
@@ -0,0 +1,97 @@
+Metadata-Version: 2.1
+Name: eradicate
+Version: 2.1.0
+Summary: Removes commented-out code.
+Home-page: https://github.com/myint/eradicate
+Author: Steven Myint
+License: Expat License
+Keywords: clean,format,commented-out code
+Platform: UNKNOWN
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Software Development :: Quality Assurance
+
+=========
+eradicate
+=========
+
+.. image::
https://github.com/myint/eradicate/actions/workflows/test.yml/badge.svg
+ :target: https://github.com/myint/eradicate/actions/workflows/test.yml
+ :alt: Build status
+
+----
+
+``eradicate`` removes commented-out code from Python files.
+
+
+Introduction
+============
+
+With modern revision control available, there is no reason to save
+commented-out code to your repository. ``eradicate`` helps cleans up
+existing junk comments. It does this by detecting block comments that
+contain valid Python syntax that are likely to be commented out code.
+(It avoids false positives like the sentence ``this is not good``,
+which is valid Python syntax, but is probably not code.)
+
+
+Example
+=======
+
+.. code-block:: bash
+
+ $ eradicate --in-place example.py
+
+Before running ``eradicate``.
+
+.. code-block:: python
+
+ #import os
+ # from foo import junk
+ #a = 3
+ a = 4
+ #foo(1, 2, 3)
+
+ def foo(x, y, z):
+ # print('hello')
+ print(x, y, z)
+
+ # This is a real comment.
+ #return True
+ return False
+
+After running ``eradicate``.
+
+.. code-block:: python
+
+ a = 4
+
+ def foo(x, y, z):
+ print(x, y, z)
+
+ # This is a real comment.
+ return False
+
+
+Whitelisting
+============
+
+False positives can happen so there is a whitelist feature to fix them
shorthand.
+You can either add entries to the default whitelist with
``--whitelist-extend`` or overwrite the default with ``--whitelist``.
+Both arguments expect a string of ``#`` separated regex strings (whitespaces
are preserved). E.g. ``eradicate --whitelist "foo#b a r" filename``
+Those regex strings are matched case insensitive against the start of the
comment itself.
+
+For the default whitelist please see ``eradicate.py``.
+
+
+Related
+=======
+
+There are different tools, plugins, and integrations for ``eradicate`` users:
+
+- `flake8-eradicate <https://github.com/sobolevn/flake8-eradicate>`_ - Flake8
plugin to find commented out or dead code.
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/eradicate.egg-info/SOURCES.txt
new/eradicate-2.1.0/eradicate.egg-info/SOURCES.txt
--- old/eradicate-1.0/eradicate.egg-info/SOURCES.txt 1970-01-01
01:00:00.000000000 +0100
+++ new/eradicate-2.1.0/eradicate.egg-info/SOURCES.txt 2022-04-06
11:46:41.000000000 +0200
@@ -0,0 +1,9 @@
+MANIFEST.in
+README.rst
+eradicate
+eradicate.py
+setup.py
+eradicate.egg-info/PKG-INFO
+eradicate.egg-info/SOURCES.txt
+eradicate.egg-info/dependency_links.txt
+eradicate.egg-info/top_level.txt
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/eradicate-1.0/eradicate.egg-info/dependency_links.txt
new/eradicate-2.1.0/eradicate.egg-info/dependency_links.txt
--- old/eradicate-1.0/eradicate.egg-info/dependency_links.txt 1970-01-01
01:00:00.000000000 +0100
+++ new/eradicate-2.1.0/eradicate.egg-info/dependency_links.txt 2022-04-06
11:46:41.000000000 +0200
@@ -0,0 +1 @@
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/eradicate.egg-info/top_level.txt
new/eradicate-2.1.0/eradicate.egg-info/top_level.txt
--- old/eradicate-1.0/eradicate.egg-info/top_level.txt 1970-01-01
01:00:00.000000000 +0100
+++ new/eradicate-2.1.0/eradicate.egg-info/top_level.txt 2022-04-06
11:46:41.000000000 +0200
@@ -0,0 +1 @@
+eradicate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/eradicate.py
new/eradicate-2.1.0/eradicate.py
--- old/eradicate-1.0/eradicate.py 2018-12-23 19:28:01.000000000 +0100
+++ new/eradicate-2.1.0/eradicate.py 2022-04-06 11:44:17.000000000 +0200
@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2015 Steven Myint
+# Copyright (C) 2012-2018 Steven Myint
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -30,172 +30,208 @@
import re
import tokenize
-__version__ = '1.0'
+__version__ = '2.1.0'
-MULTILINE_ASSIGNMENT_REGEX = re.compile(r'^\s*\w+\s*=.*[(\[{]$')
-PARTIAL_DICTIONARY_REGEX = re.compile(r'^\s*[\'"]\w+[\'"]\s*:.+[,{]\s*$')
-
-
-def comment_contains_code(line, aggressive=True):
- """Return True comment contains code."""
- line = line.lstrip()
- if not line.startswith('#'):
- return False
-
- line = line.lstrip(' \t\v\n#').strip()
-
- # Ignore non-comment related hashes. For example, "# Issue #999".
- if re.search('#[0-9]', line):
- return False
-
- if line.startswith('pylint:'):
- return False
-
- if re.match(r'.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)', line):
- return False
+class Eradicator(object):
+ """Eradicate comments."""
+ BRACKET_REGEX = re.compile(r'^[()\[\]{}\s]+$')
+ CODING_COMMENT_REGEX = re.compile(r'.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)')
+ DEF_STATEMENT_REGEX = re.compile(r"def
.+\)[\s]+->[\s]+[a-zA-Z_][a-zA-Z0-9_]*:$")
+ FOR_STATEMENT_REGEX = re.compile(r"for [a-zA-Z_][a-zA-Z0-9_]* in .+:$")
+ HASH_NUMBER = re.compile(r'#[0-9]')
+ MULTILINE_ASSIGNMENT_REGEX = re.compile(r'^\s*\w+\s*=.*[(\[{]$')
+ PARTIAL_DICTIONARY_REGEX = re.compile(r'^\s*[\'"]\w+[\'"]\s*:.+[,{]\s*$')
+ PRINT_RETURN_REGEX = re.compile(r'^(print|return)\b\s*')
+ WITH_STATEMENT_REGEX = re.compile(r"with .+ as [a-zA-Z_][a-zA-Z0-9_]*:$")
+
+ CODE_INDICATORS = ['(', ')', '[', ']', '{', '}', ':', '=', '%',
+ 'print', 'return', 'break', 'continue', 'import']
+ CODE_KEYWORDS = [r'elif\s+.*', 'else', 'try', 'finally', r'except\s+.*']
+ CODE_KEYWORDS_AGGR = CODE_KEYWORDS + [r'if\s+.*']
+ WHITESPACE_HASH = ' \t\v\n#'
+
+ DEFAULT_WHITELIST = (
+ r'pylint',
+ r'pyright',
+ r'noqa',
+ r'nosec',
+ r'type:\s*ignore',
+ r'fmt:\s*(on|off)',
+
r'isort:\s*(on|off|skip|skip_file|split|dont-add-imports(:\s*\[.*?\])?)',
+ r'TODO',
+ r'FIXME',
+ r'XXX'
+ )
+ WHITELIST_REGEX = re.compile(r'|'.join(DEFAULT_WHITELIST),
flags=re.IGNORECASE)
+
+ def comment_contains_code(self, line, aggressive=True):
+ """Return True comment contains code."""
+ line = line.lstrip()
+ if not line.startswith('#'):
+ return False
+
+ line = line.lstrip(self.WHITESPACE_HASH).strip()
+
+ # Ignore non-comment related hashes. For example, "# Issue #999".
+ if self.HASH_NUMBER.search(line):
+ return False
+
+ # Ignore whitelisted comments
+ if self.WHITELIST_REGEX.search(line):
+ return False
+
+ if self.CODING_COMMENT_REGEX.match(line):
+ return False
+
+ # Check that this is possibly code.
+ for symbol in self.CODE_INDICATORS:
+ if symbol in line:
+ break
+ else:
+ return False
- # Check that this is possibly code.
- for symbol in list('()[]{}:=%') + ['print', 'return', 'break', 'continue',
- 'import']:
- if symbol in line:
- break
- else:
- return False
+ if self.multiline_case(line, aggressive=aggressive):
+ return True
- if multiline_case(line, aggressive=aggressive):
- return True
+ for symbol in self.CODE_KEYWORDS_AGGR if aggressive else
self.CODE_KEYWORDS:
+ if re.match(r'^\s*' + symbol + r'\s*:\s*$', line):
+ return True
- symbol_list = [r'elif\s+.*', 'else', 'try',
- 'finally', r'except\s+.*']
- if aggressive:
- symbol_list.append(r'if\s+.*')
+ line = self.PRINT_RETURN_REGEX.sub('', line)
- for symbol in symbol_list:
- if re.match(r'^\s*' + symbol + r'\s*:\s*$', line):
+ if self.PARTIAL_DICTIONARY_REGEX.match(line):
return True
- line = re.sub(r'^(print|return)\b\s*', '', line)
-
- if re.match(PARTIAL_DICTIONARY_REGEX, line):
- return True
+ try:
+ compile(line, '<string>', 'exec')
+ except (SyntaxError, TypeError, UnicodeDecodeError):
+ return False
+ else:
+ return True
- try:
- compile(line, '<string>', 'exec')
- return True
- except (SyntaxError, TypeError, UnicodeDecodeError):
- return False
+ def multiline_case(self, line, aggressive=True):
+ """Return True if line is probably part of some multiline code."""
+ if aggressive:
+ for ending in ')]}':
+ if line.endswith(ending + ':'):
+ return True
+
+ if line.strip() == ending + ',':
+ return True
+
+ # Check whether a function/method definition with return value
+ # annotation
+ if self.DEF_STATEMENT_REGEX.search(line):
+ return True
-def multiline_case(line, aggressive=True):
- """Return True if line is probably part of some multiline code."""
- if aggressive:
- for ending in ')]}':
- if line.endswith(ending + ':'):
+ # Check weather a with statement
+ if self.WITH_STATEMENT_REGEX.search(line):
return True
- if line.strip() == ending + ',':
+ # Check weather a for statement
+ if self.FOR_STATEMENT_REGEX.search(line):
return True
- # Check whether a function/method definition with return value
- # annotation
- if re.search(r"def .+\)[\s]+->[\s]+[a-zA-Z_][a-zA-Z0-9_]*:$", line):
+ if line.endswith('\\'):
return True
- # Check weather a with statement
- if re.search(r"with .+ as [a-zA-Z_][a-zA-Z0-9_]*:$", line):
+ if self.MULTILINE_ASSIGNMENT_REGEX.match(line):
return True
- # Check weather a for statement
- if re.search(r"for [a-zA-Z_][a-zA-Z0-9_]* in .+:$", line):
+ if self.BRACKET_REGEX.match(line):
return True
- if line.endswith('\\'):
- return True
-
- if re.match(MULTILINE_ASSIGNMENT_REGEX, line):
- return True
-
- if re.match(r'^[()\[\]{}\s]+$', line):
- return True
-
- return False
-
-
-def commented_out_code_line_numbers(source, aggressive=True):
- """Yield line numbers of commented-out code."""
- sio = io.StringIO(source)
- try:
- for token in tokenize.generate_tokens(sio.readline):
- token_type = token[0]
- start_row = token[2][0]
- line = token[4]
-
- if (token_type == tokenize.COMMENT and
- line.lstrip().startswith('#') and
- comment_contains_code(line, aggressive)):
- yield start_row
- except (tokenize.TokenError, IndentationError):
- pass
-
-
-def filter_commented_out_code(source, aggressive=True):
- """Yield code with commented out code removed."""
- marked_lines = list(commented_out_code_line_numbers(source,
- aggressive))
- sio = io.StringIO(source)
- previous_line = ''
- for line_number, line in enumerate(sio.readlines(), start=1):
- if (line_number not in marked_lines or
- previous_line.rstrip().endswith('\\')):
- yield line
- previous_line = line
+ return False
-def fix_file(filename, args, standard_out):
- """Run filter_commented_out_code() on file."""
- encoding = detect_encoding(filename)
- with open_with_encoding(filename, encoding=encoding) as input_file:
- source = input_file.read()
+ def commented_out_code_line_numbers(self, source, aggressive=True):
+ """Yield line numbers of commented-out code."""
+ sio = io.StringIO(source)
+ try:
+ for token in tokenize.generate_tokens(sio.readline):
+ token_type = token[0]
+ start_row = token[2][0]
+ line = token[4]
+
+ if (token_type == tokenize.COMMENT and
+ line.lstrip().startswith('#') and
+ self.comment_contains_code(line, aggressive)):
+ yield start_row
+ except (tokenize.TokenError, IndentationError):
+ pass
+
+
+ def filter_commented_out_code(self, source, aggressive=True):
+ """Yield code with commented out code removed."""
+ marked_lines = list(self.commented_out_code_line_numbers(source,
+ aggressive))
+ sio = io.StringIO(source)
+ previous_line = ''
+ for line_number, line in enumerate(sio.readlines(), start=1):
+ if (line_number not in marked_lines or
+ previous_line.rstrip().endswith('\\')):
+ yield line
+ previous_line = line
+
+
+ def fix_file(self, filename, args, standard_out):
+ """Run filter_commented_out_code() on file."""
+ encoding = self.detect_encoding(filename)
+ with self.open_with_encoding(filename, encoding=encoding) as
input_file:
+ source = input_file.read()
+
+ filtered_source = ''.join(self.filter_commented_out_code(source,
+ args.aggressive))
+
+ if source != filtered_source:
+ if args.in_place:
+ with self.open_with_encoding(filename, mode='w',
+ encoding=encoding) as output_file:
+ output_file.write(filtered_source)
+ else:
+ diff = difflib.unified_diff(
+ source.splitlines(),
+ filtered_source.splitlines(),
+ 'before/' + filename,
+ 'after/' + filename,
+ lineterm='')
+ standard_out.write('\n'.join(list(diff) + ['']))
+ return True
- filtered_source = ''.join(filter_commented_out_code(source,
- args.aggressive))
- if source != filtered_source:
- if args.in_place:
- with open_with_encoding(filename, mode='w',
- encoding=encoding) as output_file:
- output_file.write(filtered_source)
+ def open_with_encoding(self, filename, encoding, mode='r'):
+ """Return opened file with a specific encoding."""
+ return io.open(filename, mode=mode, encoding=encoding,
+ newline='') # Preserve line endings
+
+
+ def detect_encoding(self, filename):
+ """Return file encoding."""
+ try:
+ with open(filename, 'rb') as input_file:
+ from lib2to3.pgen2 import tokenize as lib2to3_tokenize
+ encoding =
lib2to3_tokenize.detect_encoding(input_file.readline)[0]
+
+ # Check for correctness of encoding.
+ with self.open_with_encoding(filename, encoding) as input_file:
+ input_file.read()
+
+ return encoding
+ except (SyntaxError, LookupError, UnicodeDecodeError):
+ return 'latin-1'
+
+ def update_whitelist(self, new_whitelist, extend_default=True):
+ """Updates the whitelist."""
+ if extend_default:
+ self.WHITELIST_REGEX = re.compile(
+ r'|'.join(list(self.DEFAULT_WHITELIST) + new_whitelist),
+ flags=re.IGNORECASE)
else:
- diff = difflib.unified_diff(
- source.splitlines(),
- filtered_source.splitlines(),
- 'before/' + filename,
- 'after/' + filename,
- lineterm='')
- standard_out.write('\n'.join(list(diff) + ['']))
-
-
-def open_with_encoding(filename, encoding, mode='r'):
- """Return opened file with a specific encoding."""
- return io.open(filename, mode=mode, encoding=encoding,
- newline='') # Preserve line endings
-
-
-def detect_encoding(filename):
- """Return file encoding."""
- try:
- with open(filename, 'rb') as input_file:
- from lib2to3.pgen2 import tokenize as lib2to3_tokenize
- encoding = lib2to3_tokenize.detect_encoding(input_file.readline)[0]
-
- # Check for correctness of encoding.
- with open_with_encoding(filename, encoding) as input_file:
- input_file.read()
-
- return encoding
- except (SyntaxError, LookupError, UnicodeDecodeError):
- return 'latin-1'
+ self.WHITELIST_REGEX = re.compile(
+ r'|'.join(new_whitelist),
+ flags=re.IGNORECASE)
def main(argv, standard_out, standard_error):
@@ -209,13 +245,36 @@
parser.add_argument('-a', '--aggressive', action='store_true',
help='make more aggressive changes; '
'this may result in false positives')
+ parser.add_argument('-e', '--error', action="store_true",
+ help="Exit code based on result of check")
parser.add_argument('--version', action='version',
version='%(prog)s ' + __version__)
+ parser.add_argument('--whitelist', action="store",
+ help=(
+ 'String of "#" separated comment beginnings to
whitelist. '
+ 'Single parts are interpreted as regex. '
+ 'OVERWRITING the default whitelist: {}'
+ ).format(Eradicator.DEFAULT_WHITELIST))
+ parser.add_argument('--whitelist-extend', action="store",
+ help=(
+ 'String of "#" separated comment beginnings to
whitelist '
+ 'Single parts are interpreted as regex. '
+ 'Overwrites --whitelist. '
+ 'EXTENDING the default whitelist: {} '
+ ).format(Eradicator.DEFAULT_WHITELIST))
parser.add_argument('files', nargs='+', help='files to format')
args = parser.parse_args(argv[1:])
+ eradicator = Eradicator()
+
+ if args.whitelist_extend:
+ eradicator.update_whitelist(args.whitelist_extend.split('#'), True)
+ elif args.whitelist:
+ eradicator.update_whitelist(args.whitelist.split('#'), False)
+
filenames = list(set(args.files))
+ change_or_error = False
while filenames:
name = filenames.pop(0)
if args.recursive and os.path.isdir(name):
@@ -227,6 +286,9 @@
if not d.startswith('.')]
else:
try:
- fix_file(name, args=args, standard_out=standard_out)
+ change_or_error = eradicator.fix_file(name, args=args,
standard_out=standard_out) or change_or_error
except IOError as exception:
print('{}'.format(exception), file=standard_error)
+ change_or_error = True
+ if change_or_error and args.error:
+ return 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/setup.cfg new/eradicate-2.1.0/setup.cfg
--- old/eradicate-1.0/setup.cfg 1970-01-01 01:00:00.000000000 +0100
+++ new/eradicate-2.1.0/setup.cfg 2022-04-06 11:46:41.559085400 +0200
@@ -0,0 +1,4 @@
+[egg_info]
+tag_build =
+tag_date = 0
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/eradicate-1.0/setup.py new/eradicate-2.1.0/setup.py
--- old/eradicate-1.0/setup.py 2017-04-17 01:23:44.000000000 +0200
+++ new/eradicate-2.1.0/setup.py 2022-04-06 11:43:12.000000000 +0200
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import ast
-from distutils import core
+from setuptools import setup
def version():
@@ -17,7 +17,7 @@
with open('README.rst') as readme:
- core.setup(
+ setup(
name='eradicate',
version=version(),
description='Removes commented-out code.',
++++++ test_eradicate.py ++++++
--- /var/tmp/diff_new_pack.3cSWcJ/_old 2022-08-26 09:08:18.449385569 +0200
+++ /var/tmp/diff_new_pack.3cSWcJ/_new 2022-08-26 09:08:18.453385572 +0200
@@ -10,6 +10,11 @@
import sys
import tempfile
import unittest
+try: # pragma: no cover
+ import mock
+except ModuleNotFoundError: # pragma: no cover
+ import unittest.mock as mock
+import re
import eradicate
@@ -17,141 +22,254 @@
class UnitTests(unittest.TestCase):
def test_comment_contains_code(self):
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'#'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# This is a (real) comment.'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# 123'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# 123.1'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# 1, 2, 3'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'x = 1 # x = 1'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# pylint: disable=redefined-outer-name'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# Issue #999: This is not code'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'# x = 1'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#from foo import eradicate'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#import eradicate'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#"key": value,'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#"key": "value",'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#"key": 1 + 1,'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
"#'key': 1 + 1,"))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#"key": {'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#}'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#} )]'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#},'))
def test_comment_contains_code_with_print(self):
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#print'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#print(1)'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#print 1'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'#to print'))
def test_comment_contains_code_with_return(self):
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#return x'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'#to return'))
def test_comment_contains_code_with_multi_line(self):
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#def foo():'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#else:'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'# else : '))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'# "foo %d" % \\'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#elif True:'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#x = foo('))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'#except Exception:'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# this is = to that :('))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'#else'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'#or else:'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'#else True:'))
def test_comment_contains_code_with_sentences(self):
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'#code is good'))
def test_comment_contains_code_with_encoding(self):
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# coding=utf-8'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'#coding= utf-8'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# coding: utf-8'))
- self.assertFalse(eradicate.comment_contains_code(
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
'# encoding: utf8'))
- self.assertTrue(eradicate.comment_contains_code(
+ self.assertTrue(eradicate.Eradicator().comment_contains_code(
'# codings=utf-8'))
+ def test_comment_contains_code_with_default_whitelist(self):
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# pylint: disable=A0123'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# pylint:disable=A0123'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# pylint: disable = A0123'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# pylint:disable = A0123'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# pyright: reportErrorName=true'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# noqa'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# NOQA'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# noqa: A123'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# noqa:A123'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# nosec'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# fmt: on'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# fmt: off'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# fmt:on'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# fmt:off'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort: on'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort:on'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort: off'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort:off'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort: skip'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort:skip'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort: skip_file'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort:skip_file'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort: split'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort:split'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort: dont-add-imports'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort:dont-add-imports'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort: dont-add-imports: ["import os"]'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort:dont-add-imports: ["import os"]'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort: dont-add-imports:["import os"]'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# isort:dont-add-imports:["import os"]'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# type: ignore'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# type:ignore'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# type: ignore[import]'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# type:ignore[import]'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# TODO: Do that'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# FIXME: Fix that'))
+
+ self.assertFalse(eradicate.Eradicator().comment_contains_code(
+ '# XXX: What ever'))
+
+
def test_commented_out_code_line_numbers(self):
self.assertEqual(
[1, 3],
- list(eradicate.commented_out_code_line_numbers(
+ list(eradicate.Eradicator().commented_out_code_line_numbers(
"""\
# print(5)
# This is a comment.
@@ -166,7 +284,7 @@
def test_commented_out_code_line_numbers_with_errors(self):
self.assertEqual(
[1, 3],
- list(eradicate.commented_out_code_line_numbers(
+ list(eradicate.Eradicator().commented_out_code_line_numbers(
"""\
# print(5)
# This is a comment.
@@ -184,7 +302,7 @@
def test_commented_out_code_line_numbers_with_with_statement(self):
self.assertEqual(
[1, 2],
- list(eradicate.commented_out_code_line_numbers("""\
+ list(eradicate.Eradicator().commented_out_code_line_numbers("""\
# with open('filename', 'w') as out_file:
# json.dump(objects, out_file)
#
@@ -193,7 +311,7 @@
def test_commented_out_code_line_numbers_with_for_statement(self):
self.assertEqual(
[1, 2],
- list(eradicate.commented_out_code_line_numbers("""\
+ list(eradicate.Eradicator().commented_out_code_line_numbers("""\
# for x in y:
# oops = x.ham
""")))
@@ -208,7 +326,7 @@
# The below is another comment.
# 3 / 2 + 21
""",
- ''.join(eradicate.filter_commented_out_code(
+ ''.join(eradicate.Eradicator().filter_commented_out_code(
"""\
# print(5)
# This is a comment.
@@ -233,7 +351,7 @@
"""
self.assertEqual(
line,
- ''.join(eradicate.filter_commented_out_code(line)))
+ ''.join(eradicate.Eradicator().filter_commented_out_code(line)))
def test_filter_commented_out_code_with_larger_example(self):
self.assertEqual(
@@ -245,7 +363,7 @@
# The below is another comment.
# 3 / 2 + 21
""",
- ''.join(eradicate.filter_commented_out_code(
+ ''.join(eradicate.Eradicator().filter_commented_out_code(
"""\
# print(5)
# This is a comment.
@@ -266,13 +384,13 @@
"""
self.assertEqual(
code,
- ''.join(eradicate.filter_commented_out_code(code,
+ ''.join(eradicate.Eradicator().filter_commented_out_code(code,
aggressive=False)))
def test_filter_commented_out_code_with_annotation(self):
self.assertEqual(
'\n\n\n',
- ''.join(eradicate.filter_commented_out_code("""\
+ ''.join(eradicate.Eradicator().filter_commented_out_code("""\
# class CommentedClass(object):
# def __init__(self, prop: int) -> None:
# self.property = prop
@@ -290,7 +408,21 @@
def test_detect_encoding_with_bad_encoding(self):
with temporary_file('# -*- coding: blah -*-\n') as filename:
self.assertEqual('latin-1',
- eradicate.detect_encoding(filename))
+ eradicate.Eradicator().detect_encoding(filename))
+
+ def test_extend_whitelist(self):
+ eradicator = eradicate.Eradicator()
+ eradicator.update_whitelist(["foo"], True)
+ self.assertTrue(
+ eradicator.WHITELIST_REGEX == re.compile(
+ r'|'.join(list(eradicator.DEFAULT_WHITELIST) + ["foo"]),
flags=re.IGNORECASE
+ )
+ )
+
+ def test_update_whitelist(self):
+ eradicator = eradicate.Eradicator()
+ eradicator.update_whitelist(["foo"], False)
+ self.assertTrue(eradicator.WHITELIST_REGEX == re.compile("foo",
flags=re.IGNORECASE))
class SystemTests(unittest.TestCase):
@@ -372,6 +504,28 @@
standard_error=ignore)
self.assertFalse(output_file.getvalue())
+ def test_returns_error_code_if_requested(self):
+ with temporary_file("""\
+ # x * 3 == False
+ # x is a variable
+ """) as filename:
+ output_file = io.StringIO()
+ result = eradicate.main(argv=['my_fake_program', filename, "-e"],
+ standard_out=output_file,
+ standard_error=None)
+ self.assertTrue(result)
+
+ def test_returns_None_if_no_error_request(self):
+ with temporary_file("""\
+ # x * 3 == False
+ # x is a variable
+ """) as filename:
+ output_file = io.StringIO()
+ result = eradicate.main(argv=['my_fake_program', filename],
+ standard_out=output_file,
+ standard_error=None)
+ self.assertTrue(result is None)
+
def test_end_to_end(self):
with temporary_file("""\
# x * 3 == False
@@ -386,6 +540,26 @@
# x is a variable
""", '\n'.join(process.communicate()[0].decode().split('\n')[2:]))
+ def test_whitelist(self):
+ mock_update = mock.Mock()
+ with mock.patch.object(eradicate.Eradicator, 'update_whitelist',
mock_update):
+ with temporary_file("# empty") as filename:
+ result = eradicate.main(argv=['my_fake_program',
'--whitelist', 'foo# bar', filename],
+ standard_out=None,
+ standard_error=None)
+ self.assertTrue(result is None)
+ mock_update.assert_called_once_with(["foo", " bar"], False)
+
+ def test_whitelist_extend(self):
+ mock_update = mock.Mock()
+ with mock.patch.object(eradicate.Eradicator, 'update_whitelist',
mock_update):
+ with temporary_file("# empty") as filename:
+ result = eradicate.main(argv=['my_fake_program',
'--whitelist-extend', 'foo #bar', filename],
+ standard_out=None,
+ standard_error=None)
+ self.assertTrue(result is None)
+ mock_update.assert_called_once_with(["foo ", "bar"], True)
+
@contextlib.contextmanager
def temporary_file(contents, directory='.', prefix=''):