I want to mock out calls to urllib.request.urlopen in a module. It works when it's a single file, but when I put it in a package and import the module in the package's __init__.py, I cannot mock it out anymore.
Reproduction
Imagine I have two modules in a test package:
module.pyfrom urllib.request import urlopen def do_it(): print(urlopen.__module__) urlopen('test')module_test.pyfrom unittest import mock from .module import do_it def test_not_working(): with mock.patch('urllib.request.urlopen', lambda url: print(url)): do_it() def test_plain(): with mock.patch('test.module.urlopen', lambda url: print(url)): do_it()
test_not_working prints urllib.request as the module for urlopen, since I patched the local urlopen function in the test module, and the test fails because test is not a valid URL.
test_plain prints .module, because I succesfully patched urlopen, and the test succeeds and prints test.
My issue is that I have moved .module into a package, because I wanted to group multiple files I created. It now looks like this:
module__init__.pyfrom .module import do_itmodule.py(same asmodule.pybefore)
test_module.pyfrom unittest import mock from .module import do_it def test_packaged_fails(): with mock.patch('test.module.urlopen', lambda url: print(url)): do_it() def test_packaged_works(): with mock.patch('test.module.module.urlopen', lambda url: print(url)): do_it()
The first two tests stay the same, but test_packaged prints urllib.request, and fails as the first test because the URL test is invalid.
I understand that I failed to mock urlopen, because it evidently doesn't use test.module.urlopen but test.module.module.urlopen.
Restrictions
Actual Project
I don't know how to fix this issue, because of the module is just one of many on an open source project (OpenMensa Parsers). The Aachener parser is a package containing multiple files, instead of a single file module like the other parsers.
The issue mentioned above occurs when I want to upgrade snapshots for our regression tests. It is supposed to cache all requests that a parser makes, so that the test can be reproduced later, even if the website changes.
List
I have the following restrictions:
- I cannot hard code the path to the submodule (
test.module.module.urlopen), because I want to use the snapshot generation for the other parsers as well. - I can only use libraries that are available as Debian Wheezy packages, because of the build system and deployment. See the currently installed dependencies.
- I would like to stay with
urllib.request.urlopenfor consistency with the other parsers. - I actually do not call
do_it()directly. I call a function from another module that dynamically importsdo_it()from different parser modules and then calls it. I will leave the minimal example above as is for simplicity.
Question
How can I patch urlopen in the package, if I do not know the subpackage it is called in?