- Author:
- tclancy
- Posted:
- September 23, 2016
- Language:
- Python
- Version:
- Not specified
- Score:
- 1 (after 1 ratings)
Rough check for unused methods in our apps. Scans models, views, utils, api, forms and signals
files for what look like methods calls, then looks at all of our classes' methods to ensure each
is called. Do not trust this blindly but it's a good way to get leads on what may be dead code. Assumes a setting called LOCAL_APPS
so it only bothers to look at the code you've written rather than everything in INSTALLED_APPS
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | import fnmatch
import pyclbr
import os
import re
import logging
from django.conf import settings
from django.core.management.base import NoArgsCommand
logger = logging.getLogger(__name__)
class Command(NoArgsCommand):
help = """Rough check for unused methods in our apps. Scans models, views, utils, api, forms and signals
files for what look like methods calls, then looks at all of our classes' methods to ensure each
is called. Do not trust this blindly but it's a good way to get leads on what may be dead code.
TODO: look for classes that are never referenced - mainly to find dead form types"""
def handle_noargs(self, **options):
called_methods = self._get_list_of_called_methods()
for app in settings.LOCAL_APPS:
for f in ["models", "views", "utils", "api", "signals", "forms"]:
path = ".".join([app, f])
try:
classdict = pyclbr.readmodule(path)
logger.debug("Reading %s", path)
except ImportError:
continue
for name, klass in classdict.items():
logger.debug("Getting methods for %s", name)
for m in klass.methods:
# ignore form clean_ methods which are called implicitly
if re.match(r"^clean_", m):
continue
if m not in called_methods:
logger.warn("No calls of %s.%s", name, m)
def _get_list_of_called_methods(self):
"""
Naively open all Python files that we're interested in and get a list of unique method
calls by looking for things like function_name( preceded by either a period or space,
but not "def ". Also includes wrapped API methods like 'method_name'
"""
files = []
ignored_files = ["__init__.py", "urls.py", "tests.py"]
for root, _, filenames in os.walk("."):
if root.find("migrations") > -1 or root.find("settings") > -1 or root.find("tests") > -1:
continue
for filename in fnmatch.filter(filenames, "*.py"):
if filename in ignored_files or filename.find("wsgi") > -1:
continue
files.append(os.path.join(root, filename))
logger.info("Found %d Python files", len(files))
method_matcher = re.compile(r"""['".]([a-zA-Z_]+)[('",]""")
# prepopulate with known methods to ignore
methods = {"__unicode__", "prepend_urls", "detail_uri_kwargs", "__hash__", "create_list", "read_list",
"update_list", "delete_list", "delete_detail", "create_detail", "update_detail", "read_detail"}
for name in files:
with open(name) as f:
for match in method_matcher.finditer(f.read()):
methods.add(match.group(1))
logger.info("Found %d unique methods", len(methods))
return methods
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 8 months ago
Comments
Please login first before commenting.