I have a function written here:
def addItem(aBookcase, name, mediaType):
"""
Returns False if aBookcase is full, otherwise returns True and
adds item of given name and mediaType to aBookcase.
"""
pass
emptySpacesBefore = aBookcase.getEmptySpaces()
if aBookcase.getEmptySpaces() == 0:
added = False
return added
else:
position = findSpace(aBookcase)
aBookcase.setName(*position, name=name)
aBookcase.setType(*position, mediaType=mediaType)
added = True
emptySpacesAfter = aBookcase.getEmptySpaces()
assert added is True, "No free positions"
assert emptySpacesAfter < emptySpacesBefore, "Same amount of empty spaces"
assert aBookcase.getName(*position) is name, "Error with name"
assert aBookcase.getType(*position) is mediaType, "Error with media type"
Yet when I go to test the function with this line of code:
assert addItem(small, "Algorhythms, date structures and compatibility", BOOK)
I get an 'AssertionError' as shown here:
So if I'm right, it means I'm not handling it but I'm not sure how or why? Is it something wrong with my code? Something missing? etc.
when it works properly, your addItem function returns nothing, so it returns None, which is seen as a failure by the last assert statement that you inserted. You should return added for both cases (True or False)
BTW since you reached that line, it means that all previous assertions are OK so good news: your code is OK.
Related
How do I write multiple test cases for a single function. I want the functions to essentially iterate through a bunch of tests and then return a boolean or answer saying that the function has passed these tests.
def test_valid01():
name = 'jack'
expected = True
assert is_valid_name(name) == expected, "is_valid_name has failed."
test1 = True
this is an example of one of my functions testing another function.
A way that you could test various tests for the is_valid_name() function:
def assert_test_valid(name, expected_value):
assert is_valid_name(name) == expected_value, f"is_valid_name has failed for {name}" # allows identification of which test failed
def test_valid_all():
test_responses = { # the input and the expected response
'jack': True,
}
for key, value in test_responses.items(): # to go through all of the responses that you would like to test
assert_test_valid(key, value)
The runtime keeps telling me:
expected an indented block
But I don't want write nothing inside my except block, I just want it to catch and swallow the exception.
Just write
pass
as in
try:
# Do something illegal.
...
except:
# Pretend nothing happened.
pass
EDIT: #swillden brings up a good point, viz., this is a terrible idea in general. You should, at the least, say
except TypeError, DivideByZeroError:
or whatever kinds of errors you want to handle. Otherwise you can mask bigger problems.
For those who are very unclear as to why you would want to do this. Here is an example where I initially thought that an empty block would be a good idea:
def set_debug_dir(self, debug_dir=None):
if debug_dir is None:
debug_dir = self.__debug_dir
elif isinstance(debug_dir, (Path, str)):
debug_dir = debug_dir # this is my null operation
elif isinstance(debug_dir, list):
debug_dir = functools.reduce(os.path.join, debug_dir)
else:
raise TypeError('Unexpected type for debug_dir: {}'.format(type(debug_dir).__name__))
But it would be more clear to reorganize the statement:
def set_debug_dir(self, debug_dir=None):
if debug_dir is None:
debug_dir = self.__debug_dir
elif isinstance(debug_dir, list):
debug_dir = functools.reduce(os.path.join, debug_dir)
elif not isinstance(debug_dir, (Path, str)):
raise TypeError('Unexpected type for debug_dir: {}'.format(type(debug_dir).__name__))
I've never done this in more permanent code, but I frequently do it as a placeholder
if some_expression:
True
else:
do_something(blah)
Just sticking a True in there will stop the error. Not sure if there's anything bad about this.
Thats my first question on Stackoverflow and im a totally Python beginner.
I want to write, to get firm with python, a small Backup-Programm, the main part is done, but now i want to make it a bit "portable" and use a Config file, which i want to Validate.
My class "getBackupOptions" should be give Back a validate dict which should be enriched with "GlobalOptions" and "BackupOption" so that i finally get an fully "BackupOption" dict when i call "getBackupOptions.BackupOptions".
My Question now is, (in this Example is it easy, because its only the Function which check if the Path should be Recursive searched or not) how to simplify my Code?
For each (possible) Error i must write a new "TryExcept" Block - Can i Simplify it?
Maybe is there another way to Validate Config Files/Arrays?
class getBackupOptions:
def __init__(self,BackupOption,GlobalOptions):
self.BackupOption = BackupOption
self.GlobalOptions = GlobalOptions
self.getRecusive()
def getRecusive(self):
try:
if self.BackupOption['recursive'] != None:
pass
else:
raise KeyError
except KeyError:
try:
if self.GlobalOptions['recursive'] != None:
self.BackupOption['recursive'] = self.GlobalOptions['recursive']
else:
raise KeyError
except KeyError:
print('Recusive in: ' + str(self.BackupOption) + ' and Global is not set!')
exit()
Actually i only catch an KeyError, but what if the the Key is there but there is something else than "True" or "False"?
Thanks a lot for you help!
You may try this
class getBackupOptions:
def __init__(self,BackupOption,GlobalOptions):
self.BackupOption = BackupOption
self.GlobalOptions = GlobalOptions
self.getRecusive()
def getRecusive(self):
if self.BackupOption.get('recursive') == 'True' and self.GlobalOptions.get('recursive') == 'True':
self.BackupOption['recursive'] = self.GlobalOptions['recursive']
else:
print('Recusive in: ' + str(self.BackupOption) + ' and Global is not set!')
exit()
Here get method is used, therefore KeyError will not be faced.
If any text other than True comes in the field it will be considered as False.
I'm working with Web2Py. I'm trying to enable a textbox that isn't seemed to be defined anywhere but somehow appears on the web page.
anyways.
If a user logged in belongs to a certain group, the text box is enabled and the user can write in the textbox. If they are not a member of the group, the textbox is disabled - they can read was previously written but can not type in it.
The code that seems to affect the enabled state is this
if __userCanPerformStep(step) and not flow_completed:
flow_step_forms[step.name].element('textarea')['_rows'] = 5
__userCanPerformStep(step) is defined as
def __userCanPerformStep(step_row):
if auth.user.id in step_row.target_users:
return True
for group_id in step_row.target_groups:
if db((db.auth_membership.user_id == auth.user.id) & (db.auth_membership.group_id == group_id)).count() > 0:
return True
if auth.has_group_membership("systemadmin"):
return True
return False
has_group_membership is defined as
def has_group_membership(self, groupname):
if self.db((self.db.auth_group.id > 0) & (self.db.auth_group.role==groupname)).count() > 0:
group_id = self.db((self.db.auth_group.id > 0) & (self.db.auth_group.role==groupname)).select().first().id
return self.has_membership(group_id)
return False
Since __userCanPerformStep is used in many places, I created a new method as such:
def canAddComment(step_row):
if auth.has_group_membership_or(["groupA", "groupB", "groupC"]):
return False
if auth.user.id in step_row.target_users:
return False
return False
and has_group_membership_or defined as
def has_group_membership_or(self, groupnames):
if self.db((self.db.auth_group.id > 0) & (self.db.auth_group.role.belongs(groupnames))).count() > 0:
for groupname in groupnames:
group = self.db((self.db.auth_group.id > 0) & (self.db.auth_group.role==groupname)).select().first()
if group and self.has_membership(group.id):
return True
return False
when I now call the function as part of the IF statement like this:
if ( ( canAddComment(step)) and (not flow_completed)):
flow_step_forms[step.name].element('textarea')['_rows'] = 5
and every time a user belongs to one of the groups A,B or C. I get the following error:
'NoneType' object does not support item assignment
any hints??
SIDE NOTE
I've also forced the function to return False right away, and I don't get any errors. If I force True; I get errors. the forcing is done simply by having the first line of the method be return True
Q: how can I make python interpret my function being called to accept the value True? what am I overlooking?
UPDATE
Full traceback is
None['_rows'] = 5
throws
TypeError: 'NoneType' object does not support item assignment
So flow_step_forms[step.name].element('textarea') returns a None, presumably because flow_step_forms[step.name] has no element 'textarea' or the element is set to None.
If you need further assistance troubleshooting, please edit your question to include where you set that and I'll edit my answer.
in fucntion getLink(urls), I have return (cloud,parent,children)
in main function, I have (cloud,parent,children) = getLink(urls) and I got error of this line: TypeError: 'NoneType' object is not iterable
parent and children are all list of http links. since, it is not able to paste them here, parent is a list contains about 30 links; children is a list contains about 30 items, each item is about 10-100 links which is divide by ",".
cloud is a list contain about 100 words, like that: ['official store', 'Java Applets Centre', 'About Google', 'Web History'.....]
I didnot know why I get an error. Is there anything wrong in passing parameter? Or because the list take too much space?
#crawler url: read webpage and return a list of url and a list of its name
def crawler(url):
try:
m = urllib.request.urlopen(url)
msg = m.read()
....
return (list(set(list(links))),list(set(list(titles))) )
except Exception:
print("url wrong!")
#this is the function has gone wrong: it throw an exception here, also the error I mentioned, also it will end while before len(parent) reach 100.
def getLink(urls):
try:
newUrl=[]
parent = []
children =[]
cloud =[]
i=0
while len(parent)<=100:
url = urls[i]
if url in parent:
i += 1
continue
(links, titles) = crawler(url)
parent.append(url)
children.append(",".join(links))
cloud = cloud + titles
newUrl= newUrl+links
print ("links: ",links)
i += 1
if i == len(urls):
urls = list(set(newUrl))
newUrl = []
i = 0
return (cloud,parent,children)
except Exception:
print("can not get links")
def readfile(file):
#not related, this function will return a list of url
def main():
file='sampleinput.txt'
urls=readfile(file)
(cloud,parent,children) = getLink(urls)
if __name__=='__main__':
main()
There might be a way that your function ends without reaching the explicit return statement.
Look at the following example code.
def get_values(x):
if x:
return 'foo', 'bar'
x, y = get_values(1)
x, y = get_values(0)
When the function is called with 0 as parameter the return is skipped and the function will return None.
You could add an explicit return as the last line of your function. In the example given in this answer it would look like this.
def get_values(x):
if x:
return 'foo', 'bar'
return None, None
Update after seing the code
When the exception is triggered in get_link you just print something and return from the function. You have no return statement, so Python will return None. The calling function now tries to expand None into three values and that fails.
Change your exception handling to return a tuple with three values like you do it when everything is fine. Using None for each value is a good idea for it shows you, that something went wrong. Additionally I wouldn't print anything in the function. Don't mix business logic and input/output.
except Exception:
return None, None, None
Then in your main function use the following:
cloud, parent, children = getLink(urls)
if cloud is None:
print("can not get links")
else:
# do some more work