Unusual KeyError when formatting HTML - python

I have a class that takes an arbitrary HTML template and str.format()s it for a specific use case. For instance:
<h1>Hi, {userName}!</h1>
<p> It's {weather} today.</p>
would become:
<h1>Hi, Jon Skeet!</h1>
<p>It's sunny today.</p>
To do this, I have a Template class:
class Template:
def __init__(self, name, **kwargs):
templateDirectory = getTemplateDirectory() # we don't need to worry about this
with open(os.path.join(templateDirectory, "templates", name + ".html")) as templateFile: # we get the template we need
self.template = templateFile.read()
print(self.template) # all in order: we get the un-formatted HTML
print(kwargs) # all in order: we get a dict of things to replace (i.e. {'userName': 'Jon Skeet', 'weather': 'sunny'} )
self.final = self.template.format(**kwargs) # this should just replace things nicely, but it doesn't: why?
def __str__(self):
return self.final
I instantiate like this:
ErrorTemplate = Template('foo', var1=42, var2='foo')
print(str(ErrorTemplate))
The error I get is as follows:
Traceback (most recent call last):
File "/path/to/file.py", line 11, in <module>
ErrorTemplate = Template('foo', var1=42, var2='bar')
File "/path/to/the/file/with/Template/class.py", line 10, in __init__
self.final = self.template.format(**kwargs)
KeyError: 'document'
I'm not using 'document' anywhere. I have no idea where it gets 'document' from. What am I doing wrong?

Related

Creating single variable to consolidate multiple classes

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?

Python shelve not saving nested keys

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.

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).

RuntimeError: maximum recursion depth exceeded (without an explicit recursive call in my Python code)

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).

wsdl2py requests

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.

Categories