plainbox.impl.session – session handling

Sessions are central state holders and one of the most important classes in PlainBox. Since they are all named alike it’s a bit hard to find what the actual responsibilities are. Here’s a small shortcut, do read the description of each module and class for additional details though.

SessionState

This a class that holds all of the state and program logic. It SessionManager is a class that couples SessionState and SessionStorage. It has the methods required to alter the state by introducing additional jobs or results. It’s main responsibility is to keep track of all of the jobs, their results, if they are runnable or not (technically what is preventing them from being runnable) and to compute the order of execution that can satisfy all of the dependencies.

It holds a number of references to other pieces of PlainBox (jobs, resources and other things) but one thing stands out. This class holds references to a number of JobState objects that couple a JobResult and JobDefinition together.

JobState

A coupling class between JobDefinition and JobResult. This class also knows why a job cannot be started in a particular session, by maintaining a set of “inhibitors” that prevent it from being runnable. The actual inhibitors are managed by SessionState.

SessionStorage

This class knows how properly to save and load bytes and manages a directory for all the filesystem entries associated with a particular session. It holds no references to a session though. Typically the class is not instantiated directly but instead comes from helper methods of SessionStorageRepository.

SessionStorageRepository

This class knows how to enumerate possible instances of SessionStorage from a given location in the filesystem. It also knows how to obtain a default location using XDG standards.
class plainbox.impl.session.JobReadinessInhibitor(cause, related_job=None, related_expression=None)[source]

Bases: plainbox.impl.pod.POD

Class representing the cause of a job not being ready to execute.

It is intended to be consumed by UI layers and to provide them with enough information to render informative error messages or other visual feedback that will aid the user in understanding why a job cannot be started.

There are four possible not ready causes:

UNDESIRED:
This job was not selected to run in this session
PENDING_DEP:
This job depends on another job which was not started yet
FAILED_DEP:
This job depends on another job which was started and failed
PENDING_RESOURCE:
This job has a resource requirement expression that uses a resource produced by another job which was not started yet
FAILED_RESOURCE:
This job has a resource requirement that evaluated to a false value

All causes apart from UNDESIRED use the related_job property to encode a job that is related to the problem. The PENDING_RESOURCE and FAILED_RESOURCE causes also store related_expression that describes the relevant requirement expression.

There are three attributes that can be accessed:

cause:
Encodes the reason why a job is not ready, see InhibitionCause.
related_job:
Provides additional context for the problem. This is not the job that is affected, rather, the job that is causing the problem.
related_expression:
Provides additional context for the problem caused by a failing resource expression.
as_dict() → dict

Return the data in this POD as a dictionary.

Note

UNSET values are not added to the dictionary.

as_tuple() → tuple

Return the data in this POD as a tuple.

Order of elements in the tuple corresponds to the order of field declarations.

cause

cause (constant) of the inhibitor

Side effects of assign filters:
  • constant (read-only after initialization)
field_list = [<Field name:'cause'>, <Field name:'related_job'>, <Field name:'related_expression'>]
namedtuple_cls

alias of JobReadinessInhibitor

related_expression

an (optional) resource expression reference

Side effects of assign filters:
  • constant (read-only after initialization)
related_job

an (optional) job reference

Side effects of assign filters:
  • constant (read-only after initialization)
class plainbox.impl.session.JobState(*args, **kwargs)[source]

Bases: plainbox.impl.pod.POD

Class representing the state of a job in a session.

Contains the following basic properties of each job:

  • the readiness_inhibitor_list that prevent the job form starting
  • the result (outcome) of the run (IJobResult)
  • the effective category identifier
  • the effective certification status
  • the job that was used to create it (via_job)

For convenience (to SessionState implementation) it also has a reference to the job itself. This class is a pure state holder an will typically collaborate with the SessionState class and the UI layer.

apply_overrides()[source]

Apply overrides to effective jop values.

This method is automatically called by SessionDeviceContext to implement effective overrides originating from test plan data.

Parameters:

override_list – A list, as exposed by values of TestPlanUnitSupport.override_list, composed of a sequence of pairs (field, value), where field is the name of the field to override (without the prefix effective_) and value is any valid value of that field.

Raises:
  • AttributeError – If any of the ``field``s refer to an unknown field.
  • ValueError – If any of the ``field``s refer to fields that are not designated as overridable.
  • ValueError – If the value supplied is incorrect for the given field.
  • TypeError – If the type of the value supplied is incorrect for the given field.

