try-finally clause in Python behaves unexpectedly - python

Edit: in retrospect, this is not a well thought-out question, but I'm leaving it here for future readers who may have the same misunderstanding as me.
There may be a lapse in my understanding of how try/except/finally work in Python, but I would expect the following to work as described in comments.
from sys import argv
try:
x = argv[1] # Set x to the first argument if one is passed
finally:
x = 'default' # If no argument is passed (throwing an exception above) set x to 'default'
print(x)
I would expect that the file above (foo.py) should print default when run as python .\foo.py and would print bar if run as python .\foo.py bar.
The bar functionality works as expected, however, the default behaviour does not work; if I run python .\foo.py, I get an IndexError:
Traceback (most recent call last):
File ".\foo.py", line 4, in <module>
x = argv[1]
IndexError: list index out of range
As a result, I have two questions:
Is this a bug or is it an expected behavior in a try-finally block?
Should I just never use try-finally without an except clause?

This is expected behaviour. try:..finally:... alone doesn't catch exceptions. Only the except clause of a try:...except:... does.
try:...finally:... only guarantees that the statements under finally are always executed, whatever happens in the try section, whether the block succeeds or is exited because of a break, continue, return or an exception. So try:...finally:... is great for cleaning up resources; you get to run code no matter what happens in the block (but note that the with statement and context managers let you encapsulate cleanup behaviour too). If you want to see examples, then the Python standard library has hundreds.
If you need to handle an IndexError exception in a try block, then you must use an except clause. You can still use a finally clause as well, it'll be called after the except suite has run.
And if you ever get to work with much older Python code, you'll see that in code that must run with Python 2.4 or older try:....finally:... and try:...except:... are never used together. That's because only as of Python 2.5 have the two forms been unified.

Related

Is there a simple way to comment out or diable a python try statement without re-indenting

