AttributeError: module 'sys' has no attribute 'tracebacklimit' - python

# Python 3.8
import sys
print(sys.tracebacklimit)
Running the code results with:
AttributeError: module 'sys' has no attribute 'tracebacklimit'
But the code below works:
sys.tracebacklimit = 3
print(sys.tracebacklimit)
3
Question:
How to get the current tracebacklimit value from the code?

The documentation (search for tracebacklimit) states (with my added emphasis on the first word):
When this variable is set to an integer value, it determines the maximum number of levels of traceback information printed when an unhandled exception occurs. The default is 1000. When set to 0 or less, all traceback information is suppressed and only the exception type and value are printed.
In other words, if it's not set (or presumably also set to a non-integer), it will use 1000 as a default. So you can get the current value with something like:
try:
tbl = int(sys.tracebacklimit)
except:
tbl = 1000
You could also try the following, it is shorter but it doesn't specifically cover the case where it's set to a non-integer, so it may give you the wrong thing:
tbl = getattr(sys, "tracebacklimit", 1000)
As an aside, you could create a helper function which, given a string representation of the item in question, evaluated it for you:
def ensure(str_item, typ, deflt):
# Execute in "sandbox" context, catching problems.
local_dict = {}
try:
exec(f"myvar = {str_item}", globals(), local_dict)
except:
return deflt
# Extract, and check type of, value.
item = local_dict["myvar"]
if typ is not None and type(item) != typ:
return deflt
# Was valid, return it.
return item
# Test code.
import sys
#sys.tracebacklimit = 7 # Uncomment to test if set.
#sys.tracebacklimit = "hello" # Uncomment to test if set to non-integer.
print(ensure("sys.tracebacklimit", int, 1000))
This makes sure the item exists and that it is of the expected type (unless None is given for the type).
It's probably not needed for a simple case like this but I always like to add useful helper functions to my ever growing snippet library :-)

Related

How to / is that possible to turn off short-circuit evaluation?

I am coding a kind of command line user interface where an arbitrary boolean expression can be given as input. This expression must be repeatedly evaluated on a dictionary that is changing after some update.
Here is the simplified code :
import traceback
def update_my_dict():
return {'a': 1}
my_dict = {'a': 0}
bool_exp = input()
# -- verify code can be executed in the current context
try:
result = eval(bool_exp, my_dict)
except Exception:
print(f'Expression cannot be evaluated, evaluation raise the following error:')
print(traceback.format_exc())
quit()
# -- verify code return a boolean
if not isinstance(result, bool):
print(f'Expression return {type(result)}, expect bool')
quit()
# -- go
while not eval(bool_exp, my_dict):
my_dict = update_my_dict()
Before running the last while loop I want to verify that the expression can be executed in the current context and ensuring that its return a boolean.
My problem is if the expression is, for example bool_exp = a == 1 and b == 2 the first test evaluation of the expression while return false but do not raise exception because off lazy evaluation. But when my_dict is updated then an error will be raised.
So is that possible to, some how, disable the lazy/short-circuit evaluation for the first test evaluation ? I searched some solution using ast, but it seems complicated since bool_exp can be arbitrary long and complex, like containing entangled boolean expressions and so on.
PS: I know eval() is unsafe in a general context but my code will not be usable externaly
PS2: I know its possible to catch the exception in the while loop but it looks a bit sub-optimized knowing my_dict keys will never change when updated, only their values. Also this question is more like if its possible to control the evaluation behavior
EDIT
"but you could use & and | instead of and and or !"
No. I cannot tell what will be entered as input. So the user can input whatever s.he want.
A Correct input expression:
Should return a boolean.
Should only involve dictionary keys in the tests.
"Correct" meaning it will be repeatedly evaluated in the ending while loop without raised any exception.
We assume that the keys in the dictionary will stay constant. i.e only the values of the dict will change during the update phase. In other words, the first try/except aim to verify that the expression is only doing some test on variables that are in my_dict.
I cannot explain further the global use of this or I'll need a very long post with lost of what seems irrelevant information to resolve the issue.
You could put the "verification" code inside the loop. This makes sense as your input is changing so you should verify it on each change. You already evaluate the expression every time the dict values change, so the only added logic compared to your current code is that the isinstance check is now done as well with every change of the dict:
import traceback
def update_my_dict():
return {'a': 1}
my_dict = {'a': 0}
bool_exp = input()
# -- go
while True:
# -- verify code can be executed in the current context
try:
result = eval(bool_exp, my_dict)
except Exception:
print(f'Expression cannot be evaluated, evaluation raise the following error:')
print(traceback.format_exc())
quit()
# -- verify code return a boolean
if not isinstance(result, bool):
print(f'Expression return {type(result)}, expect bool')
quit()
if result:
break
my_dict = update_my_dict()
On the same example input a == 1 and b == 2 this will output:
Expression cannot be evaluated, evaluation raise the following error:
Traceback (most recent call last):
File "main.py", line 14, in <module>
result = eval(bool_exp, my_dict)
File "<string>", line 1, in <module>
NameError: name 'b' is not defined

