Skip to content

Background

background.task declares Python that runs while the app isn't open, and background.schedule asks the system to run it. Enable it with use = ["background"] under [plugins]. See the Background guide.

Run Python periodically while the app isn't open.

Enable it in pythonnative.toml. iOS only launches for identifiers listed in the app's Info.plist, so every task's name also goes under tasks:

[plugins]
use = ["background"]

[plugins.background]
tasks = ["sync"]

Declare tasks at module level, somewhere the app's entry module imports, so they exist when the system starts the app with no screen:

Example
from datetime import timedelta

from pythonnative import background

@background.task("sync", every=timedelta(minutes=30), requires_network=True)
async def sync() -> background.Result:
    await upload_pending()
    return background.Result.SUCCESS

background.schedule("sync")

The system decides when a task really runs: every is the shortest gap between runs, not a timer.

Classes:

Name Description
Result

What a task reports when it finishes.

TaskStatus

What the platform knows about one task.

Functions:

Name Description
task

Declare a background task. Use it as a decorator at module level.

schedule

Ask the system to run a declared task periodically, until it's canceled.

cancel

Stop scheduling a task. A run already in progress isn't interrupted.

status

Report every declared task, and any scheduled one no longer declared.

run_now

Run a declared task's Python function here and now, for development.

Attributes:

Name Type Description
MINIMUM_INTERVAL

The shortest every: WorkManager's floor for periodic work, applied on every platform.

MINIMUM_INTERVAL module-attribute

MINIMUM_INTERVAL = timedelta(minutes=15)

The shortest every: WorkManager's floor for periodic work, applied on every platform.

Result

Bases: str, Enum

What a task reports when it finishes.

A task that returns None counts as SUCCESS, and one that raises counts as FAILURE.

Attributes:

Name Type Description
SUCCESS

The work is done.

FAILURE

The work failed. The next period still runs.

RETRY

Run again soon. Android backs off and retries. iOS has no retry, so this counts as a failure until the next period.

TaskStatus dataclass

TaskStatus(
    name: str,
    scheduled: bool,
    every: Optional[timedelta] = None,
    last_run: Optional[datetime] = None,
    last_result: Optional[str] = None,
)

What the platform knows about one task.

Attributes:

Name Type Description
name str

The task's name.

scheduled bool

Whether schedule is in effect.

every Optional[timedelta]

The shortest gap between runs.

last_run Optional[datetime]

When the system last started the task from the background. run_now doesn't count.

last_result Optional[str]

How that run ended: "success", "failure", "retry", or "expired" when the system stopped it first.

task

task(
    name: str,
    *,
    every: timedelta,
    requires_network: bool = False,
    requires_charging: bool = False,
    processing: bool = False
) -> Callable[[F], F]

Declare a background task. Use it as a decorator at module level.

The decorated function may be sync or async. It runs on the application thread, with no screen on the way when the system starts the app for it. Declaring a task doesn't start it; call schedule for that.

Parameters:

Name Type Description Default
name str

A stable name of letters, digits, ., _, and -. On iOS it must also be listed in [plugins.background].tasks.

required
every timedelta

The shortest gap between runs, at least MINIMUM_INTERVAL.

required
requires_network bool

Wait for a network connection. iOS only enforces this with processing, since BGAppRefreshTask has no such constraint.

False
requires_charging bool

Wait for external power. On iOS this implies processing.

False
processing bool

On iOS, use BGProcessingTask, which allows minutes of work but usually waits until the device is idle, instead of BGAppRefreshTask, which gets about 30 seconds. Android ignores it, and always allows about 10 minutes.

False

Raises:

Type Description
ValueError

If the name is malformed or every is below the floor.

schedule

schedule(name: str) -> None

Ask the system to run a declared task periodically, until it's canceled.

Survives restarts of the app. Safe to call on every launch: an unchanged task keeps its place in the system's queue.

Parameters:

Name Type Description Default
name str

The task's name.

required

Raises:

Type Description
NativeModuleError

With the code unknown_task if no @task has this name; unregistered_task on iOS if it isn't listed in [plugins.background].tasks; unavailable on iOS if the system refuses, which it always does on a simulator and does when Background App Refresh is off; or plugin_not_enabled if background isn't in the build.

cancel

cancel(name: str) -> None

Stop scheduling a task. A run already in progress isn't interrupted.

Parameters:

Name Type Description Default
name str

The task's name. An unscheduled name does nothing.

required

Raises:

Type Description
NativeModuleError

With the code plugin_not_enabled if background isn't in the build.

status

status() -> List[TaskStatus]

Report every declared task, and any scheduled one no longer declared.

Raises:

Type Description
NativeModuleError

With the code plugin_not_enabled if background isn't in the build.

run_now async

run_now(name: str) -> Result

Run a declared task's Python function here and now, for development.

This calls the function in-process and involves no system scheduler, so it proves your code works, not that the system will start it. Exceptions propagate, and status() doesn't change. To exercise the real path, see the capability guide.

Parameters:

Name Type Description Default
name str

The task's name.

required

Returns:

Type Description
Result

What the function returned.

Raises:

Type Description
NativeModuleError

With the code unknown_task if no @task has this name.