How can I use multiple things to check in an else statement? - python

I am trying to create a machine learning program. So far, I have stored each of the 'learned' meanings in a text file in a list of all things that are attribute to that meaning. The text file is read by a python file that generates class objects that attribute the data in the text file to them. Then, in a master python file, the main prompt is where I am having trouble.
else:
try:
for obj in gc.get_objects():
try:
if isinstance(obj, LearnedClasses.learned):
if str(user.lower()) in obj.keys:
exec(obj.exstring)
chat()
break
except:
raise Exception
except Exception:
user = user.split()
for x in user:
learnlist.append(x)
learnch = random.choice(learnlist)
learnp = input("What does '{}' mean?".format(learnch))
learn(learnch, learnp)
chat()
This code is what follows the basic 'built-in' responses that I made. This is what happens after it can not find any keywords in the built-in section. I am using GC to collect all of the class objects that were generated from the text file. Then, if the prompt matches any keywords with any of its 'learned' keywords, I intend for it to respond with the responses set for that class. However, I can not get it to move on to the if ALL ELSE fails part, which starts at except Exception. How could I arrange this so that it can do what I described? Thank you.

It's a bit hard to follow this code; a couple of suggestions for improvement:
raise Exception has a typo: it should be raise Exception()
There's not much point having an except block which just raises an exception with no additional information; omit it?
The garbage collector is not a good place to store information that you will, in fact, need later; can you change the code so that the learned classes are stored in a list in a variable, which is returned or passed around somehow?
As a general rule, you should never touch the garbage collector unless you're running out of memory, and then only to figure out how to help it discard things.
As others have suggested in the comments, rather than try/except, use something like a flag variable to keep track of whether you've already answered, or the for/break/else construct:
for lc in learned_class_list:
if str(user.lower()) in lc.keys:
exec(lc.exstring)
chat()
break
else:
user = user.split()
for x in user:
learnlist.append(x)
learnch = random.choice(learnlist)
learnp = input("What does '{}' mean?".format(learnch))
learn(learnch, learnp)

Related

Error-handling function dosen't work completely

I am trying to make a python program that allows the user to order a salad by chosing ingredients they would like:
Here are some quick translations:
Tillbehörslista: List of food items (tomatoes, eggs, broccoli, pasta, etc)
-Svar: Answer
Beställning: Order
VäljaTillbehör(): ChooseFoodItems():
For my function that is supposed to allow the user to write in what they would like, I made an error handling function that makes sure that whatever is typed in is in the actual list of food items. However regardless of what I type in in the ChooseFoodItems function the error handling only jumps to the if block. So even if the answer is illegal the error handling function can't seem to differentiate it. Please help.
try:
if hurMangaLika(svar,tillbehörsLista,beställning)==True:
svar=input("")
elif hurMangaLika(svar,tillbehörsLista,beställning)==False:
svar=input("")
except:
print("error")
return beställning`
for i in range(len(tillbehörsLista)):
for svar in tillbehörsLista:
if svar==tillbehörsLista[i]:
print("här")
beställning.append(svar)
return True
#eller gör return true osen säg whiel true appendsndk
#beställning.append(svar)
elif svar!=tillbehörsLista[i]:
print("Fel")
return False`
I tried to make a function that would allow me to make sure that only proper ansewrs would be registred and added to the actual order. However as I mentioned before that didn't work.

Getting variables upon python Jupyter crash

One of the challenges I'm having is getting a stack trace or examining variables which should be in scope when an error occurs. However I am not finding this is the case. For example if a piece of code fields, I'd like to be able to see where in the loop in fails. However despite using %debug, I can never get any values out.
For example my code:
if a[field].to_list()[0] == b[field].to_list()[0]:
result = True
fails, and I'd like to know what the value of field is. But I can never find a way to make this work using %debug.
Maybe this try and except block helps you
for field in fields:
try:
if a[field].to_list()[0] == b[field].to_list()[0]:
result = True
except Exception as e:
print(field)
print(e)

