pytest - monkeypatch keyword argument default

2024/10/9 13:32:27

I'd like to test the default behavior of a function. I have the following:

# app/foo.py
DEFAULT_VALUE = 'hello'def bar(text=DEFAULT_VALUE):print(text)
# test/test_app.py
import appdef test_app(monkeypatch):monkeypatch.setattr('app.foo.DEFAULT_VALUE', 'patched')app.foo.bar()assert 0

Output is hello; not what I wanted.

One solution is to pass the default value explicitly: app.foo.bar(text=app.foo.DEFAULT_VALUE).

But I find it interesting that this doesn't seem to be an issue when defaulting to the global scope:

# app/foo.py
DEFAULT_VALUE = 'hello'def bar():print(DEFAULT_VALUE)

Output is patched.

Why does this happen? And is there a better solution than passing the default explicitly?

Answer

Function defaults are bound at function definition time.

By the time you are in test code, the module in which the function was defined has already been imported and it is too late to swap out the default by monkeypatching on the module level constant. That name was already resolved.

A workaround is to define the function like this:

def bar(text=None):if text is None:text = DEFAULT_VALUEprint(text)

Now the default value is looked up at function call time, which means a monkeypatch on the module level default will still work.

If you don't like to modify the function definition, then you can monkeypatch the function object itself:

monkeypatch.setattr("app.foo.bar.__defaults__", ("test_hello",))
https://en.xdnf.cn/q/70014.html

Related Q&A

How remove a program installed with distutils?

I have installed a python application with this setup.py:#!/usr/bin/env pythonfrom distutils.core import setup from libyouandme import APP_NAME, APP_DESCRIPTION, APP_VERSION, APP_AUTHORS, APP_HOMEPAGE,…

How to check which line of a Python script is being executed?

Ive got a Python script which is running on a Linux server for hours, crunching some numbers for me. Id like to check its progress, so Id like to see what line is being executed right now. If that was …

input to C++ executable python subprocess

I have a C++ executable which has the following lines of code in it /* Do some calculations */ . . for (int i=0; i<someNumber; i++){int inputData;std::cin >> inputData;std::cout<<"T…

pandas extrapolation of polynomial

Interpolating is easy in pandas using df.interpolate() is there a method in pandas that with the same elegance do something like extrapolate. I know my extrapolation is fitted to a second degree polyno…

Speed-up a single task using multi-processing or threading

Is it possible to speed up a single task using multi-processing/threading? My gut feeling is that the answer is no. Here is an example of what I mean by a "single task":for i in range(max):p…

Full outer join of two or more data frames

Given the following three Pandas data frames, I need to merge them similar to an SQL full outer join. Note that the key is multi-index type_N and id_N with N = 1,2,3:import pandas as pdraw_data = {type…

How can I add a level to a MultiIndex?

index = [np.array([foo, foo, qux]),np.array([a, b, a])] data = np.random.randn(3, 2) columns = ["X", "Y"] df = pd.DataFrame(data, index=index, columns=columns) df.index.names = [&qu…

decoupled frontend and backend with Django, webpack, reactjs, react-router

I am trying to decouple my frontend and my backend in my project. My frontend is made up of reactjs and routing will be done with react-router, My backend if made form Django and I plan to use the fron…

Map colors in image to closest member of a list of colors, in Python

I have a list of 19 colors, which is a numpy array of size (19,3):colors = np.array([[0, 0, 0], [0, 0, 255], [255, 0, 0], [150, 30, 150], [255, 65, 255], [150, 80, 0], [170, 120, 65], [125, 125,…

Storing a file in the clipboard in python

Is there a way to use the win32clipboard module to store a reference to a file in the windows clipboard in python. My goal is to paste an image in a way that allows transparency. If I drag and drop a…