upsies.jobs.base

Abstract base class for jobs

Functions

upsies.jobs.base.raise_if_finished(method)[source]

Decorator for JobBase methods that raises RuntimeError if the job is_started and is_finished

upsies.jobs.base.raise_if_not_started(method)[source]

Decorator for JobBase methods that raises RuntimeError if the job was not started

upsies.jobs.base.raise_if_started(method)[source]

Decorator for JobBase methods that raises RuntimeError if the job is_started

upsies.jobs.base.raise_if_terminated(method)[source]

Decorator for JobBase methods that raises RuntimeError if the job is_terminated

upsies.jobs.base.unless_job_is_finished(method)[source]

Decorator for JobBase methods that blocks calls to the decorated method if the job is_finished

If a job gets terminated early, the DaemonProcess is usually still running and can be reporting information back to the main process by calling a callback method. If the callback method calls add_output(), for example, this raises a RuntimeError because adding output on a finished job is a bad idea.

This should only happen in error cases, and ignoring callbacks should be fine because we are only interested in shutting everyting down in a somewhat controlled manner.

Classes

class upsies.jobs.base.JobBase(*, home_directory=None, cache_directory=None, cache_id='', ignore_cache=False, no_output_is_ok=False, hidden=False, autostart=True, guaranteed=False, precondition=None, prejobs=(), callbacks={}, **kwargs)[source]

Bases: ABC

Base class for all jobs

Parameters:
  • home_directory (str) – Directory that is used to store created files

  • cache_directory (str) – Directory that is used to cache output

  • cache_id (str) – See cache_id

  • ignore_cache (str) – Whether cached output and previously created files should not be re-used

  • no_output_is_ok (bool) – Whether the job can succeed without any output

  • hidden

    Whether to hide the job’s output in the UI

    This can be a bool or callable that takes no arguments and returns a bool.

  • autostart (bool) – Whether this job is started automatically

  • guaranteed (bool) – Whether this job should run and finish even if other jobs fail

  • precondition – Callable that gets no arguments and returns whether this job is enabled or disabled

  • prejobs – Sequence of prerequisite jobs

  • callbacks – Mapping of signal names to callable or sequence of callables to register() for that signal

Any additional keyword arguments are passed on to initialize().

If possible, arguments should be validated before creating a job instance. This means we can fail early before any sibling jobs have started doing expensive work (e.g. torrent creation) that has to be cancelled.

abstract property name

Internal name (e.g. for the cache file name)

abstract property label

User-facing name

property home_directory

Directory that is used to store files (e.g. generated screenshots, torrent files, etc) or empty string

The directory is guaranteed to exist.

property cache_directory

Path to existing directory that stores cache_file

Subclasses may use this directory for storing custom cache files.

This directory is guaranteed to exist.

property ignore_cache

Whether cached output and previously created files should not be re-used

property no_output_is_ok

Whether the job can succeed without any output

property hidden

Whether to hide this job’s output in the UI

This can also be set to a callable that takes no arguments and returns a bool value.

property kwargs

Keyword arguments from instantiation as dict

property autostart

Whether this job is started automatically by the UI

The UI must check this value before calling start.

If this value is falsy, start() must be called manually.

property is_guaranteed

Whether this job should run and finish even if other jobs fail

This means that calling terminate() on a guaranteed job has no effect.

property is_enabled

Whether this job is allowed to start()

A job is enabled if precondition returns anything truthy and all prejobs are either finished or disabled.

This property must be checked by the UI every time any job finishes and when the refresh_ui signal is emitted. If this property is True, this job must be started and displayed (unless it is hidden).

property signal

Signal instance

The following signals are added by the base class. Subclasses can add their own signals.

started

Emitted by start() if job is not disabled. Unlike running, this signal is also emitted if output is read from cache and run() is not called. Registered callbacks get the job instance as a positional argument.

running

Emitted when a task for run() was created by start(). Unlike started, this signal is only called if no cached output is read. Registered callbacks get the job instance as a positional argument.

finished

Emitted when a job is_finished. A job is finished when all its tasks are done or cancelled or if cached output from a previous run is successfully read. Registered callbacks get the job instance as a positional argument.

output

Emitted when add_output() is called or when output is read from cache. Registered callbacks get the value passed to add_output() as a positional argument.

info

Emitted when info is set. Registered callbacks get the new info as a positional argument.

warning

Emitted when warn() is called. Registered callbacks get the value passed to warn() as a positional argument.

error

Emitted when error() is called. Registered callbacks get the value passed to error() as a positional argument.

prompt

Emitted when add_prompt() is called. Registered callbacks get the Prompt instance passed to add_prompt() as a positional argument. The user interface MUST subscribe to this signal and present dialogs to the user when it is emitted.

refresh_ui

Emitted when the user interface should update the focused widget, remove any finished jobs, start the next interactive job, etc. The UI usually only does this when a job finishes. This signal allows a job to force the refresh immediately. For example, emitting this signal may be necessary when a series of prompts are added by the same job. Registered callbacks get no arguments.

property siblings

Map job names to job instances for all instantiated jobs

receive_all(job_name, signal, *, only_posargs=False)[source]

Iterate over signal emissions from another job

This is a convenience wrapper around siblings and receive_all().

