Pytest checking messages returned by errors - python-3.x

Something about the interaction between pytest, str() and python Error types breaks full error testing where we want to confirm the EXACT TEXT returned by the error.
Example below:
def erroring_func(name, required_item_list):
# skip boring bit. Just throw an error.
raise KeyError(f'{name} is missing required item(s): {required_item_list')
def test_erroring_func():
with pytest.raises(KeyError) as err:
name = 'This dataframe'
required_item_list = ['a column']
_ = erroring_func(name, required_item_list)
assert str(err.value) == f"{name} is missing required item(s): {required_item_list}"
This looks sensible, but will return the error:
assert '"This dataframe is missing required item(s): [\'lat\']"' == "This dataframe is missing required item(s): ['lat']
Somehow, str(err.value) creates single backslashes in the output that are EXTREMELY difficult to recreate in an f-string (actually impossible) or to insert in a string once created.

You can completely solve by matching how KeyError alters text. This can be done with an f-string with single quotes and then double quotes f'"your text {here}"'
assert str(err.value) == f'"{name} is missing required item(s): {required_item_list}"'
(With thanks to Anthony Sotile)

An incomplete patch (missing the major value of verbose errors) is to test that a fixed substring exists in the returned error.
def test_erroring_func()
with pytest.raises(KeyError) as err:
name = 'This dataframe'
required_item_list = ['a column']
_ = erroring_func(name, required_item_list)
assert "is missing required item(s):" in str(err.value)
PS. Updating to more modern pytest syntax, a regex match can be defined as a arg in pytest.raises
def test_erroring_func():
with pytest.raises(KeyError, match="is missing required item(s):") as err:
name = 'This dataframe'
required_item_list = ['a column']
_ = erroring_func(name, required_item_list)

Related

Python Try Except when a list is null

I've been searching for my problem here, but i can't find the exact answer to my problem.
I call a sympy function ( solve() ). This function can return a full list or an empty list.
I call this piece of code inside a while:
try:
sol = solve([eq1,eq2],[r,s])
rB = bin(abs(sol[0][0]))
sB = bin(abs(sol[0][1]))
stop = True
r = rB[2:len(rB)]
s = sB[2:len(sB)]
P = int("0b"+r+s,2)
Q = int("0b"+s+r,2)
print(P*Q == pubKey.n)
print("P = {}".format(P))
print("Q = {}".format(Q))
break
except ValueError:
pass
What i want is:
if the solve() returns an empty list, just pass. And if the solve() returns a full list, keep with the execution. The solve will be returning empty list until i find the right value.
This can be reached by checking sol[0][0], if there's a non-empty list this will work, but if the list is empty, this will throw an error (null pointer) i want try to flag it and pass.
What i'm having now is that when sol is empty, it tries to get sol[0][0], and ofc this throws an error that's not being catched by the try, and the whole code stops.
Anyone knows a solution for that? I'm not using try correctly?
Set sol in the beginning of each loop to some value and check it in the except clause
about else
try/except has an else which will be run the try block did not raise an Exception
and for has an else clause for when it was not broken out of!
for foo in iterable:
# set value so the name will be available
# can be set prior to the loop, but this clears it on each iteration
# which seems more desirable for your case
sol = None
try:
"logic here"
except Exception:
if isinstance(sol, list):
"case where sol is a list and not None"
# pass is implied
else: # did not raise an Exception
break
else: # did not break out of for loop
raise Exception("for loop was not broken out of!")

Python3 verify if List Items are contained in read() result

I want to verify if Items from a List are contained in what i fetch by using string.read().
How do I do this:
if string.find(lisst):
do_whatever()
elif string.find(lisst2):
do_something_else()
Example is pretty basic, but that's all I want to do. I keep getting invalid syntax error. :(
def verify(text):
lisst = ['awesome','failed','trolling']
lisst2 = ['boring','bad']
s = requests.get(text)
t = s.read()
if t.find(lisst):
print("Someone was awesome, failing or trolling!")
elif t.find(lisst2)
print("Something retarded happened")
error is thrown at elif t.find(lisst2), so I need a workaround.
elif any(n in t for n in lisst2):
^
SyntaxError: invalid syntax
Thank you in advance!
If I understood correctly, you want to do something in an if block if a string contains any the elements of a list.
if any(str in aVeryLongStringData for str in myList):
doStuff()
If you want to check if your data contains all of the elements on your list, you can just change "any" to "all"
if all(str in aVeryLongStringData for str in myList):
doStuff()

