Object doesn't implement IField - python

I have following piece of code to patch the Folder:
ATFolderSchema = ATContentTypeSchema.copy() + \
ConstrainTypesMixinSchema.copy() + NextPreviousAwareSchema.copy()
finalizeATCTSchema(ATFolderSchema, folderish=True, moveDiscussion=False)
field = StringField("rafal_shortdescription",
schemata = "default",
widget = StringWidget(
label = _(u"label_shortdescription",
default=u"Short Description"),
description = _(u"help_shortdescription",
default=u"Used in tabs."),
),
),
ATFolderSchema.addField(field)
and last line throws:
File "/home/rafal/projects/vidensportalen_v2/eggs/Products.Archetypes-1.6.4-py2.6.egg/Products/Archetypes/Schema/__init__.py", line 198, in _validateOnAdd
raise ValueError, "Object doesn't implement IField: %r" % field
zope.configuration.xmlconfig.ZopeXMLConfigurationError: File "/home/rafal/projects/vidensportalen_v2/parts/instance/etc/site.zcml", line 12.2-12.39
ZopeXMLConfigurationError: File "/home/rafal/projects/vidensportalen_v2/eggs/Plone-4.0.2-py2.6.egg/Products/CMFPlone/meta.zcml", line 39.4-43.10
ValueError: Object doesn't implement IField: <Field rafal_shortdescription(string:rw)>
Any idea why?

I'd advise you to use archetypes.schemaextender instead of using patches to alter Archetypes content types.
The package includes documentation on how to implement your additional field.
As for your error, you created a tuple with one element, a field:
>>> example = 1,
>>> print example
(1,)
Delete the trailing comma and your code should work as intended.

Related

Python Get Account using tda-api returns ValueError

I have the following api call to tda-api
orders = client.get_account(config.account_id,fields=['positions'])
Gives the Error:
File "/opt/anaconda3/lib/python3.7/site-packages/tda/client/base.py", line 361, in get_account
fields = self.convert_enum_iterable(fields, self.Account.Fields)
File "/opt/anaconda3/lib/python3.7/site-packages/tda/utils.py", line 66, in convert_enum_iterable
self.type_error(value, required_enum_type)
File "/opt/anaconda3/lib/python3.7/site-packages/tda/utils.py", line 41, in type_error
possible_members_message))
ValueError: expected type "Fields", got type "str". (initialize with enforce_enums=False to disable this checking)
the documentation follows:
Client.get_account(account_id, *, fields=None)
and if i replace with:
client.get_account(config.account_id,fields=positions)
'positions' is not defined
And if i look into the api the code for the get_account() function looks like:
class Fields(Enum):
'''Account fields passed to :meth:`get_account` and
:meth:`get_accounts`'''
POSITIONS = 'positions'
ORDERS = 'orders'
def get_account(self, account_id, *, fields=None):
fields = self.convert_enum_iterable(fields, self.Account.Fields)
params = {}
if fields:
params['fields'] = ','.join(fields)
Most likely not the correct way to go about this but I found a fix for now.
I commented out the following that checks for the type in the utils.py file for the tda package.
def convert_enum_iterable(self, iterable, required_enum_type):
if iterable is None:
return None
if isinstance(iterable, required_enum_type):
return [iterable.value]
values = []
for value in iterable:
if isinstance(value, required_enum_type):
values.append(value.value)
# elif self.enforce_enums:
# self.type_error(value, required_enum_type)
else:
values.append(value)
return values
I believe if you create your own client you can set this property to false as well.
And then I am able to use the following to get my current positions:
data = client.get_account(config.account_id,fields=['positions'])
At one point, I had these working but haven't tried in a while. I do recall it being difficult to decipher what a field type was. Depending on your import statements, you might need the entire tda.client.Client.Account.Fields.POSITIONS, for example.
r_acct_orders = client.get_account(config.ACCOUNT_ID, fields=tda.client.Client.Account.Fields.ORDERS).json() # field options None, ORDERS, POSITIONS
r = client.get_account(config.ACCOUNT_ID, fields=tda.client.Client.Account.Fields.POSITIONS).json() # field options None, ORDERS, POSITIONS
r = client.get_accounts(fields=tda.client.Client.Account.Fields.ORDERS).json() # field options None, ORDERS, POSITIONS
r = client.get_accounts(fields=None).json() # field options None, ORDERS, POSITIONS
Also, I use a config.py for account_id but you can just use your syntax as needed.

python/Pyqt5 - how to avoid eval while using ast and getting ValueError: malformed string in attemt to improve code safety

