[Patches] selfnanny.py: checking for "self" in every method

Moshe Zadka Moshe Zadka <mzadka@geocities.com>
Sat, 4 Mar 2000 15:15:04 +0200 (IST)


This simple nanny checks a Python source for methods that don't have
arguments, or that the first argument isn't called "self". This is an
important enough style guideline that I believe it is worth putting in 
a check, besides, it would stop bugs like

class foo:

	def __init__():
		self.i = 1

a = foo()

NameError: self

---------------- selfnanny.py ----------------------
#!/usr/local/bin/python

import parser, symbol, types

def check_file(file):
	return check_string(file.read())

def check_string(s):
	return check_ast(parser.suite(s))

def check_ast(ast):
	return check_tuple(ast.totuple(1)) # retain line numbers

def check_tuple(tup, classname=None):
	if type(tup) != types.TupleType:
		return []
	problems = []
	if tup[0] == symbol.funcdef:
		if classname is not None:
			args = get_function_args(tup)
			if not args or args[0] != 'self':
				funcname, funcline = tup[2][1:]
				problems.append((funcline, funcname, classname))
		classname = None
	if tup[0] == symbol.classdef:
		classname = tup[2][1]
	for t in tup[1:]:
		problems.extend(check_tuple(t, classname))
	return problems

def get_function_args(tup):
	ret = []
	for t in tup[1:]:
		if t[0] == symbol.parameters:
			parameters = t
	arglist = ()
	for t in parameters[1:]:
		if t[0] == symbol.varargslist:
			arglist = t
	for arg in arglist[1:]:
		if arg[0] == symbol.fpdef:
			ret.append(arg[1][1])
	return ret

def format_problem(problem):
	s = 'line %d: method %s in class %s missing first argument "self"'
	return s % problem

def print_problems(problems):
	for problem in problems:
		print format_problem(problem)

def nanny(filename):
	print_problems(check_file(open(filename)))


if __name__=='__main__':
	import sys
	for filename in sys.argv[1:]:
		nanny(filename)
------------------- selfnanny.py ---------------------

Legal:
I confirm that, to the best of my knowledge and belief, this
contribution is free of any claims of third parties under
copyright, patent or other rights or interests ("claims").  To
the extent that I have any such claims, I hereby grant to CNRI a
nonexclusive, irrevocable, royalty-free, worldwide license to
reproduce, distribute, perform and/or display publicly, prepare
derivative versions, and otherwise use this contribution as part
of the Python software and its related documentation, or any
derivative versions thereof, at no cost to CNRI or its licensed
users, and to authorize others to do so.

I acknowledge that CNRI may, at its sole discretion, decide
whether or not to incorporate this contribution in the Python
software and its related documentation.  I further grant CNRI
permission to use my name and other identifying information
provided to CNRI by me for use in connection with the Python
software and its related documentation.

--
Moshe Zadka <mzadka@geocities.com>. 
http://www.oreilly.com/news/prescod_0300.html