Python3 ElementTree loop stalls while parsing. Trace shows subprocess.CalledProcessError - python

My experience is with HTML/CSS/PHP but I have recently started working with python. I find myself stuck and hope someone can spot what I am doing incorrectly. The program I am working on is stalling while retrieving some variables from an xml document. I have narrowed it down to this section:
(Made up the variables)
def add_ingredients_for_selected_recipes(self, root):
recipes = ["Beef Stew", "Tuna Casserole", "Spaghetti", "Chocolate Cake"]
guest = self.settings.get('guest')
allergies = {'nuts': ["guest1", "guest2", "guest3"], 'seafood': ["guest5", "guest6"]}
for recipe in recipes:
# Add necessary ingredients for user desired recipes to our list
if self.settings.get("recipe_" + recipe):
self.queue_event('info', 'Selecting ingredients for "%s" recipe.' % recipe)
for child in root.iter(recipe):
for ing in child.iter('ingredient'):
contains = ing.attrib.get('allergy')
if contains is None:
self.queue_event('debug', 'Adding ingredient:%s' % (ing.text))
self.ingredients.append(ing.text)
elif contains in allergies and guest in allergies[contains]:
self.queue_event('debug', 'Adding ingredient:%s contains %s' % (ing.text, contains))
self.ingredients.append(ing.text)
else:
self.queue_event('debug', 'Skipping ingredient:%s contains %s' % (ing.text, contains))
Here is what I grep'd from the trace: https://dl.dropboxusercontent.com/u/60521097/fromtrace
One more thing that's relevant is if I remove the portion that checks for the attribute it works fine. So I know where the problem is but I am not seeing it. Thanks in advance for any suggestions.

Ok I figured out the problem. I previously defined which "recipes" were available as option for each of the "guests". When the main loop (for recipe in recipes:) gets to a recipe that is not defined as an available option to the "allergy" in "allergies" it shows False and the loop can't continue. I fixed this by defining the "recipes" variable based on selected "guest" like this:
self.recipes_by_guest = {"guest1": ["Beef Stew", "Tuna Casserole", "Spaghetti"],
"guest2": ["Beef Stew", "Spaghetti"],...etc}
guest = self.settings.get("guest")
recipes = self.recipes_by_guest[guest]
allergies = {'nuts': ["guest1", "guest2", "guest3"], 'seafood': ["guest5", "guest6"]}
for recipe in recipes: etc...
Thanks to everyone who had a look and commented suggestions!

Related

shodan - country code python

I want to list once my script in python search for specific strings , but I also want to add country code first two letters , but when I try then it says invalid KeyError: 'country_code', but the api says ocation.country_code how can I achieve that?
#!/usr/bin/python
import shodan
SHODAN_API_KEY="xxxxxxxxxxxxxxxxxxxx"
api = shodan.Shodan(SHODAN_API_KEY)
try:
# Search Shodan
results = api.search('ProFTPd-1.3.3c')
# Show the results
for result in results['matches']:
print '%s' % result['ip_str']
print '%s' % result['country_code']
except shodan.APIError, e:
print 'Error: %s' % e
I think this is the method You are using in Python
https://github.com/achillean/shodan-python/blob/master/shodan/client.py#L324
and it triggers:
return self._request('/shodan/host/search', args)
Shodan API documentation:
https://developer.shodan.io/api
check out /shodan/host/search API
I just saw that the answer is in Your question but You ate one letter from location (ocation).
Try this:
print '%s' % result['location']['country_code']
So field You are looking for is there but it is in another dictionary.
I would recommend to read API documentation well next time and as Nofal Daud said, Python error are self explanatory if You have KeyError on dict it means that field is not there. Next time listen to Python it will reveal the truth.

Odoo get data from another model with self.env

