how to concatenate tow Values as strings into an odoo Char field? - python

i'm trying to get fields from another model then do some operation on them, there is no problem with logic but I'm getting this error when the methods runs
psycopg2.DataError: invalid input syntax for type double precision: "1.007 t"
these all what I have done
class uom_custom(models.Model):
_inherit = 'product.template'
uom_qty = fields.Char(store=True,compute='get_qty')
#api.depends('qty_available')
def get_qty(self):
uoms=self.env['uom.uom'].search(['&',('category_id', '=', self.uom_id.category_id.id),('show_qty','=',True)])
if uoms.uom_type == 'bigger':
self.uom_qty= str(str(self.qty_available / uoms.factor_inv) + ' ' + uoms.name)
elif self.uom_type =='smaller':
self.uom_qty= str(self.qty_available * uoms.factor_inv) + ' ' + uoms.name
else:
self.uom_qty= str(self.qty_available) + ' ' + uoms.name
return self.uom_qty
so how can I display the value of mathematic operation and uom name beside it
Thanks in advance

The error states that the column in database is defined as double precision. Are you sure you've restarted Odoo and updated your module?
And there are some common mistakes in your compute method. Firstly and i can't repeat it often enough: try to stick to the Odoo naming guideline and name it compute_uom_qty. Secondly without a special decorator a compute method can and will be called with more than one record, so loop on that records. Thirdly: you search for uom.uom which can lead to more than one record, too. So either limit the search to one record or/and implement a check if something was found. uoms.name can lead to SingletonError. And at last: you don't have to return anything in compute methods.
#api.depends('qty_available')
def compute_uom_qty(self):
for record in self:
uoms = self.env['uom.uom'].search(
[('category_id', '=', record.uom_id.category_id.id),
('show_qty','=',True)], limit=1)
if uoms.uom_type == 'bigger':
qty = record.qty_available / uoms.factor_inv
record.uom_qty = "{} {}".format(qty, uoms.name)
elif uoms.uom_type =='smaller':
qty = record.qty_available * uoms.factor_inv
record.uom_qty = "{} {}".format(qty, uoms.name)
else:
record.uom_qty = "{} {}".format(record.qty_available, uoms.name)

Related

Python concatenating boolean to string doesn't work

As a part of program I wrote the following method (hidden is a boolean variable). It's located in an object called Deltext, which inherits a type called DelMsg. info_msg() is overriding and using a similar method in its parent type.
def info_msg(self):
info = DelMsg.info_msg(self)
if self.code == 'l': # If message is long message
return info + '#' + str(len(self.content)) + '#' + str(self.hidden)
elif self.code == 'm': # If message is snap message
return info + '#' + str(self.timeout) + '#' + self.content
else: # If message is a normal message
return info + '#' + self.content + '#' + str(self.hidden)
But every time I call the method (from the object instance) it displays an error: TypeError: cannot concatenate 'str' and 'bool' objects, and says the error is in the last line, even though hidden is parsed to string.
Is there any way to solve this without using conditionals?
Here's how you can proceed to debug your code:
check the type of the variables:
Edit you code to include the following print(type(variable))
def info_msg(self):
print(type(info))
print(type(self.content))
return info + '#' + self.content + '#' + str(self.hidden)
Then, run the program and see which other variable is boolean.
add str(...) to the boolean variables
At most, all variables will be of type boolean, so you can edit your code as follows:
def info_msg(self):
return str(info) + '#' + str(self.content) + '#' + str(self.hidden)
An other option is to use str.format, which will take care of casting the variables to string for you:
def info_msg(self):
return "{0}#{1}#{2}".format(info, self.content, self.hidden)
Probably info or content are boolean too. You can overcome this with
def info_msg(self):
return str(info) + '#' + str(self.content) + '#' + str(self.hidden)

python ignoring one of the 2 conditions in maya

