Docs: document the Python APIs for modules
This commit is contained in:
parent
74d65d8338
commit
fe582fb94d
@ -284,8 +284,163 @@ description if something went wrong.
|
||||
|
||||
### Python API
|
||||
|
||||
**TODO:** this needs documentation
|
||||
The interface from a Python module to Calamares internals is
|
||||
found in the *libcalamares* module. This is not a standard Python
|
||||
module, and is only available inside the Calamares "runtime" for
|
||||
Python modules (it is implemented through Boost::Python in C++).
|
||||
|
||||
A module should start by importing the Calamares internals:
|
||||
|
||||
```
|
||||
import libcalamares
|
||||
```
|
||||
|
||||
There are three important (sub)modules in *libcalamares*:
|
||||
- *globalstorage* behaves like a dictionary, and interfaces
|
||||
with the global storage in Calamares; use it to transfer
|
||||
information between modules (e.g. the *partition* module
|
||||
shares the partition layout it creates). Note that some information
|
||||
in global storage is expected to be structured, and it may be
|
||||
dicts-within-dicts.
|
||||
|
||||
An example of using globalstorage:
|
||||
```
|
||||
if not libcalamares.globalstorage.contains("lala"):
|
||||
libcalamares.globalstorage.insert("lala", 72)
|
||||
```
|
||||
- *job* is the interface to the job's behavior, with one important
|
||||
data member: *configuration* which is a dictionary derived from the
|
||||
configuration file for the module (if there is one, empty otherwise).
|
||||
Less important data is *pretty_name* (a string) and *working_path*
|
||||
which are normally not needed. The *pretty_name* value is
|
||||
obtained by the Calamares internals by calling the `pretty_name()`
|
||||
function inside the Python module.
|
||||
|
||||
There is one function: `setprogress(p)` which can be passed a float
|
||||
*p* between 0 and 1 to indicate 0% to 100% completion of the module's
|
||||
work.
|
||||
- *utils* is where non-job-specific functions are placed:
|
||||
- `debug(s)` and `warning(s)` are logger functions, which send output
|
||||
to the usual Calamares logging functions. Use these over `print()`
|
||||
which may not be visible at all.
|
||||
- `mount(device, path, type, options)` mounts a filesystem from
|
||||
*device* onto *path*, as if running the mount command from the shell.
|
||||
Use this in preference to running mount by hand. In Calamares 3.3
|
||||
this function also handles privilege escalation.
|
||||
- `gettext_path()` and `gettext_languages()` are support functions
|
||||
for translations, which would normally be called only once when
|
||||
setting up gettext (see below).
|
||||
- `obscure(s)` is a lousy string obfuscation mechanism. Do not use it.
|
||||
- A half-dozen functions for running a command and dealing with its
|
||||
output. These are recommended over using `os.system()` or the *subprocess*
|
||||
module because they handle the chroot behavior for running in the
|
||||
target system transparently. In Calamares 3.3 these functions also
|
||||
handle privilege escalation. See below, *Running Commands in Python* for details.
|
||||
|
||||
A module **must** contain a `run()` function to do the actual work
|
||||
of the module. The module **may** define the following functions
|
||||
to provide information to Calamares:
|
||||
- `pretty_name()` returns a string that is a human-readable name or
|
||||
short description of the module. Since it is human-readable,
|
||||
return a translated string.
|
||||
- `pretty_status_message()` returns a (longer) string that is a human-readable
|
||||
description of the state of the module, or what it is doing. This is
|
||||
primarily of importance for long-running modules. The function is called
|
||||
by the Calamares framework when the module reports progress through the
|
||||
`job.setprogress()` function. Since the status is human-readable,
|
||||
return a translated string.
|
||||
|
||||
### Python Translations
|
||||
|
||||
Translations in Python modules -- at least the ones in the Calamares core
|
||||
repository -- are handled through gettext. You should import the standard
|
||||
Python *gettext* module. Conventionally, `_` is used to mark translations.
|
||||
That function needs to be configured specifically for use in Calamares
|
||||
so that it can find the translations. A boilerplate solution is this:
|
||||
|
||||
```
|
||||
import gettext
|
||||
_ = gettext.translation("calamares-python",
|
||||
localedir=libcalamares.utils.gettext_path(),
|
||||
languages=libcalamares.utils.gettext_languages(),
|
||||
fallback=True).gettext
|
||||
```
|
||||
|
||||
Error messages should be logged in English, and given to the user
|
||||
in translated form. In particular, when returning an error message
|
||||
and description from the `run()` function, return translated forms,
|
||||
like the following:
|
||||
|
||||
```
|
||||
return (
|
||||
_("No configuration found"),
|
||||
_("<a longer description of the problem>"))
|
||||
```
|
||||
|
||||
### Running Commands in Python
|
||||
|
||||
The use of the `os.system()` function and *subprocess* modules is
|
||||
discouraged. Using these makes the caller responsible for handling
|
||||
any chroot or other target-versus-host-system manipulation, and in
|
||||
Calamares 3.3 may require additional privilege escalation handling.
|
||||
|
||||
The primary functions for running a command from Python are:
|
||||
- `target_env_process_output(command, callback, stdin, timeout)`
|
||||
- `host_env_process_output(command, callback, stdin, timeout)`
|
||||
They run the given *command* (which must be a list of strings, like
|
||||
`sys.argv` or what would be passed to a *subprocess* module call)
|
||||
either in the target system (within the chroot) or in the host system.
|
||||
Except for *command*, the arguments are optional.
|
||||
|
||||
A very simple example is running `ls` from a Python module (with `libcalamares.utils.` qualification omitted):
|
||||
```
|
||||
target_env_process_output(["ls"])
|
||||
```
|
||||
|
||||
The functions return 0. If the exit code of *command* is not 0, an exception
|
||||
is raised instead of returning 0.
|
||||
|
||||
Parameter *stdin* may be a string which is fed to the command as standard input.
|
||||
The *timeout* is in seconds, with 0 (or a negative number) treated as no-timeout.
|
||||
|
||||
Parameter *callback* is special:
|
||||
- If it is `None`, no special handling of the command's output is done.
|
||||
The output will be logged, though (if there is any).
|
||||
- If it is a list, then the output of the command will be appended to the list,
|
||||
one line at a time. Lines will still contain the trailing newline character
|
||||
(if there is one; output may end without a newline).
|
||||
Use this approach to process the command output after it has completed.
|
||||
- Anything else is assumed to be a callable function that takes one parameter.
|
||||
The function is called once for each line of output produced by the command.
|
||||
The line of output still contains the trailing newline character (if there is one).
|
||||
Use this approach to process the command output while it is running.
|
||||
|
||||
Here are three examples of running `ls` with different callbacks:
|
||||
```
|
||||
# No processing at all, output is logged
|
||||
target_env_process_output(["ls"])
|
||||
target_env_process_output(["ls"], None)
|
||||
|
||||
# Appends to the list
|
||||
ls_output = []
|
||||
target_env_process_output(["ls"], ls_output)
|
||||
|
||||
# Calls the function for each line, which then calls debug()
|
||||
def handle_output(s):
|
||||
debug(f"ls said {s}")
|
||||
target_env_process_output(["ls"], handle_output)
|
||||
```
|
||||
|
||||
|
||||
There are additional functions for running commands in the target,
|
||||
which can select what they return and whether exceptions are raised
|
||||
or only an exit code is returned. These functions have an overload
|
||||
that takes a single string (the name of an executable) as well. They should
|
||||
all be considered deprecated by the callback-enabled functions, above.
|
||||
|
||||
- `target_env_call(command, stdin, timeout)` returns the exit code, does not raise.
|
||||
- `check_target_env_call(command, stdin, timeout)` raises on a non-zero exit code.
|
||||
- `check_target_env_output(command, stdin, timeout)` returns a single string with the output of *command*, raises on a non-zero exit code.
|
||||
|
||||
|
||||
## PythonQt modules (deprecated)
|
||||
|
Loading…
Reference in New Issue
Block a user