I'm trying to prevent to use eval based on an example how-to-avoid-eval-in-python-for-string-conversion using ast. The challange is that there are a dozen of these self.ch%s_label's to be made but the variable for it changes based on user input in the GUI.
My code:
import ast ...etc.
....
channel_no += 1
ch_width = eval('self.ch%s_label.frameGeometry().width()' % (channel_no))
When I change it into:
ch_width = ast.literal_eval('self.ch%s_label.frameGeometry().width()' % (channel_no))
I'll get the error:
File "c:\python\anac2\lib\ast.py", line 80, in literal_eval
return _convert(node_or_string)
File "c:\python\anac2\lib\ast.py", line 79, in _convert
raise ValueError('malformed string')
ValueError: malformed string
Changing the code (using closing " ") retains the error:
ch_width = ast.literal_eval("'self.ch%s_label.frameGeometry().width()' % (channel_no)")
What other options are there... Any suggestions?
You could use getattr to get the attribute from the instance using the dynamically constructed attribute name:
ch_width = getattr(self, 'ch%s_label' % channel_no).frameGeometry().width()
Or step by step:
channel_no = 5
attr_name = 'ch%s_label' % channel_no
attr = getattr(self, attr_name)
ch_width = attr.frameGeometry().width()
Using getattr in this way also means you get an AttributeError if an object doesn't have the attribute, as you'd expect.

In wtforms How to use the example from the docs in a real form?

In the wtform docuentation the following function is described as a widget that can render a SelectMultipleField as a collection of checkboxes:
def select_multi_checkbox(field, ul_class='', **kwargs):
kwargs.setdefault('type', 'checkbox')
field_id = kwargs.pop('id', field.id)
html = [u'<ul %s>' % html_params(id=field_id, class_=ul_class)]
for value, label, checked in field.iter_choices():
choice_id = u'%s-%s' % (field_id, value)
options = dict(kwargs, name=field.name, value=value, id=choice_id)
if checked:
options['checked'] = 'checked'
html.append(u'<li><input %s /> ' % html_params(**options))
html.append(u'<label for="%s">%s</label></li>' % (field_id, label))
html.append(u'</ul>')
return u''.join(html)
I am trying to actually use this as an example to see what it looks like in one of my forms. However I am having some trouble and I am not sure how to call it since I am only used to using the default fields. This is what I have tried:
class myForm(FlaskForm):
my_choices = [('1', 'Choice1'), ('2', 'Choice2'), ('3', 'Choice3')]
my_multi_select = SelectMultipleField(choices = my_choices,id='Test')
my_checkbox_multi_select = select_multi_checkbox(my_multi_select)
This gives me the following error:
line 52, in select_multi_checkbox
field_id = kwargs.pop('id', field.id)
AttributeError: 'UnboundField' object has no attribute 'id'
My next iteration was this:
my_checkbox_multi_select = select_multi_checkbox(SelectMultipleField,ul_class='',choices=my_choices,id='test')
This also gave me an error with the id attribute but the field wasn't Unbounded anymore.
line 52, in select_multi_checkbox
field_id = kwargs.pop('id', field.id)
AttributeError: type object 'SelectMultipleField' has no attribute 'id'
I was wondering what the proper way to implement this is. I see that it is a function so I thought that it needed to be called on a field but I wasn't sure what I was doing wrong.
So I figured this out. I guess it was in the documentation but it was unclear to me for a while. Here is what I did to render this field. I guess this should have been obvious but if anyone else is looking for this here it is:
tester = SelectMultipleField(choices=my_choices, widget=select_multi_checkbox)
Just call it as a widget. Simple enough. I wish I had put that together earlier.

What can cause failure to store an `int` to an `IntField`?