Python xml.parsers.expat results differ based on buffer_text = True or False and/or buffer_size

I'm using Python's xml.parsers.expat to parse some xml data, but sometimes the tags doesn't seem to be parsed correctly. I wonder if anyone knows if why setting buffer_text and / or buffer_size might actually change whether the data body gets parsed correctly?
A sanitized example, used to parse Azure blob list:
from xml.parsers.expat import ParserCreate, ExpatError, errors
class MyParser:
def __init__(self, xmlstring):
self.current_blob_name = None
self.current_blob_hash = None
self.get_hash = False
self.get_filename = False
self.xmlstring = xmlstring
self.p = ParserCreate()
#### LINE A ####
self.p.buffer_text = True
#### LINE B ####
# self.p.buffer_size = 24
self.p.StartElementHandler = self._start_element
self.p.EndElementHandler = self._end_element
self.p.CharacterDataHandler = self._char_data
def _reset_current_blob(self):
self.current_blob_name = None
self.current_blob_hash = None
# 3 handler functions
def _start_element(self, name, attrs):
if name == 'Blob':
self._reset_current_blob()
elif name == 'Name':
self.get_filename = True
elif name == 'Content-MD5':
self.get_hash = True
def _end_element(self, name):
if name == 'Blob':
...
elif name == 'Name':
self.get_filename = False
elif name == 'Content-MD5':
self.get_hash = False
def _char_data(self, data):
if self.get_hash is True:
self.current_blob_hash = data
if self.get_filename is True:
try:
...
except Exception as e:
print('Error parsing blob name from Azure.')
print(e)
def run(self):
self.p.Parse(self.xmlstring)
Most of the time things work just fine. However, sometimes after I upload a new item to Azure and that the xml returned changes, The error "Error parsing blob name from Azure" will get triggered, since some operations in the try block gets unexpected data. Upon further inspection, I observe that one potential error happens when data is supposed to be abcdefg_123/hijk/test.jpg, only abcdefg got passed into _char_data, while _123/hijk/test.jpg gets passed into another item. There is nothing wrong with the xml returned from Azure though.
I've experimented with a few things:
Added LINE A (buffer_text = True). It fixed the issue this time but I do not know if it is just luck (e.g. whether it would break again if I upload a new item to Azure);
If both LINE A and LINE B are added - things break again (I've also experimented with different buffer sizes; all seem to break the parser);
The way it breaks is deterministic: I can rerun the code all I want and it is always the exact element that gets parsed incorrectly;
If I remove that element from the original xml data, depending on how much other data I remove along the way, it could lead to another element being parsed incorrectly, or it could lead to a "fix" / no error. It does look like it has something to do with the total length of the data returned from Azure. My data is quite long (3537860 characters at this moment), and if I remove a fixed length from anywhere in the xml data, once the length reach a certain value, no more errors occur.
Unfortunately I am not able to share the raw xml I am parsing since it would take too much effort to sanitize, but hopefully this contains enough information! Let me know if I can add anything else.
Thanks!
Thanks to Walter:
https://bugs.python.org/msg385104
Just a guess, but the buffer size might be so small that the text that you expect gets passed via two calls to _char_data(). You should refactor your code the simply collect all the text in _char_data() and act on it in the _end_element() handler.
So this probably isn't a bug in xml.parsers.expat.
This fix is working for me so far. What I did not understand is that I thought the default buffer was 24, but if I set it to say 48 (a larger buffer), I would again see the issue (before this fix). In any case, collecting all data in the _char_data() section does make sense to me.

Understanding `traceback.format_exception_only()`

I wanted to just print exception type and message.
I initially tried:
try:
raise Exception("duh!!!")
except Exception as err:
print(err)
But this only printed exception message.
duh!!!
Then I went through the whole traceback doc and I felt traceback.format_exception_only() is the one I am looking for.
So i tried it as follows:
try:
raise Exception("duh!!!")
except:
etype, evalue, tb = sys.exc_info()
print(traceback.format_exception_only(etype, evalue)))
and it printed following:
['Exception: duh!!!\n']
which looked a bit unexpected to me. So I re-read the doc for this method. It says following:
Format the exception part of a traceback. The arguments are the exception type and value such as given by sys.last_type and sys.last_value. The return value is a list of strings, each ending in a newline. Normally, the list contains a single string; however, for SyntaxError exceptions, it contains several lines that (when printed) display detailed information about where the syntax error occurred. The message indicating which exception occurred is the always last string in the list.
So I understood that the doc says its a list, which is why there is a list in the output [...]. Also the doc says each line ends in newline, thats why there is \n in the output. But I dont get when there will be multiple lines in case of SyntaxError? I am not able to produce SyntaxError which will result in multiple lines in the return value of format_exception_only().
Also it suddenly clicked to me that I can simply do
try:
raise Exception("duh!!!")
except:
etype, evalue, tb = sys.exc_info()
print('{}: {}'.format(etype.__name__, evalue))
to get
Exception: duh!!!
But then how format_exception_only() adds more value to this?
Python is open source so you can view the implementation and decide what the extra value is for yourself:
if self.exc_type is None:
yield _format_final_exc_line(None, self._str)
return
stype = self.exc_type.__qualname__
smod = self.exc_type.__module__
if smod not in ("__main__", "builtins"):
stype = smod + '.' + stype
if not issubclass(self.exc_type, SyntaxError):
yield _format_final_exc_line(stype, self._str)
else:
yield from self._format_syntax_error(stype)
It's a fairly simple function so yes, per your question if you ignore the parts of the functionality you don't use it doesn't add much value to you.
Of course, you're now on the hook for maintaining your code if there's any Exception changes in the future, or if turns out the Exception raiser starts returning SyntaxErrors, or any other edge cases that come in the future.
Reduced maintenance and increased readability (because everyone knows what the library code does) are the two relatively universal advantages of using standard library code.

