2015-10-04 23:02:03 +02:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
|
|
|
|
2016-01-04 07:12:39 +01:00
|
|
|
# Copyright 2015-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
# This file is part of qutebrowser.
|
|
|
|
#
|
|
|
|
# qutebrowser is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# qutebrowser is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
"""Run vulture on the source files and filter out false-positives."""
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import tempfile
|
|
|
|
import inspect
|
2015-10-20 22:48:01 +02:00
|
|
|
import argparse
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
import vulture
|
|
|
|
|
|
|
|
import qutebrowser.app # pylint: disable=unused-import
|
|
|
|
from qutebrowser.commands import cmdutils
|
|
|
|
from qutebrowser.utils import utils
|
2016-06-13 10:49:58 +02:00
|
|
|
from qutebrowser.browser.webkit import rfc6266
|
|
|
|
from qutebrowser.browser.webkit.network import qutescheme
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
def whitelist_generator():
|
2015-10-05 06:53:56 +02:00
|
|
|
"""Generator which yields lines to add to a vulture whitelist."""
|
2015-10-04 23:02:03 +02:00
|
|
|
# qutebrowser commands
|
|
|
|
for cmd in cmdutils.cmd_dict.values():
|
|
|
|
yield utils.qualname(cmd.handler)
|
|
|
|
|
|
|
|
# pyPEG2 classes
|
|
|
|
for name, member in inspect.getmembers(rfc6266, inspect.isclass):
|
|
|
|
for attr in ('grammar', 'regex'):
|
|
|
|
if hasattr(member, attr):
|
2016-06-13 10:49:58 +02:00
|
|
|
yield 'qutebrowser.browser.webkit.rfc6266.{}.{}'.format(name, attr)
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
# PyQt properties
|
|
|
|
for attr in ('prompt_active', 'command_active', 'insert_active',
|
|
|
|
'caret_mode'):
|
|
|
|
yield 'qutebrowser.mainwindow.statusbar.bar.StatusBar.' + attr
|
|
|
|
yield 'qutebrowser.mainwindow.statusbar.url.UrlText.urltype'
|
|
|
|
|
|
|
|
# Not used yet, but soon (or when debugging)
|
|
|
|
yield 'qutebrowser.config.configtypes.Regex'
|
|
|
|
yield 'qutebrowser.utils.debug.log_events'
|
|
|
|
yield 'qutebrowser.utils.debug.log_signals'
|
|
|
|
yield 'qutebrowser.utils.debug.qflags_key'
|
|
|
|
yield 'qutebrowser.utils.qtutils.QtOSError.qt_errno'
|
|
|
|
yield 'qutebrowser.utils.usertypes.NeighborList.firstitem'
|
|
|
|
yield 'scripts.utils.bg_colors'
|
|
|
|
yield 'scripts.utils.print_subtitle'
|
|
|
|
|
|
|
|
# Qt attributes
|
|
|
|
yield 'PyQt5.QtWebKit.QWebPage.ErrorPageExtensionReturn().baseUrl'
|
|
|
|
yield 'PyQt5.QtWebKit.QWebPage.ErrorPageExtensionReturn().content'
|
|
|
|
yield 'PyQt5.QtWebKit.QWebPage.ErrorPageExtensionReturn().encoding'
|
|
|
|
yield 'PyQt5.QtWebKit.QWebPage.ErrorPageExtensionReturn().fileNames'
|
|
|
|
yield 'PyQt5.QtGui.QAbstractTextDocumentLayout.PaintContext().clip'
|
|
|
|
yield 'PyQt5.QtWidgets.QStyleOptionViewItem.backgroundColor'
|
|
|
|
|
2015-11-04 17:45:16 +01:00
|
|
|
# qute:... handlers
|
|
|
|
for func in qutescheme.HANDLERS.values():
|
2016-06-13 10:49:58 +02:00
|
|
|
yield 'qutebrowser.browser.webkit.network.qutescheme.' + func.__name__
|
2015-11-04 17:45:16 +01:00
|
|
|
|
2015-10-04 23:02:03 +02:00
|
|
|
# Globals
|
|
|
|
# https://bitbucket.org/jendrikseipp/vulture/issues/10/
|
|
|
|
yield 'qutebrowser.misc.utilcmds.pyeval_output'
|
|
|
|
yield 'utils.use_color'
|
2016-06-13 10:49:58 +02:00
|
|
|
yield 'qutebrowser.browser.webkit.mhtml.last_used_directory'
|
2016-02-03 20:27:11 +01:00
|
|
|
yield 'qutebrowser.utils.utils.fake_clipboard'
|
|
|
|
yield 'qutebrowser.utils.utils.log_clipboard'
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
# Other false-positives
|
|
|
|
yield ('qutebrowser.completion.models.sortfilter.CompletionFilterModel().'
|
|
|
|
'lessThan')
|
|
|
|
yield 'qutebrowser.utils.jinja.Loader.get_source'
|
|
|
|
yield 'qutebrowser.utils.log.VDEBUG'
|
|
|
|
yield 'qutebrowser.utils.log.QtWarningFilter.filter'
|
|
|
|
yield 'logging.LogRecord.log_color'
|
2015-12-20 20:08:24 +01:00
|
|
|
yield 'qutebrowser.browser.pdfjs.is_available'
|
2015-10-27 08:07:11 +01:00
|
|
|
# vulture doesn't notice the hasattr() and thus thinks netrc_used is unused
|
|
|
|
# in NetworkManager.on_authentication_required
|
|
|
|
yield 'PyQt5.QtNetwork.QNetworkReply.netrc_used'
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
for attr in ('fileno', 'truncate', 'closed', 'readable'):
|
|
|
|
yield 'qutebrowser.utils.qtutils.PyQIODevice.' + attr
|
|
|
|
|
2015-12-01 07:48:33 +01:00
|
|
|
for attr in ('priority', 'visit_call'):
|
2015-10-04 23:02:03 +02:00
|
|
|
yield 'scripts.dev.pylint_checkers.config.' + attr
|
|
|
|
|
|
|
|
yield 'scripts.dev.pylint_checkers.modeline.process_module'
|
|
|
|
|
|
|
|
for attr in ('_get_default_metavar_for_optional',
|
2016-04-27 18:30:54 +02:00
|
|
|
'_get_default_metavar_for_positional', '_metavar_formatter'):
|
2015-10-04 23:02:03 +02:00
|
|
|
yield 'scripts.dev.src2asciidoc.UsageFormatter.' + attr
|
|
|
|
|
|
|
|
|
|
|
|
def filter_func(item):
|
2015-10-05 06:53:56 +02:00
|
|
|
"""Check if a missing function should be filtered or not.
|
|
|
|
|
|
|
|
Return:
|
|
|
|
True if the missing function should be filtered/ignored, False
|
|
|
|
otherwise.
|
|
|
|
"""
|
2015-11-13 22:27:41 +01:00
|
|
|
return bool(re.match(r'[a-z]+[A-Z][a-zA-Z]+', str(item)))
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
def report(items):
|
2015-10-05 06:53:56 +02:00
|
|
|
"""Generate a report based on the given vulture.Item's.
|
|
|
|
|
|
|
|
Based on vulture.Vulture.report, but we can't use that as we can't set the
|
|
|
|
properties which get used for the items.
|
|
|
|
"""
|
2015-10-20 23:25:50 +02:00
|
|
|
output = []
|
2015-10-05 06:53:56 +02:00
|
|
|
for item in sorted(items, key=lambda e: (e.file.lower(), e.lineno)):
|
2015-10-04 23:02:03 +02:00
|
|
|
relpath = os.path.relpath(item.file)
|
|
|
|
path = relpath if not relpath.startswith('..') else item.file
|
2016-01-22 19:40:10 +01:00
|
|
|
output.append("{}:{}: Unused {} '{}'".format(path, item.lineno,
|
|
|
|
item.typ, item))
|
2015-10-20 23:25:50 +02:00
|
|
|
return output
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
|
2015-10-20 23:25:50 +02:00
|
|
|
def run(files):
|
|
|
|
"""Run vulture over the given files."""
|
2015-10-04 23:02:03 +02:00
|
|
|
with tempfile.NamedTemporaryFile(mode='w', delete=False) as whitelist_file:
|
|
|
|
for line in whitelist_generator():
|
|
|
|
whitelist_file.write(line + '\n')
|
|
|
|
|
|
|
|
whitelist_file.close()
|
|
|
|
|
|
|
|
vult = vulture.Vulture(exclude=[], verbose=False)
|
2015-10-20 23:25:50 +02:00
|
|
|
vult.scavenge(files + [whitelist_file.name])
|
2015-10-04 23:02:03 +02:00
|
|
|
|
|
|
|
os.remove(whitelist_file.name)
|
|
|
|
|
|
|
|
filters = {
|
|
|
|
'unused_funcs': filter_func,
|
2015-10-20 23:31:46 +02:00
|
|
|
'unused_props': lambda item: False,
|
|
|
|
'unused_vars': lambda item: False,
|
|
|
|
'unused_attrs': lambda item: False,
|
2015-10-04 23:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
items = []
|
|
|
|
|
|
|
|
for attr, func in filters.items():
|
|
|
|
sub_items = getattr(vult, attr)
|
|
|
|
for item in sub_items:
|
|
|
|
filtered = func(item)
|
|
|
|
if not filtered:
|
|
|
|
items.append(item)
|
|
|
|
|
2015-10-20 23:25:50 +02:00
|
|
|
return report(items)
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser()
|
2016-04-27 18:30:54 +02:00
|
|
|
parser.add_argument('files', nargs='*', default=['qutebrowser', 'scripts'])
|
2015-10-20 23:25:50 +02:00
|
|
|
args = parser.parse_args()
|
|
|
|
out = run(args.files)
|
|
|
|
for line in out:
|
|
|
|
print(line)
|
|
|
|
sys.exit(bool(out))
|
2015-10-05 06:53:56 +02:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|