django - how to replace repeated code in form validation - django

In my django forms.py file, I am trying to replace two occurrences of repeated validation code. Each attempt I make to have only one occurrence of each, does not seem to work.
I cannot figure out how to write the code so that I have only one occurrence of each of the repeated code in the validation. It should be possible, but I cannot understand how to achieve this.
I am hoping that someone can help me out as this has me confused.
Here is my validation code:
def clean(self):
cd_cdf = super(CertificationDetailsForm, self).clean()
# Must check the most specific cases first, then the general cases.
if 'certification_type' in cd_cdf and cd_cdf['certification_type'] == '':
self._errors['certification_type'] = self.error_class([_("This field is required.")])
elif 'certification_type' in cd_cdf and cd_cdf['certification_type'] == display_types.ENTER_MY_OWN_TYPE_DESCRIPTION:
if 'certification_type_description' in cd_cdf and len(cd_cdf['certification_type_description'].strip()) == 0:
self._errors['certification_type_description'] = self.error_class([_("This field is required.")])
# repeated code occurrence #1.1.
if 'certification_title' in cd_cdf and len(cd_cdf['certification_title'].strip()) == 0:
self._errors['certification_title'] = self.error_class([_("This field is required.")])
# repeated code occurrence #2.1.
if 'certification_date' in cd_cdf and cd_cdf['certification_date'] is not None:
if cd_cdf['certification_date'] > date.today():
self._errors['certification_date'] = self.error_class([_("Date must not be greater than today.")])
elif 'certification_type' in cd_cdf and cd_cdf['certification_type'] != display_types.ENTER_MY_OWN_DETAILS:
# repeated code occurrence #1.2.
if 'certification_title' in cd_cdf and len(cd_cdf['certification_title'].strip()) == 0:
self._errors['certification_title'] = self.error_class([_("This field is required.")])
# repeated code occurrence #2.2.
if 'certification_date' in cd_cdf and cd_cdf['certification_date'] is not None:
if cd_cdf['certification_date'] > date.today():
self._errors['certification_date'] = self.error_class([_("Date must not be greater than today.")])
elif 'certification_type' in cd_cdf and cd_cdf['certification_type'] == display_types.ENTER_MY_OWN_DETAILS:
if 'certification_description' in cd_cdf and len(cd_cdf['certification_description'].strip()) == 0:
self._errors['certification_description'] = self.error_class([_("This field is required.")])
# remove the entered value and/or assign a default value, when the certification type only requires minimum data.
if 'certification_type_description' in cd_cdf and len(cd_cdf['certification_type_description'].strip()) > 0:
cd_cdf['certification_type_description'] = None
if 'certification_title' in cd_cdf and len(cd_cdf['certification_title'].strip()) > 0:
cd_cdf['certification_title'] = None
if 'certification_institution' in cd_cdf and len(cd_cdf['certification_institution'].strip()) > 0:
cd_cdf['certification_institution'] = None
if 'certification_date' in cd_cdf and cd_cdf['certification_date'] is not None:
cd_cdf['certification_date'] = None
return cd_cdf
Here is the types code, just in case:
CERTIFICATE = 1
CERTIFICATE_LEVEL_I = 2
CERTIFICATE_LEVEL_II = 3
CERTIFICATE_LEVEL_III = 4
CERTIFICATE_LEVEL_IV = 5
STANDARD_CERTIFICATE = 6
INTERMEDIATE_CERTIFICATE = 7
ADVANCED_CERTIFICATE = 8
ACADEMIC_CERTIFICATE = 9
PROFESSIONAL_CERTIFICATE = 10
OTHER_CERTIFICATE = 11
ENTER_MY_OWN_TYPE_DESCRIPTION = 7777 # 7777 triggers a hidden text field to be displayed.
ENTER_MY_OWN_DETAILS = 9999
CERTIFICATION_TYPES = (
(CERTIFICATE, _('Certificate')),
(CERTIFICATE_LEVEL_I, _('Certificate Level I')),
(CERTIFICATE_LEVEL_II, _('Certificate Level II')),
(CERTIFICATE_LEVEL_III, _('Certificate Level III')),
(CERTIFICATE_LEVEL_IV, _('Certificate Level IV')),
(STANDARD_CERTIFICATE, _('Standard Certificate')),
(INTERMEDIATE_CERTIFICATE, _('Intermediate Certificate')),
(ADVANCED_CERTIFICATE, _('Advanced Certificate')),
(ACADEMIC_CERTIFICATE, _('Academic Certificate')),
(PROFESSIONAL_CERTIFICATE, _('Professional Certificate')),
(OTHER_CERTIFICATE, _('Other Certificate')),
(ENTER_MY_OWN_TYPE_DESCRIPTION, _('Enter my own Type Description')),
(ENTER_MY_OWN_DETAILS, _('Enter my own details'))
)

