Created
November 26, 2011 15:02
-
-
Save voldmar/1395817 to your computer and use it in GitHub Desktop.
Django command for getting info about template tags and filters within your project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
'''Django command for getting info about template tags and filters within your project | |
It suports two output formats: human readable (with extra doc) and vim quickfix format | |
Usage: ./manage.py tag_info tag_or_filter_name | |
''' | |
import os | |
import sys | |
from optparse import make_option | |
import inspect | |
import textwrap | |
from django.core.management.base import BaseCommand, CommandError | |
from django.template import get_templatetags_modules, get_library, InvalidTemplateLibrary, builtins | |
from django.utils.importlib import import_module | |
FORMATS = { | |
'vim': '{path}:{line}:{name}', | |
'human': '{name} in line {line} of {path}', | |
} | |
class Command(BaseCommand): | |
help = 'Show all signals receivers' | |
option_list = BaseCommand.option_list + ( | |
make_option('--format', | |
dest='line_format', | |
default='human', | |
choices=FORMATS.keys(), | |
help='Line format (available choices: {0})'.format(', '.join(FORMATS)), | |
), | |
make_option('--show-doc', | |
action='store_true', | |
dest='show_doc', | |
help='Show docstring for found tag or filter, if --format=human (default: False)', | |
), | |
) | |
def handle(self, name, *args, **options): | |
line_format = options['line_format'] | |
show_doc = options['show_doc'] | |
if line_format not in FORMATS: | |
raise CommandError('format must be on of {0}, not {1}'.format(line_format, FORMATS.keys())) | |
msg = FORMATS[line_format] | |
libraries = set(builtins[:]) | |
for module in set(get_templatetags_modules()): | |
templatetags_module = import_module(module) | |
files = os.listdir(os.path.dirname(templatetags_module.__file__)) | |
lib_names = [lib_name for lib_name, ext in map(os.path.splitext, files) if ext == '.py' and not lib_name.startswith('_')] | |
for lib_name in lib_names: | |
try: | |
libraries.add(get_library(lib_name)) | |
except InvalidTemplateLibrary: | |
pass | |
def print_info(obj): | |
# Here be dragons | |
# | |
# Very strange Python and Django magic: `inclusion_tag` and | |
# `simple_tag` returns curried function named `generic_tag_compiler` | |
# that has Node as it fourth arg and Node has `render` method with | |
# free variables containing our original functions | |
# | |
# After that knowledge other is very easy but lil’ tricky | |
template = None | |
if obj.func_name == '_curried': | |
cls = obj.func_closure[0].cell_contents[3] | |
# It evaluates to string for inslusion_tag | |
template = cls.render.im_func.func_closure[0].cell_contents | |
orig = cls.render.im_func.func_closure[1].cell_contents | |
obj = orig | |
# import ipdb; ipdb.set_trace() | |
if line_format == 'human' and show_doc: | |
args, varargs, keywords, defaults = inspect.getargspec(obj) | |
doc = inspect.getdoc(obj) | |
spec = [] | |
if args: | |
if defaults: | |
spec.append(', '.join(args[:len(defaults)])) | |
spec.append(', '.join('{0}={1!r}'.format(key, value) for key, value in zip(args[len(defaults):], defaults))) | |
else: | |
spec.append(', '.join(args)) | |
if varargs: | |
spec.append('*' + varargs) | |
if keywords: | |
spec.append('**' + keywords) | |
print '{name}({spec})'.format(name=obj.func_name, spec=', '.join(spec)), | |
if template: | |
print '- decorated by inclusion_tag("{template}")'.format(template=template) | |
else: | |
print ' # Line {line} of {path}'.format(name=obj.func_name, line=inspect.getsourcelines(obj)[1], path=inspect.getsourcefile(obj)) | |
if doc: | |
for line in doc.splitlines(): | |
print ' ' + line | |
else: | |
print msg.format(name=obj.func_name, line=inspect.getsourcelines(obj)[1], path=inspect.getsourcefile(obj)) | |
for lib in libraries: | |
if name in lib.tags: | |
print_info(lib.tags[name]) | |
if name in lib.filters: | |
print_info(lib.filters[name]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment