I am using the shelve module to save some Python objects (strings in the example).
When I am trying to save an object as a nested key, then it is not being saved.
class Car:
def __init__(self, ID):
self.id = ID
def save_to_shelf(self):
with shelve.open('shelf') as shelf:
if not shelf.get('users'):
shelf['users'] = {}
print(shelf['users'])
try:
shelf['users'][self.id] = "hello"
except Exception as e:
print(e)
print('saved')
print(shelf['users'])
car = Car(123)
car.save_to_shelf()
The code should print:
{}
saved
{123: hello}
But instead it prints:
{}
saved
{}
Meaning that it is not getting saved
If I print the value of the key, it gives KeyError
shelf['users'][self.id] = "hello"
print(shelf['users'][self.id])
Error
Traceback (most recent call last):
File "P:/Python practice/Shelll/main.py", line 3, in <module>
car.save_to_shelf()
File "P:/Python practice/Shelll\db.py", line 20, in save_to_shelf
print(shelf['users'][self.id])
KeyError: '123'
I am able to save it if I do the following while saving
Instead of
with shelve.open('shelf') as shelf:
shelf['users'][self.id] = "hello"
This works
with shelve.open('shelf') as shelf:
USERS = shelf['users']
USERS[self.id] = self.id
shelf['users'] = USERS
# or this works
# with shelve.open('shelf') as shelf:
# shelf['users'] = {self.id:"hello"}
I want to understand the reason behind this. As far as I know, shelve objects work as a dictionary. So the way I was saving earlier should work but does not.
Related
I have a dictionary (dict1)
dict1={
'lala':{
'name':'lala',
'lula':0xcafecafe,
},
'mene':{
'name':'mene',
'lula':0xdeadbeef,
},}
After that i created a register class to parse in the information
class register:
def __init__(self,name):
self.name = dict1[name].get('name')
self.data = dict1[name].get('lula')
def self_add(self):
value = self.data + self.data
print('self_add value : {}'.format(value))
and create a for loop to populate the it
for name, info in dict1.items():
reg_class = register(name)
vars()[reg_class.name]=reg_class ##work
vars()['base_path'+'.'+reg_class.name]= reg_class ## not working
however, when i use vars()[reg_class.name]=reg_class it is working
>>> mene.data
3735928559
>>> hex(mene.data)
'0xdeadbeef'
but when i use vars()['base_path'+'.'+reg_class.name]= reg_class it is not working
>>> base_path.mene.data
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'base_path' is not defined
How can i do that correctly?
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).
I am trying to read key-value pairs from an already existing shelf to create a new class object with a updated field and write that class object to a new shelf.
My class object : SongDetails
This is the procedure which fails:
def updateShelfWithTabBody(shelfFileName, newShelfFileName):
"""this function updates songDetails with
html body i.e. just the part that contains lyrics and
chords in the tab """
#read all songDetails
shelf = shelve.open(shelfFileName)
listOfKeys = shelf.keys()
#create new songDetails object
temporaryShelfObject = SongDetails.SongDetails()
#iterate over list of keys
for key in listOfKeys:
#print "name:"+shelf[key].name
#fill details from temporaryShelfObject
temporaryShelfObject.name = shelf[key].name
temporaryShelfObject.tabHtmlPageContent = shelf[key].tabHtmlPageContent
#add new detail information
htmlPageContent = shelf[key].tabHtmlPageContent
temporaryShelfObject.htmlBodyContent = extractDataFromDocument.fetchTabBody(htmlPageContent)
#write SongDetails back to shelf
writeSongDetails.writeSongDetails(temporaryShelfObject, newShelfFileName)
Definitions for functions used in above code:
def fetchTabBody(page_contents):
soup = BeautifulSoup(page_contents)
HtmlBody = ""
try:
#The lyrics and chords of song are contained in div with id = "cont"
#Note: This assumtption is specific to ultimate-guitar.com
HtmlBody = soup.html.body.find("div",{"id":"cont"})
except:
print "Error: ",sys.exc_info()[0]
return HtmlBody
def writeSongDetails(songDetails, shelfFileName):
shelf = shelve.open(shelfFileName)
songDetails.name = str(songDetails.name).strip(' ')
shelf[songDetails.name] = songDetails
shelf.close()
SongDetails class:
class SongDetails:
name = ""
tabHtmlPageContent = ""
genre = ""
year = ""
artist = ""
chordsAndLyrics = ""
htmlBodyContent = ""
scale = ""
chordsUsed = []
This is the error that I get:
Traceback (most recent call last):
File "/l/nx/user/ndhande/Independent_Study_Project_Git/Crawler/updateSongDetailsShelfWithNewAttributes.py", line 69, in <module>
updateShelfWithTabBody(shelfFileName, newShelfFileName)
File "/l/nx/user/ndhande/Independent_Study_Project_Git/Crawler/updateSongDetailsShelfWithNewAttributes.py", line 38, in updateShelfWithTabBody
writeSongDetails.writeSongDetails(temporaryShelfObject, newShelfFileName)
File "/home/nx/user/ndhande/Independent_Study_Project_Git/Crawler/writeSongDetails.py", line 7, in writeSongDetails
shelf[songDetails.name] = songDetails
File "/usr/lib64/python2.6/shelve.py", line 132, in __setitem__
p.dump(value)
File "/usr/lib64/python2.6/copy_reg.py", line 71, in _reduce_ex
state = base(self)
File "/u/ndhande/.local/lib/python2.6/site-packages/BeautifulSoup.py", line 476, in __unicode__
return str(self).decode(DEFAULT_OUTPUT_ENCODING)
**RuntimeError: maximum recursion depth exceeded**
I couldn't find any reason why I'm getting this error even though there is no explicit recursive call in my code. I have seen this error in other stackoverflow posts, but they did have recursive calls in their case.
str(self) calls __str__ or calls __unicode__ calls str(self).
I want to store an integer key in shelve. But when I try to store integer key in shelve it give me an error
Traceback (most recent call last):
File "./write.py", line 12, in
data[id] = {"Id": id, "Name": name}
File "/usr/lib/python2.5/shelve.py", line 124, in __setitem__
self.dict[key] = f.getvalue()
File "/usr/lib/python2.5/bsddb/__init__.py", line 230, in __setitem__
_DeadlockWrap(wrapF) # self.db[key] = value
File "/usr/lib/python2.5/bsddb/dbutils.py", line 62, in DeadlockWrap
return function(*_args, **_kwargs)
File "/usr/lib/python2.5/bsddb/__init__.py", line 229, in wrapF
self.db[key] = value
TypeError: Integer keys only allowed for Recno and Queue DB's
My Code :
#!/usr/bin/python
import shelve
data = shelve.open("data.txt")
ans = 'y'
while ans == "y":
id = input("Enter Id : ")
name = raw_input("Enter name : ")
data[id] = {"Id": id, "Name": name}
ans = raw_input("Do you want to continue (y/n) ? : ")
data.close()
Is something wrong in my program or shelve does not supports integer keys at all ?
Edit 1 :
In program I am trying to store a dictionary of Id and Name inside another dictionary with Id as a key. And then trying to store it in a file.
Do I need to use Recno or Queue DB's along with shelve? I am a beginner and things are confusing.
Let me know if I am not clear with my question.
Thanks.
In your example the keys in your database will always be integers, so it should work fine to convert them to strings,
data[str(id)] = {"Id": id, "Name": name}
My test code
def shelve_some_data(filename):
db = shelve.open(filename, flag="c")
try:
# note key has to be a string
db[str(1)] = "1 integer key that's been stringified"
db[str(2)] = "2 integer key that's been stringified"
db[str(3)] = "3 integer key that's been stringified"
db[str(10)] = "10 integer key that's been stringified"
finally:
db.close()
def whats_in(filename):
db = shelve.open(filename, flag="r")
for k in db:
print("%s : %s" % (k, db[k]))
return
filename = "spam.db"
shelve_some_data(filename)
whats_in(filename)
And the output; it works like a dict so it's not sorted.
2 : 2 integer key that's been stringified
10 : 10 integer key that's been stringified
1 : 1 integer key that's been stringified
3 : 3 integer key that's been stringified
The shelve module uses an underlying database package (such as dbm, gdbm or bsddb) .
A "shelf" is a persistent, dictionary-like object. The difference with "dbm" databases is that the values (not the keys!) in a shelf can be essentially arbitrary Python objects -- anything that the pickle module can handle. This includes most class instances, recursive data types, and objects containing lots of shared sub-objects. The keys are ordinary strings. The examples section gives you the proof.
This should work. Here's what I do in my code -
import shelve
#Create shelve
s = shelve.open('test_shelf.db')
try:
s['key1'] = { 'int': 10, 'float':9.5, 'string':'Sample data' }
finally:
s.close()
#Access shelve
s = shelve.open('test_shelf.db')
try:
existing = s['key1']
finally:
s.close()
print existing
UPDATE: You could try pickle module. It is not a key-value database but you can always build your data structure as a key-value pairs and then send it to pickle -
If you have an object x, and a file object f that's been opened for writing, the simplest way to pickle the object takes only one line of code
pickle.dump(x, f)
To unpickle the object again, if f is a file object which has been opened for reading:
x = pickle.load(f)
I hear cPickle is a lot faster than pickle. You can try this if you have lot of data to store.
I'm trying to get results from a SOAP service called Chrome ADS (for vehicle data). They provided php and Java samples, but I need python (our site is in Django). My question is:
What should I be passing as a request to the SOAP service when using wsdl2py-generated classes?
Following the examples I'm using a DataVersionsRequest object as the request parameter, but the code generated by wsdl2py seems to want a getDataVersions object, and there's something like that defined at the bottom of the generated _client.py file. But that too seems to throw an error. So I'm not sure what I should be passing as the request obj. Any suggestions?
$sudo apt-get install python-zsi
$wsdl2py http://platform.chrome.com/***********
$python
>>> url = "http://platform.chrome.com/***********"
>>> from AutomotiveDescriptionService6_client import *
>>> from AutomotiveDescriptionService6_types import *
>>> locator = AutomotiveDescriptionService6Locator()
>>> service = locator.getAutomotiveDescriptionService6Port()
>>> locale = ns0.Locale_Def('locale')
>>> locale._country="US"
>>> locale._language="English"
>>> acctInfo = ns0.AccountInfo_Def('accountInfo')
>>> acctInfo._accountNumber=*****
>>> acctInfo._accountSecret="*****"
>>> acctInfo._locale = locale
>>> dataVersionsRequest = ns0.DataVersionsRequest_Dec()
>>> dataVersionsRequest._accountInfo = acctInfo
>>> service.getDataVersions(dataVersionsRequest)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "AutomotiveDescriptionService6_client.py", line 36, in getDataVersions
raise TypeError, "%s incorrect request type" % (request.__class__)
TypeError: <class 'AutomotiveDescriptionService6_types.DataVersionsRequest_Dec'> incorrect request type
>>> dataVersionsRequest = getDataVersions
>>> dataVersionsRequest._accountInfo = acctInfo
>>> service.getDataVersions(dataVersionsRequest)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "AutomotiveDescriptionService6_client.py", line 36, in getDataVersions
raise TypeError, "%s incorrect request type" % (request.__class__)
AttributeError: class DataVersionsRequest_Holder has no attribute '__class__'
>>> quit()
$cat AutomotiveDescriptionService6_client.py
.....
# Locator
class AutomotiveDescriptionService6Locator:
AutomotiveDescriptionService6Port_address = "http://platform.chrome.com:80/AutomotiveDescriptionService/AutomotiveDescriptionService6"
def getAutomotiveDescriptionService6PortAddress(self):
return AutomotiveDescriptionService6Locator.AutomotiveDescriptionService6Port_address
def getAutomotiveDescriptionService6Port(self, url=None, **kw):
return AutomotiveDescriptionService6BindingSOAP(url or AutomotiveDescriptionService6Locator.AutomotiveDescriptionService6Port_address, **kw)
# Methods
class AutomotiveDescriptionService6BindingSOAP:
def __init__(self, url, **kw):
kw.setdefault("readerclass", None)
kw.setdefault("writerclass", None)
# no resource properties
self.binding = client.Binding(url=url, **kw)
# no ws-addressing
# op: getDataVersions
def getDataVersions(self, request, **kw):
if isinstance(request, getDataVersions) is False:
raise TypeError, "%s incorrect request type" % (request.__class__)
# no input wsaction
self.binding.Send(None, None, request, soapaction="", **kw)
# no output wsaction
response = self.binding.Receive(getDataVersionsResponse.typecode)
return response
.....
getDataVersions = GED("urn:description6.kp.chrome.com", "DataVersionsRequest").pyclass
Also, as an aside, I'm not sure that the strings I'm passing to the pname parameter are correct, I assume that those are the ones I see inside the XML when I explore the service with SOAP UI, right?
It looks like you might be passing a class to service.getDataVersions() the second time instead of an instance (it can't be an instance if it doesn't have __class__).
What's happening is isinstance() returns false, and in the process of trying to raise a type error, an attribute error gets raised instead because it's trying to access __class__ which apparently doesn't exist.
What happens if you try:
>>> dataVersionsRequest = getDataVersions**()**
>>> dataVersionsRequest._accountInfo = acctInfo
>>> service.getDataVersions(dataVersionsRequest)
?
Based on the line:
if isinstance(request, getDataVersions) is False:
raise TypeError, "%s incorrect request type" % (request.__class__)
it definitely looks like you should be passing an instance of getDataVersions, so you're probably on the right track.
You probably need to be instantiating your definition objects and then populating them. Look for type == pyclass_type objects associated with the request you're wanting to make and instantiate them.
e.g. (just guessing)
>>> versionrequest = getDataVersions()
>>> versionrequest.AccountInfo = versionrequest.new_AccountInfo()
>>> versionrequest.AccountInfo.accountNumber = "123"
>>> versionrequest.AccountInfo.accountSecret = "shhhh!"
>>> service.getDataVersions(versionrequest)
I found that the code generated by wsdl2py was too slow for my purposes. Good luck.