I'm pretty new with python (20days) but I already created few stuff in maya, for example pickers, ik-fk snap, and few more things. Now I'm trying to create a button to mirror the pose.
the problem is that i must give 2 conditions to my if cycle but maya is ignoring the second condition
import maya.cmds as cmds
cmds.select('arm_lf_FK_ctrl1', 'arm_lf_FK_ctrl2', 'arm_lf_FK_ctrl3')
baseOBJ = cmds.ls(sl=True)
cmds.select('arm_rt_FK_ctrl1', 'arm_rt_FK_ctrl2', 'arm_rt_FK_ctrl3')
targetOBJ = cmds.ls(sl=True)
attr = ['translateX', 'translateY', 'translateZ', 'rotateX', 'rotateY', 'rotateZ', 'IK' ]
for i in range(len (attr) ):
for x in range(len (targetOBJ) ):
if (cmds.attributeQuery(attr[i], node = targetOBJ[x], exists = True) \
and cmds.getAttr(targetOBJ[x] + '.' + attr[i], lock = False)):
newValue = cmds.getAttr(baseOBJ[x] + '.' + attr[i])
cmds.setAttr(baseOBJ[x] + '.' + attr[i], newValue)
else:
pass
the error is:
Error: RuntimeError: file <maya console> line 17: setAttr: The attribute 'arm_lf_FK_ctrl1.translateX' is locked or connected and cannot be modified. #
but in the if cycle I wrote: cmds.getAttr(targetOBJ[x] + '.' + attr[i], lock = False)
any hint?
EDIT SOLUTION:
here is the code fixed
import maya.cmds as cmds
cmds.select('arm_lf_FK_ctrl1', 'arm_lf_FK_ctrl2', 'arm_lf_FK_ctrl3')
baseOBJ = cmds.ls(sl=True)
cmds.select('arm_rt_FK_ctrl1', 'arm_rt_FK_ctrl2', 'arm_rt_FK_ctrl3')
targetOBJ = cmds.ls(sl=True)
attr = ['translateX', 'translateY', 'translateZ', 'rotateX', 'rotateY', 'rotateZ', 'IK' ]
for i in range(len (attr) ):
for x in range(len (baseOBJ) ):
if (cmds.attributeQuery(attr[i], node = baseOBJ[x], exists = True) \
and cmds.getAttr(baseOBJ[x] + '.' + attr[i], lock = False)):
newValue = cmds.getAttr(baseOBJ[x] + '.' + attr[i])
cmds.setAttr(targetOBJ[x] + '.' + attr[i], newValue)
else:
pass
You need to specify
cmds.getAttr(item + attribute, lock=True)
even if you are checking for an attribute you expect to be locked: the 'lock = true' says 'tell me the lock state', not 'tell me if lock is true'.
You can do this a little more simply using three common python tricks (and also by not adding the extra selections, which will just duplicate the lists you've passed in)
The first is to use a foreach loop -- getting values directly out of the list -- instead of using array indices. This is the standard method for doing loops in python. So instead of
for index in range(len(list_of_things)):
do_something(list_of_things[index])
you just do
for item in list_of_things:
do_something(item)
The second is to use zip() to match up to lists and loop over them as pairs: This makes it much easier to write loops that read cleanly as you keep values in sync.
The final thing is to use try...except and allow some kinds of errors to happen rather than pre-checking. This is a common python trick since exceptions are not expensive and the resulting code is often much more readable.
Putting these together you could do the same code like this:
sources = ('arm_lf_FK_ctrl1', 'arm_lf_FK_ctrl2', 'arm_lf_FK_ctrl3')
targets = ('arm_rt_FK_ctrl1', 'arm_rt_FK_ctrl2', 'arm_rt_FK_ctrl3')
attr = ('.translateX', '.translateY', '.translateZ', '.rotateX', '.rotateY', '.rotateZ', '.IK' )
for source, target in zip(sources, targets):
for attrib in attr:
try:
val = cmds.getAttr(source + attrib)
cmds.setAttr(target + attrib, val)
except Exception as e:
print 'skipped', source + attrib, target + attrib
In this case Maya will throw a RuntimeError if you pass it a bad object, a bad attribute, or if you try to set a locked attribute. You'll really want to be more careful with the check than I was here, depending on what you wish to do when the system tries to do something impossible.
One last trick that will make your life easier is to separate out your condition checks from the logic. Instead of
if (cmds.attributeQuery(attr[i], node = baseOBJ[x], exists = True) \
and cmds.getAttr(baseOBJ[x] + '.' + attr[i], lock = False)):
You may find it easier in the long run to do :
exists, locked = False
try:
exists = cmds.ls(object + attrib) is not None
locked = cmds.getAttr(object + attrib, lock = True)
except:
pass # if the object or attrib is missing, both vals will still be false
if exists and not locked:
#do something
writing it this way makes it easier to insert debug printouts when things go wrong.
I do not know maya, but it looks like the issue is happening in the first condition itself, thus the second is being ignored. moreover the exception says issue while running setAttr. This function will be call when you run an attributeQuery, saying exists = True, which would essentially mean you will end up adding the attribute if not already present.

How to write tests for generic method used to insert queries

I have a database class and this class contains a method used to insert records. This is how the method looks:
def insertRecord(self, **kwargs):
if 'table' not in kwargs.keys():
raise Exception('The table keyword is required')
table = kwargs['table']
del kwargs['table']
query_fields = kwargs.keys()
pg_fields = []
for field in query_fields:
pg_fields.append('%(' + field + ')s')
query_field_string = ', '.join(query_fields)
query_pg_string = ', '.join(pg_fields)
self.cur.execute('INSERT INTO ' + table + '(' +
query_field_string + ') VALUES (' + query_pg_string + ')',
kwargs
)
self.conn.commit()
The method accepts variable arguments list so the user can use this method to insert entries in any table. Bassically, the method is constructing a query string of the form INSERT INTO <table>(<field1>, <field2>...) VALUES (%(field1)s, %(field2)s...), since the execute method accepts as the second argument a dictionary of the form <field>: <value> all the strings of the form %(field)s will be replaced with the corresponding value.
Basically, the method works fine, but I don't know how should I test it. Should I make a test database and see if the values passed to it are in the database after calling it? How would you write tests for such a method?
Refactor the code to format the SQL command, then test that. In this way it's much simpler -- pass in args, get a formatted string and a dictionary back. No mocking needed.
source
# python -m unittest insertrec
import unittest
def formatInsert(table, **kwargs):
assert table
query_fields = kwargs.keys()
pg_fields = []
for field in query_fields:
pg_fields.append('%(' + field + ')s')
query_field_string = ', '.join(query_fields)
query_pg_string = ', '.join(pg_fields)
return (
'INSERT INTO ' + table + '(' +
query_field_string + ') VALUES (' + query_pg_string + ')',
kwargs
)
class TestInsert(unittest.TestCase):
def test_err_notable(self):
self.assertRaises(AssertionError, formatInsert, None)
def test_insert1(self):
self.assertEquals(
formatInsert('mytab', beer='tasty'),
('INSERT INTO mytab(beer) VALUES (%(beer)s)',
{'beer': 'tasty'}
),
)

Function: Lambda is not a string — what does this mean?

I'm relatively new to this, but I'm trying to create a computedproperty for my NDB entity in Google App Engine. Right now I have:
class Player(ndb.Model):
name = ndb.StringProperty(required=True)
wins = ndb.IntegerProperty(required=True)
losses = ndb.IntegerProperty(required=True)
record = ndb.ComputedProperty(lambda self: 1. * self.wins / (self.wins + self.losses))
rank = ndb.IntegerProperty(lambda self: self.record * 1000 if self.wins + self.losses >= 10 else 500 + 1000 * (self.record-0.5) * (self.wins+self.losses) * (self.wins+self.losses) / 100)
And one of these two lambda properties (I'm not sure which, since neither is line 850) is causing an error when I try to create a Player object. I get the message (on the console):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 850, in __init__
raise TypeError('Name %r is not a string' % (name,))
TypeError: Name <function <lambda> at 0x10c531a28> is not a string
What am I doing wrong? Why does the lambda function need to be a string? And, how can I make it into a string that does what I want it to do? I've tried a simpler version too, without the if/else statement, and I get the same error.
Let me know what else you need to know and I will be happy to oblige.
The first positional argument to an IntegerProperty (which you're using for 'rank') is taken to be its datastore-name, which has to be a string. Did you mean this to be another ComputedProperty?

Printing individual list objects within __str__ using .format(**self.__dict__)

I'm printing a stat block for a game character object. In a previous question I was demonstrated a way to display the object data using in the __str__ function like so:
def __str__(self):
if self.poisoned is True:
status = "[POISONED]"
else:
status = ""
self.status = status
return ('NAME: {name} {status}\n' \
'XP: {xp}\n' \
'HP: {hit_points}\n' \
'SP: {spell_points}\n' \
'STR: {strength}\n' \
'DEX: {dexterity}\n' \
'WEAPON: {weapon}\n' \
'SPELL: {spell}\n' \
'ITEM: {item}\n' \
'AURA: {aura}\n' \
).format(**self.__dict__)
The problem I want to solve has to do with the WEAPON, SPELL, ITEM and AURA variables. These items are defined in the Character object as single item lists: weapon=[] and so on. Using the above method returns the list object instead of the object it contains without the []. I'd rater see a blank " " string or the list's contained object if one exists and not [].
NAME: Bones
XP: 0
HP: 100
SP: 100
STR: 14
DEX: 19
WEAPON: []
SPELL: []
ITEM: []
AURA: []
I've tried a number of experiments including replacing the {weapon} reference with {current_weapon} after defining current_weapon = weapon[0] which won't work if the list object is empty. That just errors with IndexError: list index out of range. I could generate the items at object instantiation, but that won't work as self.item will at times be an empty list container.
I could propagate the lists with " " objects but would then have to juggle them out with replacement items and keep track of this which seems very inelegant and potentially cumbersome.
I just can't seem to wrap my head around an elegant way to print the list object in the above __str__ return as currently designed. I'm still learning Python and want to believe there is a simple addition I could append to this return string to do this.
Another option is to use the power of string formatting to check attributes of what it's passed in, and the fact that self is a local variable within the method:
def __str__(self):
status = '[POISONED]' if self.poisoned else ''
weapon = self.weapon[0] if self.weapon else ''
spell = self.spell[0] if self.spell else ''
item = self.item[0] if self.item else ''
aura = self.aura[0] if self.aura else ''
return ('NAME: {self.name} {status}\n'
'XP: {self.xp}\n'
'HP: {self.hit_points}\n'
'SP: {self.spell_points}\n'
'STR: {self.strength}\n'
'DEX: {self.dexterity}\n'
'WEAPON: {weapon}\n'
'SPELL: {spell}\n'
'ITEM: {item}\n'
'AURA: {aura}\n'
).format(**locals())
You could just create a local copy of your dict, and modify the values you want, before passing that on to the format:
def __str__(self):
local_data = self.__dict__.copy()
local_data['status'] = "[POISONED]" if self.poisoned else ""
local_data['weapon'] = " " if not self.weapon else ','.join(self.weapon)
return ('NAME: {name} {status}\n' \
'XP: {xp}\n' \
'HP: {hit_points}\n' \
'SP: {spell_points}\n' \
'STR: {strength}\n' \
'DEX: {dexterity}\n' \
'WEAPON: {weapon}\n' \
'SPELL: {spell}\n' \
'ITEM: {item}\n' \
'AURA: {aura}\n' \
).format(**local_data)
It is probably better to do that, than to modify your attributes simple for the formatting, like you were doing with your self.status. Now you are just modifying temp copies.
You can do it in a simple way, even if not so trivial. You can modify the string format to take the whole object and harness the power of the properties.This has the advantage of not creating a copy of your dictionary, that can be expensive for big object.
I'll give you an example that should be close to what you need:
class A(object):
def __init__(self):
# one full list and one empty one
self.c = [1,2,3]
self.d = []
#these two preperties create a string versione when requeste
c_str = property(lambda self: ", ".join(str(i) for i in self.c))
d_str = property(lambda self: ", ".join(str(i) for i in self.d))
def __str__(self):
#you have to use the dotted version because properties are not visibles
# from the dict attribute
string = "c = {0.c_str} \nd = {0.d_str}"
return string.format(self)
a = A()
print str(a)
# c = 1, 2, 3
# d =
If you are programming some kind of game properties can be a huge lifesavers, as you can use them to obtain complicated values as attribute instead of functions, creating a lot more cleaner code. They allow you to implement even check for the insertion of value, for examples that a value is positive.
EDIT:
Why I am using the 0.c_str instead of c_str? it is because the properties are special objects that will be called only if you access them with the dot notation (self.c_str). They do not exist in the objects __dict__ so you can't use it. If you try to print the __dict__ you will see only the values c and d.
That's why I passed to the format function the whole object and accessed its attributes instead of passing it the object dictionary.
If you don't like the 0.c_str notation you can escape it differently, for example keeping it close to the usual notation:
"{self.c_str}".format(self=self)
or
"{foo.c_str}".format(foo=self)

Categories

Resources