Tools to help developers reading class hierarchy faster - python

I mostly spend time on Python/Django and Objective-C/CocoaTouch and js/jQuery in the course of my daily work.
My editor of choice is vim for Python/Django and js/jQuery and xcode for Objective-C/CocoaTouch.
One of the bottlenecks on my development speed is the pace at which I read existing code, particularly open source libraries which I use.
In Python/Django for example, when I encounter some new features introduced by django developers, I get curious and begin exploring the code base manually. For example, when class-based views were introduced from django 1.3 onwards, reference - https://docs.djangoproject.com/en/dev/topics/class-based-views/ - I will check out the example code shown:
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = "about.html"
And try it out on one of my projects. More importantly, I am curious about what goes on behind the scenes, so I will dig into the source code -
# django/views/generic/__init__.py file
from django.views.generic.base import View, TemplateView, RedirectView
from django.views.generic.dates import (ArchiveIndexView, YearArchiveView, MonthArchiveView,
WeekArchiveView, DayArchiveView, TodayArchiveView,
DateDetailView)
from django.views.generic.detail import DetailView
from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView
from django.views.generic.list import ListView
class GenericViewError(Exception):
"""A problem in a generic view."""
pass
From here, I will trace it backwards to the django/views/generic/base.py file and find out exactly what TemplateView class does:-
class TemplateView(TemplateResponseMixin, View):
"""
A view that renders a template.
"""
def get_context_data(self, **kwargs):
return {
'params': kwargs
}
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
And here's it shows that TemplateView class inherits from TemplateResponseMixin and View classes... and I continue digging further... and so on...
The problem is, this is an extremely inefficient and slow process (to "follow" class hierachies manually and opening up each file along the way).
So the question is - is there an easy way/UI tool (or other visual solution) that parses Python code in a particular project and visualize class hierarchies which I can then inspect easily by "clicking" on a specific class I am interested to read about?
Note that I am aware of IPython shell but that doesn't seem as user-friendly as a visual display tool.
For example, there's F-Script in the world of Objective-C/iOS/Mac programming, which not only provides a shell (much like python or IPython shell), but provides a visual way for developers to introspect class hierachies.
Reference screenshot:-
So is there a class-hierarchy visualization tool (for Python specifically, but even better if it's generic and can be used for different languages)??? What are your methods of getting up to speed efficiently when reading open source source code???
UPDATED
Per advice below, I tried out ctags and vim plugin taglist and I was able to use :TlistOpen to open up a side buffer in vim like this:-
This looks really cool as :TlistOpen now essentially shows me all the classes and functions that are available on my currently open buffer.
My problem now is that when I attempt to do Ctrl] while my cursor is on TemplateView, I get the following error:-
What am I doing wrong? Is it because my django source code is in a virtualenv? Or is there something specific I have to do to make ctags/taglist "aware" of the django source code?

Tags are a very good start indeed. (There's too much stuff all over the place on it, so I'll just provide you with one extra keyword to search with: ctags.)
In Vim, it ends up (in the basic case) with Ctrl+] to go to a class/function definition and Ctrl+T to return.

The IDLE editor included with Python has an effective class browser that efficiently navigates everything in a given module. I believe in would not be difficult to modify that tool to navigate a full class-hierarchy with some assistance from the inspect module and the pyclbr module.

I've been using exuberant ctags with taglist for vim. Use ctrl] to jump to class definition in the current window, ctrlw] to jump to the definition in a split window.
You can install exuberant ctags via homebrew:
brew install ctags
Be sure to use the one installed at /usr/local/bin by homebrew, not the old ctags in /usr/bin.
It is also helpful to put --python-kinds=-vi in ~/.ctags to skip indexing variables and imports for Python files.
Another alternative would be to use a variant of cscope or pyscope though you must have your vim compiled with cscope option enabled.

Related

Is there a good way to apply pychecker/pylint to the python code in Tornado templates?