Note

Consult field specification for details on what types and values are valid for that field.

Example:

>>> from plainbox.vendor.mock import Mock
>>> job = Mock(spec=JobDefinition)
>>> job_state = JobState(job)
>>> job_state.apply_overrides([
...     ('category_id', 'new-category-id'),
...     ('certification_status', 'blocker')])
>>> job_state.effective_category_id
'new-category-id'
>>> job_state.effective_certification_status
'blocker'
as_dict() → dict

Return the data in this POD as a dictionary.

Note

UNSET values are not added to the dictionary.

as_tuple() → tuple

Return the data in this POD as a tuple.

Order of elements in the tuple corresponds to the order of field declarations.

attempts

number of attempts remaining (in auto-retry mode)

can_start()[source]

Quickly check if the associated job can run right now.

effective_auto_retry

the ability to automatically retry this job if it fails

effective_category_id

the effective categorization of this test in a session

effective_certification_status

the effective certification status of this job

field_list = [<Field name:'job'>, <Field name:'readiness_inhibitor_list'>, <Field name:'result'>, <Field name:'result_history'>, <Field name:'via_job'>, <OverridableJobField name:'effective_category_id'>, <Field name:'attempts'>, <OverridableJobField name:'effective_certification_status'>, <OverridableJobField name:'effective_auto_retry'>]
get_readiness_description()[source]

Get a human readable description of the current readiness state.

job

the job associated with this state

namedtuple_cls

alias of JobState

on_result_changed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_result_history_changed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
readiness_inhibitor_list

the list of readiness inhibitors of the associated job

result

the result of running the associated job

result_history

a tuple of result_history of the associated job

Side effects of assign filters:
  • type-checked (value must be of type tuple)
  • type-checked sequence (items must be of type IJobResult)
via_job

the parent job definition

class plainbox.impl.session.SessionManager(*args, **kwargs)[source]

Bases: plainbox.impl.pod.POD

Manager class for coupling SessionStorage with SessionState.

This class allows application code to manage disk state of sessions. Using the checkpoint() method applications can create persistent snapshots of the SessionState associated with each SessionManager.

add_device_context(context)[source]

Add a device context to the session manager

Parameters:context – The SessionDeviceContext to add.
Raises:ValueError – If the context is already in the session manager or the device represented by that context is already present in the session manager.

This method fires the on_device_context_added() signal

add_local_device_context()[source]

Create and add a SessionDeviceContext that describes the local device.

The local device is always the device executing plainbox. Other devices may execute jobs or parts of plainbox but they don’t need to store or run the full plainbox code.

as_dict() → dict

Return the data in this POD as a dictionary.

Note

UNSET values are not added to the dictionary.

as_tuple() → tuple

Return the data in this POD as a tuple.

Order of elements in the tuple corresponds to the order of field declarations.

checkpoint()[source]

Create a checkpoint of the session.

After calling this method you can later reopen the same session with SessionManager.load_session().

classmethod create(repo=None, legacy_mode=False, prefix='pbox-')[source]

Create an empty session manager.

This method creates an empty session manager. This is the most generic API that allows applications to freely work with any set of devices.

Typically applications will use the add_device_context() method to add additional context objects at a later time. This method creates and populates the session storage with all of the well known directories (using WellKnownDirsHelper.populate()).

Parameters:
  • repo – If specified then this particular repository will be used to create the storage for this session. If left out, a new repository is constructed with the default location.
  • legacy_mode – Propagated to create() to ensure that legacy (single session) mode is used.
Ptype repo:

SessionStorageRepository.

Ptype legacy_mode:
 

bool

Returns:

fresh SessionManager instance

create_exporter(exporter_id, option_list=(), strict=True)[source]

Create an exporter object with the specified name and options.

Parameters:
  • exporter_id – Identifier of the exporter unit (which must have been loaded into the session device context of the first device). For backwards compatibility this can also be any of the legacy identifiers xml, html, json, rfc822, text or xlsx.
  • option_list – (optional) A list of options to pass to the exporter. Each option is a string. Some strings may be of form ‘key=value’ but those are handled by each exporter separately. By default an empty tuple is used so no special options are enabled.
  • strict – (optional) Strict mode, in this mode option_list must not contain any options that are unrecognized by the exporter. Since many options (but not all) are shared among various exporters, using non-strict mode might make it easier to use a single superset of options to all exporters and let them silently ignore those that they don’t understand.
