# Observations

Observations provide a high-level interface to retrieve observation data that is being created during execution.

# Observations

machinable.Observations(storage=None, database=None)

Interface to manage machinable observations

The interface is read-only. machinable will never modify any of the collected observations.

# Examples

import machinable as ml
mlo = ml.Observations('~/observations')
mlo.find()

# Arguments

  • storage: String, URL of storage location.
  • database: String, optional path to SQLite database used for indexing. Defaults to non-persistent in-memory database.

# query property

Returns a query builder to build customized queries

# add

add(self, storage, lazy=False)

Load a storage location

# Arguments

  • storage: String, URL to index
  • lazy: Boolean, whether location should only be loaded on demand. Defaults to False.

# find

find(self, observation_id=None, rerun=False)

Finds an observation

# Arguments

  • observation_id: String, observation ID. If None, all available observations will be returned. Alternatively, a 6-digit task ID or a 9-digit execution ID can be used to retrieve observations.
  • rerun: Integer, optional number of rerun if observation has been reproduced multiple times

# Returns

Instance or collection of machinable.Observation

# find_all

find_all(self)

Returns a collection of all available observations

# Returns

Instance or collection of machinable.Observation

# find_by_child_component

find_by_child_component(self, child)

Finds observations that were produced by a given child component

# Arguments

  • child: String, the search name

# Returns

Instance or collection of machinable.Observation

# find_by_execution

find_by_execution(self, execution_id)

Finds observations of a given execution

# Arguments

  • execution_id: String|Task|Observation that specifies the execution

# Returns

Instance or collection of machinable.Observation

# find_by_most_recent_task

find_by_most_recent_task(self, criterion='started')

Finds all observations of the most recent task

# Arguments

  • criterion: String, the field by which the tasks should be ordered in descending order.

# Returns

Instance or collection of machinable.Observation or None if no tasks are available

# find_by_node_component

find_by_node_component(self, node)

Finds observations that were produced by a given node component

# Arguments

  • node: String, the search name

# Returns

Instance or collection of machinable.Observation

# find_by_storage

find_by_storage(self, storage)

Finds observations of a given storage

# Arguments

  • storage: String, the search name

# Returns

Instance or collection of machinable.Observation

# find_by_task

find_by_task(self, task_id)

Finds all observations of a task

# Arguments

  • task_id: String, task ID. Alternatively, a list of task ID can be used.

# Returns

Instance or collection of machinable.Observation

# find_by_task_name

find_by_task_name(self, name)

Finds observations of tasks with a given name

# Arguments

  • name: String, the search name

# Returns

Instance or collection of machinable.Observation

# find_many

find_many(self, observations, rerun=False)

Finds many observations

# Arguments

  • observations: List of observation ID strings.
  • rerun: Integer, optional number of rerun if observations have been reproduced multiple times

# Returns

Instance or collection of machinable.Observation

# refresh

refresh(self, storage=None, or_add=True)

Reloads all observations

# Arguments

  • storage: String, optional URL of storage that should be reloaded. If None, all registered storages will be reloaded
  • or_add: If True, non-existing storage location will be added otherwise ignored.

# remove

remove(self, storage)

Unloads a storage location.

Note that this does NOT remove any data, the location can be reloaded at any time.

# reset

reset(self, database=':memory:')

Resets the interface and deletes the database index

# Arguments

  • database: String, optional location of the SQLite database

# Collection

machinable.observations.collections.Collection(items=None)

# items property

Items of the collection

# all

all(self)

Get all of the items in the collection.

Returns the underlying list represented by the collection

Collection([1, 2, 3]).all()

#### [1, 2, 3]

# append

append(self, value)

Add an item onto the end of the collection.

# Arguments

  • value: The value to push
collection = Collection([1, 2, 3, 4])

collection.push(5)

collection.all()

#### [1, 2, 3, 4, 5]

# as_json

as_json(self, **options)

Converts the collection into JSON

# Arguments

  • options: JSON encoding options
collection = Collection([{'name': 'Desk', 'price': 200}])

collection.to_json()

#### '[{"name": "Desk", "price": 200}]'

# as_numpy

as_numpy(self)

Converts the collection into a numpy array

# as_table

as_table(self, mode='html', headers=(), **kwargs)

Converts the collection into a table

# Arguments

  • mode: String 'html' or any other mode of the tabulate package
  • headers: Optional header row **kwargs: Options to pass to tabulate