Like this:
def clean(self):
cd_cdf = super(CertificationDetailsForm, self).clean()
ctype = 'certification_type'
ctypedesc = 'certification_type_description'
ctitle = 'certification_title'
cdate = 'certification_date'
cdesc = 'certification_description'
cinst = 'certification_institution'
# Must check the most specific cases first, then the general cases.
if ctype in cd_cdf:
if cd_cdf[ctype] == '':
self._errors[ctype] = self.error_class([_("This field is required.")])
elif (cd_cdf[ctype] == display_types.ENTER_MY_OWN_TYPE_DESCRIPTION) or (cd_cdf[ctype] != display_types.ENTER_MY_OWN_DETAILS):
if cd_cdf[ctype] == display_types.ENTER_MY_OWN_TYPE_DESCRIPTION:
if ctypedesc in cd_cdf and len(cd_cdf[ctypedesc].strip()) == 0:
self._errors[ctypedesc] = self.error_class([_("This field is required.")])
else:
if ctitle in cd_cdf and len(cd_cdf[ctitle].strip()) == 0:
self._errors[ctitle] = self.error_class([_("This field is required.")])
if cdate in cd_cdf and cd_cdf[cdate] is not None:
if cd_cdf[cdate] > date.today():
self._errors[cdate] = self.error_class([_("Date must not be greater than today.")])
elif cd_cdf[ctype] == display_types.ENTER_MY_OWN_DETAILS:
if cdesc in cd_cdf and len(cd_cdf[cdesc].strip()) == 0:
self._errors[cdesc] = self.error_class([_("This field is required.")])
# remove the entered value and/or assign a default value, when the certification type only requires minimum data.
forcheck = [ctypedesc, ctitle, cinst]
for i in forcheck:
if i in cd_cdf and len(cd_cdf[i].strip()) > 0:
cd_cdf[i] = None
if cdate in cd_cdf and cd_cdf[cdate] is not None:
cd_cdf[cdate] = None
return cd_cdf
I replaced your frequently mentioned strings with self-obvious variables and joined the second and third conditions. I haven't tested this.
I agree with the first answer, it's ineligant and unpythonic, but I have no idea what all these conditions are about so I can't shorten the code any further.

Related

Django 3.2 post_save signal invoked for all model instances even if 1 instance is used in the code to save