Raises:

LookupError – If the exporter identifier cannot be found. Note that this might indicate that appropriate provider has not been loaded yet.

Returns:

A ISessionStateExporter instance with appropriate configuration.

classmethod create_with_state(state, repo=None, legacy_mode=False)[source]

Create a session manager by wrapping existing session state.

This method populates the session storage with all of the well known directories (using WellKnownDirsHelper.populate())

Parameters:
  • stage – A pre-existing SessionState object.
  • repo – If specified then this particular repository will be used to create the storage for this session. If left out, a new repository is constructed with the default location.
  • legacy_mode – Propagated to create() to ensure that legacy (single session) mode is used.
Ptype repo:

SessionStorageRepository.

Ptype legacy_mode:
 

bool

Returns:

fresh SessionManager instance

classmethod create_with_unit_list(unit_list=None, repo=None, legacy_mode=False)[source]

Create a session manager with a fresh session.

This method populates the session storage with all of the well known directories (using WellKnownDirsHelper.populate())

Parameters:
  • unit_list – If specified then this will be the initial list of units known by the session state object.
  • repo – If specified then this particular repository will be used to create the storage for this session. If left out, a new repository is constructed with the default location.
  • legacy_mode – Propagated to create() to ensure that legacy (single session) mode is used.
Ptype repo:

SessionStorageRepository.

Ptype legacy_mode:
 

bool

Returns:

fresh SessionManager instance

default_device_context

The default (first) session device context if available

In single-device sessions this is the context that is used to execute every single job definition. Applications that use multiple devices must access and use the context list directly.

destroy()[source]

Destroy all of the filesystem artifacts of the session.

This basically calls remove()

device_context_list

A list of session device context objects

Note

You must not modify this field directly.

This is not enforced but please use the add_device_context() or remove_device_context() if you want to manipulate the list. Currently you cannot reorder the list of context objects.

Side effects of assign filters:
  • type-checked (value must be of type list)
  • type-checked sequence (items must be of type SessionDeviceContext)
  • constant (read-only after initialization)
exporter_map

Map from exporter id to the corresponding exporter unit.

field_list = [<Field name:'device_context_list'>, <Field name:'storage'>, <Field name:'test_plans'>]
classmethod get_throwaway_manager(provider_list=None)[source]

Create a temporary session manager.

Parameters:provider_list – (optional) A list of providers to put into the session manager. By default all known providers are added. You can use this argument to customize the behaviour beyond defaults.
Returns:A new SessionManager object that will be destroyed when the context manager is left.

This method can be used to create a throw-away session manager which is not really meant for running jobs but can be useful to access exporters and other objects stored in providers.

classmethod load_session(unit_list, storage, early_cb=None, flags=None)[source]

Load a previously checkpointed session.

This method allows one to re-open a session that was previously created by SessionManager.checkpoint()

Parameters:
  • unit_list – List of all known units. This argument is used to reconstruct the session from a dormant state. Since the suspended data cannot capture implementation details of each unit reliably, actual units need to be provided externally. Unlike in create_session() this list really needs to be complete, it must also include any generated units.
  • storage – The storage that should be used for this particular session. The storage object holds references to existing directories in the file system. When restoring an existing dormant session it is important to use the correct storage object, the one that corresponds to the file system location used be the session before it was saved.
  • early_cb – A callback that allows the caller to “see” the session object early, before the bulk of resume operation happens. This method can be used to register callbacks on the new session before this method call returns. The callback accepts one argument, session, which is being resumed. This is being passed directly to plainbox.impl.session.resume.SessionResumeHelper.resume()
  • flags – An optional set of flags that may influence the resume process. Currently this is an internal implementation detail and no “public” flags are provided. Passing None here is a safe equvalent of using this API before it was introduced.
Ptype storage:

SessionStorage

Raises:

Anything that can be raised by load_checkpoint() and resume()

Returns:

Fresh instance of SessionManager

namedtuple_cls

alias of SessionManager

on_device_context_added

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_device_context_removed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_test_plans_changed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
remove_device_context(context)[source]

Remove an device context from the session manager

