When, why and how to avoid KeyError in Odoo Development - keyerror

I´ve noticed that some custom modules that I develop can be installed on databases with records, while others throw the KeyError message, unless the database is empty (no records). Generally the errors appear when the module contains computed fields. So, does anybody know why this happens? and how my code should look like to avoid this kind of errors?
an example computed field that throws this errors looks like this:
from odoo import models, fields, api
from num2words import num2words
Class InheritingAccountMove(models.Model):
_inherit = 'account.move'
total_amount_text = fields.Char(string='Total', compute='_compute_total_amount_text', store=True)
#api.depends('amount_total')
def _compute_total_amount_text(self):
lang_code = self.env.context.get('lang') or self.env.user.lang
language = self.env['res.lang'].search([('iso_code', '=', lang_code)])
separator = language.read()[0]['decimal_point']
for record in self:
decimal_separator = separator
user_language = lang_code[:2]
amount = record.amount_total
amount_list = str(amount).split(decimal_separator)
amount_first_part = num2words(int(amount_list[0]), lang=user_language).title() + ' '
amount_second_part = amount_list[1]
if len(amount_second_part) == 0:
amount_text = amount_first_part + '00/100'
elif len(amount_second_part) < 2:
amount_text = amount_first_part + amount_second_part + '0/100'
else:
amount_text = amount_first_part + amount_second_part[:2] + '/100'
record.total_amount_text = amount_text

UPDATED
The reason your code has a problem in this situation is that when there are no records in the table(at time of installation) your loop won’t run which result in no value assigning of your computed field so
Add the first line of code in function
self.total_amount_text = False This is required to assign value to the computed field in compute function from Odoo 13 and maybe 12
----------------------------------------------------------------
Other reasons could be :
This error occurs when one tries to access a key from a dictionary that doesn't exist like,
language.read()[0]['decimal_point']
the dictionary may not have 'decimal_point' at the time of installation of the module, which may have returned this error a common way to handle this is by checking if the key exists or not before accessing it like,
if 'decimal_point' in language.read()[0].keys()
also, a dictionary can also be empty in that case the language.read()[0] will throw an error

I´ve changed my code making it specifically for spanish and the error doesn´t appear anymore. I appreciate Muhammad´s answer, maybe he´s right but anyway here is the modified code:
#api.depends('invoice_line_ids')
def _compute_total_amount_text(self):
for record in self:
amount = record.amount_total
amount_list = str(amount).split('.')
amount_first_part = num2words(int(amount_list[0]), lang='es').title() + ' '
amount_second_part = amount_list[1]
if len(amount_second_part) == 0:
amount_text = amount_first_part + '00/100'
elif len(amount_second_part) < 2:
amount_text = amount_first_part + amount_second_part + '0/100'
else:
amount_text = amount_first_part + amount_second_part[:2] + '/100'
record.total_amount_text = amount_text

Related

How do I get the full list list sent via telegram when web scrapping

