Skip to content Skip to sidebar Skip to footer

How Do I Patch A Sys Attribute Using A Decorator?

I have a function which depends on the Python version. I would like to test this in a unittest by mocking sys.version info. The following code works: def test_python_version(self):

Solution 1:

Edit:

Yes it works. The original function returns a named tuple with major, minor and micro fields. You can mimic it by building your own named tuple. I just use a simple tuple as you access with int index instead. Problem with your code is in the way you indexed with [0] which was not right.

Edit2:

As Zaur Nasibov pointed out sys.version_info is not a function, and so my code was wrong despite looking fine with the mocks (as GenError also found). I have done a little change to fix it (see GenError answer for an alternative using PropertyMock)

import sys
from unittest.mock import patch

defmy_func():
    version = sys.version_info # removed the ()print('Detected version:', version)
    if version[0] < 3:
        print('Error: Python 3 required.')

@patch('__main__.sys')deftest_python_version(mock_sys):
        mock_sys.version_info = (3,6,2)
        my_func()
        print()
        mock_sys.version_info = (2,7,0)
        my_func()


test_python_version()

Outputs

Detected version:(3,6,2)Detected version:(2,7,0)Error:Python3required.

Solution 2:

I found the answer by progmatico but it has a serious issue for me, as it requires to call sys.version_info() instead of sys.version_info which would break the code if ran normally.

Example:

#filename: a.pyimport sys
defdo_something():
    if sys.version_info > (3,5):
        print('Python 3.5 or newer')
    else:
        print('Python pre 3.5')

Now if I want to test both cases in a unit test @patch("sys.version_info") will lead to an error as given by OP. Changing do_something() to use sys.version_info() would break it if the mock is not used.

Test file:

#filename: test_a.pyfrom unittest.mock import patch, PropertyMock
import a

@patch('a.sys')deftest_a(mock_sys):
    type(mock_sys).version_info = PropertyMock(return_value=(3,4))
    a.do_something() # will show mocked python version

So you have to mock the sys module imported in the module a and set a PropertyMock on it.

Post a Comment for "How Do I Patch A Sys Attribute Using A Decorator?"