How to say in Pythonese - do something unless it causes an error (without resorting to multilevel try/execpt blocks)

This is a little difficult to explain, so let's hope I'm expressing the problem coherently:
Say I have this list:
my_list = ["a string", 45, 0.5]
The critical point to understand in order to see where the question comes from is that my_list is generated by another function; I don't know ahead of time anything about my_list, specifically its length and the datatype of any of its members.
Next, say that every time <my_list> is generated, there is a number of predetermined operations I want to perform on it. For example, I want to:
my_text = my_list[1]+"hello"
some_var = my_list[10]
mini_list = my_list[0].split('s')[1]
my_sum = my_list[7]+2
etc. The important point here is that it's a large number of operations.
Obviously, some of these operations would succeed with any given my_list and some would fail and, importantly, those which fail will do so with an unpredictable Error type; but I need to run all of them on every generation of my_list.
One obvious solution would be to use try/except on each of these operations:
try:
my_text = my_list[1]+"hello"
except:
my_text = "None"
try:
some_var = my_list[10]
except:
some_var = "couldn't do it"
etc.
But with a large number of operations, this gets very cumbersome. I looked into the various questions about multiple try/excepts, but unless I'm missing something, they don't address this.
Based on someone's suggestion (sorry, lost the link), I tried to create a function with a built-in try/except, create another list of these operations, and send each operation to the function. Something along the lines of
def careful(op):
try:
return op
else:
return "None"
And use it with, for example, the first operation:
my_text = careful(my_list[1]+"hello")
The problem is python seems to evaluate the careful() argument before it's sent out to the function and the error is generated before it can be caught...
So I guess I'm looking for a form of a ternary operator that can do something like:
my text = my_list[1]+"hello" if (this doesn't cause any type of error) else "None"
But, if one exist, I couldn't find it...
Any ideas would be welcome and sorry for the long post.
Maybe something like this?
def careful(op, default):
ret = default
try:
ret = computation()
else:
pass
return ret
If you must do this, consider keeping a collection of the operations as strings and calling exec on them in a loop
actions = [
'my_text = my_list[1]+"hello"',
'some_var = my_list[10]',
'mini_list = my_list[0].split("s")[1]',
'my_sum = my_list[7]+2',
]
If you make this collection a dict, you may also assign a default
Note that if an action default (or part of an action string) is meant to be a string, it must be quoted twice. Consider using block-quotes for this if you already have complex escaping, like returning a raw strings or a string representing a regular expression
{
"foo = bar": r"""r'[\w]+baz.*'"""
}
complete example:
>>> actions_defaults = {
... 'my_text = my_list[1]+"hello"': '"None"',
... 'some_var = my_list[10]': '"couldn\'t do it"',
... 'mini_list = my_list[0].split("s")[1]': '"None"',
... 'my_sum = my_list[7]+2': '"None"',
... }
>>>
>>> for action, default in actions_defaults.items():
... try:
... exec(action)
... except Exception: # consider logging error
... exec("{} = {}".format(action.split("=")[0], default))
...
>>> my_text
'None'
>>> some_var
"couldn't do it"
Other notes
this is pretty evil
declaring your vars before running to be their default values is probably better/clearer (sufficient to pass in the except block, as the assignment will fail)
you may run into weird scoping and need to access some vars via locals()
This sounds like an XY Problem
If you can make changes to the source logic, returning a dict may be a much better solution. Then you can determine if a key exists before doing some action, and potentially also look up the action which should be taken if the key exists in another dict.

accessing a variable in if __name__ == "main"

I have a program that compares two classes in a series of tests.
The main program (called initial.py) assigns both values to a dictionary
import testcheck
values = {}
valueChange = False
if __name__ == "__main__":
values['valueOne'] = testcheck.assignValue() #see note 1
values['valueTwo'] = testcheck.assignValueTwo()
testcheck.checkValues() #see note 2
while valueChange is True :
values['valueTwo'] = testcheck.assignValueTwo()
testcheck.checkValues()
Note 1: both of these return the same class but with different values
Note 2: compares the two classes. after a series of tests, valueChange is set to True, and one value is to be deleted using this code
import initial
...
if initial.valueChange is True:
del initial.values['valueTwo']
...
This returns the error
del initial.values['valueTwo']
KeyError: 'valueTwo'
I thought it was because adding valueOne and valueTwo would be adding it in the local scope, but even with global values it doesn't fix it. How would I go about solving this?
This appears to be a design issue. You seem to be setting up circular imports, which should be avoided if possible. If what you are after is to share a global state across modules of your package, you might want to make use of storing the state within your testcheck module, and not in a global variable of your initial.py
testcheck.py
# module globals
_TEST_VALUES = {}
valueChanged = False
...
def getTestValue(name):
return _TEST_VALUES.get('name', None)
def assignValue():
# do stuff
result = 'foo'
_TEST_VALUES['valueOne'] = result
return result
def assignValueTwo():
# do stuff
result = 'bar'
_TEST_VALUES['valueOne'] = result
return result
...
initial.py
testcheck.assignValue()
testcheck.assignValueTwo()
testcheck.checkValues()
while testcheck.valueChange:
testcheck.assignValueTwo()
testcheck.checkValues()
otherModule.py
import testcheck
...
if testcheck.valueChange:
try:
del initial.values['valueTwo']
except KeyError:
pass
...
I have no idea where this whole thing is going in terms of real usage. But maybe this will give you an idea of where to start looking. There is no longer a circular import of other modules importing your intial.py entry point. You are storing all the globals within the testcheck module. This example is very quick and dirty. Its only to illustrate.
No module should ever try to be accessing data of another module which handles the data within an if __name__ == "__main__" block. Because now you are making the assumption that it will always be used as the entry point (never imported by something else) and you start putting restrictions on your code.

"Function object is unsubscriptable" in basic integer to string mapping function

I'm trying to write a function to return the word string of any number less than 1000.
Everytime I run my code at the interactive prompt it appears to work without issue but when I try to import wordify and run it with a test number higher than 20 it fails as "TypeError: 'function' object is unsubscriptable".
Based on the error message, it seems the issue is when it tries to index numString (for example trying to extract the number 4 out of the test case of n = 24) and the compiler thinks numString is a function instead of a string. since the first line of the function is me defining numString as a string of the variable n, I'm not really sure why that is.
Any help in getting around this error, or even just help in explaining why I'm seeing it, would be awesome.
def wordify(n):
# Convert n to a string to parse out ones, tens and hundreds later.
numString = str(n)
# N less than 20 is hard-coded.
if n < 21:
return numToWordMap(n)
# N between 21 and 99 parses ones and tens then concatenates.
elif n < 100:
onesNum = numString[-1]
ones = numToWordMap(int(onesNum))
tensNum = numString[-2]
tens = numToWordMap(int(tensNum)*10)
return tens+ones
else:
# TODO
pass
def numToWordMap(num):
mapping = {
0:"",
1:"one",
2:"two",
3:"three",
4:"four",
5:"five",
6:"six",
7:"seven",
8:"eight",
9:"nine",
10:"ten",
11:"eleven",
12:"twelve",
13:"thirteen",
14:"fourteen",
15:"fifteen",
16:"sixteen",
17:"seventeen",
18:"eighteen",
19:"nineteen",
20:"twenty",
30:"thirty",
40:"fourty",
50:"fifty",
60:"sixty",
70:"seventy",
80:"eighty",
90:"ninety",
100:"onehundred",
200:"twohundred",
300:"threehundred",
400:"fourhundred",
500:"fivehundred",
600:"sixhundred",
700:"sevenhundred",
800:"eighthundred",
900:"ninehundred",
}
return mapping[num]
if __name__ == '__main__':
pass
The error means that a function was used where there should have been a list, like this:
def foo(): pass
foo[3]
You must have changed some code.
By the way, wordify(40) returned "fourty". I spell it "forty"
And you have no entry for zero
In case someone looks here and has the same problem I had, you can also get a pointer to a function object if the wrong variable name is returned. For example, if you have function like this:
def foo():
my_return_val = 0
return return_val
my_val = foo()
then my_val will be a pointer to a function object which is another cause to "TypeError: 'function' object is unsubscriptable" if my_val is treated like a list or array when it really is a function object.
The solution? Simple! Fix the variable name in foo that is returned to my_return_val.

Returning None or a tuple and unpacking

I am always annoyed by this fact:
$ cat foo.py
def foo(flag):
if flag:
return (1,2)
else:
return None
first, second = foo(True)
first, second = foo(False)
$ python foo.py
Traceback (most recent call last):
File "foo.py", line 8, in <module>
first, second = foo(False)
TypeError: 'NoneType' object is not iterable
The fact is that in order to correctly unpack without troubles I have either to catch the TypeError or to have something like
values = foo(False)
if values is not None:
first, second = values
Which is kind of annoying. Is there a trick to improve this situation (e.g. to so set both first and second to None without having foo returning (None, None)) or a suggestion about the best design strategy for cases like the one I present ? *variables maybe ?
Well, you could do...
first,second = foo(True) or (None,None)
first,second = foo(False) or (None,None)
but as far as I know there's no simpler way to expand None to fill in the entirety of a tuple.
I don't see what is wrong with returning (None,None). It is much cleaner than the solutions suggested here which involve far more changes in your code.
It also doesn't make sense that you want None to automagically be split into 2 variables.
I think there is a problem of abstraction.
A function should maintain some level of abstraction, that helps in reducing complexity of the code.
In this case, either the function is not maintaining the right abstraction, either the caller is not respecting it.
The function could have been something like get_point2d(); in this case, the level of the abstraction is on the tuple, and therefore returning None would be a good way to signal some particular case (e.g. non-existing entity). The error in this case would be to expect two items, while actually the only thing you know is that the function returns one object (with information related to a 2d point).
But it could also have been something like get_two_values_from_db(); in this case the abstraction would be broken by returning None, because the function (as the name suggest) should return two values and not one!
Either way, the main goal of using a function - reducing complexity - is, at least partially, lost.
Note that this issue would not appear clearly with the original name; that's also why it is always important to give good names to function and methods.
I don't think there's a trick. You can simplify your calling code to:
values = foo(False)
if values:
first, second = values
or even:
values = foo(False)
first, second = values or (first_default, second_default)
where first_default and second_default are values you'd give to first and second as defaults.
How about this:
$ cat foo.py
def foo(flag):
if flag:
return (1,2)
else:
return (None,)*2
first, second = foo(True)
first, second = foo(False)
Edit: Just to be clear, the only change is to replace return None with return (None,)*2. I am extremely surprised that no one else has thought of this. (Or if they have, I would like to know why they didn't use it.)
You should be careful with the x or y style of solution. They work, but they're a bit broader than your original specification. Essentially, what if foo(True) returns an empty tuple ()? As long as you know that it's OK to treat that as (None, None), you're good with the solutions provided.
If this were a common scenario, I'd probably write a utility function like:
# needs a better name! :)
def to_tup(t):
return t if t is not None else (None, None)
first, second = to_tup(foo(True))
first, second = to_tup(foo(False))
def foo(flag):
return ((1,2) if flag else (None, None))
OK, I would just return (None, None), but as long as we are in whacko-land (heh), here is a way using a subclass of tuple. In the else case, you don't return None, but instead return an empty container, which seems to be in the spirit of things. The container's "iterator" unpacks None values when empty. Demonstrates the iterator protocol anyway...
Tested using v2.5.2:
class Tuple(tuple):
def __iter__(self):
if self:
# If Tuple has contents, return normal tuple iterator...
return super(Tuple, self).__iter__()
else:
# Else return a bogus iterator that returns None twice...
class Nonerizer(object):
def __init__(self):
self.x=0
def __iter__(self):
return self
def next(self):
if self.x < 2:
self.x += 1
return None
else:
raise StopIteration
return Nonerizer()
def foo(flag):
if flag:
return Tuple((1,2))
else:
return Tuple() # It's not None, but it's an empty container.
first, second = foo(True)
print first, second
first, second = foo(False)
print first, second
Output is the desired:
1 2
None None
Over 10 years later, if you want to use default values I don't think there is a better way than the one already provided:
first, second = foo(False) or (first_default, second_default)
However, if you want to skip the case when None is returned, starting from Python 3.8 you can use the walrus operator (ie. assignment expressions) - also note the simplified foo:
def foo(flag):
return (1, 2) if flag else None
if values := Foo(False):
(first, second) = values
You could use an else branch to assign default values that's worse than the previous or option.
Sadly, the walrus operator does not support unparenthesized tuples so it is just a one line gain compared to:
values = foo(False)
if values:
first, second = values
One mechanism you can use to avoid the problem entirely when you have control of the method foo is to change the prototype to allow giving a default. This works if you are wrapping state but can't guarantee that a particular tuple value exists.
# self.r is for example, a redis cache
# This method is like foo -
# it has trouble when you unpack a json serialized tuple
def __getitem__(self, key):
val = self.r.get(key)
if val is None:
return None
return json.loads(val)
# But this method allows the caller to
# specify their own default value whether it be
# (None, None) or an entire object
def get(self, key, default):
val = self.r.get(key)
if val is None:
return default
return json.loads(val)
I found a solution for this problem:
Return None or return an object.
However you don't want to have to write a class just to return an object. For this, you can use a named tuple
Like this:
from collections import namedtuple
def foo(flag):
if flag:
return None
else:
MyResult = namedtuple('MyResult',['a','b','c']
return MyResult._make([1,2,3])
And then:
result = foo(True) # result = True
result = foo(False) # result = MyResult(a=1, b=2, c=3)
And you have access to the results like this:
print result.a # 1
print result.b # 2
print result.c # 3

Categories