I have managed to get the text I want but I can't seem to send the entire list to a telegram message. I only manage to send the first line.
service = Service(executable_path=ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get("")
Source = driver.page_source
soup = BeautifulSoup(Source, "html.parser")
for cars in soup.findAll(class_="car-title"):
print(cars.text)
driver.close()
def telegram_bot_sendtext(bot_message):
bot_token = ''
bot_chatID = ''
send_text = 'https://api.telegram.org/bot' + bot_token + '/sendMessage?chat_id=' + bot_chatID + '&parse_mode=Markdown&text=' + bot_message
response = requests.get(send_text)
return response.json()
test = telegram_bot_sendtext(cars.text)
The print function gives me this
AUDI E-TRON
MERCEDES-BENZ EQC
TESLA MODEL 3
NISSAN LEAF
MERCEDES-BENZ EQV
AUDI E-TRON
At some point I would like to add a function to check for updates and if there any changes then send a push message to telegram. If someone could point me in the right direction I would be grateful.
What happens?
Your sending one line, cause you do not store the results anywhere and only the last result from iterating is in memory.
How to fix?
Asuming you want to send text as in the question, you should store results in variable - Iterate over resultset, extract text and join() results by newline character:
cars = '\n'.join([cars.text for cars in soup.find_all(class_="car-title")])
Example
...
cars = '\n'.join([cars.text for cars in soup.find_all(class_="car-title")])
def telegram_bot_sendtext(bot_message):
bot_token = ''
bot_chatID = ''
send_text = 'https://api.telegram.org/bot' + bot_token + '/sendMessage?chat_id=' + bot_chatID + '&parse_mode=Markdown&text=' + bot_message
response = requests.get(send_text)
return response.json()
test = telegram_bot_sendtext(cars)

How I can save multiple screenshots when the test is fail

I use selenium with pytest to do some automation testing and I use a fixture to take a screenshot when it fails here is the code for the fixture:
timestamp = datetime.now().strftime('%H-%M-%S')
pytest_html = item.config.pluginmanager.getplugin('html')
outcome = yield
report = outcome.get_result()
extra = getattr(report, 'extra', [])
if report.when == 'call':
# always add url to report
# extra.append(pytest_html.extras.url('E:\Python Projects\StackField\screenshot'))
xfail = hasattr(report, 'wasxfail')
if (report.skipped and xfail) or (report.failed and not xfail):
feature_request = item.funcargs["request"]
driver = feature_request.getfixturevalue("setup")
img_name = "name.png"
img_path = os.path.join("E:\Python Projects\StackField\screenshot", img_name)
driver.save_screenshot(img_path)
# extra.append(pytest_html.extras.image('E:\Python Projects\StackField\screenshot' + timestamp + '.png'))
if (report.skipped and xfail) or (report.failed and not xfail):
# only add additional html on failure
extra.append(pytest_html.extras.image(img_path))
extra.append(pytest_html.extras.html('<div>Additional HTML</div>'))
report.extra = extra
And I got an issue when more than 1 test is failed the same screenshot is added to the report my next question is how can I add more than 1 screenshot inside?
Thank you in advance!
Seems you save all screenshots with the same name.
Try to set the unique name for the screenshot:
from random import randrange
if (report.skipped and xfail) or (report.failed and not xfail):
feature_request = item.funcargs["request"]
driver = feature_request.getfixturevalue("setup")
timestamp = datetime.now().strftime('%H-%M-%S')
img_name = "name" + timestamp + ".png"
# (even better also add some random number in advance "name" + timestamp + randrange(100) + ".png"
img_path = os.path.join("E:\Python Projects\StackField\screenshot", img_name)
driver.save_screenshot(img_path)

Get sender message if keyword is in it then use part of it

i want to use a command /price, if only /price is send give price of 1 unit.
if its /price 5 give price of 5 units.
in normal telegram import i can use this:
def handleCommandPrice(self, update, context):
message = update.message
text = message.text
try:
priceMultiplier = Decimal(text.replace("/" + COMMAND_PRICE, "").replace(' ', ''))
except InvalidOperation:
priceMultiplier = Decimal(1)
priceMultiplied = getCurrentCoinPrice() * priceMultiplier
priceMultiplied = round(priceMultiplied, 5)
update.message.reply_text(text = "$ " + str(priceMultiplied), parse_mode=telegram.ParseMode.HTML)
How to make this in Telethon? can you give me an advise or hint please?
Greetings

Amount to text conversion not found in odoo11

In odoo 10 we have amount_to_text_en.py file in odoo/tools. I was looking for similar file in odoo 11. But I can't find it . What to do ?
Need I require to create that file in my custom module or is it present in odoo11 with different file name ? Please Help. Thanks in Advance ..
or simply add this span to your report:
<span t-if="doc.currency_id" t-esc="doc.currency_id.amount_to_text(doc.amount_total)"/>
I think this is the function you're looking for,
#api.multi
def amount_to_text(self, amount):
self.ensure_one()
def _num2words(number, lang):
try:
return num2words(number, lang=lang).title()
except NotImplementedError:
return num2words(number, lang='en').title()
if num2words is None:
logging.getLogger(__name__).warning("The library 'num2words' is missing, cannot render textual amounts.")
return ""
formatted = "%.{0}f".format(self.decimal_places) % amount
parts = formatted.partition('.')
integer_value = int(parts[0])
fractional_value = int(parts[2] or 0)
lang_code = self.env.context.get('lang') or self.env.user.lang
lang = self.env['res.lang'].search([('code', '=', lang_code)])
amount_words = tools.ustr('{amt_value} {amt_word}').format(
amt_value=_num2words(integer_value, lang=lang.iso_code),
amt_word=self.currency_unit_label,
)
if not self.is_zero(amount - integer_value):
amount_words += ' ' + _('and') + tools.ustr(' {amt_value} {amt_word}').format(
amt_value=_num2words(fractional_value, lang=lang.iso_code),
amt_word=self.currency_subunit_label,
)
return amount_words
You can find this function in base/res/res_currency.py.
And you can call this function like below,
words = self.currency_id.with_context(lang=self.partner_id.lang or 'es_ES').amount_to_text(amount_i).upper()
I hope this will help you.

3Ds MAx Script for Reading Pixels from an image

We are trying to read the pixels from an uploaded Bitmap image, yet the line
aBrightness = (0.2126*aPixel[1].red) + (0.7152*aPixel[1].green) + (0.0722*aPixel[1].blue) always gives an error saying "Unknown property: "red" in undefined".
Our current script is:
aBitmap = selectBitMap caption:"Select a Bitmap"
Print(aBitmap.height)
Print(aBitmap.width)
aLength = aBitmap.height
aWidth = aBitmap.width
for i = 0 to (aLength - 10) by 10 do
(
for j = 0 to (aWidth - 10) by 10 do
(
Print(i)
Print(j)
aPixel = getPixels aBitmap [i,j] 1
aBrightness = (0.2126*aPixel[1].red) + (0.7152*aPixel[1].green) + (0.0722*aPixel[1].blue)
aBox = box pos:[i,j,0] width:0.1 length:0.1 height:aBrightness
)
)
We would really appreciate any help regarding this script.
You have your coordinates wrong. The X value goes first.
It should be
APixels = Getpixels aBitmap [j, i] 1
You can check to see if aPixel is undefined before using it.
aPixel = getPixels aBitmap [i,j] 1
if (aPixel == undefined) do ( format "ERROR!!! [%,%]\n" i, j to:listener; continue )
aBrightness = (0.2126*aPixel[1].red) + (0.7152*aPixel[1].green) + (0.0722*aPixel[1].blue)
This might help you figure where the bug is. Often a function will return 'undefined' to a variable so you need to check if it is undefined. In this case, once you fix the bug, you can remove this type of code since you will have eliminated undefined behavior. Notice I used "format" instead of "print", this is much nicer to use for just a tiny extra code.
I see two suspicious things to check.
1) Most indexing in maxscript starts with 1 not 0. Check the documentation.
2) As Rotem pointed out, [x,y], not [y,x]