Parameters:unit – The SessionDeviceContext to remove.

This method fires the on_device_context_removed() signal

state

SessionState associated with this manager

storage

A SesssionStorage instance

Side effects of assign filters:
  • type-checked (value must be of type SessionStorage)
  • constant (read-only after initialization)
test_plans

Test plans that this session is processing.

This field contains a tuple of test plans that are active in the session. Any changes here are propagated to each device context participating in the session. This in turn makes all of the overrides defined by those test plans effective.

Note

Currently there is no facitly that would allow to use this field to drive test execution. Such facility is likely to be added later.

Side effects of assign filters:
  • type-checked (value must be of type tuple)
  • type-checked sequence (items must be of type TestPlanUnit)
  • unique elements (sequence elements cannot repeat)
class plainbox.impl.session.SessionMetaData(title=None, flags=None, running_job_name=None, app_blob=None, app_id=None)[source]

Bases: object

Class representing non-critical state of the session.

The data held here allows applications to reason about sessions in general but is not relevant to the runner or the core in general

FLAG_BOOTSTRAPPING = 'bootstrapping'
FLAG_INCOMPLETE = 'incomplete'
FLAG_SUBMITTED = 'submitted'
app_blob

Custom, application specific binary blob.

The type and value of this property is irrelevant as it is not inspected by plainbox at all. Reasonable applications will not make use of this property for storing large amounts of data. If you are tempted to do that, please redesign your application or propose changes to plainbox.

app_id

Application identifier.

A string identifying the application that stored app_blob. It is recommended to use reverse domain names or UUIDs.

flags

a set of flags that are associated with this session.

This set is persisted by persistent_save() and can be used to keep track of how the application wants to interpret this session state.

Intended usage is to keep track of “testing finished” and “results submitted” flags. Some flags are added as constants to this class.

running_job_name

id of the running job.

Note

This property has a confusing name. It actually refers to job ID, not name.

This property should be updated to keep track of the name of the job that is being executed. When either plainbox or the machine it was running on crashes during the execution of a job this value should be preserved and can help the GUI to resume and provide an error message.

The property MUST be set before starting the job itself.

title

the session title.

Title is just an arbitrary string that can be used to distinguish between multiple sessions.

The value can be changed at any time.

class plainbox.impl.session.SessionPeekHelper[source]

Bases: plainbox.impl.session.resume.EnvelopeUnpackMixIn

A helper class to peek at session state meta-data quickly.

peek(data)[source]

Peek at the meta-data of a dormant session.

Parameters:

data – Bytes representing the dormant session

Returns:

a SessionMetaData object

Raises:
unpack_envelope(data)

Unpack the binary envelope and get access to a JSON object.

Parameters:data – Bytes representing the dormant session
Returns:the JSON representation of a session stored in the envelope
Raises:CorruptedSessionError – if the representation of the session is corrupted in any way
exception plainbox.impl.session.SessionResumeError[source]

Bases: Exception

Base for all session resume exceptions.

Base class for exceptions that can be raised when attempting to resume a dormant session.

args
with_traceback()

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

class plainbox.impl.session.SessionState(unit_list)[source]

Bases: object

Class representing all state needed during a single program session.

This is the central glue/entry-point for applications. It connects user intents to the rest of the system / plumbing and keeps all of the state in one place.

The set of utility methods and properties allow applications to easily handle the lower levels of dependencies, resources and ready states.

SessionState has the following instance variables, all of which are currently exposed as properties.

