Could you help me to figure out the anti patterns and problems in my code. I can't seem to figure out the anti patterns of this code and the solution. I've fixed some errors but I believe there are still many mistakes:
class Stringchecker():
def __init__(self):
pass
def check_pass(people_text):
result = []
for k in people_text:
if people_text[k] =="pass":
result.append(k)
else:
return result
if __name__== "__main__":
people_text = {'Mia': 'pass', 'Mike': 'fail', 'Jack': 'pass')
sc = StringChecker()
print sc.check_pass(people_text)
Your code has several syntax issues and some logic problem. Also you are not using class constructor properly, just giving it a pass is not a good practice. Another thing is to use list comprehension for your check_pass method. I made some corrections to your code:
class StringChecker(object):
def __init__(self, people_text):
self.people_text = people_text
def check_pass(self):
return [k for k, v in self.people_text.items() if v == "pass"]
if __name__ == "__main__":
sc = StringChecker({'Mia': 'pass', 'Mike': 'fail', 'Jack': 'pass'})
print sc.check_pass()
Output:
['Mia', 'Jack']
Note: Updated list comprehension with suggestion from #JLPeyret
Errors:
not using self as first parameter to check_pass
returning the result after the first failure (if no failures, result will not be returned; if a failure occurs before successes would, result won't have all the data)
return result should be at the same indentation level as for k in ...
Anti-patterns:
a class with only one non-__init__ method (just use a function)
(assuming else branch has a pass instead) - useless else branch
Related
I want to be able to mock a function that mutates an argument, and that it's mutation is relevant in order for the code to continue executing correctly.
Consider the following code:
def mutate_my_dict(mutable_dict):
if os.path.exists("a.txt"):
mutable_dict["new_key"] = "new_value"
return True
def function_under_test():
my_dict = {"key": "value"}
if mutate_my_dict(my_dict):
return my_dict["new_key"]
return "No Key"
def test_function_under_test():
with patch("stack_over_flow.mutate_my_dict") as mutate_my_dict_mock:
mutate_my_dict_mock.return_value = True
result = function_under_test()
assert result == "new_value"
**Please understand i know i can just mock os.path.exists in this case but this is just an example. I intentionally want to mock the function and not the external module.
**
I also read the docs here:
https://docs.python.org/3/library/unittest.mock-examples.html#coping-with-mutable-arguments
But it doesn't seem to fit in my case.
This is the test i've written so far, but it obviously doesn't work since the key changes:
def test_function_under_test():
with patch("stack_over_flow.mutate_my_dict") as mutate_my_dict_mock:
mutate_my_dict_mock.return_value = True
result = function_under_test()
assert result == "new_value"
Thanks in advance for all of your time :)
With the help of Peter i managed to come up with this final test:
def mock_mutate_my_dict(my_dict):
my_dict["new_key"] = "new_value"
return True
def test_function_under_test():
with patch("stack_over_flow.mutate_my_dict") as mutate_my_dict_mock:
mutate_my_dict_mock.side_effect = mock_mutate_my_dict
result = function_under_test()
assert result == "new_value"
How it works is that with a side effect you can run a function instead of the intended function.
In this function you need to both change all of the mutating arguments and return the value returned.
A very similar question was asked, however it doesn't answer my doubt.
#mock.patch('myget.myvalue.myfrom.myAPI')
def test_thatdoesntwork(myAPI_mock):
orig_function = myget.myvalue.myfrom.myAPI
nth_value = get_valuefrom_myDB(n=111)
def mock_function_for_nth_value_only(myvalue):
if myvalue == nth_value:
return get_valuefrom_myDB(n+1)
else:
return orig_function(n)
nplus1th_value = get_valuefrom_myDB(n=112)
myvalue = myget.myvalue.myfrom.myAPI(nplus1th_value)
# getting "CRITICAL: maximum recursion level exceeded"
am assuming when I call orig_function , I am actually calling the mocked function, and that causes the CRITICAL recursion error....
but what am I doing wrong?
Thanks!!
The #mock.patch decorator replaces the function before your code starts, so orig_function = myget.myvalue.myfrom.myAPI already points to the mocked version.
Instead, you can use the context manager to ensure that you only replace the function in the scope you want.
This test version should work better for you:
def test_that_works():
orig_function = myget.myvalue.myfrom.myAPI
nth_value = get_valuefrom_myDB(n=111)
def mock_function_for_nth_value_only(myvalue):
if myvalue == nth_value:
return get_valuefrom_myDB(myvalue + 1)
else:
return orig_function(myvalue)
with mock.patch('myget.myvalue.myfrom.myAPI',
side_effect=mock_function_for_nth_value_only):
nplus1th_value = get_valuefrom_myDB(n=112)
myvalue = myget.myvalue.myfrom.myAPI(nplus1th_value)
I already have a working, but in my oppinion not beautiful solution for a part of a long script.
My script uses several similar methods, that differ too much to combine. However I came to a point where I want to call one of those methods depending on a given variable.
The names of the methods are build up like this:
def read_A():
#doing sth
def read_B():
#doing sth else
def read_C():
etc.
Now I would like to call those methods in a pythonic way, when the letter ('A', 'B', 'C', ...) is given as a variable.
A non-pythonic solution would be:
if var == "A":
read_A()
if var == "B":
read_B() .....
And I hope to find a more pythonic solution that allows me to call those methods simply like this:
var = "A"
read_var() #This would call the method 'read_A()'
Please mind that the code above is only an image of what I hope to do, it is not a working example!
I dont see an issue with just using
if var == 'A':
read_a()
but if you'd like to make it more 'pythonic' you could map your variables to the methods using a dictionary and execute it based on the result of what's stored in your dictionary:
def read_a():
print('Running method read_a')
def read_b():
print('Running method read_b')
switch = {'A': read_a, 'B': read_b}
case = 'A'
switch.get(case)()
>> 'Running method read_a'
case = 'B'
switch.get(case)()
>> 'Running method read_b'
Stick the functions in a dictionary, and use the dictionary to dispatch to the chosen one:
read = {'A': read_a, 'B': read_b, 'C': read_c}
choice = 'A'
read[choice]()
On that last line, you lookup the function that matches your choice in the dictionary, then you immediately call it.
you may use next construction:
def execute_func(x):
return {
'0':read_A(),
'1':read_B()
}[x]
Set your variables instead '0' and '1' or more and pass your params to execute_func().
You can do it in this way if you have many functions named read_a, read_b...etc, instead of writing huge dictionary.
def read_a():
print('Running method read_a')
def read_b():
print('Running method read_b')
def read_c():
print("running method read_c")
def read_d():
print("running method read_d")
............
............
def read_z():
print("running method read_z")
def _read_var(var):
method = "read_{}".format(var.lower())
try:
eval(method)()
except NameError:
raise NotImplementedError
var = "A"
_read_var(var)# will invoke read_a method
"""
modified from
https://stackoverflow.com/questions/65163600/how-to-call-a-class-method-given-its-name
"""
class MyClass(object):
def __init__(self):
pass
def call_method_by_string(self, method_name):
getattr(self, method_name)() # call local method based on string
def get_year(self):
print("here")
if __name__ == "__main__":
mc = MyClass()
mc.call_method_by_string(method_name="get_year")
easiest way to explain this one:
import unittest
from element import Element
class TestHTMLGen(unittest.TestCase):
def test_Element(self):
page = Element("html", el_id=False)
self.assertEqual(page, Element("html", el_id=False)) # this is where I need help
I get the following error:
AssertionError: <element.Element object at 0x025C1B70> != <element.Element object at 0x025C1CB0>
I know the objects are not exactly the same but is there any way to check that they are equal? I would think that assertEqual would work.
edit: I am working with the addTypeEqualityFunc. However, I am still having trouble
def test_Element(self):
page = Element("html", el_id=False)
self.addTypeEqualityFunc(Element, self.are_elements_equal)
self.assertEqual(page, Element("html", el_id=False))
def are_elements_equal(self, first_element, second_element, msg=None):
print first_element.attribute == second_element.attribute
return type(first_element) is type(second_element) and first_element.tag == second_element.tag and first_element.attribute == second_element.attribute
This is the output I get:
False
and it says the test passed. It should not pass because first_element.attribute is not equal to second_element.attribute. Furthermore, even if I just have return false for are_elements_equal, the test still passes.
Solution:
import unittest
from element import Element
class TestHTMLGen(unittest.TestCase):
def test_Element(self):
page = Element("html", el_id=False)
self.addTypeEqualityFunc(Element, self.are_elements_equal)
self.assertEqual(page, Element("html", el_id=False)) # this is where I need help
def are_elements_equal(self, first_element, second_element, msg=None):
self.assertEqual(type(first_element), type(second_element))
self.assertEqual(first_element.tag, second_element.tag)
self.assertEqual(first_element.attribute, second_element.attribute)
however, a lot of times self.assertEqual(vars(page), vars(Element("html", el_id=False))) will do the trick
edit: also, I should add. I made a cool little function that can check if objects are equal. Should work in most cases.
def are_elements_equal(self, first_element, second_element, msg=None):
self.assertEqual(type(first_element), type(second_element))
try:
type(vars(first_element)) is dict
except:
self.assertEqual(first_element, second_element)
else:
for i in vars(first_element).keys():
try:
type(vars(vars(first_element)[i])) is dict
except:
if type(vars(first_element)[i]) is list:
for j in range(len(vars(first_element)[i])):
self.are_elements_equal(vars(first_element)[i][j], vars(second_element)[i][j])
else:
self.assertEqual(vars(first_element)[i], vars(second_element)[i])
else:
self.are_elements_equal(vars(first_element)[i], vars(second_element)[i])
Use vars():
Return the dict attribute for a module, class, instance, or any other object with a dict attribute.
self.assertEqual(vars(page), vars(Element("html", el_id=False)))
Given Python code,
def foo():
def bar():
pass
bar()
foo()
bar()
I'd like to get a list of functions which, if I execute the Python code, will result in a NameError.
In this example, the list should be ['bar'], because it is not defined in the global scope and will cause an error when executed.
Executing the code in a loop, each time defining new functions, is not performant enough.
Currently I walk the AST tree, record all function definitions and all function calls, and subtract one from the other. This gives the wrong result in this case.
it seems you are trying to write some static analyzer for python. maybe you are working on C, but i think it would be faster for me to show the idea only in python:
list_token = # you have tokenized the program now.
class Env:
def __init__(self):
self.env = set()
self.super_env = None # this will point to Env instance
def __contains__(self, key):
if key in self.env:
return True
if self.sub_env is not None:
return key in self.super_env
def add(self, key):
self.env.add(key)
topenv = Env()
currentenv = topenv
ret = [] # return list
for tok in list_token:
if is_colon(tok): # is ':', ie. enter a new scope
newenv = Env()
currentenv.super_env = newenv
currentenv = newenv
else if is_exiting(tok): # exit a scope
currentenv = currentenv.super_env
else if refing_symbol(tok):
if tok not in currentenv: ret.add(tok)
else if new_symbol(tok):
currentenv.add(tok)
else: pass
if you think this code is not enough, please point out the reason. and if you want to capture all by static analysis, i think it's not quite possible.