# avg

avg(self, key=None)

Get the average value of a given key.

# Arguments

  • key: The key to get the average for
Collection([1, 2, 3, 4, 5]).avg()
#### 3

If the collection contains nested objects or dictionaries, you must pass a key to use for determining which values to calculate the average:

collection = Collection([
    {'name': 'JavaScript: The Good Parts', 'pages': 176},
    {'name': 'JavaScript: The Defnitive Guide', 'pages': 1096}
])
#### 636
collection.avg('pages')

# chunk

chunk(self, size)

Chunk the underlying collection.

The chunk method breaks the collection into multiple, smaller collections of a given size:

collection = Collection([1, 2, 3, 4, 5, 6, 7])

chunks = collection.chunk(4)

chunks.serialize()

#### [[1, 2, 3, 4], [5, 6, 7]]

# Arguments

  • size: The chunk size

# collapse

collapse(self)

Collapses a collection of lists into a flat collection

collection = Collection([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
collapsed = collection.collapse()
collapsed.all()
#### [1, 2, 3, 4, 5, 6, 7, 8, 9]

# contains

contains(self, key, value=None)

Determines if an element is in the collection

# Arguments

  • key: Integer|String|callable The element
  • value: The value of the element
collection = Collection(['foo', 'bar'])

collection.contains('foo')

#### True

You can also use the in keyword:

'foo' in collection

#### True

You can also pass a key / value pair to the contains method, which will determine if the given pair exists in the collection:

collection = Collection([
    {'name': 'John', 'id': 1},
    {'name': 'Jane', 'id': 2}
])

collection.contains('name', 'Simon')

#### False

Finally, you may also pass a callback to the contains method to perform your own truth test:

collection = Collection([1, 2, 3, 4, 5])

collection.contains(lambda item: item > 5)

#### False

# count

count(self)

Returns the total number of items in the collection:

collection = Collection([1, 2, 3, 4])

collection.count()

#### 4

The len function can also be used:

len(collection)

#### 4

# diff

diff(self, items)

Compares the collection against another collection, a list or a dict

# Arguments

  • items: The items to diff with
collection = Collection([1, 2, 3, 4, 5])
diff = collection.diff([2, 4, 6, 8])
diff.all()
#### [1, 3, 5]

# each

each(self, callback)

Iterates over the items in the collection and passes each item to a given callback

# Arguments

  • callback: callable The callback to execute
collection = Collection([1, 2, 3])
collection.each(lambda x: x + 3)

Return False from your callback to break out of the loop:

observations.each(lambda data: data.save() if data.name == 'mnist' else False)

TIP

It only applies the callback but does not modify the collection's items. Use the transform() method to modify the collection.

# empty

empty(self)

Returns True if the collection is empty; otherwise, False is returned

# every

every(self, step, offset=0)

Create a new collection consisting of every n-th element.

# Arguments

  • step: int The step size
  • offset: int The start offset
collection = Collection(['a', 'b', 'c', 'd', 'e', 'f'])

collection.every(4).all()

#### ['a', 'e']

You can optionally pass the offset as the second argument:

collection.every(4, 1).all()

#### ['b', 'f']

# filter

filter(self, callback=None)

Filters the collection by a given callback, keeping only those items that pass a given truth test

# Arguments

  • callback: callable|None The filter callback
collection = Collection([1, 2, 3, 4])

filtered = collection.filter(lambda item: item > 2)

filtered.all()

#### [3, 4]

# first

first(self, callback=None, default=None)

Returns the first element in the collection that passes a given truth test

# Arguments

  • callback: Optional callable truth condition to find first element
  • default: A default value
collection = Collection([1, 2, 3, 4])

collection.first(lambda item: item > 2)

#### 3

You can also call the first method with no arguments to get the first element in the collection. If the collection is empty, None is returned:

collection.first()

#### 1

# flatten

flatten(self)

Flattens a multi-dimensional collection into a single dimension

collection = Collection([1, 2, [3, 4, 5, {'foo': 'bar'}]])

flattened = collection.flatten()

flattened.all()

#### [1, 2, 3, 4, 5, 'bar']

# forget

forget(self, *keys)

Remove an item from the collection by key.

# Arguments

  • keys: The keys to remove
collection = Collection([1, 2, 3, 4, 5])
collection.forget(1)
collection.all()
#### [1, 3, 4, 5]

WARNING

Unlike most other collection methods, forget does not return a new modified collection; it modifies the collection it is called on.

# get

get(self, key, default=None)

Returns the item at a given key. If the key does not exist, None is returned

# Arguments

  • key: The index of the element
  • default: The default value to return
collection = Collection([1, 2, 3])
collection.get(3)
#### None

You can optionally pass a default value as the second argument:

collection = Collection([1, 2, 3])
collection.get(3, 'default-value')
#### default-value

# implode

implode(self, value, glue='')

Joins the items in a collection. Its arguments depend on the type of items in the collection.

# Arguments

  • value: The value
  • glue: The glue

If the collection contains dictionaries or objects, you must pass the key of the attributes you wish to join, and the "glue" string you wish to place between the values:

collection = Collection([
    {'account_id': 1, 'product': 'Desk'},
    {'account_id': 2, 'product': 'Chair'}
])

collection.implode('product', ', ')

#### Desk, Chair

If the collection contains simple strings, simply pass the "glue" as the only argument to the method:

collection = Collection(['foo', 'bar', 'baz'])

collection.implode('-')

#### foo-bar-baz

# last

last(self, callback=None, default=None)

Returns the last element in the collection that passes a given truth test

# Arguments

  • callback: Optional callable truth condition
  • default: The default value
collection = Collection([1, 2, 3, 4])

last = collection.last(lambda item: item < 3)

#### 2

You can also call the last method with no arguments to get the last element in the collection. If the collection is empty, None is returned:

collection.last()

#### 4

# map

map(self, callback)

Iterates through the collection and passes each value to the given callback. The callback is free to modify the item and return it, thus forming a new collection of modified items

# Arguments

  • callback: The map function
collection = Collection([1, 2, 3, 4])

multiplied = collection.map(lambda item: item * 2)

multiplied.all()

#### [2, 4, 6, 8]

WARNING

Like most other collection methods, map returns a new Collection instance; it does not modify the collection it is called on. If you want to transform the original collection, use the transform method.

# max

max(self, key=None)

Get the max value of a given key.

# Arguments

  • key: The key

# merge

merge(self, items)

Merges the given list into the collection

# Arguments

  • items: The items to merge
collection = Collection(['Desk', 'Chair'])
collection.merge(['Bookcase', 'Door'])
collection.all()
#### ['Desk', 'Chair', 'Bookcase', 'Door']

WARNING

Unlike most other collection methods, merge does not return a new modified collection; it modifies the collection it is called on.

# min

min(self, key=None)

Get the min value of a given key.

key: The key

# only

only(self, *keys)

Get the items with the specified keys.

# Arguments

  • keys: tuple The keys to keep

# pluck

pluck(self, value, key=None)

Retrieves all of the collection values for a given key

# Arguments

  • value: Value
  • key: Optional key
collection = Collection([
    {'product_id': 1, 'product': 'Desk'},
    {'product_id': 2, 'product': 'Chair'}
])

plucked = collection.pluck('product')

plucked.all()

#### ['Desk', 'Chair']

You can also specify how you wish the resulting collection to be keyed:

plucked = collection.pluck('name', 'product_id')

plucked

#### {1: 'Desk', 2: 'Chair'}

# pluck_or_nan

pluck_or_nan(self, value, key=None)

Pluck method that returns NaNs if key is not present

# Arguments

  • value: Value
  • key: Key

# pluck_or_none

pluck_or_none(self, value, key=None, none=None)

Pluck method that returns None if key is not present

# Arguments

  • value: Value
  • key: Key
  • none: Return value if key is not present

# pop

pop(self, key=None)

Removes and returns the last item from the collection. If no index is specified, returns the last item.

# Arguments

  • key: The index of the item to return
collection = Collection([1, 2, 3, 4, 5])
collection.pop()
#### 5

collection.all()
#### [1, 2, 3, 4]

# prepend

prepend(self, value)

Adds an item to the beginning of the collection

# Arguments

  • value: The value to push
collection = Collection([1, 2, 3, 4])

collection.prepend(0)

collection.all()

#### [0, 1, 2, 3, 4]

# pull

pull(self, key, default=None)

Removes and returns an item from the collection by its key

# Arugments

key: The key default: The default value

collection = Collection([1, 2, 3, 4])

collection.pull(1)

collection.all()

#### [1, 3, 4]

# put

put(self, key, value)

Sets the given key and value in the collection

# Arguments

  • key: The key
  • value: The value
collection = Collection([1, 2, 3, 4])
collection.put(1, 5)
collection.all()

#### [1, 5, 3, 4]

TIP

It is equivalent to collection[1] = 5

# reduce

reduce(self, callback, initial=None)

Reduces the collection to a single value, passing the result of each iteration into the subsequent iteration

# Arguments

  • callback: The callback
  • initial: The initial value
collection = Collection([1, 2, 3])

collection.reduce(lambda result, item: (result or 0) + item)

#### 6

The value for result on the first iteration is None; however, you can specify its initial value by passing a second argument to reduce:

collection.reduce(lambda result, item: result + item, 4)

#### 10

# reject

reject(self, callback)

Filters the collection using the given callback. The callback should return True for any items it wishes to remove from the resulting collection

# Arguments

  • callback: The truth test
collection = Collection([1, 2, 3, 4])

filtered = collection.reject(lambda item: item > 2)

filtered.all()

#### [1, 2]

For the inverse of reject, see the filter method.

# reverse

reverse(self)

Reverses the order of the collection's items

collection = Collection([1, 2, 3, 4, 5])
reverse = collection.reverse()
reverse.all()
#### [5, 4, 3, 2, 1]

# section

section(self, of, reduce=None)

Performs horizontal reduce through collection

# Arguments

  • of: String|Callable Selector of reduce values
  • reduce: Optional callable reduce method

# serialize

serialize(self)

Converts the collection into a list

collection = Collection([User.find(1)])
collection.serialize()
#### [{'id': 1, 'name': 'John'}]

WARNING

serialize also converts all of its nested objects. If you want to get the underlying items as is, use the all method instead.

# sort

sort(self, callback=None)

Sorts the collection

# Arguments

  • callback: Sort callable
collection = Collection([5, 3, 1, 2, 4])

sorted = collection.sort()

sorted.all()

#### [1, 2, 3, 4, 5]

# sum

sum(self, callback=None)

Returns the sum of all items in the collection

callback: The callback

Collection([1, 2, 3, 4, 5]).sum()

#### 15

If the collection contains dictionaries or objects, you must pass a key to use for determining which values to sum:

collection = Collection([
    {'name': 'JavaScript: The Good Parts', 'pages': 176},
    {'name': 'JavaScript: The Defnitive Guide', 'pages': 1096}
])

collection.sum('pages')

#### 1272

In addition, you can pass your own callback to determine which values of the collection to sum:

collection = Collection([
    {'name': 'Chair', 'colors': ['Black']},
    {'name': 'Desk', 'colors': ['Black', 'Mahogany']},
    {'name': 'Bookcase', 'colors': ['Red', 'Beige', 'Brown']}
])

collection.sum(lambda product: len(product['colors']))

#### 6

# take

take(self, limit)

Take the first or last n items.

# Arguments

  • limit: The number of items to take
collection = Collection([0, 1, 2, 3, 4, 5])
chunk = collection.take(3)
chunk.all()
#### [0, 1, 2]

You can also pass a negative integer to take the specified amount of items from the end of the collection:

chunk = collection.chunk(-2)
chunk.all()
#### [4, 5]

# transform

transform(self, callback)

Transform each item in the collection using a callback.

Iterates over the collection and calls the given callback with each item in the collection. The items in the collection will be replaced by the values returned by the callback.

# Arguments

  • callback: The callback
collection = Collection([1, 2, 3, 4, 5])
collection.transform(lambda item: item * 2)
collection.all()

#### [2, 4, 6, 8, 10]

WARNING

Unlike most other collection methods, transform modifies the collection itself. If you wish to create a new collection instead, use the map method.

# unique

unique(self, key=None)

Returns all of the unique items in the collection

# Arguments

  • key: The key to check uniqueness on
collection = Collection([1, 1, 2, 2, 3, 4, 2])

unique = collection.unique()

unique.all()

#### [1, 2, 3, 4]

When dealing with dictionaries or objects, you can specify the key used to determine uniqueness:

collection = Collection([
    {'name': 'iPhone 6', 'brand': 'Apple', 'type': 'phone'},
    {'name': 'iPhone 5', 'brand': 'Apple', 'type': 'phone'},
    {'name': 'Apple Watch', 'brand': 'Apple', 'type': 'watch'},
    {'name': 'Galaxy S6', 'brand': 'Samsung', 'type': 'phone'},
    {'name': 'Galaxy Gear', 'brand': 'Samsung', 'type': 'watch'}
])

unique = collection.unique('brand')

unique.all()

#### [
####     {'name': 'iPhone 6', 'brand': 'Apple', 'type': 'phone'},
####     {'name': 'Galaxy S6', 'brand': 'Samsung', 'type': 'phone'}
#### ]

You can also pass your own callback to determine item uniqueness:

unique = collection.unique(lambda item: item['brand'] + item['type'])

unique.all()

#### [
####     {'name': 'iPhone 6', 'brand': 'Apple', 'type': 'phone'},
####     {'name': 'Apple Watch', 'brand': 'Apple', 'type': 'watch'},
####     {'name': 'Galaxy S6', 'brand': 'Samsung', 'type': 'phone'},
####     {'name': 'Galaxy Gear', 'brand': 'Samsung', 'type': 'watch'}
#### ]

# where

where(self, key, value)

Filter items by the given key value pair.

# Arguments

  • key: The key to filter by
  • value: The value to filter by
collection = Collection([
    {'name': 'Desk', 'price': 200},
    {'name': 'Chair', 'price': 100},
    {'name': 'Bookcase', 'price': 150},
    {'name': 'Door', 'price': 100},
])

filtered = collection.where('price', 100)

filtered.all()

#### [
####     {'name': 'Chair', 'price': 100},
####     {'name': 'Door', 'price': 100}
#### ]

# without

without(self, *keys)

Get all items except for those with the specified keys.

# Arguments

  • keys: tuple The keys to remove

# zip

zip(self, *items)

Merges together the values of the given list with the values of the collection at the corresponding index

# Argument

*items: Zip items

collection = Collection(['Chair', 'Desk'])
zipped = collection.zip([100, 200])
zipped.all()
#### [('Chair', 100), ('Desk', 200)]

# Observation

machinable.observations.views.observation.Observation(model, cache=None)

# children property

Provides access the child component data of this observation (if existing)

# config property

Returns the observation config

# execution_id property

Returns the execution ID

# finished property

Returns the finishing time

# flags property

Return the observation flags

# heartbeat property

Returns the last heartbeat time

# host property

Returns information on the host that produced this observation

# id property

Returns the observation ID

# log property

Returns the content of the log file

# output property

Returns the content of the log file

# records property

Returns the record interface

# started property

Returns the starting time

# storage property

Returns the storage location of the observation

# task property

The task of this observation

# as_json

as_json(self)

Returns a json representation of the data

# get_records_writer

get_records_writer(self, scope=None)

Returns a record writer

# Arguments

  • scope: The name of the record writer

# is_active

is_active(self)

True if not finished and alive

# is_alive

is_alive(self)

True if last heartbeat occurred less than 30 seconds ago

# is_finished

is_finished(self)

True if finishing time has been written

# serialize

serialize(self)

Serializes the data

# store

store(self, name=None)

Retrieves element from the storage

This is the counterpart to the Observer.store method.

# Arguments

  • name: Key or filename of the object that is to be retrieved. If None, a list of available objects is returned

# ObservationsQueryBuilder

machinable.observations.observations.ObservationsQueryBuilder(cache=None)

# object property

Returns the query object

# alive

alive(self)

# finished

finished(self, time=None, operator='<')

# first

first(self)

Returns the first observation of the specified query

# get

get(self)

Returns the observations of the specified query

# has_code_backup

has_code_backup(self)

# has_no_code_backup

has_no_code_backup(self)

# latest

latest(self, field='started')

# not_finished

not_finished(self)

# not_tuning

not_tuning(self)

# oldest

oldest(self, field='started')

# or_where

or_where(self, field, operator='=', value=None)

# or_where_between

or_where_between(self, field, values)

# or_where_in

or_where_in(self, field, values)

# or_where_not_between

or_where_not_between(self, field, values)

# or_where_not_in

or_where_not_in(self, field, values)

# or_where_not_task_between

or_where_not_task_between(self, field, values)

# or_where_storage

or_where_storage(self, url)

# or_where_storage_in

or_where_storage_in(self, values)

# or_where_storage_not_in

or_where_storage_not_in(self, values)

# or_where_task

or_where_task(self, field, operator='=', value=None)

# or_where_task_between

or_where_task_between(self, field, values)

# or_where_task_in

or_where_task_in(self, field, values)

# or_where_task_not_in

or_where_task_not_in(self, field, values)

# order_by

order_by(self, field, direction='asc')

# rerun

rerun(self, number)

# skip

skip(self, value)

# take

take(self, value)

# tuning

tuning(self)

# union

union(self, query, all=False)

# union_all

union_all(self, query)

# where

where(self, field, operator='=', value=None, boolean='and')

# where_between

where_between(self, field, values, boolean='and', negate=False)

# where_has

where_has(self, relation, extra, operator='>=', count=1)

# where_in

where_in(self, field, values, boolean='and', negate=False)

# where_not_between

where_not_between(self, field, values, boolean='and')

# where_not_in

where_not_in(self, field, values, boolean='and')

# where_not_storage_in

where_not_storage_in(self, values, boolean='and')

# where_not_task_between

where_not_task_between(self, field, values, boolean='and')

# where_not_task_in

where_not_task_in(self, field, values, boolean='and')

# where_storage

where_storage(self, url, boolean='and')

# where_storage_in

where_storage_in(self, values, boolean='and', negate=False)

# where_task

where_task(self, field, operator='=', value=None, boolean='and')

# where_task_between

where_task_between(self, field, values, boolean='and', negate=False)

# where_task_in

where_task_in(self, field, values, boolean='and', negate=False)

# Records

machinable.observations.views.records.Records(models, scope='default')

# query property

Returns a query builder to build customized queries

# as_dataframe

as_dataframe(self)

Returns collection as Pandas dataframe

# find

find(self, record_id=None)

Returns a record by ID

# Arguments

  • record_id: Int or list of Int with record IDs. If None, all records are returned

Returns None or empty collection if record is not found

# find_all

find_all(self)

Returns all records as a collection

# find_many

find_many(self, records)

Returns a collections of records with a given list of IDs

# Arguments

  • records: List of Record IDs

# info

info(self, echo=False)

Returns information about the records as dictionary

columns: List of columns indexed_columns: List of columns that have been indexed and are available in a query builder

# Arguments

  • echo: If True, information will be printed

# refresh

refresh(self, disable_sql=False)

Reloads records from the storage

# Arguments

  • disable_sql: Boolean to disable the indexing of records into the in-memory SQL database used by self.query

# RecordsQueryBuilder

machinable.observations.views.records.RecordsQueryBuilder(db, data)

# object property

Returns the query object

# first

first(self)

Returns the first query result

# get

get(self)

Returns the query result

# or_where

or_where(self, field, operator='=', value=None)

# or_where_between

or_where_between(self, field, values)

# or_where_in

or_where_in(self, field, values)

# or_where_not_between

or_where_not_between(self, field, values)

# or_where_not_in

or_where_not_in(self, field, values)

# order_by

order_by(self, field, direction='asc')

# skip

skip(self, value)

# take

take(self, value)

# union

union(self, query, all=False)

# union_all

union_all(self, query)

# where

where(self, field, operator='=', value=None, boolean='and')

# where_between

where_between(self, field, values, boolean='and', negate=False)

# where_has

where_has(self, relation, extra, operator='>=', count=1)

# where_in

where_in(self, field, values, boolean='and', negate=False)

# where_not_between

where_not_between(self, field, values, boolean='and')

# where_not_in

where_not_in(self, field, values, boolean='and')

# Task

machinable.observations.views.task.Task(model)

# code_backup property

True if code backup is available

# code_version property

Returns information about the source code version as a dictionary

project:
  path: VCS url
  commit: Commit hash or None
  is_dirty: Whether everything has been commited to VCS
vendor: List of vendor project information with the same structure as above

# execution_id property

Returns the execution ID

# finished property

Returns the finishing time

# heartbeat property

Returns the last heartbeat time

# id property

6-digit task ID, e.g. #F4K3r6

# name property

Returns the name of the task

# observations_count property

Returns the number of observations in this task

# rerun property

Number of rerun

# seed property

Returns the global random seed used in the task

# started property

Returns the starting time

# tune property

True if task is a tuning task

# is_active

is_active(self)

True if not finished and alive

# is_alive

is_alive(self)

True if last heartbeat occurred less than 30 seconds ago

# is_finished

is_finished(self)

True if finishing time has been written