Variables:
  • job_list (list) –

    A list of all known jobs

    Not all the jobs from this list are going to be executed (or selected for execution) by the user.

    It may change at runtime because of local jobs. Note that in upcoming changes this will start out empty and will be changeable dynamically. It can still change due to local jobs but there is no API yes.

    This list cannot have any duplicates, if that is the case a DependencyDuplicateError is raised. This has to be handled externally and is a sign that the job database is corrupted or has wrong data. As an exception if duplicates are perfectly identical this error is silently corrected.

  • unit_list (list) –

    A list of all known units

    This list contains all the known units, including all the know job definitions (and in the future, all test plans).

    It may change at runtime because of local jobs and template instantiations.

  • job_state_map (dict) –

    mapping that tracks the state of each job

    Mapping from job id to JobState. This basically has the test result and the inhibitor of each job. It also serves as a plainbox.impl.job.JobDefinition.id-> job lookup helper.

    Directly exposed with the intent to fuel part of the UI. This is a way to get at the readiness state, result and readiness inhibitors, if any.

    XXX: this can loose data job_list has jobs with the same id. It would be better to use job id as the keys here. A separate map could be used for the id->job lookup. This will be fixed when session controller branch lands in trunk as then jobs are dynamically added to the system one at a time and proper error conditions can be detected and reported.

  • desired_job_list (list) –

    subset of jobs selected for execution

    This is used to compute run_list. It can only be changed by calling update_desired_job_list() which returns meaningful values so this is not a settable property.

  • run_list (list) –

    sorted list of jobs to execute

    This is basically a superset of desired_job_list and a subset of job_list that is topologically sorted to allowing all desired jobs to run. This property is updated whenever desired_job_list is changed.

  • resource_map (dict) –

    all known resources

    A mapping from resource id to a list of plainbox.impl.resource.Resource objects. This encapsulates all “knowledge” about the system plainbox is running on.

    It is needed to compute job readiness (as it stores resource data needed by resource programs). It is also available to exporters.

    This is computed internally from the output of checkbox resource jobs, it can only be changed by calling update_job_result()

  • metadata (dict) – instance of SessionMetaData
add_job(new_job, recompute=True)[source]

Add a new job to the session.

Parameters:
  • new_job – The job being added
  • recompute – If True, recompute readiness inhibitors for all jobs. You should only set this to False if you’re adding a number of jobs and will otherwise ensure that _recompute_job_readiness() gets called before session state users can see the state again.
Returns:

The job that was actually added or an existing, identical job if a perfect clash was silently ignored.

Raises:

DependencyDuplicateError – if a duplicate, clashing job definition is detected

The new_job gets added to all the state tracking objects of the session. The job is initially not selected to run (it is not in the desired_job_list and has the undesired inhibitor).

The new_job may clash with an existing job with the same id. Unless both jobs are identical this will cause DependencyDuplicateError to be raised. Identical jobs are silently discarded.

Note

This method recomputes job readiness for all jobs

Deprecated since version 0.9: use the add_unit() method instead

add_unit(new_unit, recompute=True)[source]

Add a new unit to the session.

Parameters:
  • new_unit – The unit being added
  • recompute – If True, recompute readiness inhibitors for all jobs. You should only set this to False if you’re adding a number of jobs and will otherwise ensure that _recompute_job_readiness() gets called before session state users can see the state again.
Returns:

The unit that was actually added or an existing, identical unit if a perfect clash was silently ignored.

Raises:

DependencyDuplicateError – if a duplicate, clashing job definition is detected

Note

The following applies only to newly added job units:

The new_unit gets added to all the state tracking objects of the session. The job unit is initially not selected to run (it is not in the desired_job_list and has the undesired inhibitor).

The new_unit job may clash with an existing job with the same id. Unless both jobs are identical this will cause DependencyDuplicateError to be raised. Identical jobs are silently discarded.

Note

This method recomputes job readiness for all jobs unless the recompute=False argument is used. Recomputing takes a while so if you want to add a lot of units consider setting that to False and only recompute at the last call.

desired_job_list

List of jobs that are on the “desired to run” list.

This is a list, not a set, because the dependency solver algorithm retains as much of the original ordering as possible. Having said that, the actual order can differ widely (for instance, be reversed)

get_certification_status_map(outcome_filter=('fail', ), certification_status_filter=('blocker', ))[source]

Get a map of jobs that have a specific certification blocker status.

Filter the Job state map to only return items with given outcomes and certification statuses.

Parameters:
  • outcome_filter – Only consider job results with those outcome values
  • certification_status_filter – Only consider jobs with those certification status values
Returns:

a Job state map only containing job with a given outcome and certification status value.

get_estimated_duration(manual_overhead=30.0)[source]

Estimate the total duration of the session.

Provide the estimated duration of the jobs that have been selected to run in this session (maintained by calling update_desired_job_list).

Manual jobs have an arbitrary figure added to their runtime to allow for execution of the test steps and verification of the result.

Returns:(estimate_automated, estimate_manual)

where estimate_automated is the value for automated jobs only and estimate_manual is the value for manual jobs only. These can be easily combined. Either value can be None if the value could not be calculated due to any job lacking the required estimated_duration field.