These calls are mostly equivalent:

job.siblings['other_job'].receive_all('some_signal')
job.receive_all('other_job, 'some_signal')
Raises:

ValueError – if no job has the name job_name

receive_one(job_name, signal, *, only_posargs=False)[source]

Return the first signal emission from another job

This is a convenience wrapper around siblings and receive_one().

Note

Because this will always only return the first emission, you probably shouldn’t use this to receive signals that are emitted multiple times.

These calls are equivalent:

job.siblings['other_job'].receive_one('some_signal')
job.receive_one('other_job, 'some_signal')
Raises:

ValueError – if no job has the name job_name

async wait_for(job_name, signal)[source]

Wait for signal from job_name

This is a convenience wrapper around siblings and wait_for().

Note

Because this will always only return the first emission, you probably shouldn’t use this to receive signals that are emitted multiple times.

These calls are equivalent:

job.siblings['other_job'].wait_for('some_signal')
job.wait_for('other_job, 'some_signal')
Raises:

ValueError – if no job has the name job_name

property precondition

Callable that gets no arguments and returns whether this job should be started

See also is_enabled.

property prejobs

Sequence of prerequisite jobs

All prejobs must be either finished or disabled before this job can start.

See also is_enabled.

initialize()[source]

Called by __init__() with additional keyword arguments

This method should handle its arguments and return quickly.

abstractmethod async run()[source]

Do the work

This method is called by start(). Its coroutine is passed to add_task().

Any keyword arguments passed to initialize() are available via kwargs.

The job is_finished when all added tasks are done or cancelled. (See also finalize() and finalization().)

This method may call add_task() if more tasks are required.

start()[source]

Load cached output if available, otherwise call run()

This method must be called by the UI if autostart is True.

Nothing is done if the job is already started, finished, terminated. or not enabled,

property is_started

Whether start() was called while this job is_enabled

Note

This does not mean that run() was called. A job is also considered to be started if output is read from cache.

add_task(coro, callback=None)[source]

Run asynchronous coroutine in background task

The job is_finished when all added tasks are done or cancelled.

Any exceptions from coro are raised by wait_finished() or made available via raised.

Parameters:
  • coro – Any awaitable object

  • callback

    Callable that is called with the return value or exception of coro

    callback is not called if the task was cancelled.

Returns:

asyncio.Task instance

add_prompt(prompt)[source]

Create a dialog in the user interface

Parameters:

promptPrompt object that specifies the dialog and handles callbacks

Returns:

prompt so the add_prompt() call can be conveniently awaited to get the result

async wait_started()[source]

Block until start() is called successfully

This is a convenience wrapper around receive_one() that waits for the emission of the started signal.

See signal.

async wait_running()[source]

Block until run() is called

This is a convenience wrapper around receive_one() that waits for the emission of the running signal.

See signal.

async wait_finished()[source]

Block until all added tasks are either done or cancelled and job is_finished

But first, wait for any prejobs to finish and then check if precondition returns anything truthy. Then wait_started() is called, so it is ok to call this method if the job was not started yet.

If finalization() was called, finalize() must be called before this method returns.

Any exception raised by tasks are ignored here. It can be accessed via raised.

terminate(reason=None)[source]

Cancel all added tasks

Do nothing if job is_finished or is_terminated.

Parameters:

reason – Why this job is terminated (only used for debugging)

property is_terminated

Whether terminate() was called to end this job prematurely

finalize()[source]

Unblock any calls awaiting finalization() or wait_finished()

async finalization()[source]

Block until finalize() is called

This is useful for interactive jobs that don’t have running tasks at all times. You can simply await self.finalization() in run() and call finalize() later to finish the job.

property is_finished

Whether all tasks are done

If finalization() is awaited, finalize() must also be called.

Before this job is started, None is returned.

property exit_code

0 if job was successful, > 0 otherwise, None before job is_finished

add_output(output)[source]

Append output to output and emit output signal

Note

All output is converted to str.

property output

Immutable sequence of strings passed to add_output()

This value is supposed to be the effective product of running this job and should be usable by other jobs (e.g. URL(s) or path(s)).

property info

Additional information (str) that is only displayed to the user while the job is running

Setting this property emits the info signal.

warn(warning)[source]

Append warning to warnings and emit warning signal

property warnings

Sequence of non-critical error messages the user can override or resolve

Unlike errors, warnings do not imply failure.

clear_warnings()[source]

Empty warnings

error(error)[source]

Append error to errors, emit error signal and terminate() this job

property errors

Sequence of critical errors (strings or exceptions)

By default, exit_code is non-zero if any errors were reported.

exception(exception)[source]

Make exception available as raised unless it is already set

Warning

This method is mostly for internal use. Setting an exception means you want to throw a traceback at the user.

Parameters:

exception (Exception) – Exception instance (nothing is done if this argument is falsy)

property raised

Exception passed to exception()

property cache_file

File path in cache_directory to store cached output in

If this property returns None, cache is not read or written.

property cache_id

Any object that makes a job’s output unique

If this property returns None, cache_file is not read or written.

If this property returns any other object, it is converted to a string and appended to name. Multibyte characters and directory delimiters are replaced.

By default, the cache_id argument from initialization is used, which is an empty string by default.