Problem:
Sometimes it is nice to be able to remove or apply a try statement temporarily. Is there a convenient way to disable the try statement without re-indenting?
For example, if there was a python block statement equivalent called "goForIt:" one could edit the word "try:" to "goForIt:" and it would just execute the block as though it were not wrapped in a "try" and ignore the "except" line too.
The problem I'm trying to solve is that while I want the try statement in production I want to be able to remove it temporarily while debugging to see the error traceback rather than have it trap and process the exception.
Currently I work around this by commenting out the "try" then re-indent the code in the block. Then comment out the entire "except" block. This seems clumsy.
Instead of removing the try, you could make the except re-raise the exception:
try:
raise ValueError('whoops')
except ValueError as e:
raise # <-- just put this here
print('caught')
This will raise the error, just as if it were not caught:
ValueError Traceback (most recent call last)
<ipython-input-146-a6be6779c161> in <module>
1 try:
----> 2 raise ValueError('whoops')
3 except ValueError as e:
4 raise
5 print('caught')
ValueError: whoops
I do not believe there is a way to fix this.
Is it adequate to catch the exception, print it out and, if wanted, end the program?
try:
# code
except Exception as e:
print(e)
# end program if wanted
If you want a none code solution you need to use an IDE or a good text editor.
I am using Visual Studio code where I can indent with a keyboard shortcut (Ctrl + ` in my case)
(This is not my answer, but the answer from Alani's comment. If credits, find the original comment under the question.)
The solution is good because it allows global replacement:
try: --> if 1: # try:
except --> if 0: # except
The 2nd one is a little unsure. Exact and full word match should be used, or replace twice (for except<space> and except:). Or you can fix error fast by hand if there is any.
The replacement back is sure.
I need now such solution to debug error in strawberry which is only printed. So I think I need deactivate all try/except structures in 3 libraries (strawberry + 2 libs for django).

Syntax error only in python 3

I have the following code which runs fine on python 2 but throws error on python 3
import sys
if sys.version_info > (3,):
#print("Python 3")
#Try Block
except urllib2.HTTPError as err:
else:
#print "Python 2" # Throws error on python 3
#Try Block
except urllib2.HTTPError, err: # Throws error on python 3.
The above code returns "Python 2" in python 2, but throws syntax error on python 3 (For python 2 syntax ).
Can anyone tell me why is this happening ? And what is the work around to fix those syntax errors in python 3 ?
Note : I am aware of print syntax on Python 3
Thanks you!
The problem is that the parser runs before any code is evaluated at runtime. Your check sys.version_info > (3,) runs at run time, after the code was already parsed and compiled. So doing such checks, you are able to make changes at runtime, but that does not help you when dealing with syntax changes.
The syntax is parsed and compiled before any code is interpreted, that is why you get syntax errors even for code that is never run at runtime.
If you are trying to create a polyglot script that is able to run on both Python 3 and Python 2, then you will need to make sure to use a syntax that works on both. For print in particular, you can import the print function in Python 2, so you can use it just like you would in Python 3:
from __future__ import print_function
Some newer features won’t work that way (for example everything async), but for the most part, you can make it work somehow.
If you end up depending on stuff with Python 3 that requires Python 2-incompatible syntax, then you could put that into a separate module and import that module conditionally at runtime. That way it won’t be loaded for Python 2, so the Python 2 parser wouldn’t attempt to load the incompatible syntax.
As for why Python 2 does not throw an error, that’s actually very simple: print('foo bar') is valid syntax in Python 2, even with the print statement. That is because you can put parentheses around anything without impacting the value. So what you actually do there is this:
print ('foo bar')
^^^^^
print statement
^^^^^^^^^^^
value, wrapped in parentheses (that don’t do anything)
That’s also the reason, why the following produces different results in Python 3 and 2:
print('foo', 'bar')
In Python 3, you get foo bar as the output, while Python 2 gives you ('foo', 'bar'). That is because the comma inside the parentheses now makes this a tuple, so you pass a tuple to the print statement. – Importing the print function fixes this to give you the same behavior on Python 2 as on Python 3.
Even though the line print "Python 2" will never be executed in Python 3, it will still be compiled to byte code (or at least attempted). That line is a syntax error in Python 3, which requires the printed items to be in parentheses. Look up the documentation for more details: other changes to print were also made.
So remove the error. Make the line
print("Python 2") # Throws error on python 3
instead. That way it works in both Python 2 and in 3. There are many sites that discuss how to write code that executes in both versions of Python. The parentheses are merely ignored in version 2 but are needed in version 3. This works if you print only one item: more than one gets more complicated.
There is another way to do printing in both versions, using from __future__ import print_function but the way I showed is easier.
Note that your attempted comment in the line is also not proper Python syntax. Change the // to # and it works.

Can Syntax Errors be handled?

Consider the following code:
try:
if True a = 1 #It's missing a colon So it's a SyntaxError!!!!!!!
except SyntaxError:
print 'hey'
You'd expect it to print hey However It raises a SyntaxError, The same error I'm trying to avoid. So Can all Exceptions be handled using a try-except block? Well If SyntaxError's were an exception why is it included in the built-in exceptions? and finally how can I fix the above piece of code so that it handles the exception properly?
Note: I know what I'm trying to do Is utterly pointless and serves no real purpose
SyntaxError is a perfectly ordinary built-in exception. It is not special in any way. Only the circumstances of when it's (usually) thrown are a bit unusual.
A syntax error means that the code featuring said error cannot be parsed. It doesn't even begin to be a valid program, hence it cannot be executed. Therefore SyntaxError exceptions are raised before the program is run, and hence can't be caught from within the program.
More specifically, this exception is raised by the parser. Because the parser runs fully before the code is executed, rather then interleaved with it, a program can't catch its own syntax errors.
The parser itself is just another program though: Code invoking the parser can catch SyntaxErrors like every other exception (because it is like every other exception). Examples of "invoking the parser" include:
compile, exec, eval
import statements
Several functions in modules like ast, tokenizer, parser, etc.
Of course you need SyntaxError as a built-in exception - what else should be raised if the compiler/parser encounters a syntax error?
You're right that this error usually happens at compile time, which is before you're able to catch it (runtime). (And how would you recover from it?)
I can think of one exception, though:
>>> try:
... eval("hello =")
... except SyntaxError:
... print("Hey! Who's using eval() anyway??")
...
Hey! Who's using eval() anyway??

Ignore exceptions thrown and caught inside a library

The Python standard library and other libraries I use (e.g. PyQt) sometimes use exceptions for non-error conditions. Look at the following except of the function os.get_exec_path(). It uses multiple try statements to catch exceptions that are thrown while trying to find some environment data.
try:
path_list = env.get('PATH')
except TypeError:
path_list = None
if supports_bytes_environ:
try:
path_listb = env[b'PATH']
except (KeyError, TypeError):
pass
else:
if path_list is not None:
raise ValueError(
"env cannot contain 'PATH' and b'PATH' keys")
path_list = path_listb
if path_list is not None and isinstance(path_list, bytes):
path_list = fsdecode(path_list)
These exceptions do not signify an error and are thrown under normal conditions. When using exception breakpoints for one of these exceptions, the debugger will also break in these library functions.
Is there a way in PyCharm or in Python in general to have the debugger not break on exceptions that are thrown and caught inside a library without any involvement of my code?
in PyCharm, go to Run-->View Breakpoints, and check "On raise" and "Ignore library files".
The first option makes the debugger stop whenever an exception is raised, instead of just when the program terminates, and the second option gives PyCharm the policy to ignore library files, thus searching mainly in your code.
The solution was found thanks to CrazyCoder's link to the feature request, which has since been added.
For a while I had a complicated scheme which involved something like the following:
try( Closeable ignore = Debugger.newBreakSuppression() )
{
... library call which may throw ...
} <-- exception looks like it is thrown here
This allowed me to never be bothered by exceptions that were thrown and swallowed within library calls. If an exception was thrown by a library call and was not caught, then it would appear as if it occurred at the closing curly bracket.
The way it worked was as follows:
Closeable is an interface which extends AutoCloseable without declaring any checked exceptions.
ignore is just a name that tells IntelliJ IDEA to not complain about the unused variable, and it is necessary because silly java does not support try( Debugger.newBreakSuppression() ).
Debugger is my own class with debugging-related helper methods.
newBreakSuppression() was a method which would create a thread-local instance of some BreakSuppression class which would take note of the fact that we want break-on-exception to be temporarily suspended.
Then I had an exception breakpoint with a break condition that would invoke my Debugger class to ask whether it is okay to break, and the Debugger class would respond with a "no" if any BreakSuppression objects were instantiated.
That was extremely complicated, because the VM throws exceptions before my code has loaded, so the filter could not be evaluated during program startup, and the debugger would pop up a dialog complaining about that instead of ignoring it. (I am not complaining about that, I hate silent errors.) So, I had to have a terrible, horrible, do-not-try-this-at-home hack where the break condition would look like this: java.lang.System.err.equals( this ) Normally, this would never return
true, because System.err is not equal to a thrown exception, therefore the debugger would never break. However, when my Debugger class would get initialized, it would replace System.err with a class of its own,
which provided an implementation for equals(Object) and returned true if the debugger should break. So, essentially, I was using System.err as an eternal global variable.
Eventually I ditched this whole scheme because it is overly complicated and it performs very bad, because exceptions apparently get thrown very often in the java software ecosystem, so evaluating an expression every time an exception is thrown tremendously slows down everything.
This feature is not implemented yet, you can vote for it:
add ability to break (add breakpoint) on exceptions only for my files
There is another SO answer with a solution:
Debugging with pycharm, how to step into project, without entering django libraries
It is working for me, except I still go into the "_pydev_execfile.py" file, but I haven't stepped into other files after adding them to the exclusion in the linked answer.

Problem with variable scoping in Python

This problem is partly due to my lack of completely understanding scoping in python, so I'll need to review that. Either way, here is a seriously trivial piece of code that keeps crashing on my Django test app.
Here's a snippet:
#login_required
def someview(request):
try:
usergroup = request.user.groups.all()[0].name
except:
HttpResponseRedirect('/accounts/login')
if 'client' in usergroup:
stafflist = ProxyUserModel.objects.filter(groups__name='staff')
No brain surgery here, the problem is I get an error such as the following:
File "/usr/local/django/myapp/views.py", line 18, in someview
if 'client' in usergroup:
UnboundLocalError: local variable 'usergroup' referenced before assignment
My question here is, why is usergroup unbound? If it's unbound, that means the try statement had an exception thrown at which point an HttpResponseRedirect should happen, but it never does. Instead I get an HTTP 500 error back, which is slightly confusing.
Yes I can write smarter code and ensure that the user logging in definitely has a group associated with them. But this isn't a production app, I'm just trying to understand / learn Python/Django. Why exactly is the above happening when a user that's not associated with a group logs in instead of a redirect to a login page?
In this case I'm intentionally logging in as a user that isn't part of a group. That means that the above code should throw an IndexError exception like the following:
>>> somelist = []
>>> print somelist[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
HttpResponseRedirect('/accounts/login')
You're creating it but not returning it. Flow continues to the next line, which references usergroup despite it never having been assigned due to the exception.
The except is also troublesome. In general you should never catch ‘everything’ (except: or except Exception:) as there are lots of odd conditions in there you could be throwing away, making debugging very difficult. Either catch the specific exception subclass that you think is going to happen when the user isn't logged on, or, better, use an if test to see if they're logged on. (It's not really an exceptional condition.)
eg. in Django normally:
if not request.user.is_authenticated():
return HttpResponseRedirect('/accounts/login')
or if your concern is the user isn't in any groups (making the [0] fail):
groups= request.user.groups.all()
if len(groups)==0:
return HttpResponseRedirect('/accounts/login')
usergroup= groups[0].name
Try moving you if 'client' part inside you try block. Either that or define usergroup = None right above the try.
In cases where you have a try…except suite and you want code to run iff no exceptions have occurred, it's a good habit to write the code as follows:
try:
# code that could fail
except Exception1:
# handle exception1
except Exception2:
# handle exception2
else: # the code-that-could-fail didn't
# here runs the code that depends
# on the success of the try clause

Categories

Resources