Passing constructor parameter to a function that generates default value fails - python-2.7

I am very new to Python so I assume I am doing something terribly wrong, but I don't see what and Google has not helped this far too. What is wrong with this ?
def lookup_permille(name):
# TODO: implement a permille lookup table
return 0
def lookup_known_product(name):
# TODO: implement a known product lookup table
return 0
class ProductEntry:
def __init__(self, source, name, price, volume, permille = lookup_permille(name), known_product_id = lookup_known_product(name), category = 0):
self.source = source
self.name = name
self.price = price
self.volume = volume
self.permille = permille
self.price_per_permille = self.permille / self.price;
self.category = category
self.known_product_id = known_product_id
Calling the constructor of ProductEntry fails with:
def __init__(self, source, name, price, volume, permille = lookup_permille(name), known_product_id = lookup_known_product(name), category = 0):
NameError: name 'name' is not defined

The expressions defining default arguments are evaluated when the function is defined, not when it is called. At the point when __init__ is being defined, name does not exist, so it cannot be used in an expression to calculate a default argument.
The usual way to do something like this is to have a stand-in value as your default argument, and replace it with whatever value you actually want inside the body of your function.
def __init__(self, source, name, price, volume,
permille=None, known_product_id=None, category=0):
if permille is None:
permille = lookup_permille(name)
if known_product_id is None:
known_product_id = lookup_known_product(name)
...

Related

Replacement for django `render_options`

So I am implementing this answer: Country/State/City dropdown menus inside the Django admin inline, but the def render piece of code needs to be redone.... I have managed to redo it, but I am struggling to find a replacement (or the correct code) for the self.render_options method (which was deprecated on 1.11) of the Widget class.
I am on Django 2.1.
What should I change?
Here is my code:
class StateChoiceWidget(widgets.Select):
def render(self, name, value, attrs=None, renderer=None):
self.choices = [(u"", u"---------")]
if value is None:
value = ''
model_obj = self.form_instance.instance
if model_obj and model_obj.country:
for m in model_obj.country.state_set.all():
self.choices.append((m.id, smart_text(m)))
else:
obj = State.objects.get(id=value)
for m in State.objects.filter(country=obj.country):
self.choices.append((m.id, smart_text(m)))
final_attrs = self.build_attrs(attrs)
output = ['<select%s>' % flatatt(final_attrs)]
for option in self.choices:
output.append('<option value="%s">%s</option>' % (option[0], option[1]))
output.append('</select>')
return mark_safe(''.join(output))
Original poster updated the sample code, so now it doesn't show the code in the question: see previous revision https://stackoverflow.com/revisions/52174508/1
So I figured out the answer. Will post it here in case someone runs into the same issue.
class StateChoiceWidget(widgets.Select):
def render(self, name, value, attrs=None, renderer=None):
self.choices = [(u"", u"---------")]
if value is None or value == '':
value = ''
model_obj = self.form_instance.instance
if model_obj and model_obj.country:
for m in model_obj.country.state_set.all():
self.choices.append((m.id, smart_text(m)))
else:
obj = State.objects.get(id=value)
for m in State.objects.filter(country=obj.country):
self.choices.append((m.id, smart_text(m)))
final_attrs = self.build_attrs(attrs)
s = widgets.Select(choices=self.choices)
select_html = s.render(name=name,value=value,attrs=attrs)
return mark_safe(''.join(select_html))

How to execute a function when a variable's value is changed?

In Odoo 10, I want to change the value of a variable when the forecasted quantity of a product is changed. I tried using the #api.onchange decorator, but it doesn't work. The forecasted quantity change, but the variable keeps the same value. I have this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default = False)
#api.onchange('virtual_available')
def qtychanged(self):
self.was_changed = True
_logger.info('Product_Qty_Cahnged: %s',str(self.virtual_available))
In this code, if the forecasted quantity of a product would change, the variable was_changed should be set to True, but nothing happens.
After that, I tried to overwrite the write method for my custom class, like this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default=False)
#api.multi
def write(self, values):
if values['virtual_available']:
values['was_changed'] = True
# THE FOLLOWING LINES WERE IN THE ORIGINAL WRITE METHOD
res = super(MyProduct, self).write(values)
if 'standard_price' in values:
self._set_standard_price(values['standard_price'])
return res
But still, I have the same result. I can't seem to get that flag to change. So, any ideas?
Try this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default = False)
#api.onchange('virtual_available')
def qtychanged(self):
self.write({'was_changed': True})
_logger.info('Product_Qty_Cahnged: %s',str(self.virtual_available))

Change a series I have been given

