beeware / beeware/toga

Document passing arguments to event handlers

Open
#2,099 14 comments 0 reactions 0 assignees View on GitHub
documentation
Dominant language
Python
Stars
5.4k
Forks
827
Avg merge
15h 39m
Merged PRs (30d)
40

Description

**Summary by @freakboy3742**

We are regularly asked either (a) how to "pass in arguments to event handlers", or (b) for a feature addition to do the same. This isn't something that needs additional functionality - it just needs a better understanding of how Python can be used.

We should add a topic guide describing how to pass in additional details to an event handler, including:
* state variables on the app
* generator functions
* functools.partial
* using something other than `add_background_task` for background work.

Originally framed in the form of a feature request, asking for the ability to pass in coroutines to add_background_task; details follow. The comments following the ticket give a starting point for a discussion in the topic guide.

-----

**Original post by @Cimbali**

### What is the problem or limitation you are having?

Currently `add_background_task` accepts generators and coroutine functions (i.e. functions that return a coroutine). This makes passing an asynchronous function that takes arguments quite awkward.

Suppose I have an async function (“coroutine function”) that takes some arguments:
```
async def func(arg1, arg2):
pass
```

With asyncio, the idiom is call the function, have it return a coroutine, and let asyncio take care of running it:
```
asyncio.run(func('a', 'b'))
```

In toga, the idiom requires toga to call the function, which means we are now fixing the prototype of the function:
```
app.add_background_function(func) # Does not fit func’s prototype!
```

### Describe the solution you'd like

If `add_background_function` supported passing in coroutines, we could do:

```
app.add_background_function(func('a', 'b'))
```

### Describe alternatives you've considered

If I want to pass several arguments to an async function run in the background, the most concise I can do is:
```
async def wrapper(app):
return await func('a', 'b')

app.add_background_function(wrapper)
```

Which in more complex code becomes quite annoying, and means a function closure for every call, plus an additional `await`.

### Additional context

Note you also can’t do:
```
def wrapper(app):
return func('a', 'b')
```
This also returns a coroutine which is awaitable (and `asyncio.run(wrapper(app))` woulc work as expected) but the wrapper isn’t _decorated_ as a coroutine function.

Contributor guide

Open the contributing guide

Research direction

Start by locating the topic-guide documentation for event handlers and the existing add_background_task guidance. Use the examples in this issue to cover app state variables, generator functions, functools.partial, and alternatives for background work. Done means the guide explains how to pass additional details without requiring new functionality.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
documentation
Issue type
Documentation
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.