Thanks for excellent explanations. I almost got this working. I just have one more problem, that is:

When user enter incorrect number of arguments for a method, I naturally get a type error. I could probably fix that with try and catch, but that is not very explanatory to the user. Is there a way to get expected number of arguments to the method so that I can generate an error report?

You can find my codes as attachment. I have split them into two files. In order to run it, you should run cli.py like:

python cli.py

Thanks in advance,

Yaşar Arabacı

15-03-2011 05:39, bob gailer yazmış:
On 3/14/2011 8:49 PM, Yaşar Arabacı wrote:
As I try to implement things with getattr, I am getting a really
strange error. This is my file:

Various interspersed comments:

#!/usr/bin/env python
# -*- encoding:utf-8 -*-
class global_variables:

It is customary to start class names with an uppercase letter

"Holds class attributes, so that other classes can share them"
products = 0
best_bundle = []
class dispatcher:
def GetMethod(self,class_name,method_name):

It is customary to start method names with a lowercase letter

"""This method first finds a class if desired classexists.
Then, instansites it, and returns a reference to desired method of
the instance it created.
"""

from sys import modules

It is customary to place import statements close to the top of the
program, not in any class or function.

module = modules[self.__module__]
if hasattr(module,class_name):

What are the module's attributes?
insert print dir(module) to see ALL the attributes.

print "#debug : hasattr is true"
cls = getattr(module,class_name)
else:
print "#debug : hasattr is false"
return None

"if we get a valid class, lets instantie it"
if cls:
a=cls()
else:
return None
return hasattr(a,method_name) and getattr(a,method_name) or None

def dispatch_command(self):
"""Gets command from user, finds appropriate Class/method to run
and then runs it. Beware of the fact that, to be able to successfully
run the method, method should take exactly two arguments,
arg 1: instance of class which method resides (e.g. self)
arg 2: list of other needed variables

list of other variables can be used to get as many variables as possible
"""

command = raw_input(">>>")
args = command.split(" ")
if len(args) < 2:
return None
method = self.GetMethod(args[0],args[1])
return method and method(args[2:]) or None

class calculate(global_variables):
def bundle(self,args):
print "your best bundle is -->"

a = dispatcher()
a.dispatch_command()

Alternative 1
- put all the user-callable class definitions inside a Container class
(or whatever name you want)
- then use getattr on the Container class
class Container:
class Calculate(global_variables):
def bundle(self,args):
print "your best bundle is -->"

Alternative 2 - use the following to create a dictionary of classes in
which you look up the desired class by name
import sys, inspect
thisModule = sys.modules[__name__]
classDict = dict((name.lower(), value) for name, value in
inspect.getmembers(thisModule, inspect.isclass))
...
cls = classDict[className]

Alternative 3
cls = getattr(module,class_name)
try:
if issubclass(cls, global_variables)
a=cls()
except TypeError:
pass

I wanted to see what happens when someone gives an nonexistent
function. But when I put a b, it gives me error, when I put c d it
doesn't. I don't have either a or c classes, but a somehow causes
problems :S This is what I did:

yasar@yasar-laptop:~/best_buy> ./main.py
>>>a b
#debug : hasattr is true
Traceback (most recent call last):
File "./main.py", line 57, in <module>
a.dispatch_command()
File "./main.py", line 44, in dispatch_command
method = self.GetMethod(args[0],args[1])
File "./main.py", line 25, in GetMethod
a=cls()
AttributeError: dispatcher instance has no __call__ method

The error tells you what a is. Isn't it obvious now? Remember to read
and understand such messages.

yasar@yasar-laptop:~/best_buy> ./main.py
>>>c d
#debug : hasattr is false




"""
This is supposed to an generic command line tool, to be used
with any kind of module, you should import whatever module you
want to use as book like;

import xxx as book

License Notice:

This program comes with absolutely no warranty, use at your own risk,
you can use, modify, redistribute, or do whatever else you want to do
with it provided that:

**Author of this code cannot be held responsible for any damage this code
may do.

Author: Yasar Arabaci

"""
import main as book

class Dispatcher:
	force_subclass = "Best_buy" # Enter name of base class, or None to enable all!
	def getMethod(self,class_name,method_name):
		"""This method first finds a class if desired class exists. First letter,
		of the class name must be uppercased!
		Then, instansites it, and returns a reference to desired method of
		the instance it created.
		"""
		if hasattr(book,class_name):
			if self.force_subclass: # if this option is enabled, we will only get subclasses
				try:
					if not issubclass(getattr(book,class_name),getattr(book,self.force_subclass)):
						return "You cannot access this class!"
				except TypeError:
					return "There was an type error!"
			"Create an instance"
			class_instance = getattr(book,class_name)()
			if hasattr(class_instance,method_name):
				method_reference = getattr(class_instance,method_name)
				if callable(method_reference):
					return method_reference
				else:
					return "%s is not callable" % method_name
			else:
				return "% has no attribute %s" % (method_name,class_instance)
		else:
			return "Module %s has no attribute as %s" % book.__name__,class_name
		

	def dispatchCommand(self,command):
		"""Gets command from user, finds appropriate Class/method to run 
		and then runs it."""
		
		if command == "help":
			return self.help()
		elif command == "quit":
			quit()
		args = command.split(" ")
		if len(args) < 2:
			return self.invalid_command(command)
		method = self.getMethod(args[0].capitalize(),args[1])
		if not callable(method):
			return self.invalid_command(command)
		return method(*args[2:])
	def invalid_command(self,command):
		print "There were some errors on your request:"
		print command
		print "For a list of available commands,"
		print "type : help"
		return None
	def help(self):
		"""
		This method returns, all doc string of all first order
		methods of classes that came with book, this also check
		if force_sublass enabled to limit the documentation.
		"""

		"Get the list of references to all attributes in book"
		attributes = [getattr(book,attr) for attr in dir(book) if callable(getattr(book,attr))]

		"If sublassing forced, filter the attributes, be aware of nasty type errors"
		classes=[]
		if self.force_subclass:
			for class_name in attributes:
				try:
					if issubclass(class_name,getattr(book,self.force_subclass)):
						classes.append(class_name)
				except TypeError:
					continue
		else: classes = attributes
		for class_name in classes:
			methodList = [getattr(class_name,method) for method in dir(class_name) if callable(getattr(class_name,method))]
			print "\n".join(["%s %s:%s" % (str(class_name.__name__), str(method.__name__),str(method.__doc__)) for method in methodList])

command_line = Dispatcher()
while True:
	command = raw_input(">>>")
	answer = command_line.dispatchCommand(command)
	if answer: print answer

from sys import modules
"""
Main classes of Best buy application. 
"""
class Best_buy:
	"""Ancestor of all user callable methods, and this holds global variables
	All changes on variables must be done in class level, as in:

	self.__class__.variable = 1
	"""
	product_list= [["ali","15",20],["veli",40,50]] #some initial values,
	best_bundle = []


class Calculate(Best_buy):
	def bundle(self):
		"Calculates best bundle and then returns it."
		#Calculate best bundle here
		return "testing bundle!"

class List(Best_buy):
	def products(self):
		"Gets list of all added products"
		for product in self.product_list:
			print "Name:" + product[0] + "\tPrice:"+str(product[1])+"\tRating:"+str(product[2])
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to