I am using Tornado 2.0 (Python 2.6.5) to build a simple web app.
Naturally, my Tornado templates contain snippets of Python code. For my non-template code, I am using pychecker and pylint to check for errors, etc.
However, obviously pychecker and pylint can't be run over the templates directly, b/c the templates are not python files proper (for non-Tornado users: they are html-like snippets w/ some control sequences and embedded python code).
So, my question is: can anyone suggest a good way to apply pychecker/pylint to the python code in these template files? Presumably this would involve extracting the code from the files.
I can hazard a few guesses as to how to do this, but I am curious if other people perceive this as a problem and what solutions they have pursued. I am still fairly new to web app design/construction so I am interested in answers guided by practical experience.
You need to use view class pattern to avoid cluttering your template with Python code which cannot be analyzed.
Create a Python class to process your view, instead of function
Have all "template logic" code as class methods. Your template calls them like {{ view.get_full_name }} and def get_full_name(self): return self.item.first_name + " " + self.item.last_name
Make instance out of your class
make call() as starting point for your processing
Pass "self" to your template as a context var
Some instructions for Django, but generally all Python frameworks (Pyramid, Zope) follow the same pattern:
Class views in Django
"$yourframeworkname view class" should yield more tutorials in Google.

Django admin site: implement a singleton for global variables?

Does anyone have experience (Django 1.x pref 1.3) with implementing a sort of singleton accessible from the admin page to expose some global variables for editing (site name, keywords, ...).
I cant find anything like this and it sounds quite unbelievable!
thanks
(django-preferences is broken with 1.x)
As lazerscience says, you probably want Django-dbsettings. I have a fork at Github that works with the latest Django versions.
after some playing I had dbsettings working... but with a few glitches:
- Aptana doesnt recognise the import preferences as a valid reference
- when I access my /settings/ page with the fields of the model I created and then save it I have a CSRF token missing or incorrect. error
NOTE: The official googlecode repository doesnt work (with 1.3), Daniel's version does instead (I guess he changed newforms -> forms etc). The way I created a new model for the settings veiw is:
from django.db import models
import dbsettings
class ImageLimits(dbsettings.Group):
maximum_width = dbsettings.PositiveIntegerValue()
maximum_height = dbsettings.PositiveIntegerValue()
options = ImageLimits()
You should avoid using singleton's as much as possible.
Are Singletons really that bad?
What is so bad about singletons?
For the rest, site name is editable in Django admin (see django.contrib.sites module).
Talking about keywords - it's bad to repeat them, thus, you better implement it in your item model (page, news article, etc).
Could you maybe give more examples of what do you need it for?

Preprocess SHPAML in Django's template loader?

Is there any way to make Django's template loader run all templates it loads (i.e. directly or via extend/include) through SHPAML if it figures the HTML is out of date?
I know how to invoke SHPAML recursively over an entire directory, but I would prefer to be able to run it on demand so I don't have to remember to sync the HTML every time I change the SHPAML source.
I guess invoking SHPAML from manage.py would work too (at least for test servers), but being able to hack into Django's template engine and make it run every file it loads through a preprocessor would be nicer.
I suspect you can achieve what you want by inheriting from django.template.loaders.app_directories.Loader (or whatever loader you use) and overwriting the load_template_source method, e.g.:
from django.template.loaders.app_directories import Loader
from shpaml import convert_text
class SHPAMLLoader(Loader):
def load_template_source(self, *args, **kwargs):
shpaml_source = super(SHPAMLLoader, self).load_template_source(*args, **kwargs)
html = convert_text(shpaml_source)
return html
Then put your loader at the beginning of the TEMPLATE_LOADERS tuple in your settings.py. Of course, you will be doing the SHPAML to HTML dance every time a template is loaded, so you may see some overhead. The upcoming Django 1.2 features template caching, which could help mitigating that overhead...
Disclaimer: this code is completely untested, sorry.
Just created a project based on the snippet in piquadrat's answer. It's a little more feature complete and supports django 1.1 and 1.2 (probably 1.0 as well)
django-shpaml-template-loader on bitbucket
Thought it might come in handy for the future :)

