Over my head with descriptors

Sarcastic Zombie sarcasticzombie at gmail.com
Thu Dec 14 13:11:11 EST 2006


Code included below.

Basically, I've created a series of "question" descriptors, which each
hold a managed value. This is so I can implement validation, and render
each field into html automatically for forms.

My problem is this: every instance of my "wizard" class has unique self
values, but they share the exact same descriptor values.

Meaning, if

t = Test("ar")
y = Test("ar")

t is y
False

t.age is y.age
True

t.age = 9
y.age
9

Code below. What am I not understanding?
-----------------------------------------

import datetime, re

class Question(object):
	def __init__(self, qtext, name, default=None, required=False,
max_length=None, choices=None):
		self._name = name
		self._qtext = qtext
		self._value = default
		self._error = None
		self._max_length = max_length
		self._required = required
		self._choices = choices

	def __get__(self, instance, owner):
		return self

	def __set__(self, instance, value):
		error = self.validate(value)
		if not error:
			self._value = self.cast(value)
			self._error = None
		else:
			self._value = value
			self._error = error
			print error

	def __str__(self):
		return str(self._value)

	def __repr__(self):
		return str(self._value)

	def cast(self, value):
		return value

	def validate(self, value):
		return True

	def html(self):
		#ugly html renderer removed; irrelevant to problem
		return html

	def error(self):
		if self._error:
			return True


class Q_Integer(Question):
	def validate(self, value):
		if self._required and not value:
			return "Field is required."
		elif not value:
			return None
		try:
			int(value)
			return None
		except:
			return "Answer must be a whole number."

	def cast(self, value):
		if value:
			return int(value)

class Q_Float(Question):
	def validate(self, value):
		if self._required and not value:
			return "Field is required."
		elif not value:
			return None
		try:
			float(value)
			return None
		except:
			return "Answer must be a decimal number."

	def cast(self, value):
		if value:
			return float(value)

class Q_Chars(Question):
	def validate(self, value):
		try:
			if self._required and not value:
				return "Field is required."
			elif not value:
				return None
			if self._max_length:
				if len(value) > self._max_length:
					return "Too many characters; max of %s allowed." %
self._max_length
			return None
		except:
			return "Invalid entry."

	def cast(self, value):
		if value:
			return str(value)

class Q_Long(Question):
	def validate(self, value):
		try:
			if self._required and not value:
				return "Field is required."
			elif not value:
				return None
		except:
			return "Invalid entry."

	def cast(self, value):
		if value:
			return str(value)

	def html(self):
		#ugly html renderer removed; irrelevant to problem
		return html

class Q_Bool(Question):
	def validate(self, value):
		return None

	def cast(self, value):
		return bool(value)

	def html(self):
		#ugly html renderer removed; irrelevant to problem
		return html

class Q_Phone(Question):
	def validate(self, value):
		try:
			if self._required and not value:
				return "Field is required."
			elif not value:
				return None

			pieces = value.split("-")
			if len(pieces[0]) == 3 and len(pieces[1]) == 3 and len(pieces[2]) ==
4:
				int(pieces[0])
				int(pieces[1])
				int(pieces[2])
				return None
			else:
				return "Requires Valid Phone Number in XXX-XXX-XXXX format."
		except:
			return "Requires Valid Phone Number in XXX-XXX-XXXX format."


class Q_Date(Question):
	def validate(self, value):
		try:
			if self._required and not value:
				return "Field is required."
			elif not value:
				return None

			r = re.compile(r"\d{1,2}[-/.]\d{1,2}[-/.]\d{1,4}")
			month, day, year =
r.findall(value)[0].replace("/","-").replace(".","-").split("-")
			date = datetime.date(year=int(year), month=int(month), day=int(day)
)
			return None
		except:
			return "Requires valid date in mm-dd-yy format."

	def cast(self, value):
		if value:
			r = re.compile(r"\d{1,2}[-/.]\d{1,2}[-/.]\d{1,4}")
			month, day, year =
r.findall(value)[0].replace("/","-").replace(".","-").split("-")

			year = int(year)
			if year < 70:
				year += 2000
			elif year < 100:
				year += 1000

			date = datetime.date(year=int(year), month=int(month), day=int(day)
)

			return date

	def __str__(self):
		date = self._value
		return "%s/%s/%s" % (date.month, date.day, date.year)

## Wizard Base Object

class Wizard(object):
	def __init__(self, action):
		self.action = action
		self.init_time = datetime.datetime.now()

	pagediv = "box"
	title = "A Dynamic Wizard"
	instructions = "There are no real instructions here. Sorry."

	grouping = [ ]

	def render_form(self):
		#ugly html renderer removed; irrelevant to problem
		return form

	def flatten(self, post):
		for key in post:
			if not key == "command":
				errors = ""
				cblock = "self.%s = '%s'\n" % (key, post[key])
				ab_save = compile( cblock, errors, 'exec')
				exec(ab_save)

	def errorcheck(self):
		error = 0
		for section in self.grouping:
			for question in section:
				t = eval( "self.%s.validate(self.%s._value)" % (question, question)
)
				if t:
					error = 1
		return error



C_CHOICES = (
	("red", "Red"),
	("blue", "Blue"),
	("green", "Green"),
	)

class Test(Wizard):
	grouping = [
		[ 'age', 'weight' ],
		[ 'feet', 'inches' ],
		['name', 'cash', 'fav_color', 'happy', 'birthday'] ]

	def __new__(self):
		age = Q_Integer("Your Age:", "age", 99)
		weight = Q_Integer("Your Weight:", "weight", 200)
		feet = Q_Integer("Feet tall:", "feet", 6)
		inches = Q_Integer("Inches Tall:", "inches", 0)
		name = Q_Chars("Your Name:", "name", max_length=15, required=True)
		cash = Q_Float("Money in hand?", "cash", required=True,
default=55.50)
		fav_color = Q_Chars("Your favorite color?", "fav_color",
required=True, max_length=50, choices=C_CHOICES)
		homezip = Q_Zip("Your zip code?", "homezip", required=True, )
		happy = Q_Bool("Are you happy?", "happy", default=False)
		birthday = Q_Date("Your Birthday:", "birthday")




More information about the Python-list mailing list