For the Odoo warehouse module I have to do a check if all required fields have been filled when quality control wants to transfer the products to stock.
At this moment everything works but the location for quality control is currently hardcoded. This means that when someone is using another stock location for quality control they would have to change the code.
I have searched trough the Odoo documentation and as far as I can see for the new api I have to use self.env instead of self.pool.get. (I added the old code as a comment.)
When debugging it seems that stock.warehouse is in self.pool and not in self.env (But I guess this might just be one of those "Odoo" things).
Second thing is that I have hardcoded the current company_id "1".
I think it would be best if that could also be best if that would be a variable.
I hope someone can help me solve this.
Thanks in advance
class stock_transfer_details(models.TransientModel):
_inherit = "stock.transfer_details"
#api.one
def do_detailed_transfer(self):
res = super(stock_transfer_details, self).do_detailed_transfer()
# Check if all the required lot additional fields have been filled.
# Else raise warning.
# TODO Replace hardcoded Quality location by database reference
warehouse = self.env("stock.warehouse").search([("company_id", "=", "1")])
# self.pool.get("stock.warehouse").browse(cr, uid, item["wh_qc_stock_loc_id"], context=context)
qc_location = warehouse.wh_qc_stock_loc_id
missing_mandatory_fields = []
if self.picking_source_location_id.id == 14:
item_ids = self.mapped("item_ids")
for item in item_ids:
additional_fields = item.lot_id.mapped("lot_lot_additional_fields")
for field in additional_fields:
if field.lot_additional_fields.mandatory and not field.value:
if item.lot_id.name not in missing_mandatory_fields:
missing_mandatory_fields.append(item.lot_id.name)
if missing_mandatory_fields:
error_message = "All required fields for the serial numbers must be filled! \n"
error_message += "Serial numbers: \n"
for item in missing_mandatory_fields:
error_message += item + "\n"
raise exceptions.Warning(error_message)
return res
Try the next code:
for item in self.pack_move_items:
warehouse = self.env['stock.warehouse'].browse(item.wh_qc_stock_loc_id.mapped('id'))
After a lot of research I have been able to figure out how this works.
This is the code I have used to get the current warehouse quality location:
wh_qa_location = (self.env["stock.warehouse"].search([("partner_id.id", "=", self.create_uid.company_id.id)])).wh_qc_stock_loc_id
First I will look for the current warehouse the employee is in. Once that is found I will simply get the value of the wh_qc_stock_loc_id

python TUI popup

I need some hints to find a simple solution for inserting a popup window inside a python console app.
This app runs normally unattended, because it's done to be launched from crontab.
It uses everywhere logging to display messages and save them to logfiles.
However, in some cases, the app needs user intervention to choose some options when it is not able to find a suitable one.
That's why I inserted a --interactive option in argparse, and when the app needs user intervention, a popup window in console should appear, allowing the user to choose between some items in a list.
Here's an extract of the output to give you an example :
INFO : Try to fuzzy-match 'Orange Itbn'
INFO : Fuzzy-matched alternative entries : ['Orange Is The New Black']
INFO : Fuzzy matched 'Orange Itbn' as seriesname 'Orange Is The New Black'
INFO : MOVE /Users/spadazz/testing/orange itbn.s03e10.hdtv.720p.mkv TO:
/Volumes/NAS/TV Shows/Orange Is The New Black/S03/Orange Is The New Black.S03E10.hdtv.720p.mkv
INFO : Try to fuzzy-match 'Sur'
INFO : Fuzzy-matched alternative entries : ['Survivors 2008', 'Survivors']
WARNING :
Series 'Sur' not uniquely matched in titles
Choose between these titles :
['Survivors 2008', 'Survivors']
WARNING :
******************************************
**** INSERT HERE THE CALL TO THE POPUP ***
******************************************
Now, I've read some documentation about tkinter, curses and npyscreen but I wasn't able to come up with something simple for this purpose.
I don't wanna mess with the app structure or put the log messages in a main window..
I just wanna a popup that allows me to choose between some options, even with a simple keypress like '1' and '2' etc...
This should be a python solution too, possibly without calling external commands from os.
Any ideas ??
Thanks
With a little help from Nicholas Cole, who wrote npyscreen, I was able to fix this :
import npyscreen as np
class myPop(np.NPSApp):
def setopt(self, title, oList, multi):
self.title = title
self.options = oList
self.multi = multi
self.height = len(self.options)+1
def main(self):
F = np.Popup(name="Choose an option")
if self.multi:
opt = F.add(np.TitleMultiSelect, name=self.title, max_height=self.height, values=self.options, scroll_exit=True)
else:
opt = F.add(np.TitleSelectOne, name=self.title, max_height=self.height, values=self.options, scroll_exit=True)
F.edit()
self._values = opt.get_selected_objects()
self.result = ( self._values if self.multi and len(self._values) > 1 else self._values[0] )
def ChooseOption(title, oList, multi=False):
pop = myPop()
pop.setopt(title, oList, multi)
pop.run()
return pop.result
# Show a popup with radiobuttons to select 1 item from a list
print ChooseOption('choose a single element', ['a','b','c','d'])
# Show a popup with radiobuttons to multi-select items from a list
print ChooseOption('choose multi-elements', ['a','b','c','d'], True)
Hope this helps.
Enrico
Since npyscreen was written to make that kind of thing really simple, I'd use npyscreen. :)
The example code here is almost exactly what you are asking for.

get a list of comma separated values in python and use that list to perform a command as many times as necessary with each value