from sqlalchemy import Column, Integer, String, Boolean, Float, DateTime, ForeignKey
from sqlalchemy.orm import relationship, reconstructor
from app import utils
import datetime
import pandas
from base import Base
from series import Series
class ConstantSeries(Series):
__tablename__ = 'constantseries'
# ID Primary Key (linked to parent)
id = Column(Integer, ForeignKey('series.id'), primary_key=True)
# The value of this series to be returned for all periods.
value = Column(Float)
__mapper_args__ = {'polymorphic_identity': 'constantseries'}
def GetData(self, scenario, periods):
"""Get data values for the specified periods.
"""
return pandas.Series(data=[self.value]*len(periods), index=periods)
I have been given the code above but I want to be able to change it so that I can have a series that has different values depending on what day it is. For example if it is a weekday I have a value of 100 and for a weekend have a value of 200
Can you tell me how you are calling the above code and what it currently returns?
It seems that the GetData function just returns a data structure, i.e. it returns the structure of a Column for every period, but no actual data.
What's not shown here is how the actual data in the Columns is populated and accessed.
You could loop through your periods and build the Series data according to the day e.g if periods contained ['mon','tue','wed','thu','fri','sat','sun']
def GetData(self, scenario, periods):
mydata = {}
for p in periods:
if p in ['sat','sun']:
e[p] = 200
else:
e[p] = 100
return pandas.Series(mydata, index=periods)
Then calling GetData should return something like
'mon' 100
'tue' 100
...
'sat' 200
'sun' 200
but thats not the structure you want and i dont think its how the Getdata function is being used.
def GetData(self, scenario, periods):
rtn = {}
for timest, val in cap.GetData(base_scenario,utils.enumerate_periods(start,end,'H','CET')).iteritems():
if timest.weekday_name in ['Saturday', 'Sunday']:
rtn[timest.weekday_name] = (0.72 * val)
#0.46*2574
else:
rtn[timest.weekday_name] = (1.0 * val)
return [rtn]
#Define ConstantSeries class
#I have made no changes here, just what you already had
class ConstantSeries(Series):
__tablename__ = 'constantseries'
# ID Primary Key (linked to parent)
id = Column(Integer, ForeignKey('series.id'), primary_key=True)
# The value of this series to be returned for all periods.
value = Column(Float)
__mapper_args__ = {'polymorphic_identity': 'constantseries'}
def GetData(self, scenario, periods):
"""Get data values for the specified periods.
"""
return pandas.Series(data=[self.value]*len(periods), index=periods)
#End of class definition
#Define new special Cap2Series class
class Cap2Series(Series):
#I'm not sure how tablename is used so be aware, might need to put constantseries as before
__tablename__ = 'cap2series'
# ID Primary Key (linked to parent)
id = Column(Integer, ForeignKey('series.id'), primary_key=True)
# The value of this series to be returned for all periods.
value = Column(Float)
#Same as above, I'm not sure how this is used so be aware, might need to put constantseries as before
__mapper_args__ = {'polymorphic_identity': 'cap2series'}
#Define GetData method of our new special class
def GetData(self, scenario, periods):
#instantiate new ConstantSeries instance called cap when you call GetData
cap = (ConstantSeries(value=self.value))
rtn = {}
for timest, val in cap.GetData(scenario, periods).iteritems():
if timest.weekday_name in ['Saturday', 'Sunday']:
rtn[timest.weekday_name] = (0.72 * val)
#0.46*2574
else:
rtn[timest.weekday_name] = (1.0 * val)
return pandas.Series(data=rtn, index=periods)
#End of class definition
#Instantiate new Cap2Series instance called cap2
cap2 = Cap2Series(1647)
#Call GetData method of cap2 instance
cap2.GetData(base_scenario, utils.enumerate_periods(start,end,'H','CET')).plot()
#Is this something like what you're trying to do?

object inheritance arugment input error

Playing around with inheritance and came across an error stating that I am inputing too many arguments. What could I be doing wrong?
This first file is called media.py
class Video():
def __init__(self, title, duration):
self.title = title
self.duration = duration
class Movie(Video):
def __init__(self, movie_story, movie_poster, trailer_youtube):
Video.__init__(self, title, duration)
self.storyline = movie_story
self.poster_image_url = movie_poster
self.trailer_youtube_url = trailer_youtube
def show_trailer(self):
webbrowser.open(self.trailer_youtube_url)
class TvShow(Video):
def __init__(self, season, episode, tv_station):
Video.__init__(self, title, duration)
self.season = season
self.episode = episode
self.tv_station = tv_station
This second file creates the objects.
import fresh_tomatoes
import media
family_guy = media.TvShow("Family Guy",
"2000-Present",
"Fifteen Seasons",
"Twenty-Eight",
"Fox")
print family_guy.title
The terminal output states I'm passing 6 arguments when only 4 may be accepted. Why is that?
Calling the parent __init__ will only invoke it , but you still need to pass in the arguments to it.
So when you invoke __init__ method for TvShow it only expects 3 +1(self) arguments , while you were trying to send more than that. So to solve the issue you just need to increase the number of arguments excepted by the __init__.
class Video():
def __init__(self, title, duration):
self.title = title
self.duration = duration
class Movie(Video):
def __init__(self, movie_story, movie_poster, trailer_youtube):
Video.__init__(self, title, duration)
self.storyline = movie_story
self.poster_image_url = movie_poster
self.trailer_youtube_url = trailer_youtube
def show_trailer(self):
webbrowser.open(self.trailer_youtube_url)
class TvShow(Video):
def __init__(self, season, episode, tv_station, title, duration):
Video.__init__(self, title, duration)
self.season = season
self.episode = episode
self.tv_station = tv_station

Is it dangerous to define __contains__ on a metaclass?

I'm writing a custom EnumMeta class in Python 2.7 that will collect enum keys and values from some class and augment that class with some additional fields.
class EnumMeta(type):
def __init__(cls, name, bases, props):
cls.__all_values__ = [...] # collect all interesting properties
def __contains__(cls, value):
return value in cls.__all_values__
class TheFellowshipOfTheRing(object):
__metaclass__ = EnumMeta
FRODO = 'Frodo Baggins'
SAM = 'Samwise "Sam" Gamgee'
MERRY = 'Meriadoc "Merry" Brandybuck'
PIPPIN = 'Peregrin "Pippin" Took'
GANDALF = 'Gandalf the Grey'
ARAGORN = 'Aragorn (Strider)'
LEGOLAS = 'Legolas'
GIMLI = 'Gimli'
BOROMIR = 'Boromir'
print 'Gandalf the Grey' in TheFellowshipOfTheRing
# True
print 'Saruman' in TheFellowshipOfTheRing
# False
I'm wondering if implementing container-specific functions, such as __contains__, on a metaclass is a dangerous thing to do, and if so, why?