xobox Documentation Contents¶
xobox Documentation¶
This documentation covers both, usage and development of xobox. Please read the appropriate sections carefully before raising an issue or ask for support otherwise - there’s a good chance your question might be answered by the information provided through this documentation. Please note that though related this documentation does not cover general X-Plane or FSEconomy end user guidance.
Note
This documentation is perpetually updated from the project’s central git repository’s master branch. To ensure you work with the latest version available, please make sure to access this documentation exclusively at https://stormrose-va.github.io/xobox/
How the documentation is organised¶
- If you’re an X-Plane user, wishing to use xobox for analysing your recorded flight data (e. g. to create FSEconomy relevant profile information), try the User’s Guide.
- The Project Documentation will tell you about the development process, and how you can contribute.
- Reference guides contain technical reference for APIs and other aspects of the xobox machinery. They describe how it works and how to use it but assume that you have a sound understanding of programming concepts and profound Python knowledge.
Documentation Reference¶
Looking for a more structured overview? Have a look at our detailed table of contents, or – when seeking specific information – the Index and Module Index. For terms and notions, check out the Glossary.
User’s Guide¶
Project Documentation¶
This part of the documentation is for people hacking on xobox itself. It is a mandatory source of information for anyone wishing to contribute to xobox’ development. This guide describes code standards as well as processes and tools around the management of xobox’ source code.
Important
By contributing to this project, the contributor accepts all contributions (code, documentation, etc.) are publicly made available and become subject to the terms of the MIT License.
Coding Style Guide¶
Introduction¶
In brief: stick to PEP 8 and PEP 257, and you will be fine in 99% of all cases that may occur. But since those two PEPs only refer to code style and inline documentation, you might want to continue reading this style guide, particularly considering the sections on unit tests and documentation.
Python Compatibility¶
The Air-Child Payslip code has to be compatible with Python 3.4, 3.5, 3.6 and newer versions. There is no need for backwards compatibility to Python’s 3.3, 3.2, 3.1, 2.x or earlier branches. In consequence, all functions, classes, data types etc. available either built-in or by the Python standard library may be used. However, functions, classes, data types etc. introduced with a Python version newer than the ones explicitly covered may not be used or have to be wrapped by a compatibility layer.
Using Libraries¶
Functionality provided by the Python standard library may be used without any further restriction (apart from the Python version restriction indicated above). In order to avoiding a dependency hell, using third party libraries should strictly be limited to cases where the third party library
- is written in pure Python code
- is well documented
- is actively maintained
- has a stable API
- is available via the Python Package Index
Any third party library usage needs to be announced within the requirements.txt
file residing in the repository’s
root directory.
Code Style¶
In general, PEP 8 really covers what needs being said about code style. However, there are some points that might need clarification; in particular when to deviate from the PEP 8 instructions…
Indentation¶
As specified by PEP 8, the general rule is to use 4 spaces (no tabs!) for code indentation. However, in multi-line constructs it is mandatory to line up the closing brace/bracket/parenthesis with the first character of the line where the multi-line construct was started:
my_dict = {
'foo': 'bar',
'goo': 'baz',
}
Source File Encoding¶
All source files must be encoded in UTF-8 without BOM, and introduce their encoding in the first line:
# -*- coding: utf-8 -*-
# ... more stuff that's not interesting right now...
The only exception from this mandatory file header is a completely empty file such as an __init__.py
file
bearing no code at all. In this specific case, the file size has to be zero bytes.
Inline Documentation¶
All functions, classes, methods and class members must be documented using Python docstrings. All docstrings (except those for class members) have to be written as multi-line docstrings, surrounded with three double quotes on a separate line:
class foo:
"""
This is the foo class' docstring
"""
#: I am the docstring of a class member
_foo = 'bar'
def __init__(self):
"""
I am the class constructor's docstring
"""
The following rules shall be regarded when writing docstrings:
- Methods and functions docstrings shall document all arguments (except
self
) by the:param <type> <name>: description
statement - Constructor parameters shall be documented in the class’ docstring instead of the constructor’s docstring
- Methods and functions (except properties) returning something shall document their return behaviour by the
:returns <description>
statement.
API Documentation¶
All packages, modules, classes, exceptions and functions defined within this project must be documented
within the API documentation. The minimum documentation would be one of the autodoc variants
offered by Sphinx, e. g. .. autoclass:: classname
.
Unit Testing¶
All classes, exceptions, methods and functions defined within this project shall be covered by a corresponding unit
test. For this purpose, each package shall be mirrored by a corresponding package within the tests
package. By
convention, the test package shall bear the same name as the corresponding code package, but prefixed with t_
(to
avoid cluttering of the name space). Modules inside a package shall be mirrored the same way, but prefixed with
test_
.
The sub-structure there below (i. e. within the test modules) may be chosen as suitable for the respective application package, based on the following set of rules:
- Tests for each function or class shall be represented by a dedicated test case class
- Test case classes have to inherit from
unittest.TestCase
- Each test case class shall reside within a dedicated Python module named
test_*.py
, where*
should be seen as a wild card indicating the module or class being tested with the test cases defined within this module
Note
All unit tests following the above given guidelines will be automatically detected and run by the unit test command
scripts/runtest.py
when executed. This command is used for automated testing.
Project Roles¶
Project Owner¶
The Stormrose project and all child projects (i. e. including xobox) are owned by its founder, Jesco Freund (aka daemotron). The project owner has the final say in all matters, and can veto all core team decisions. Furthermore, the project owner is admonished to arbitrate in any dispute among core team members.
Note
This role may be subject to review, change or replacement in the future. Relieving the owner of any pecuniary and non-pecuniary engagement is considered as conditio sine qua non for this to happen.
Core Team¶
The core team is the group of people managing the project, and steering in which direction it goes. Core team members are expected to act as role models for the community and custodians of the project, on behalf of the community and all those who rely on Stormrose or any of its child projects.
Prerogatives¶
Core team members are formally entitled to exercise certain privileges, but are also asked to comply with requirements. Both are listed here:
- Core team members may participate in formal votes, typically to rule on matters (e. g. feature requests) or decide about new developers.
- In return, they are asked to avail themselves as mentors for new developers.
- Core team members are authorised to accept or reject pull requests for protected branches.
- Administrative privileges for other parts of the project’s infrastructure (e. g. the GitHub project group, tracker, servers, etc.) is granted as needed to core team members, based on assigned tasks. This means being a core team member does not automatically include receiving these privileges, but is sine qua non for receiving them if needed.
- In return, the core team is in charge of supporting operation of the Stormrose infrastructure.
Membership¶
Core team members are appointed by the project owner. For becoming a core team member candidate, a person needs to be nominated by a proponent already being a member of the core team, advocating in favour of this candidate becoming a core team member.
There is no time limit on core team membership. However, in order to provide the wider project stakeholders with a reasonable idea of who is maintaining the Stormrose applications, core team members who have stopped contributing are encouraged to declare themselves as “past team members”. Those who haven’t made any non-trivial contribution in two years may be asked to move themselves to this category, and moved there if they don’t respond. Past team members lose their privileges such as voting rights and commit access.
Core team membership can be revoked either directly by the project owner, or by a two thirds majority of votes cast in a core team vote and no veto by the project owner.
Developers¶
Developers contribute to the Stormrose code base and documentation. Their main focus is the development, improvement and maintenance of Stormrose applications.
Prerogatives¶
- Developers are authorised to commit on feature branches
- They may create pull requests
- Access to necessary resources (e. g. tracker, kanban board, etc.) is granted to all developers
Membership¶
Prior to becoming a developer, candidates usually will pass through a mentoring phase, supervised by a core team member. During that time, they may receive already limited privileges (e. g. read-only access to the blessed repository, or commit privileges for a dedicated feature branch) if the core team endorses this.
Everyone interested in becoming a developer candidate may address to a core team member. Having contributed already previously without having a formal developer status, or providing references proving the candidate’s programming skills usually facilitates and accelerates the process of assigning a mentor.
Full developer privileges are then granted by a two thirds majority of votes cast in a core team vote and no veto by the project owner. Nominees may be proposed by their respective core team mentor.
There is no time limit on being a developer. However, in order to provide the wider project stakeholders with a reasonable idea of who is developing the Stormrose applications, developers who have stopped contributing are encouraged to declare themselves as “past team members”. Those who haven’t made any non-trivial contribution in two years may be asked to move themselves to this category, and moved there if they don’t respond. Past developers lose their privileges such as commit access.
Developer privileges can be revoked either directly by the project owner, or by a two thirds majority of votes cast in a core team vote and no veto by the project owner.
Changing the Roles¶
Changes to this document require a quorum of two thirds majority of votes cast in a core team vote and no veto by the project owner.
Source Code Repository¶
xobox uses Git for managing source code repositories. The project’s “blessed” Git repository (origin
) resides at
GitHub. It is publicly accessible, but only core team members can push into this blessed
repository. Developers and other contributors are requested to fork the repository into their
personal space and offer code changes as pull request.
Repository Structure¶
Protected Branches¶
The eternal branch, master
, is managed as protected branch:
master
is the main (eternal) branch. It represents the latest state of development.- direct commits to
master
are not permitted, instead, pull requests have to be used
In addition to master
, also release branches become protected branches after the
initial version (patch level zero) has been released.
Feature Branches¶
Feature branches are used to develop new features for the upcoming or a distant future release. When starting
development of a feature, the target release in which this feature will be incorporated may well be unknown at that
point. The essence of a feature branch is that it exists as long as the feature is in development, but will eventually
be merged back into master
.
Important
Feature branches are not intended to exist in the blessed repository itself, but instead
they should be limited to forks and local clones of the project’s Git repository (origin
).
- Feature branches must be branched off
master
- Feature branches must relate to a GitHub issue
- By convention, their name shall be prefixed with
feature/
and the issue ID they refer to - Feature branches merge back into
master
via pull request - Feature branches are deleted after being merged back into
master
. They typically exist in developer repos only, but not inorigin
.
Release Branches¶
Release branches support preparation of a new production release. They allow for last-minute minor bug fixes and preparing meta-data for a release (version number, build dates, etc.). Beyond preparation, they also serve as maintenance branches for a release post publication of that release. Once being in maintenance mode, release branches are managed as protected branches.
- Release branches must be branched off
master
- By convention, their name shall be prefixed with
release/
, followed by the release’s version number (release/<version>
). The version number is a combination ofmajor.minor
, withoutpatch
suffix. - Release branches merge back into
master
via pull request. A merge of a release branch back intomaster
absolutely requires a release tag to be set on the head of the release branch prior merging.
Hotfix Branches¶
Hotfix branches are very much like feature branches in that they are also meant to introduce code changes into a protected branch, albeit unplanned. They arise from the necessity to act immediately upon an undesired state of a maintained, published production version. When a critical bug in a production version must be resolved immediately, a hotfix branch may be branched off from the corresponding release branch that marks the production version.
- Hotfix branches must be branched off the corresponding release tag on the corresponding release branch
- By convention, their name shall be prefixed with
hotfix/
, followed by the release’s version number and hotfix suffix, as well as a reference to the corresponding issue (hotfix/<version>/<issue id>/<description>
). - Hotfix branches merge back into the release branch eventually into
master
via pull request. A merge of a hotfix branch back intomaster
is only recommended ifmaster
has not evolved/diverged so much from the release maintenance branch that the fix hasn’t lost its relevance. In such a case, a cherry-pick is potentially the right approach instead of a fully-fledged merge.
Git Workflow¶
For the xobox project, we chose to follow a dedicated flow for development. The following graph illustrates the flow:

