2021年9月17日 星期五

[ Python 常見問題 ] When using unittest.mock.patch, why is autospec not True by default?

 Source From Here

Question
When you patch a function using mock, you have the option to specify autospec as True:
If you set autospec=True then the mock with be created with a spec from the object being replaced. All attributes of the mock will also have the spec of the corresponding attribute of the object being replaced. Methods and functions being mocked will have their arguments checked and will raise a TypeError if they are called with the wrong signature.

(http://www.voidspace.org.uk/python/mock/patch.html)

I'm wondering why this isn't the default behavior? Surely we would almost always want to catch passing incorrect parameters to any function we patch?

HowTo
The only clear way to explain this, is to actually quote the documentation on the downside of using auto-speccing and why you should be careful when using it:
This isn’t without caveats and limitations however, which is why it is not the default behaviour. In order to know what attributes are available on the spec object, autospec has to introspect (access attributes) the spec. As you traverse attributes on the mock a corresponding traversal of the original object is happening under the hood. If any of your specced objects have properties or descriptors that can trigger code execution then you may not be able to use autospec. On the other hand it is much better to design your objects so that introspection is safe [4].

A more serious problem is that it is common for instance attributes to be created in the init method and not to exist on the class at all. autospec can’t know about any dynamically created attributes and restricts the api to visible attributes.

I think the key takeaway here is to note this line: autospec can’t know about any dynamically created attributes and restricts the api to visible attributes

So, to help being more explicit with an example of where autospeccing breaks, this example taken from the documentation shows this:
  1. >>> class Something:  
  2. ...   def __init__(self):  
  3. ...     self.a = 33  
  4. ...  
  5. >>> with patch('__main__.Something', autospec=True):  
  6. ...   thing = Something()  
  7. ...   thing.a  
  8. ...  
  9. Traceback (most recent call last):  
  10.   ...  
  11. AttributeError: Mock object has no attribute 'a'  
As you can see, auto-speccing has no idea that there is an attribute a being created when creating your Something object. There is nothing wrong with assigning a value to your instance attribute.

Observe the below functional example:
  1. import unittest  
  2. from mock import patch  
  3.   
  4. def some_external_thing():  
  5.     pass  
  6.   
  7. def something(x):  
  8.     return x  
  9.   
  10. class MyRealClass:  
  11.     def __init__(self):  
  12.         self.a = some_external_thing()  
  13.   
  14.     def test_thing(self):  
  15.         return something(self.a)  
  16.   
  17.   
  18.   
  19. class MyTest(unittest.TestCase):  
  20.     def setUp(self):  
  21.         self.my_obj = MyRealClass()  
  22.   
  23.     @patch('__main__.some_external_thing')      
  24.     @patch('__main__.something')  
  25.     def test_my_things(self, mock_something, mock_some_external_thing):  
  26.         mock_some_external_thing.return_value = "there be dragons"  
  27.         self.my_obj.a = mock_some_external_thing.return_value  
  28.         self.my_obj.test_thing()  
  29.   
  30.         mock_something.assert_called_once_with("there be dragons")  
  31.   
  32.   
  33. if __name__ == '__main__':  
  34.     unittest.main()  
So, I'm just saying for my test case I want to make sure that the some_external_thing() method does not affect the behaviour of my unittest, so I'm just assigning my instance attribute the mock per mock_some_external_thing.return_value = "there be dragons".

2021年9月4日 星期六

[ Bash 範例代碼 ] Scripts with pre-defined information

 Source From Here

- goscript.sh
  1. #!/bin/bash  
  2. read -r -p "Enter name of script: " script  
  3. read -r -p "Whats your fullname: " fname  
  4. read -r -p "Whats the description of this script: " description  
  5. script_dir_path="$HOME/ps/"  
  6.   
  7. if [ ! -d $script_dir_path ]; then  
  8.   mkdir ${script_dir_path}  
  9. fi  
  10.   
  11. script_path="${script_dir_path}/${script}"  
  12. echo "Preparing ${script_path}"  
  13. echo "#!/bin/bash" > "${script_path}"  
  14. echo  
  15. echo "###########################################" >> ${script_path}  
  16. echo  
  17. echo "#Author: " $fname >> ${script_path}  
  18. echo  
  19. echo "#Date: " $(date) >> ${script_path}  
  20. echo  
  21. echo "#Description: " $description >> ${script_path}  
  22. echo  
  23. echo "#Modified: " $(date) >> ${script_path}  
  24. echo  
  25. echo "###########################################" >> ${script_path}  
  26. echo  
  27. chmod a+x ${script_path}  
  28. vim ${script_path}  
Supplement
Linuxize - Bash read Command

2021年9月3日 星期五

[ Python 常見問題 ] Why do Python classes inherit object?

 Source From Here

Question
Is there any reason for a class declaration to inherit from object? I just found some code that does this and I can't find a good reason why.
  1. class MyClass(object):  
  2.     # class code follows...  
Answer:
In Python 3, apart from compatibility between Python 2 and 3, no reason. In Python 2, many reasons.

Python 2.x story:
In Python 2.x (from 2.2 onwards) there's two styles of classes depending on the presence or absence of object as a base-class:

1. "classic" style classes: they don't have object as a base class:
  1. >>> class ClassicSpam:      # no base class  
  2. ...     pass  
  3. >>> ClassicSpam.__bases__  
  4. ()  
2. "new" style classes: they have, directly or indirectly (e.g inherit from a built-in type), object as a base class:
  1. >>> class NewSpam(object):           # directly inherit from object  
  2. ...    pass  
  3. >>> NewSpam.__bases__  
  4. (<type 'object'>,)  
  5. >>> class IntSpam(int):              # indirectly inherit from object...  
  6. ...    pass  
  7. >>> IntSpam.__bases__  
  8. (<type 'int'>,)   
  9. >>> IntSpam.__bases__[0].__bases__   # ... because int inherits from object    
  10. (<type 'object'>,)  
Without a doubt, when writing a class you'll always want to go for new-style classes. The perks of doing so are numerous, to list some of them:

Support for descriptors. Specifically, the following constructs are made possible with descriptors:
classmethod: A method that receives the class as an implicit argument instead of the instance.
staticmethod: A method that does not receive the implicit argument self as a first argument.
properties with property: Create functions for managing the getting, setting and deleting of an attribute.
more...

* The __new__ static method: lets you customize how new class instances are created.
Method resolution order (MRO): in what order the base classes of a class will be searched when trying to resolve which method to call.
* More

If you don't inherit from object, forget these. A more exhaustive description of the previous bullet points along with other perks of "new" style classes can be found here.

One of the downsides of new-style classes is that the class itself is more memory demanding. Unless you're creating many class objects, though, I doubt this would be an issue and it's a negative sinking in a sea of positives.

Python 3.x story:
In Python 3, things are simplified. Only new-style classes exist (referred to plainly as classes) so, the only difference in adding object is requiring you to type in 8 more characters. This:
  1. class ClassicSpam:  
  2.     pass  
is completely equivalent (apart from their name :-) to this:
  1. class NewSpam(object):  
  2.      pass  
and to this:
  1. class Spam():  
  2.     pass  
All have object in their __bases__.
  1. >>> [object in cls.__bases__ for cls in {Spam, NewSpam, ClassicSpam}]  
  2. [True, True, True]  
So, what should you do?
In Python 2: always inherit from object explicitly. Get the perks.

In Python 3: inherit from object if you are writing code that tries to be Python agnostic, that is, it needs to work both in Python 2 and in Python 3. Otherwise don't, it really makes no difference since Python inserts it for you behind the scenes.

[ Python 常見問題 ] When using unittest.mock.patch, why is autospec not True by default?

  Source From  Here Question When you patch a function using  mock , you have the option to specify  autospec  as True: If you set  autospec...