I have the following MongonEngine models:
from app import db
from datetime import datetime
from mongoengine import signals
class PathEmbedded(db.EmbeddedDocument):
"""
To be embedded.
"""
_id = db.ObjectIdField(required=False)
distance = db.IntField(required=False, min_value=0, default=0)
meta = {
"allow_inheritance": True,
}
def __unicode__(self):
return "Path '%s': %d m" % (self.id, self.distance)
class Path2(PathEmbedded, db.Document):
"""
Same as above, but standalone version to be stored in its own collection.
"""
_id = db.ObjectIdField()
orig = db.ObjectIdField(required=True)
dest = db.ObjectIdField(required=True)
updateStamp = db.DateTimeField(required=True)
ok_to_use = db.BooleanField(required=True, default=False)
meta = {
'indexes': [
{
'fields': ['ok_to_use', 'orig', 'dest'],
'cls': False, # does this affect performance?!
},
],
}
#classmethod
def pre_save(cls, sender, document, **kwargs):
document.updateStamp = datetime.utcnow()
def to_embedded(self):
"""
Converts the standalone Path instance into an embeddadle PathEmbedded instance.
"""
import json
temp = json.loads(self.to_json())
#remove the {"_cls": "Location"} key.
#If we don't do this, the output will be a 'Location' instance, not a 'LocationEmbedded' instace
temp.pop('_cls')
return PathEmbedded().from_json(json.dumps(temp))
def get_from_gmaps(self):
"""
Get distance from Google maps using the directions API and append to the 'paths' list.
Return False on error or True on success.
"""
try:
self.distance = 10,
self.save()
except Exception, e:
print str(e)
return False
else:
return True
# connect event hooks:
signals.pre_save.connect(Path2.pre_save, sender=Path2)
So, at some point I'm updating a path instance by calling get_from_gmaps():
from app.models.Path2 import Path2 as P
from bson import ObjectId
p=P(orig=ObjectId(), dest=ObjectId())
p.save()
p.get_from_gmaps()
which raises:
>>> p.get_from_gmaps()
ValidationError (Path2:54d34b97362499300a6ec3be) (10 could not be converted to int: ['distance'])
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "[...]app/models/Path2/get_from_gmaps.py", line 18, in get_from_gmaps
self.save()
File "[...]venv/local/lib/python2.7/site-packages/mongoengine/document.py", line 224, in save
self.validate(clean=clean)
File "[...]venv/local/lib/python2.7/site-packages/mongoengine/base/document.py", line 323, in validate
raise ValidationError(message, errors=errors)
ValidationError: ValidationError (Path2:54d34b97362499300a6ec3be) (10 could not be converted to int: ['distance'])
Originally I was storing an integer parsed from some json and converted to int, and thought somthing was wrong there, but i replaced it with an int value for debugging and now get this. I really don't know where to start o.O
EDIT: expanded code to provide complete [non]working example.
There's an extra comma after the 10:
self.distance = 10,
^
You are setting distance to a tuple containing an int, instead of an int.
HINT: The reason why your are seeing such an unhelpful message is that MongoEngine is using %s format string improperly. In fact, the result of "%s" % something depends on the type of something, as tuples are special cased. Compare:
>>> '%s' % 10
'10'
>>> '%s' % (10,)
'10'
>>> '%s' % (10, 11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
>>> '%s' % ((10,),) # This is the correct way of formatting strings
'(10,)' # when the type of the argument is unknown.
This is a MongoEngine's problem of course, but if you want to avoid the same kind of mistake in your code, remember to always use tuples at the right of the % operator, or even better use the .format() method.
Are you sure the self model you send is the right one?
This ValidationError is thrown when you have declare a ReferenceField in a document, and you try to save this document before saving the referenced document (Mongoengine represents a reference field in MongoDB as an dictionnay containing the class and the ObjectId of the reference).

mongoengine: test1 is not a valid ObjectId

I got the following error message:
$ python tmp2.py
why??
Traceback (most recent call last):
File "tmp2.py", line 15, in <module>
test._id = ObjectId(i[0])
File "/home/mictadlo/.virtualenvs/unisnp/lib/python2.7/site-packages/bson/objectid.py", line 92, in __init__
self.__validate(oid)
File "/home/mictadlo/.virtualenvs/unisnp/lib/python2.7/site-packages/bson/objectid.py", line 199, in __validate
raise InvalidId("%s is not a valid ObjectId" % oid)
bson.errors.InvalidId: test1 is not a valid ObjectId
with this code:
from bson.objectid import ObjectId
from mongoengine import *
class Test(Document):
_id = ObjectIdField(required=True)
tag = StringField(required=True)
if __name__ == "__main__":
connect('dbtest2')
print "why??"
for i in [('test1', "a"), ('test2', "b"), ('test3', "c")]:
test = Test()
test._id = ObjectId(i[0])
test.char = i[1]
test.save()
How is it possible to use its own ids which are unique too?
According to the documentation: http://docs.mongoengine.org/apireference.html#fields, ObjectIdField is 'A field wrapper around MongoDB’s ObjectIds.'. So it cannot accept a string test1 as an object id.
You may have to change the code to something like this:
for i in [(bson.objectid.ObjectId('test1'), "a"), (bson.objectid.ObjectId('test2'), "b"), (bson.objectid.ObjectId('test3'), "c")]:
for your code to work (Assuming test1 etc are valid id)
Two things:
ObjectId receives a 24 hex string, you can't initialize it with that string. For instance, instead of using 'test1' you can use a string such as '53f6b9bac96be76a920e0799' or '111111111111111111111111'. You don't even need to initialize an ObjectId, you could do something like this:
...
test._id = '53f6b9bac96be76a920e0799'
test.save()
...
I don't know what are you trying to accomplish by using _id. If you are trying to produce and id field or "primary key" for you document, it's not necessary because one is generated automatically. Your code would be:
class Test(Document):
tag = StringField(required=True)
for i in [("a"), ("b"), ("c")]:
test = Test()
test.char = i[0]
test.save()
print(test.id) # would print something similar to 53f6b9bac96be76a920e0799
If you insist in using a field named _id you must know that your id will be the same, because internally, MongoDB calls it _id. If you still want to use string1 as identifier you should do:
class Test(Document):
_id = StringField(primary_key=True)
tag = StringField(required=True)

Categories