Python ldap3 print entries based on variable

I am new to Python, stupid question ahead
I need to compare the entries from a MySQL database with ldap. I created a dictionary to hold the corresponding values, when I try to loop through the dictionary and pass them to ldap3 entries to show the results it takes the variable as literal.
for x in values_dict:
value2=values_dict[x]
try:
ldap_conn.entries[0].value2
except Exception as error:
print(error)
else:
print(value2)
attribute 'value2' not found
If I replace value2 with 'sn' or any of the other attributes I have pulled it works fine. I have also played around with exec() but this returns nothing.
for x in values_dict:
value2=values_dict[x]
test1='ldap_conn.entries[0].{}'.format(value2)
try:
result1=exec(test1)
except Exception as error:
print(error)
else:
print(result1)
None
Any ideas?
EDIT 1 : As requested here are the values for values_dict. As stated previously the loop does parse these correctly, ldap does return the attributes, but when I try to use a variable to lookup the attributes from entries the variable is taken literally.
values_dict = {
"First_Name": "givenname",
"Middle_Name": "middlename",
"Last_Name": "sn",
"Preferred_Name": "extensionattribute2",
"Work_Location": "physicaldeliveryofficename",
"Work_City": "l",
"Work_State": "st",
"Work_Postal": "postalcode",
"Work_Email": "mail"
}
The syntax somevariable.someattr, which you are using here:
ldap_conn.entries[0].value2
Always means "access an attribute named someattr of somevariable". It's always interpreted as a literal string. If you need to dynamically access an attribute, use the getattr function:
getattr(ldap_conn.entries[0], value2)
You're not currently assigning that that result anywhere, so you probably want something like:
result1 = getattr(ldap_conn.entries[0], value2)

how compare a str object with None

I have meet a problem, when I develop a web use python3+flask, when name has no in put, I am confused, the result is True in print
name = request.args.get('name')
if name is not None:
print('True')
else:
print('False')
I refer to python documents, "A is not B" means A and B is not same object.
And I make the following test:
print(name) #None
print(type(name)) #<class "str">
print(type(None)) #<class "NoneType">
I found the answer, but when I use the following format
if name:
print('True')
else:
print('False')
it prints True and print(name) I get None
I have to write like the following:
if name != str(None):
print('True')
else:
print('False')
I feel it a little uncomfortable when use it like this, how I can compare it in a elegant way.
Getting a string "None" as part of a request commonly happens when you return a None value as part of a previous response.
Example:
# given a variable that is passed to a jinja template as None
# instead of as an empty string
name = None
Will result in a link with "None" as a string.
<a href="/some/link?name={{ name }}>click here</a>
Instead of trying to handle for a string "None" in any given request where you expect a string, you should output the original variable as an empty string:
name = None
...
# convert Nones to empty strings right before sending to jinja
if not name:
name = ''
print(True if "None" not in name else False)
I think that's more elegant way of printing out in your case.

If Try statement

In my scripts I wanna cleanup my error Handling. What I read is that I need:
try:
do something
exept:
raise Error("give error")
finaly:
print("something else")
The problem I have is that I don't know how to handle an error in this way in my former written function.
How do I create a try statement with multiple conditions like the simple example below.
def varlist(var, length):
from numpy import array
if len(array(var)) > length:
return(False)
raise ValueError('list is to long only first ' + str(length) + ' paramerets will be used')
elif len(array(var)) < length:
return(False)
raise ValueError('list is to short ' + str(length) + ' is less than required')
else:
return(True)
So in general my question is: How to handle an if/ try statement with multiple outputs all baased on their value....
In this case I have two outputs but I have others with more values( sometimes strings)
I don't quite get your problem but here is a code using the try statement:
def varlist(var, length):
from numpy import array
try:
return True
except len(array(var)) > length :
return False
raise ValueError('#Your Error message 1')
except len(array(var)) < length :
return False
raise ValueError('#Your Error message 2')
If you meant how to return multiple values, just 'pack' them in a tuple like this:
returntuple = ('statement1', 'statement2', etc)
return returntuple
Then you can 'unpack' it like this:
returntuple[1]
will return 'statement2'
Like this you can return multiple values. You need to trick python, because it doesn't provide returning multiple values(, as far as I know!). But if you 'pack' your values in a tuple or a listeverything is fine!
If those two answers doesn't get your problem, I'm sorry I just don't get the question.
Sincerely, heureka

Resources