get_outcome_stats()[source]

Process the JobState map to get stats about the job outcomes.

Returns:a mapping of “outcome”: “total” key/value pairs

Note

Only the outcomes seen during this session are reported, not all possible values (such as crash, not implemented, ...).

job_list

List of all known jobs.

Not necessarily all jobs from this list can be, or are desired to run. For API simplicity this variable is read-only, if you wish to alter the list of all jobs re-instantiate this class please.

job_state_map

Map from job id to JobState associated with each job.

mandatory_job_list

List of all mandatory jobs that must run.

Testplan units can specify a list of jobs that have to be run and are not supposed to be deselected by the application user.

metadata

meta-data object associated with this session state.

on_job_added

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_job_removed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_job_result_changed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_job_state_map_changed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_unit_added

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_unit_removed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
remove_unit(unit, *, recompute=True)[source]

Remove an existing unit from the session.

Parameters:
  • unit – The unit to remove
  • recompute – If True, recompute readiness inhibitors for all jobs. You should only set this to False if you’re adding a number of jobs and will otherwise ensure that _recompute_job_readiness() gets called before session state users can see the state again.

Note

This method recomputes job readiness for all jobs unless the recompute=False argument is used. Recomputing takes a while so if you want to add a lot of units consider setting that to False and only recompute at the last call.

resource_map

Map from resource id to a list of resource records.

run_list

List of jobs that were intended to run, in the proper order.

The order is a result of topological sorting of the desired_job_list. This value is recomputed when change_desired_run_list() is called. It may be shorter than desired_run_list due to dependency errors.

set_resource_list(resource_id, resource_list)[source]

Add or change a resource with the given id.

Resources silently overwrite any old resources with the same id.

trim_job_list(qualifier)[source]

Discard jobs that are selected by the given qualifier.

Parameters:qualifier – A qualifier that selects jobs to be removed
Ptype qualifier:
 IJobQualifier
Raises:ValueError – If any of the jobs selected by the qualifier is on the desired job list (or the run list)

This function correctly and safely discards certain jobs from the job list. It also removes the associated job state (and referenced job result) and results (for jobs that were resource jobs)

unit_list

List of all known units.

update_desired_job_list(desired_job_list, include_mandatory=True)[source]

Update the set of desired jobs (that ought to run).

This method can be used by the UI to recompute the dependency graph. The argument ‘desired_job_list’ is a list of jobs that should run. Those jobs must be a sub-collection of the job_list argument that was passed to the constructor.

It never fails although it may reduce the actual permitted desired_job_list to an empty list. It returns a list of problems (all instances of DependencyError class), one for each job that had to be removed.

update_job_result(job, result)[source]

Notice the specified test result and update readiness state.

This function updates the internal result collection with the data from the specified test result. Results can safely override older results. Results also change the ready map (jobs that can run) because of dependency relations.

Some results have deeper meaning, those are results for local and resource jobs. They are discussed in detail below:

Resource jobs produce resource records which are used as data to run requirement expressions against. Each time a result for a resource job is presented to the session it will be parsed as a collection of RFC822 records. A new entry is created in the resource map (entirely replacing any old entries), with a list of the resources that were parsed from the IO log.

Local jobs produce more jobs. Like with resource jobs, their IO log is parsed and interpreted as additional jobs. Unlike in resource jobs local jobs don’t replace anything. They cannot replace an existing job with the same id.

update_mandatory_job_list(mandatory_job_list)[source]

Update the set of mandatory jobs (that must run).

This method simply stores the list of mandatory jobs inside the session state. The next time the set of desired jobs is altered via a call update_desired_job_list() the effective selection will also include mandatory jobs.

class plainbox.impl.session.SessionStorage(location)[source]

Bases: object

Abstraction for storage area that is used by SessionState to keep some persistent and volatile data.

This class implements functions performing input/output operations on session checkpoint data. The location property can be used for keeping any additional files or directories but keep in mind that they will be removed by SessionStorage.remove()

This class indirectly collaborates with SessionSuspendHelper and SessionResumeHelper.

break_lock()[source]

Forcibly unlock the storage by removing a file created during atomic filesystem operations of save_checkpoint().

This method might be useful if save_checkpoint() raises LockedStorageError. It removes the “next” file that is used for atomic rename.