Is post_save signal called for all the mailbox model instances when we click save button in django model admin? Does the post_save signal work continuously in Apache server?When it is executed behind Apache, just when we refresh the page it again saving the same password in next password column as the previous password column.I need to check password history for 5 passwords to not repeat.The post_save code:
def check_oldest_password_instance(mbox):
passwd_list = []
oldest_password = None
oldest_password_datetime = datetime.now()
pfield = '1'
n = 0
mphistory = Phistory.objects.filter(mbox=mbox)
if mphistory:
print('======phistory exists====', mphistory)
for p in mphistory:
if p.password1:
passwd_list.append(p.password1)
oldest_password_datetime = p.datetime1
oldest_password = p.password1
pfield = '1'
if p.password2:
passwd_list.append(p.password2)
if oldest_password_datetime > p.datetime2:
oldest_password_datetime = p.datetime2
oldest_password = p.password2
pfield = '2'
if p.password3:
passwd_list.append(p.password3)
if oldest_password_datetime > p.datetime3:
oldest_password_datetime = p.datetime3
oldest_password = p.password3
pfield = '3'
if p.password4:
passwd_list.append(p.password4)
if oldest_password_datetime > p.datetime4:
oldest_password_datetime = p.datetime4
oldest_password = p.password4
pfield = '4'
if p.password5:
passwd_list.append(p.password5)
if oldest_password_datetime > p.datetime5:
oldest_password_datetime = p.datetime5
oldest_password = p.password5
pfield = '5'
print(len(passwd_list),pfield,'passwd_list_len,pfield_oldest')
n = len(passwd_list)
# For new mailbox, check if all 5 values are populated
# if n == 0:
# pfield = '1'
if n == 1:
pfield = '2'
if n == 2:
pfield = '3'
if n == 3:
pfield = '4'
if n == 4:
pfield = '5'
print(pfield,n, 'pfield-n------------------')
else:
oldest_password = None
n = 0
pfield = '1'
return (pfield, passwd_list)
def mbox_post_save(sender, instance, created, **kwargs):
mphistory = None
new_phistory = None
mphistory = None
print('post save callllll')
if created:
# Store the hashed password in Phistory table
#----------------
new_phistory = Phistory()
new_phistory.mbox = instance
new_phistory.password1 = instance.mpassword
new_phistory.datetime1 = datetime.now()
new_phistory.save()
#----------------
else:
print('# edit mbox post_save')
# Store the hashed password in Phistory table
#----------------
try:
mphistory = Phistory.objects.get(mbox=instance)
print(mphistory,'mppppp=======================')
except Exception as e:
print(e)
if mphistory:
print('PHISTORY--------')
(oldest_pfield, passwd_list) = check_oldest_password_instance(instance)
if oldest_pfield == '1':
mphistory.password1 = instance.mpassword
mphistory.datetime1 = datetime.now()
elif oldest_pfield == '2':
mphistory.password2 = instance.mpassword
mphistory.datetime2 = datetime.now()
elif oldest_pfield == '3':
mphistory.password3 = instance.mpassword
mphistory.datetime3 = datetime.now()
elif oldest_pfield == '4':
mphistory.password4 = instance.mpassword
mphistory.datetime4 = datetime.now()
elif oldest_pfield == '5':
mphistory.password5 = instance.mpassword
mphistory.datetime5 = datetime.now()
mphistory.save()
else:
if not mphistory:
print('# Add new phistory object 1st time for existing mbox')
new_phistory = Phistory()
new_phistory.mbox = instance
new_phistory.password1 = instance.mpassword
new_phistory.datetime1 = datetime.now()
new_phistory.save()
#----------------
return
The way the post_save signal is connected:
post_save.connect(mbox_post_save, sender=Mbox)
To answer your questions:
Post_save will still kick in if you save an object from the /admin section
It should be listening for all saves of a particular object - it should not be kicking off post_save routines for every object of that type. If this is happening to you there is likely something else going wrong, but I can't see it in the code provided here.
To check the existence of previous passwords is fairly simple. However I think you are making a mistake to put all this as a post_save signal. If you do it post_save you will have saved the mailbox password already, a change you will need to reverse if your password history check fails.
This is better put in the clean() function of your form (or validate() function of your API), so you can case an error if there is a history match.
I'd do it something like this:
forms.py
#first some support functions
def get_password_history(mbox):
#Is there an existing Phistory?
try:
mphistory = Phistory.objects.get(mbox=mbox)
except Phistory.DoesNotExist
return False
return mphistory
def is_password_used(mphistory, password):
#look for the password in the existing records
password_list = [
mphistory.password1,
mphistory.password2,
mphistory.password3,
mphistory.password4,
mphistory.password5,
]
if password in password_list:
return True
return False
def update_password_history(mphistory, password):
#I haven't bothered with datetime here as the oldest is always the highest,
#but if you need it you can add lines for that field to do a similar swap.
mphistory.password5 = mphistory.password4
mphistory.password4 = mphistory.password3
mphistory.password3 = mphistory.password2
mphistory.password2 = mphistory.password1
mphistory.password1 = password
mphistory.save()
then in your form.py clean method (or validation method for an API)
def clean(self):
cleaned_data = super().clean()
history = get_password_history(self)
if history:
previous_password_exists = is_password_used(history, cleaned_data.get('mpassword')
if previous_password_exists:
raise forms.ValidationError(
"The password has been used in the last five changes"
)
else:
#the below could also be done in your view after form.is_valid for clarity
update_password_history(history, cleaned_data.get('mpassword'))
Now you can keep your post_save just for creating a new password history in the event of mailbox creation.
def mbox_post_save(sender, instance, created, **kwargs):
print('post save phistory creation')
if created:
# Store the hashed password in Phistory table
#----------------
new_phistory = Phistory()
new_phistory.mbox = instance
new_phistory.password1 = instance.mpassword
new_phistory.datetime1 = datetime.now()
new_phistory.save()
#----------------
return

AWS Lambda : Unexpected Multiple Invocation Issue (no errors)

from binance import Client
import os
def get_position_amt(bot, symbol):
get_position = bot.futures_position_information(symbol=symbol)
amt = float(get_position[0]['positionAmt'])
return amt
def close_all_position(bot, symbol):
print('close_all_position')
amt = get_position_amt(bot, symbol)
if amt > 0:
close_order = bot.futures_create_order(
symbol=symbol, side="SELL", type="MARKET", quantity=amt
)
print(close_order)
elif amt < 0:
close_order = bot.futures_create_order(
symbol=symbol, side="BUY", type="MARKET", quantity=abs(amt)
)
print(close_order)
else:
print("no position : amt is zero")
def lambda_handler(event, context):
bot = Client(api_key=os.environ.get('api_key'), api_secret=os.environ.get('api_sc'))
data = eval(event['body'])
side=data.get('side')
symbol=data.get('market')
amt = get_position_amt(bot, symbol)
if side == "BUY":
if amt < 0:
close_all_position(bot, symbol)
elif side == "SELL":
if amt > 0:
close_all_position(bot, symbol)
ord_type = data.get('ord_type')
if ord_type == 'limit':
order = bot.futures_create_order(
symbol=data.get('market'), side=data.get('side'), type="LIMIT", timeInForce='GTC', quantity=float(data.get('volume')), price=float(data.get('price'))
)
print(order)
elif ord_type == 'market':
order = bot.futures_create_order(
symbol=data.get('market'), side=data.get('side'), type="MARKET", quantity=float(data.get('volume'))
)
print(order)
elif ord_type == 'close':
close_all_position(bot, data.get('market'))
else:
raise ValueError
I need only 1 request but this invoke 4 different requests.
4 request IDs are all different so this means it's not an error.
I tried changing time limit and number of retrys on configuration but nothing happened.
I would appreciate it if anyone know how to handle this problem.

How can I assign different platform ID to multiple candidates before saving it to the database?

I have a formset that takes in 7 candidates and each candidate should have a platform id.
When I try to assign a platform to a candidate in a for loop, it only assigns the first platform ID to all candidates.
here is my view fuction.
def addcandidate(request):
party = PartyList.objects.all()
partylist_form = PartylistForm()
PlatformSet = formset_factory( PlatformForm,extra=7)
candidateFormSet = formset_factory(CandidateProfileForm,extra=7)
form1 = PlatformSet(prefix='platform')
form2 = candidateFormSet(prefix='candidate')
if request.method == 'POST':
partylist_form = PartylistForm(request.POST)
form1 = PlatformSet(request.POST, prefix='platform')
form2 = candidateFormSet(request.POST,request.FILES,prefix='candidate')
if form1.is_valid() and form2.is_valid() and partylist_form.is_valid():
try:
partylist = PartyList.objects.get(partylist_name=request.POST['partylist_name'])
except ObjectDoesNotExist:
partylist = partylist_form.save()
for f1 in form1:
p1 = f1.cleaned_data['platform']
p2 = f1.cleaned_data['platform2']
p3 = f1.cleaned_data['platform3']
try:
Platform.objects.get(candidate_platform=p1)
except ObjectDoesNotExist:
platform = Platform(candidate_platform=p1,candidate_platform2=p2,candidate_platform3=p3)
platform.save()
for count,f2 in enumerate(form2):
name = f2.cleaned_data['name']
img = f2.cleaned_data['Candidate_Img']
try:
CandidateProfile.objects.get(name=name)
except ObjectDoesNotExist:
candidate = CandidateProfile(Candidate_Img=img,name=name)
candidate.save()
candidate.platform = platform
candidate.partylist = partylist
if count == 0:
candidate.position = Position.objects.get(id=1)
elif count == 1:
candidate.position = Position.objects.get(id=2)
elif count == 2:
candidate.position = Position.objects.get(id=3)
elif count == 3:
candidate.position = Position.objects.get(id=4)
elif count == 4:
candidate.position = Position.objects.get(id=5)
elif count == 5:
candidate.position = Position.objects.get(id=6)
elif count == 6:
candidate.position = Position.objects.get(id=7)
candidate.save()
return redirect(request.META['HTTP_REFERER'])
else:
print(form1.errors)
print(form2.errors)
print(form1.non_form_errors)
print(form2.non_form_errors)
context = {'form1':form1,'form2':form2,'party':party}
return render(request,"accounts/admindashboard.html", context)
I have tried saving it after assigning a platform ID but the result was the same. only the fist platform is being assigned to all candidates.

Pyomo: Extending the "car ampl example" with additional constraints

After having seen the nice implementation of the "ampl car example" in Pyomo repository, I would like to keep extending the problem with new features and constraints, but I have found the next problems during development. Is someone able of fix them?
1) Added new constraint "electric car": Now the acceleration is limited by adherence until a determined speed and then constant power model is used. I am not able of implement this constraint as i would think. It is commented in the, but Pyomo complains about that a constraint is related to a variable. (now Umax depends of the car speed).
2) Added new comfort acceleration and jerk constraints. It seems they are working right, but should be nice if a Pyomo guru supervise them and tell me if they are really implemented in the correct way.
3) About last one, in order of reducing verbosity. Is there any way of combine accelerationL and accelerationU in a unique constraint? Same for jerkL and jerkU.
4) The last feature is a speed limit constraint divided in two steps. Again, I am not able of getting it works, so it is commented in code. Does anybody dare to fix it?
# Ampl Car Example (Extended)
#
# Shows how to convert a minimize final time optimal control problem
# to a format pyomo.dae can handle by removing the time scaling from
# the ContinuousSet.
#
# min tf
# dx/dt = v
# dv/dt = u - R*v^2
# x(0)=0; x(tf)=L
# v(0)=0; v(tf)=0
# -3 <= u <= 1 (engine constraint)
#
# {v <= 7m/s ===> u < 1
# u <= { (electric car constraint)
# {v > 7m/s ===> u < 1*7/v
#
# -1.5 <= dv/dt <= 0.8 (comfort constraint -> smooth driving)
# -0.5 <= d2v/dt2 <= 0.5 (comfort constraint -> jerk)
# v <= Vmax (40 kmh[0-500m] + 25 kmh(500-1000m])
from pyomo.environ import *
from pyomo.dae import *
m = ConcreteModel()
m.R = Param(initialize=0.001) # Friction factor
m.L = Param(initialize=1000.0) # Final position
m.T = Param(initialize=50.0) # Estimated time
m.aU = Param(initialize=0.8) # Acceleration upper bound
m.aL = Param(initialize=-1.5) # Acceleration lower bound
m.jU = Param(initialize=0.5) # Jerk upper bound
m.jL = Param(initialize=-0.5) # Jerk lower bound
m.NFE = Param(initialize=100) # Number of finite elements
'''
def _initX(m, i):
return m.x[i] == i*m.L/m.NFE
def _initV(m):
return m.v[i] == m.L/50
'''
m.tf = Var()
m.tau = ContinuousSet(bounds=(0,1)) # Unscaled time
m.t = Var(m.tau) # Scaled time
m.x = Var(m.tau, bounds=(0,m.L))
m.v = Var(m.tau, bounds=(0,None))
m.u = Var(m.tau, bounds=(-3,1), initialize=0)
m.dt = DerivativeVar(m.t)
m.dx = DerivativeVar(m.x)
m.dv = DerivativeVar(m.v)
m.da = DerivativeVar(m.v, wrt=(m.tau, m.tau))
m.obj = Objective(expr=m.tf)
def _ode1(m, i):
if i==0:
return Constraint.Skip
return m.dt[i] == m.tf
m.ode1 = Constraint(m.tau, rule=_ode1)
def _ode2(m, i):
if i==0:
return Constraint.Skip
return m.dx[i] == m.tf * m.v[i]
m.ode2 = Constraint(m.tau, rule=_ode2)
def _ode3(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] == m.tf*(m.u[i] - m.R*m.v[i]**2)
m.ode3 = Constraint(m.tau, rule=_ode3)
def _accelerationL(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] >= m.aL*m.tf
m.accelerationL = Constraint(m.tau, rule=_accelerationL)
def _accelerationU(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] <= m.aU*m.tf
m.accelerationU = Constraint(m.tau, rule=_accelerationU)
def _jerkL(m, i):
if i==0:
return Constraint.Skip
return m.da[i] >= m.jL*m.tf**2
m.jerkL = Constraint(m.tau, rule=_jerkL)
def _jerkU(m, i):
if i==0:
return Constraint.Skip
return m.da[i] <= m.jU*m.tf**2
m.jerkU = Constraint(m.tau, rule=_jerkU)
'''
def _electric(m, i):
if i==0:
return Constraint.Skip
elif value(m.v[i])<=7:
return m.a[i] <= 1
else:
return m.v[i] <= 1*7/m.v[i]
m.electric = Constraint(m.tau, rule=_electric)
'''
'''
def _speed(m, i):
if i==0:
return Constraint.Skip
elif value(m.x[i])<=500:
return m.v[i] <= 40/3.6
else:
return m.v[i] <= 25/3.6
m.speed = Constraint(m.tau, rule=_speed)
'''
def _initial(m):
yield m.x[0] == 0
yield m.x[1] == m.L
yield m.v[0] == 0
yield m.v[1] == 0
yield m.t[0] == 0
m.initial = ConstraintList(rule=_initial)
discretizer = TransformationFactory('dae.finite_difference')
discretizer.apply_to(m, nfe=value(m.NFE), wrt=m.tau, scheme='BACKWARD')
#discretizer = TransformationFactory('dae.collocation')
#discretizer.apply_to(m, nfe=value(m.NFE), ncp=4, wrt=m.tau, scheme='LAGRANGE-RADAU')
solver = SolverFactory('ipopt')
solver.solve(m,tee=True)
print("final time = %6.2f" %(value(m.tf)))
t = []
x = []
v = []
a = []
u = []
for i in m.tau:
t.append(value(m.t[i]))
x.append(value(m.x[i]))
v.append(3.6*value(m.v[i]))
a.append(10*value(m.u[i] - m.R*m.v[i]**2))
u.append(10*value(m.u[i]))
import matplotlib.pyplot as plt
plt.plot(x, v, label='v (km/h)')
plt.plot(x, a, label='a (dm/s2)')
plt.plot(x, u, label='u (dm/s2)')
plt.xlabel('distance')
plt.grid('on')
plt.legend()
plt.show()
Thanks a lot in advance,
Pablo
(1) You should not think of Pyomo constraint rules as callbacks that are used by the solver. You should think of them more as a function to generate a container of constraint objects that gets called once for each index when the model is constructed. Meaning it is invalid to use a variable in an if statement unless you are really only using its initial value to define the constraint expression. There are ways to express what I think you are trying to do, but they involve introducing binary variables into the problem, in which case you can no longer use Ipopt.
(2) Can't really provide any help. Syntax looks fine.
(3) Pyomo allows you to return double-sided inequality expressions (e.g., L <= f(x) <= U) from constraint rules, but they can not involve variable expressions in the L and U locations. It doesn't look like the constraints you are referring to can be combined into this form.
(4) See (1)