How to externally populate a Django model?

What is the best idea to fill up data into a Django model from an external source?
E.g. I have a model Run, and runs data in an XML file, which changes weekly.
Should I create a view and call that view URL from a curl cronjob (with the advantage that that data can be read anytime, not only when the cronjob runs), or create a python script and install that script as a cron (with DJANGO _SETTINGS _MODULE variable setup before executing the script)?
There is excellent way to do some maintenance-like jobs in project environment- write a custom manage.py command. It takes all environment configuration and other stuff allows you to concentrate on concrete task.
And of course call it directly by cron.
You don't need to create a view, you should just trigger a python script with the appropriate Django environment settings configured. Then call your models directly the way you would if you were using a view, process your data, add it to your model, then .save() the model to the database.
I've used cron to update my DB using both a script and a view. From cron's point of view it doesn't really matter which one you choose. As you've noted, though, it's hard to beat the simplicity of firing up a browser and hitting a URL if you ever want to update at a non-scheduled interval.
If you go the view route, it might be worth considering a view that accepts the XML file itself via an HTTP POST. If that makes sense for your data (you don't give much information about that XML file), it would still work from cron, but could also accept an upload from a browser -- potentially letting the person who produces the XML file update the DB by themselves. That's a big win if you're not the one making the XML file, which is usually the case in my experience.
"create a python script and install that script as a cron (with DJANGO _SETTINGS _MODULE variable setup before executing the script)?"
First, be sure to declare your Forms in a separate module (e.g. forms.py)
Then, you can write batch loaders that look like this. (We have a LOT of these.)
from myapp.forms import MyObjectLoadForm
from myapp.models import MyObject
import xml.etree.ElementTree as ET
def xmlToDict( element ):
return dict(
field1= element.findtext('tag1'),
field2= element.findtext('tag2'),
)
def loadRow( aDict ):
f= MyObjectLoadForm( aDict )
if f.is_valid():
f.save()
def parseAndLoad( someFile ):
doc= ET.parse( someFile ).getroot()
for tag in doc.getiterator( "someTag" )
loadRow( xmlToDict(tag) )
Note that there is very little unique processing here -- it just uses the same Form and Model as your view functions.
We put these batch scripts in with our Django application, since it depends on the application's models.py and forms.py.
The only "interesting" part is transforming your XML row into a dictionary so that it works seamlessly with Django's forms. Other than that, this command-line program uses all the same Django components as your view.
You'll probably want to add options parsing and logging to make a complete command-line app out of this. You'll also notice that much of the logic is generic -- only the xmlToDict function is truly unique. We call these "Builders" and have a class hierarchy so that our Builders are all polymorphic mappings from our source documents to Python dictionaries.

Separating Models and Request Handlers In Google App Engine

I'd like to move my models to a separate directory, similar to the way it's done with Rails to cut down on code clutter. Is there any way to do this easily?
Thanks,
Collin
I assume you're using the basic webkit and not Django or something fancy. In that case just create a subdirectory called models. Put any python files you use for your models in here. Create also one blank file in this folder called __init__.py.
Then in your main.py or "controller" or what have you, put:
import models
at the top.
You just created a python package.
Brandon's answer is what I do. Furthermore, I rather like Rails's custom of one model per file. I don't stick to it completely but that is my basic pattern, especially since Python tends to encourage more-but-simpler lines of code than Ruby.
So what I do is I make models a package too:
models/
models/__init__.py
models/user.py
models/item.py
models/blog_post.py
In the main .py files I put my basic class definition, plus perhaps some helper functions (Python's module system makes it much safer to keep quickie helper functions coupled to the class definition). And my __init__.py stitches them all together:
"""The application models"""
from user import User
from item import Item
from blog_post import BlogPost
It's slightly redundant but I have lots of control of the namespace.

Categories

Resources