classmethod create(base_dir, legacy_mode=False, prefix='pbox-')[source]

Create a new SessionStorage in a random subdirectory of the specified base directory. The base directory is also created if necessary.

Parameters:
  • base_dir – Directory in which a random session directory will be created. Typically the base directory should be obtained from SessionStorageRepository.get_default_location()
  • legacy_mode – If False (defaults to True) then the caller is expected to handle multiple sessions by itself.
  • prefix – String which should prefix all session filenames. The prefix is sluggified before use.

Note

Legacy mode is where applications using PlainBox API can only handle one session. Creating another session replaces whatever was stored before. In non-legacy mode applications can enumerate sessions, create arbitrary number of sessions at the same time and remove sessions once they are no longer necessary.

Legacy mode is implemented with a symbolic link called ‘last-session’ that keeps track of the last session created using legacy_mode=True. When a new legacy-mode session is created the target of that symlink is read and recursively removed.

id

identifier of the session storage (name of the random directory)

load_checkpoint()[source]

Load checkpoint data from the filesystem

Returns:

data from the most recent checkpoint

Return type:

bytes

Raises:
  • IOError, OSError – on various problems related to accessing the filesystem
  • NotImplementedError – when openat(2) is not available on this platform. Should never happen on Linux or Windows where appropriate checks divert to a correct implementation that is not using them.
location

location of the session storage

remove()[source]

Remove all filesystem entries associated with this instance.

save_checkpoint(data)[source]

Save checkpoint data to the filesystem.

The directory associated with this SessionStorage must already exist. Typically the instance should be obtained by calling SessionStorage.create() which will ensure that this is already the case.

Raises:
  • TypeError – if data is not a bytes object.
  • LockedStorageError – if leftovers from previous save_checkpoint() have been detected. Normally those should never be here but in certain cases that is possible. Callers might want to call break_lock() to resolve the problem and try again.
  • IOError, OSError – on various problems related to accessing the filesystem. Typically permission errors may be reported here.
  • NotImplementedError – when openat(2), renameat(2), unlinkat(2) are not available on this platform. Should never happen on Linux or Windows where appropriate checks divert to a correct implementation that is not using them.
session_file

pathname of the session state file

class plainbox.impl.session.SessionStorageRepository(location=None)[source]

Bases: object

Helper class to enumerate filesystem artefacts of current or past Sessions

This class collaborates with SessionStorage. The basic use-case is to open a well-known location and enumerate all the sessions that are stored there. This allows to create SessionStorage instances to further manage each session (such as remove them by calling :meth:SessionStorage.remove()`)

classmethod get_default_location()[source]

Get the default location of the session state repository

The default location is defined by $PLAINBOX_SESSION_REPOSITORY which must be a writable directory (created if needed) where plainbox will keep its session data. The default location, if the environment variable is not provided, is ${XDG_CACHE_HOME:-$HOME/.cache}/plainbox/sessions

get_last_storage()[source]

Find the last session storage object created in this repository.

Returns:SessionStorage object associated with the last session created in this repository using legacy mode.

Note

This will only return storage objects that were created using legacy mode. Nonlegacy storage objects will not be returned this way.

get_storage_list()[source]

Enumerate stored sessions in the repository.

If the repository directory is not present then an empty list is returned.

Returns:list of SessionStorage representing discovered sessions sorted by their age (youngest first)
location

pathname of the repository

class plainbox.impl.session.InhibitionCause[source]

Bases: plainbox.vendor.enum.IntEnum

There are four possible not-ready causes.

UNDESIRED:
This job was not selected to run in this session
PENDING_DEP:
This job depends on another job which was not started yet
FAILED_DEP:
This job depends on another job which was started and failed
PENDING_RESOURCE:
This job has a resource requirement expression that uses a resource produced by another job which was not started yet
FAILED_RESOURCE:
This job has a resource requirement that evaluated to a false value
FAILED_DEP = <InhibitionCause.FAILED_DEP: 2>
FAILED_RESOURCE = <InhibitionCause.FAILED_RESOURCE: 4>
PENDING_DEP = <InhibitionCause.PENDING_DEP: 1>
PENDING_RESOURCE = <InhibitionCause.PENDING_RESOURCE: 3>
UNDESIRED = <InhibitionCause.UNDESIRED: 0>
comments powered by Disqus