Python (Django) Class that aliases/overloads list index behavior to attributes

I have a class that stores information about a week:
from django.db import models
#A django model, so can't subclass list (at least not easily)
class MyWeek(models.Model):
sunday = "foo"
monday = "foo"
tuesday = "foo"
wednesday = "foo"
thursday = "foo"
friday = "foo"
saturday = "foo"
I'd like to be able to access these attributes as if the class was a list:
aweek = Myweek()
#I want this
aweek[0] = "bar"
myvar = aweek[1]
#To be shorthand for this
aweek.monday = "bar"
myvar = aweek.tuesday
#and of course
aweek[7]
ValueError/IndexError: Week indexes monday to 0 and sunday to 6, there is no 7
Everything about python makes think this is possible and easy, if only I know the right set of things to overload.
I've thought of #property, but that doesn't help so much because I want to be able to use a variable to access it:
#I want to be able to do this
aweek[somevar] = "bar"
#and via property, i'd have to use exec
#and this is just ugly and scary from an "oh god, what could somevar be" perspective
exec("aweek.%s = 'bar'" % somevar)
#Or, as kojiro pointed out below, it could be done like this:
setattr(aweek, "somevar", "bar")
Thanks.
Edit: Working code, hattip to kojiro for helping with the right methods to overload:
# overload []
def __getitem__(self, index):
index = int(index) #will raise value error if uncoercable, this is desired behavior
if index < 0 or index > 6:
raise ValueError("Requires an integer index between 0 and 6, monday is 0 sunday is 6")
if index == 0:
return self.monday
elif index == 1:
return self.tuesday
elif index == 2:
return self.wednesday
elif index == 3:
return self.thursday
elif index == 4:
return self.friday
elif index == 5:
return self.saturday
elif index == 6:
return self.sunday
# overload set []
def __setitem__(self, index, item):
index = int(index) #will raise value error if uncoercable, this is desired behavior
if index < 0 or index > 6:
raise ValueError("Requires an integer index between 0 and 6, monday is 0 sunday is 6")
if index == 0:
self.monday = item
return
elif index == 1:
self.tuesday = item
return
elif index == 2:
self.wednesday = item
return
elif index == 3:
self.thursday = item
return
elif index == 4:
self.friday = item
return
elif index == 5:
self.saturday = item
return
elif index == 6:
self.sunday = item
return
To create a list-like object in python you need to create the following methods:
__len__, __getitem__, __setitem__, __delitem__, __iter__, and __contains__
Link to explanatory example.