qutebrowser/scripts/dev/run_vulture.py

195 lines
6.9 KiB
Python
Raw Normal View History

#!/usr/bin/env python
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
2017-05-09 21:37:03 +02:00
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# 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
import vulture
import qutebrowser.app # pylint: disable=unused-import
from qutebrowser.commands import cmdutils
from qutebrowser.utils import utils
from qutebrowser.browser.webkit import rfc6266
2016-09-14 10:18:25 +02:00
# To run the decorators from there
2016-09-14 11:35:31 +02:00
# pylint: disable=unused-import
2016-09-14 10:18:25 +02:00
from qutebrowser.browser.webkit.network import webkitqutescheme
2016-09-14 11:35:31 +02:00
# pylint: enable=unused-import
2016-09-14 10:18:25 +02:00
from qutebrowser.browser import qutescheme
2017-07-04 12:31:01 +02:00
from qutebrowser.config import configtypes
def whitelist_generator():
2015-10-05 06:53:56 +02:00
"""Generator which yields lines to add to a vulture whitelist."""
# 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):
yield 'qutebrowser.browser.webkit.rfc6266.{}.{}'.format(name,
attr)
# PyQt properties
2017-05-11 07:33:10 +02:00
yield 'qutebrowser.mainwindow.statusbar.bar.StatusBar.color_flags'
yield 'qutebrowser.mainwindow.statusbar.url.UrlText.urltype'
# Not used yet, but soon (or when debugging)
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 'scripts.utils.bg_colors'
# 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.QtWidgets.QStyleOptionViewItem.backgroundColor'
## qute://... handlers
2016-09-14 11:35:31 +02:00
for name in qutescheme._HANDLERS: # pylint: disable=protected-access
2017-05-30 17:07:31 +02:00
name = name.replace('-', '_')
2016-09-14 11:35:31 +02:00
yield 'qutebrowser.browser.qutescheme.qute_' + name
# Other false-positives
2017-08-19 23:37:57 +02:00
yield 'qutebrowser.completion.models.listcategory.ListCategory().lessThan'
yield 'qutebrowser.utils.jinja.Loader.get_source'
yield 'qutebrowser.utils.log.QtWarningFilter.filter'
yield 'qutebrowser.browser.pdfjs.is_available'
2016-09-11 20:16:03 +02:00
yield 'QEvent.posted'
2016-09-15 13:56:27 +02:00
yield 'log_stack' # from message.py
2017-03-16 07:50:23 +01:00
yield 'propagate' # logging.getLogger('...).propagate = False
# vulture doesn't notice the hasattr() and thus thinks netrc_used is unused
# in NetworkManager.on_authentication_required
yield 'PyQt5.QtNetwork.QNetworkReply.netrc_used'
2017-07-31 16:41:43 +02:00
yield 'qutebrowser.browser.downloads.last_used_directory'
yield 'PaintContext.clip' # from completiondelegate.py
yield 'logging.LogRecord.log_color' # from logging.py
yield 'scripts.utils.use_color' # from asciidoc2html.py
for attr in ['pyeval_output', 'log_clipboard', 'fake_clipboard']:
yield 'qutebrowser.misc.utilcmds.' + attr
for attr in ['fileno', 'truncate', 'closed', 'readable']:
yield 'qutebrowser.utils.qtutils.PyQIODevice.' + attr
2017-07-04 12:31:01 +02:00
for attr in ['msgs', 'priority', 'visit_attribute']:
yield 'scripts.dev.pylint_checkers.config.' + attr
2017-07-04 12:31:01 +02:00
for attr in ['visit_call', 'process_module']:
yield 'scripts.dev.pylint_checkers.modeline.' + attr
for name, member in inspect.getmembers(configtypes, inspect.isclass):
yield 'qutebrowser.config.configtypes.' + name
2017-09-15 00:10:24 +02:00
yield 'qutebrowser.config.configexc.ConfigErrorDesc.traceback'
yield 'qutebrowser.config.configfiles.ConfigAPI.load_autoconfig'
yield 'types.ModuleType.c' # configfiles:read_config_py
2017-09-22 11:07:54 +02:00
for name in ['configdir', 'datadir']:
yield 'qutebrowser.config.configfiles.ConfigAPI.' + name
2017-07-04 12:31:01 +02:00
yield 'include_aliases'
for attr in ['_get_default_metavar_for_optional',
'_get_default_metavar_for_positional', '_metavar_formatter']:
yield 'scripts.dev.src2asciidoc.UsageFormatter.' + attr
2017-09-19 22:18:02 +02:00
# attrs
yield 'qutebrowser.browser.webkit.network.networkmanager.ProxyId.hostname'
yield 'qutebrowser.command.command.ArgInfo._validate_exclusive'
yield 'scripts.get_coredumpctl_traces.Line.uid'
yield 'scripts.get_coredumpctl_traces.Line.gid'
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.
"""
return bool(re.match(r'[a-z]+[A-Z][a-zA-Z]+', item.name))
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 = []
2017-08-23 08:33:50 +02:00
for item in sorted(items,
key=lambda e: (e.filename.lower(), e.first_lineno)):
output.append(item.get_report())
2015-10-20 23:25:50 +02:00
return output
2015-10-20 23:25:50 +02:00
def run(files):
"""Run vulture over the given files."""
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(verbose=False)
2015-10-20 23:25:50 +02:00
vult.scavenge(files + [whitelist_file.name])
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,
}
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()
2017-05-17 14:29:17 +02:00
parser.add_argument('files', nargs='*', default=['qutebrowser', 'scripts',
'setup.py'])
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()