How to use TideSDK openFolderChooseDialog

I'm trying to use TideSDK and python tp get the user to select a folder from the hard drive. Everything works, but I have no idea how obtain which folder the user selected.
I can't seem to find documentation on what Ti.UI.UserWindow.openFolderChooseDialog returns and what kind of object the callback function uses. I just get errors that "window" in "onopen" in my code below is a None Type object when I try to print it out.
Is there any documentation on the proper use of the openFolderChooseDialog, what signature the callback needs to be and how to get the Folder/directory from the dialog?
My code:
def onopen(window):
Ti.App.stdout("------------------ Opening Dialog")
Ti.App.stdout(window)
def burndir():
try:
dir = Ti.UI.getCurrentWindow().openFolderChooserDialog(onopen)
Ti.App.stdout(dir)
except:
Ti.App.stderr("------ There was an error: ")
Ti.App.stderr(sys.exc_info()[0])
Ti.App.stderr(sys.exc_info()[1])
Ti.App.stderr(sys.exc_info()[2])
Any help is much appreciated
I found the answer in a Javascript Code example here:
https://github.com/appcelerator/titanium_developer/blob/master/Resources/perspectives/projects/js/projects.js#L1338
It appears that openFolderChooserDialog return nothing (a None object in Python). The callback function passes one argument which is a StaticBoundList (a Tuple object in Python) that contains all of the selected folders (in case of allowing multiple selections)
Here is the updated code:
def onopen(window):
if (len(window) > 0):
Ti.App.stdout("------------------ Opening Dialog")
Ti.App.stdout(window[0])
else:
Ti.App.stdout("------------------ Nothing Selected")
def burndir():
try:
Ti.UI.getCurrentWindow().openFolderChooserDialog(onopen)
except:
Ti.App.stderr("------ There was an error: ")
Ti.App.stderr(sys.exc_info()[0])
Ti.App.stderr(sys.exc_info()[1])
Ti.App.stderr(sys.exc_info()[2])
I hope this helps someone struggling to find the same documentation!

Categories

Resources