The development of a new feature, or the improvement of an existing feature (including bug fixing) always starts with opening an issue. Once the issue is created and assigned, a feature branch has to be created, following this naming convention:
feature/<class>/<issue id>/<description>
Note
Please note that the branch name must comply with reference name rules (cf. git check-ref-format).
The Issue ID is the numerical identifier generated by GitHub, padded to six digits (left padding with 0
).
The class may be one of
- new – for new features
- imp – for optimisation or enhancement
- doc – for documentation only updates
- pro – for project related changes (code reorganization, governance changes, …)
- qca – for quality control & assurance related changes (policy, code quality, …)
Do the following in your local copy of your own fork:
git fetch
git checkout master
git pull
git checkout -b feature/new/001234/supergadget master
As soon as the feature branch is created and work has started, the related issue status should be updated to “in progress”.
Important
Do not use issue closing hooks (e. g. Fixes #1234
) in your commit messages when committing to the feature branch.
Closing the issue is reserved for the pull request.
Once the work on the feature branch is done and continuous integration testing shows positive results, a pull request can be opened to notify the core team. The status of the corresponding issue should be updated to “ready”.
In case of acceptance, the pull request is authorised by a core team member, the feature branch gets merged into
master
and can then deleted in your fork. The issue status is updated to “Integration”, which
means the issue can now be tested in the nightly builds.
Further reading on related models, including corresponding Git command line instructions:
Pull Request¶
GitHub Pull Requests are used to merge new code from a feature branch into a protected branch or from one protected branch into another.
This section concentrates on pull requests opened by developers in order to have a feature
branch merged into origin/master
. Any other case, where pull requests are used (e. g. cleansing of branches etc.)
are processes solely played within the core team.
Important
When opening a pull request from your personal fork, please consider the hints given in Allowing Changes to a Pull Request. Otherwise it might be difficult to proceed with the PR.
Hint
Before opening a pull request, please ensure your feature branch is updated (rebased) to the latest HEAD
of
origin/master
, to ensure that only intended code changes become part of your PR.
Hint
You can use a pull request for intermediate reviews with the core team. In that case, keep the
status of the corresponding issue set to “in progress”, prefix the merge
request title with [WIP]
and do not assign the pull request to anyone.
Pull requests may be accepted straight away (mostly in very simple cases, e. g. a simple bug fix) – although this most likely will rather be an exception. In such a case, the status of the corresponding issue will be updated to “Integration” by the core team member who accepted the pull request.
If otherwise the core team accepts the pull request for review, they will update the
issue status to “Review” and assign a core team member to the pull request. In this
(much more likely) scenario, the core team member in charge will review the content of the change request and its
implications for the code in origin/master
together with the developer who opened the pull
request.
Note
Do not abuse pull requests to mature your code. As a general rule, a pull request should only be opened if implementation work on the feature branch is completed, and CI testing gives a green status.
In case of obvious immaturity or non-quality, non-compliance with governance and coding style, a pull request may be rejected by the core team. In such a case, the core team member rejecting the pull request shall write a justification statement (as a comment on the pull request), explaining why this pull request has been rejected.
Issue Management¶
Issues are managed centrally via GitHub Issues. For better visualisation, the project uses a Kanban Board. Three types of labels are used to classify issues.
Type¶
The type label indicates what kind the issue is of. These types are available:
- bug marks an error within the source code or the application logic
- regression marks an error that was introduced by another fix or feature
- feature marks a request for a new feature
- enhancement marks a request for enhancing an existing feature
- optimisation marks a request for optimising a feature or the corresponding source code
- quality marks a request to improve code quality or test coverage
- doc marks a request for amending or updating the documentation
- legal marks issues related to legal affairs (e. g. licensing, patents, etc.)
- infrastructure marks issues related to the project’s technical infrastructure
- project marks issues related to general project management
- releng marks issues related to release management (e. g. version bumps etc.)
- support marks requests for technical support
Priority¶
The Stormrose Project uses these priority labels to mark issues which require fast attention:
- security – top priority label marking security issues
- critical – non-security related label for top priority issues endangering or blocking production use
Otherwise, priorities are expressed by the sorting order within the respective column of the Kanban Board – an issue placed above another issue within the column has a higher priority than the one placed below.
Priorities may be subject to review by the core team. They will adjust proposed priorities if necessary to the right level.
Status¶
The status of an issue is not managed by a label, but instead by a column on the Kanban Board the issue is assigned to.
The xobox project uses these columns (i. e. status messages):
- Backlog – all issues that are waiting to be worked on.
- In Progress – issues that are currently being worked on (i. e. a feature branch exists for these issues).
- Ready – issues whose feature branch is considered ready for merge into the
origin/master
branch (i. e. a pull request has been created for the respective issue). - Review – issues which are subject to an extended review by the core team, pending validation or feedback or whose progress is blocked by whatever reason. Issues with this status are subject to regular reviews by the core team members.
- Rejected – issues which have been rejected by the core team, usually after a longer review period. Issues violating xobox’ project objectives or the overall Stormrose policies may be immediately rejected.
- Done – issues that are considered complete after integration test. May be closed after review/confirmation.
Release Management¶
Version Scheme¶
xobox follows a semantic version scheme complying with PEP 440. Version indicators are of the form
major.minor[.patch][{a|b|rc|.dev}N]
with the following meaning of version components:
- major
- The major version number, indicating the release family. Changes breaking backwards compatibility shall entail an increase of the major version number.
- minor
- The minor version number, indicating the version inside a release family. Changes not breaking backwards compatibility (e. g. an additional feature or option) shall entail an increase of the minor version number.
- patch
- The patch number. By default, all releases start with patch number
0
. In this case, the patch number is omitted from the version information. Patches indicate errata fixes (either concerning security or functionality), but are limited to changes not modifying the product functionality or even breaking compatibility. - pre-release suffix (a, b, rc)
- Suffix indicating a pre-release stage of the current version, i. e. “alpha” (indicated by a), “beta” (indicated by b) or “release candidate” (indicated by rc) versions. Any pre-release suffix is mandatorily followed by a numeric sequence indicator (i. e. a1 = “alpha number one”, rc2 = “release candidate number two”).
- .dev suffix
- The .dev suffix is mutually exclusive to pre-release suffices and indicates a version that is still under development. The .dev suffix is always followed by a numeric indicator pointing to the corresponding Git commit.
Internally, version numbers are represented as Python tuple with the following elements:
(major, minor, patch, stage, suffix)
Major, minor and patch are numeric (non-negative integers) with the same meaning as indicated above.
- stage
- is a string, reading either
alpha
,beta
,rc
, orfinal
, marking the stage of development. - suffix
- is numeric (non-negative integer) and indicates the sequence for stages
alpha
,beta
andrc
. For thefinal
stage, suffix has to be zero. If stage is set toalpha
and the suffix is zero, this has a special meaning (development version, designated with a.devN
suffix). Forbeta
andrc
stages, suffix must be greater than zero (minimum 1).
Release Process¶
Once all feature branches selected for a specific release are finalized and merged back in origin/master
, the
release process can start.
Stage 1: Code Slush¶
The first phase of a release publishing cycle starts with a code slush. Under code slush, origin/master
is not hard
protected against any change, but stabilization PRs (i. e. bug fixes, quality improvements) will get a higher priority.
The priority order expressed in PR classes:
- qca (bug fixes, quality improvements)
- doc (documentation updates and polishing)
- imp (improvements, enhancements, optimisation)
new and pro class PRs should be avoided and postponed to after the release has been finalized.
The code slush phase ends with production of the first alpha release.
Stage 2: Code Freeze¶
The second phase begins with the release of the first alpha version. From here on, a strict code freeze is imposed on
origin/master
. This means no PRs will be accepted and merged unless linked to the upcoming release. Normally, this
means only qca class PRs linked to issues related to the upcoming release milestone will be considered.
Under code freeze, alpha and beta versions are tagged in master and released for wider testing.
Stage 3: Pre-Release¶
If maturity in origin/master
is considered sufficient for release, a dedicated
release branch for the release is created (release/major.minor
). The code freeze on
master persists. From now on, release-related qca fixes are to be applied to the release branch. During the
pre-release phase, release candidate releases are tagged in the release branch and published to further mature the
release.
Stage 4: Release¶
As soon as the maturity in the release branch is sufficient for a final release, all pending PRs have to be either merged or rejected. The head of the release branch has to be tagged with the final release number, and the release branch has thereafter to be converted into a protected branch.
The release itself has to be created on GitHub using the final release tag as anchor reference.
The release branch has now to be merged back into origin/master
, and with a further local PR, the version in
origin/master
has to be bumped to the next release cycle (this is no final decision, it can be reverted at a later
stage). This formally lifts the code freeze on origin/master
and allows to proceed with PRs that use a properly
rebased feature branch with most recent changes in origin/master
.
Stage 5: Maintenance¶
As the release branch is now managed as protected branch, direct commits to this branch are no longer possible. Instead, if a published release needs fixing, and the fix is well contained so it can be contained as patch and not as minor or even major release change, the following procedure has to be applied:
A hotfix branch has to be created (outside``origin``), based on the release branch at the last published version tag. There the necessary amendments can be developed and matured. Once finalized, the hotfix branch has to be merged back into the release branch via pull request, and subsequently a new patch version has to be tagged in the release branch, and the new patch release shall be published.
Important
Support for all prior versions from a release branch cedes the moment a new patch version is published.
As a final step after a patch has been published, the fix needs to be introduced to origin/master
if still
applicable there (e. g. an intermediate architectural change could have removed entirely the concerned code from
origin/master
). If still applicable, the method of injection has to be chosen on how far origin/master
has
diverted from the (now patched) release branch.
If both branches are still closely enough together, a pull request would be the preferred technique to merge the
changes into origin/master
. If however both branches have diverted significantly (e. g. due to long-term support),
other techniques such as cherry-picking the patch commit or even a “manual” injection via a dedicated feature branch
might be the appropriate solution.
Hint
While bringing a fix back into origin/master
is mandatory, the choice of technique to accomplish this is
subject to common sense of the core team, as it is nearly impossible to anticipate any
combination of factors that might arise in the future around that subject.
API Documentation¶
xobox Package API¶
The xobox
package itself provides some constants and functions documented in
the sections below. Apart from mirroring functionality already existing deeper within the
xobox
package (for easier access), no functionality shall be implemented at
this level.
-
xobox.
COPYRIGHT
= ('2017', 'the Stormrose Project team')¶ Official copyright information for the
xobox
package
-
xobox.
APPINFO
= ('Stormrose', 'xobox')¶ Official app name and author
-
xobox.
get_version
(*args, **kwargs)[source]¶ Function providing the official version information for a xobox installation.
Currently, this is a mirror of
xobox.utils.version.get_version()
, provided for convenience, e. g. for easier use in a setup script or similar.Warning
Since the implementation of this function may change in the future, always use this function and not
xobox.utils.version.get_version()
when retrieving official version information.
-
xobox.
get_development_status
(*args, **kwargs)[source]¶ Function providing the official development status for a xobox installation.
Currently, this is a mirror of
xobox.utils.version.get_development_status()
, provided for convenience, e. g. for easier use in a setup script or similar.Warning
Since the implementation of this function may change in the future, always use this function and not
xobox.utils.version.get_development_status()
when retrieving official development status information.
-
xobox.
get_app_name
(*args, **kwargs)[source]¶ Function providing the official application name for xobox.
This information is mainly required to construct configuration and data paths, etc. This function is a wrapper function provided for convenience, ensuring a consistent interface to this information.
Function providing the official author name for xobox.
This information is mainly required to construct configuration and data paths, etc. This function is a wrapper function provided for convenience, ensuring a consistent interface to this information.
xobox’ Command Line Interface¶
xobox’ command line interface is contained within the xobox.cli
package. It offers only one function at
package level which can be called directly. This function is usually called from a Python script acting as executable
interface.
-
xobox.cli.
execute
(argv=None)[source]¶ Function being called from the executable to launch the CLI. This is the initial entrance point for any xobox processing. Usually, this function is invoked by an executable Python script to start the actual xobox CLI process. This could look like the following example:
import sys from xobox.cli import execute sys.exit(execute(sys.argv))
Parameters: argv (list) – list of (command line) arguments The
execute()
function will create aCommandDispatcher
instance, which provides the logic for invoking a command.
Dispatcher¶
-
class
xobox.cli.dispatch.
CommandDispatcher
(argv=None)[source]¶ Class encapsulating the logic for starting a command.
Parameters: argv (list) – list of (command line) arguments -
execute
()[source]¶ Based on the given command line arguments and the available subcommands, this method creates the appropriate command line parser and starts the corresponding subcommand.
-
status
¶ Exit status
-
Command Line Commands¶
Command line commands are implemented as modules within the xobox.cli.commands
package.
The module name itself must be unique within the commands
package, but has no
direct link to the command’s external designator used on the command line.
All command line commands are implemented as classes, inheriting from xobox.cli.base.BaseCommand
:
-
class
xobox.cli.base.
BaseCommand
(global_args=None, cmd_args=None, logger=None)[source]¶ The base class from which all CLI commands derive.
Attributes affecting the behaviour of a Command object:
help
- A short description of the command, which will be used to construct help messages or usage instructions for the command.
name
- The name under which the command is known. Internally, the name only differs from an alias in the fact that it’s used as the “main” alias in help and usage messages.
aliases
- A tuple of alias names for the command
arguments
- A tuple of arguments accepted by the command. Each argument
consists of a tuple with two elements.
The first element is a tuple containing the short and long
option identifiers; e. g. (‘-f’, ‘–foo’)
The second element is a dictionary containing arbitrary elements.
All keyword arguments accepted by
argparse.ArgumentParser.add_argument()
are allowed as key names within this dictionary.
-
execute
()[source]¶ Set up environment for running the command. Then call the handle() method which needs to be implemented by each command.
Writing a Command Line Command¶
Writing a command line command can be as easy as creating a Python module within the
xobox.cli.commands
package containing a class inheriting from
BaseCommand
and overriding some basic settings:
from xobox.cli.base import BaseCommand
class MyCommand(BaseCommand)
name = 'foo'
aliases = ('bar', 'baz')
help = 'The super foo command that makes you bar'
Looks easy? It actually is, since CommandDispatcher
is performing all the black magic needed to detect available commands, make up decent usage
messages out of the information provided by each command’s implementation, parsing eventual
command line arguments required by the different commands and finally setting up the environment
and running the command.
Unfortunately, this command would not be of any use – once invoked by the dispatcher, it will
simply raise a NotImplementedError
exception. This is simply for the fact that each
command needs to implement its own handle()
method.
Since this has not happened here, the handle()
method
inherited from the CommandDispatcher
class will be used, and
this one simply raises a NotImplementedError
exception.
When implementing your own handle()
method, please
take care of the following conventions.
User Interaction¶
Whenever possible, user interaction shall be avoided. The concept of xobox is to gather all required information either form command line arguments or from configuration files, and then to run silently, only outputting status information according to the log level set by the user.
This restriction has been set in order to respecting that one important use case is to run xobox as batch job, where no user interaction is possible.
Output¶
All output to the user interface shall be channelled through the appropriate log_...()
methods
each command class has inherited from the BaseCommand
class.
This ensures the output is only sent if the user has selected the corresponding log level, and it
is sent through the right channel.
Warning
Never use Python’s print()
function to generate and send output to the user
interface. This will break xobox’s promise of being 100% batch job enabled, including
logging its output to a file.
Status¶
xobox uses the status
property any command
has inherited from the BaseCommand
class for setting an
appropriate exit status when terminating xobox’s main process.
By default, a command object’s status is set to os.EX_OK
. If necessary or appropriate, the
status information can be changed within the handle()
method
by overwriting the internal _status
member:
def handle(self):
self._status = xobox.utils.compat.EX_USAGE
Existing Command Line Commands¶
Version Command¶
-
class
xobox.cli.commands.version.
VersionCommand
(global_args=None, cmd_args=None, logger=None)[source]¶ Command class implementing the version command.
-
aliases
= ('--version', '-v')¶
-
arguments
= ((('-s', '--short'), {'help': 'only print the version string', 'action': 'store_true'}),)¶
-
help
= 'Show version and copyright information'¶
-
name
= 'version'¶
-
Logging Interface¶
The logger
module is responsible for handling any
output that shall be transported to the user. It implements the magic behind
the log_...()
methods provided by the CommandDispatcher
class, allowing command implementations to easily transporting information to the user interface.
The logger
module provides a class interface,
offering a flexible message output system:
-
class
xobox.cli.logger.
Logger
¶ -
get_instance
(*args, **kwargs)¶ Obtain the reference to the instance of
Logger
. If no instance exists yet, one will be created and its reference returned.Warning
If a logger instance already exists (e. g. due to an earlier invocation from another module or function), any passed keyword arguments will be ignored. Therefore, it is safer to not using any keyword arguments, but setting the logger’s properties appropriately after having received the logger instance’s reference.
-
log
(level, message)¶ Register a log message within the logging queue and flush the queue afterwards (currently log messages are not cached).
Parameters:
-
log_error
(message)¶ Convenience shortcut for registering messages with log level error
Parameters: message (str) – The message string to be recorded
-
log_warning
(message)¶ Convenience shortcut for registering messages with log level warning
Parameters: message (str) – The message string to be recorded
-
log_notice
(message)¶ Convenience shortcut for registering messages with log level notice
Parameters: message (str) – The message string to be recorded
-
log_info
(message)¶ Convenience shortcut for registering messages with log level info
Parameters: message (str) – The message string to be recorded
-
log_debug
(message)¶ Convenience shortcut for registering messages with log level debug
Parameters: message (str) – The message string to be recorded
-
log_usage
(message)¶ Convenience shortcut for registering messages with log level usage
Parameters: message (str) – The message string to be recorded
-
color
¶ Boolean switch indicating whether this logger allows colored output.
-
file
¶ The log file used when run as file logger. Must be a string indicating the path name of the file to log into.
-
level
¶ The log level (string). Expected to be one of mute, error, warning, info or debug.
-
type
¶ The logger type (string). Expected to be one of term or file.
-
xobox’ Application Configuration¶
xobox’ application configuration module provides an interface for accessing
built-in default configuration constants. Instead of scattering default constants
all over the application’s code, default values shall be centralized in
xobox.conf.default
. This being the case, these configuration defaults
can be accessed by either the function interface, or by a class interface.
Function Interface¶
Class Interface¶
-
class
xobox.conf.
ApplicationConf
¶ -
get_instance
(*args, **kwargs)¶ Obtain the reference to the instance of
ApplicationConf
. If no instance exists yet, one will be created and its reference returned.Note
Although the
get_instance()
method accepts arbitrary positional and keyword arguments, they will be ignored by the constructor.
-
Default Configuration Values¶
Core Settings¶
-
xobox.conf.default.
DEFAULT_CHARSET
= 'utf-8'¶ Default character set to be used for any byte sequence or string conversion operations
-
xobox.conf.default.
DEFAULT_XOBOX_EXECUTABLE
= 'sphinx-build'¶ Default xobox Executable
-
xobox.conf.default.
DEFAULT_CONF_FILE
= '/home/docs/.config/xobox/xobox.ini'¶ Default configuration file name
Logging Settings¶
-
xobox.conf.default.
DEFAULT_LOG_TYPE
= 'term'¶ Default log type
-
xobox.conf.default.
DEFAULT_LOG_LEVEL
= 'notice'¶ Default log level
-
xobox.conf.default.
DEFAULT_LOG_FILE
= '/home/docs/.cache/xobox/xobox.log'¶ Default log file
-
xobox.conf.default.
DEFAULT_LOG_TIMESTAMP
= '%Y-%m-%d %H:%M:%S'¶ Default timestamp format for file logging
-
xobox.conf.default.
DEFAULT_LOG_COLOR
= True¶ By default, use colors for logging where available
xobox Core Modules¶
Utility Modules¶
Compatibility Utility¶
The compat
module provides data, functions and classes whose interfaces have
changed with newer Python versions, or which are not available on all operating systems supported by
xobox. This allows using the most recent interface of these functions and classes within the xobox code,
without hacking around all along the code. Therefore, this module centralises all the dirty hacks which
become necessary when the Python standard library does not provide its own compatibility layer.
Constants¶
-
xobox.utils.compat.
EX_OK
= 0¶ Exit code that means no error occurred.
-
xobox.utils.compat.
EX_USAGE
= 64¶ Exit code that means the command was used incorrectly, such as when the wrong number of arguments are given.
-
xobox.utils.compat.
EX_DATAERR
= 65¶ Exit code that means the input data was incorrect.
-
xobox.utils.compat.
EX_NOINPUT
= 66¶ Exit code that means an input file did not exist or was not readable.
-
xobox.utils.compat.
EX_NOUSER
= 67¶ Exit code that means a specified user did not exist.
-
xobox.utils.compat.
EX_NOHOST
= 68¶ Exit code that means a specified host did not exist.
-
xobox.utils.compat.
EX_UNAVAILABLE
= 69¶ Exit code that means that a required service is unavailable.
-
xobox.utils.compat.
EX_SOFTWARE
= 70¶ Exit code that means an internal software error was detected.
-
xobox.utils.compat.
EX_OSERR
= 71¶ Exit code that means an operating system error was detected, such as the inability to fork or create a pipe.
-
xobox.utils.compat.
EX_OSFILE
= 72¶ Exit code that means some system file did not exist, could not be opened, or had some other kind of error.
-
xobox.utils.compat.
EX_CANTCREAT
= 73¶ Exit code that means a user specified output file could not be created.
-
xobox.utils.compat.
EX_IOERR
= 74¶ Exit code that means that an error occurred while doing I/O on some file.
-
xobox.utils.compat.
EX_TEMPFAIL
= 75¶ Exit code that means a temporary failure occurred. This indicates something that may not really be an error, such as a network connection that couldn’t be made during a retryable operation.
-
xobox.utils.compat.
EX_PROTOCOL
= 76¶ Exit code that means that a protocol exchange was illegal, invalid, or not understood.
-
xobox.utils.compat.
EX_NOPERM
= 77¶ Exit code that means that there were insufficient permissions to perform the operation (but not intended for file system problems).
-
xobox.utils.compat.
EX_CONFIG
= 78¶ Exit code that means that some kind of configuration error occurred.
-
xobox.utils.compat.
EX_NOTFOUND
= 16¶ Exit code that means something like “an entry was not found”.
Convert Utility¶
The convert utility functions can convert unicode strings into byte sequences and vice versa. Independent of the Python version used, they ensure a string (as seen by the convert utilities) is always a unicode string, and a byte sequence (as seen by the convert utilities) is always a sequence of bytes, and not a multi-byte sequence.
Dynamic Utility¶
The dynamic utility provides two abstract classes which are intended to be inherited from or being used in a stand-alone mode. Both classes provide means for dynamically creating properties, based on a given set of information.
Dynamic Class¶
-
class
xobox.utils.dynamic.
Dynamic
(*args, **kwargs)[source]¶ Dynamic class generating properties from kwargs
The constructor of the
Dynamic
class uses all keyword arguments passed to the constructor for creatingproperty()
attributes with the same name as the keyword argument, returning the value submitted with the keyword argument.
Usage Example:
>>> from xobox.utils.dynamic import Dynamic
>>> obj = Dynamic(foo='bar')
>>> 'foo' in dir(obj)
True
>>> hasattr(obj, 'foo')
True
>>> getattr(obj, 'foo')
'bar'
>>> obj.foo
'bar'
Dynamic Iterable Class¶
The dynamic iterable class interface is much more complex than the pure Dynamic
class. It not only provides dynamically generated property()
attributes, but also acts as a
dict
instance, allowing to access all attribute values by using their names as keys. Furthermore,
attributes are dynamically created, updated or deleted when the object is manipulated via its dictionary interface.
In addition, the Dynamic
class allows for registering hook methods or
functions, which can be used to manipulate the item setting and deletion behaviour.
-
class
xobox.utils.dynamic.
DynamicIterable
(dict=None, **kwargs)[source]¶ A dynamic iterable object is similar to a normal Python dictionary, except it offers all keys also as properties.
Note
Since
UserDict
in Python 2.x is an old-style class, this class also inherits from object to become a new style class.Parameters: - dict (dict) – dictionary with initial data to be filled in
- kwargs – keyword arguments to be transformed into dictionary data
-
register_hook
(hook_type, method)[source]¶ Register a hook within the corresponding hook queue.
Parameters: - hook_type (str) – one of pre-set, post-set, pre-del, post-del, pre-get, post-get
- method – reference to a method or function taking two arguments (key, value) and returning exactly this tuple (however, with different content if necessary to fulfil the hook’s purpose).
Usage example:
>>> from xobox.utils.dynamic import DynamicIterable
>>> obj = DynamicIterable(foo='bar')
>>> 'foo' in dir(obj)
True
>>> hasattr(obj, 'foo')
True
>>> getattr(obj, 'foo')
'bar'
>>> obj.foo
'bar'
>>> 'foo' in obj
True
>>> obj['foo']
'bar'
>>> hasattr(obj, 'fuu')
False
>>> obj['fuu'] = 'baz'
>>> hasattr(obj, 'fuu')
True
Hooks example:
from xobox.utils.dynamic import DynamicIterable
class MyIterable(DynamicIterable):
def __init__(self, dict=None, **kwargs):
self.register_hook('pre-set', my_hook)
self.register_hook('pre-get', my_hook)
super(MyIterable, self).__init__(dict=dict, **kwargs)
@staticmethod
def my_hook(key, value)
return str(key).upper(), value
This example demonstrates how one can render the DynamicIterable’s keys case-agnostic.
Loader Utility¶
The loader utility detecting and dynamically loading of class modules during runtime. Detection can be limited to classes inheriting from a specified class.
Warning
The loader utility only works with new style classes which inherit at least
from object
.
Note
The loader utility works best with Python modules or packages containing only Python modules, and not sub-packages (recursive search does not properly work).
Detect Class Modules¶
-
xobox.utils.loader.
detect_class_modules
(mod, parent=<class 'object'>)[source]¶ Detect available class modules or packages and return a dictionary of valid class names, referring to the module they are contained within.
Parameters: - mod (str) – the module or package to be scanned for classes
- parent – the class potential candidates must be derived off
Returns: dictionary of detected classes, mapping the class name to the module name in which the class has been detected
Example:
>>> from xobox.utils.loader import detect_class_modules
>>> detect_class_modules('queue', object)
{'deque': 'queue', 'Queue': 'queue', 'Empty': 'queue', 'PriorityQueue': 'queue', 'Full': 'queue', 'LifoQueue': 'queue'}
>>> detect_class_modules('zlib', object)
{'error': 'zlib'}
>>> detect_class_modules('math', object)
{}
Load Member¶
-
xobox.utils.loader.
load_member
(mod, member)[source]¶ Load a member (function, class, …) from a module and return it
Parameters: Returns: reference to the loaded member (i. e. class or function pointer)
Example:
>>> from xobox.utils.loader import load_member
>>> f = load_member('math', 'ceil')
>>> f(1.4)
2
Singleton Utility¶
The singleton utility provides a class decorator, allowing to easily create singleton classes.
-
class
xobox.utils.singleton.
Singleton
(decorated)[source]¶ Decorator class to turn any other class into a lazy singleton.
This class must be applied as a decorator instead of inheriting from this class.
Restrictions
- The decorated class can define one
__init__
function, but this constructor is restricted to theself
,*args
and**kwargs
arguments (in fact those must be present). - To get the singleton instance, the
get_instance()
method has to be used. Trying to use__call__
will result in aTypeError
being raised. - The actual instance will not be created before
get_instance()
has been called (lazy behaviour). - The decorated class cannot be inherited from. Therefore, this decorator can only be applied to final classes.
- This decorator shows good manners and takes care of
__doc__
,__module__
,__name__
,__annotations__
and__qualname__
context of the decorated class. This allows care-free handling in conjunction with automated documentation extraction tools such as Sphinx autodoc or similar.
Parameters: decorated – The Python class to be wrapped. -
get_instance
(*args, **kwargs)[source]¶ Returns the singleton instance. Upon its first call, it creates a new instance of the decorated class and calls its
__init__
method. On all subsequent calls, the already created instance is returned. :param args: positional arguments to be passed to the wrapped class’ constructor :param kwargs: keyword arguments to be passed to the wrapped class’ constructor :return: instance of the singleton-decorated class.
- The decorated class can define one
Termcolor Utility¶
The termcolor utility provides means to detect whether a system environment technically supports
coloured output on a terminal (sys.stdout
) or not. It relies on information provided
by the file object itself and sys.platform
.
Timer Utility¶
-
xobox.utils.timer.
counter
()[source]¶ Return the value (in fractional seconds) of a performance counter with the best resolution available.
The counter actually used depends on the platform and Python version:
- For Python versions >=3.3,
time.perf_counter()
is used. - For Python versions < 3.3 on Windows,
time.clock()
is used. - For Python versions < 3.3 on other platforms,
time.time()
is used.
Returns: progressing counter value (in fractional seconds) Return type: float - For Python versions >=3.3,
Version Utility¶
-
xobox.utils.version.
get_version
(*args, **kwargs)[source]¶ Derives a PEP 440 compliant version number from VERSION, assuming VERSION is a quintuple consisting of these elements:
(major, minor, patch, stage, suffix)
major
,minor
,patch
andsuffix
are integer values, whereasstage
is a string, containing one of these key words:- final means this version is a release. In this case,
suffix
will be ignored. - candidate means this version is a release candidate. In this case,
suffix
must be greater than zero and indicate the ordinal numbering of the release candidate. - beta means this version is a beta release. In this case,
suffix
must be greater than zero and indicate the ordinal numbering of the beta release. - alpha means this version is either an alpha release, or a development version.
For the first case,
suffix
must be greater than zero and indicate the ordinal numbering of the alpha release. For the latter case,suffix
must be set to zero.
The version quintuple may be passed as (only) positional argument, or as value of the
version
keyword argument. If no version quintuple is provided by argument,xobox.VERSION
is used instead.Note
The keyword argument overrides any positional argument. If two version quintuples are passed, one by positional and one by keyword argument, the one passed by keyword argument will win.
Parameters: - args – positional arguments, of which only the first one (if present) will be taken as version quintuple
- kwargs – keyword arguments, of which only the value of
version
(if present) will be taken as version quintuple
Returns: PEP 440 compliant version string
- final means this version is a release. In this case,
-
xobox.utils.version.
get_development_status
(*args, **kwargs)[source]¶ Derive the development status compliant to PEP 301 Trove Classifiers from VERSION, assuming VERSION is a quintuple consisting of these elements:
(major, minor, patch, stage, suffix)
major
,minor
,patch
andsuffix
are integer values, whereasstage
is a string, containing one of these key words:- final means this version is a release. In this case,
suffix
will be ignored. - candidate means this version is a release candidate. In this case,
suffix
must be greater than zero and indicate the ordinal numbering of the release candidate. - beta means this version is a beta release. In this case,
suffix
must be greater than zero and indicate the ordinal numbering of the beta release. - alpha means this version is either an alpha release, or a development version.
For the first case,
suffix
must be greater than zero and indicate the ordinal numbering of the alpha release. For the latter case,suffix
must be set to zero.
The version quintuple may be passed as (only) positional argument, or as value of the
version
keyword argument. If no version quintuple is provided by argument,xobox.VERSION
is used instead.Note
The keyword argument overrides any positional argument. If two version quintuples are passed, one by positional and one by keyword argument, the one passed by keyword argument will win.
Parameters: - args – positional arguments, of which only the first one (if present) will be taken as version quintuple
- kwargs – keyword arguments, of which only the value of
version
(if present) will be taken as version quintuple
Returns: Trove classifier string
- final means this version is a release. In this case,
-
xobox.utils.version.
get_git_changeset
(path=None)[source]¶ Returns a numeric identifier of the latest Git changeset.
Since the Git revision hash does not fulfil the requirements of PEP 440, the UTC timestamp in YYYYMMDDHHMMSS format is used instead. This value is not guaranteed to be unique, however the likeliness of collisions is small enough to be acceptable for the purpose of building version numbers.
Parameters: path (str) – Path to the Git repository to detect the latest commit timestamp from. If not indicated, the parent path of the xobox package is used. Returns: a string of the format GIT-timestamp
with timestamp being either a 14 digit integer, or the string “unknown” in cases where the changeset timestamp could not be detected.
Glossary¶
- X-Plane
- A flight simulation software for Mac, Windows and Linux, developed by Laminar Research
- xobox
- Orange Box for X-Plane - a flight data analysis tool for recorded in-flight data