I'm sure this is something easy to do for someone with programming skills (unlike me). I am playing around with the Google Sites API. Basically, I want to be able to batch-create a bunch of pages, instead of having to do them one by one using the slow web form, which is a pain.
I have installed all the necessary files, read the documentation, and successfully ran this sample file. As a matter of fact, this sample file already has the python code for creating a page in Google Sites:
elif choice == 4:
print "\nFetching content feed of '%s'...\n" % self.client.site
feed = self.client.GetContentFeed()
try:
selection = self.GetChoiceSelection(
feed, 'Select a parent to upload to (or hit ENTER for none): ')
except ValueError:
selection = None
page_title = raw_input('Enter a page title: ')
parent = None
if selection is not None:
parent = feed.entry[selection - 1]
new_entry = self.client.CreatePage(
'webpage', page_title, '<b>Your html content</b>',
parent=parent)
if new_entry.GetAlternateLink():
print 'Created. View it at: %s' % new_entry.GetAlternateLink().href
I understand the creation of a page revolves around page_title and new_entry and CreatePage. However, instead of creating one page at a time, I want to create many.
I've done some research, and I gather I need something like
page_titles = input("Enter a list of page titles separated by commas: ").split(",")
to gather a list of page titles (like page1, page2, page3, etc. -- I plan to use a text editor or spreadsheet to generate a long list of comma separated names).
Now I am trying to figure out how to get that string and "feed" it to new_entry so that it creates a separate page for each value in the string. I can't figure out how to do that. Can anyone help, please?
In case it helps, this is what the Google API needs to create a page:
entry = client.CreatePage('webpage', 'New WebPage Title', html='<b>HTML content</b>')
print 'Created. View it at: %s' % entry.GetAlternateLink().href
Thanks.
Whenever you want to "use that list to perform a command as many times as necessary with each value", that's a for loop. (It may be an implicit for loop, e.g., in a map call or a list comprehension, but it's still a loop.)
So, after this:
page_titles = raw_input("Enter a list of page titles separated by commas: ").split(",")
You do this:
for page_title in page_titles:
# All the stuff that has to be done for each single title goes here.
# I'm not entirely clear on what you're doing, but I think that's this part:
parent = None
if selection is not None:
parent = feed.entry[selection - 1]
new_entry = self.client.CreatePage(
'webpage', page_title, '<b>Your html content</b>',
parent=parent)
if new_entry.GetAlternateLink():
print 'Created. View it at: %s' % new_entry.GetAlternateLink().href
And that's usually all there is to it.
You can use a for loop to loop over a dict object and create multiple pages. Here is a little snippet to get you started.
import gdata.sites.client
client = gdata.sites.client.SitesClient(
source=SOURCE_APP_NAME, site=site_name, domain=site_domain)
pages = {"page_1":'<b>Your html content</b>',
"page_2":'<b>Your other html content</b>'}
for title, content in pages.items():
feed = client.GetContentFeed()
parent = None
if selection is not None:
parent = feed.entry[selection - 1]
client.CreatePage('webpage', page_title, content, parent=parent)
as for feeding your script from an external source I would recommend something like a csv file
##if you have a csv file called pages.csv with the following lines
##page_1,<b>Your html content</b>
##page_2,<b>Your other html content</b>
import csv
with open("pages.csv", 'r') as f:
reader = csv.reader(f)
for row in reader:
title, content = row
client.CreatePage('webpage', title, content, parent=parent)

Rhythmbox plugin to access podcast files doesn't see them

I am writing a Rhythmbox plugin to iterate over all podcast files currently known to Rhythmbox (whether downloaded or not) and to do something with them.
After some research and testing in the Rhythmbox's Python Shell, I succeeded to get a list of all objects. However, when I coded it into a plugin, I get an error:
(rhythmbox:7500): GLib-GObject-WARNING **: invalid cast from `RhythmDBTree' to `RhythmDBEntryType'
and the entries list is empty:
def run(self, action, shell):
db = shell.get_property('db')
entry_type = db.entry_type_get_by_name('podcast-post')
print entry_type
entries = []
db.entry_foreach_by_type(entry_type, entries.append)
print entries
However, the print entry_type returns: <rhythmdb.EntryType object at 0xa7ea34c (RhythmDBEntryType at 0xa106988)>, so the db object is apparently valid.
What am I doing wrong?
First try to reinstall rhythmbox.
See what this outputs, it runs fine on my machine, post what this outputs on your machine
from __future__ import print_function
def plugin_create(database):
print(database)
db.entry_foreach_by_type(db.entry_type_get_by_name('podcast-post'), print)
I tried the following:
def run(self, action, shell):
db = shell.get_property('db')
entry_type = db.entry_type_get_by_name('podcast-post')
print entry_type
entries = []
db.entry_foreach(entries.append)
print entries
for entry in entries:
if entry.get_type() == entry_type:
# process entry...
and it works correctly. Well, not the most beautiful solution, but it is OK for my needs.

Categories

Resources