The Item class
- class mktl.Item(store, key, subscribe=True, authoritative=False, pub=None)
An Item represents a key/value pair, where the key is the name of the Item, and the value is whatever is provided by the authoritative daemon. The principal way for both clients and daemons to get or set the value is via the
valueproperty.A non-authoritative Item will automatically
subscribe()itself to any available updates.- Variables:
key – The key (name) for this item.
full_key – The store and key for this item, in store.key format.
store – The
mktl.Storeinstance containing this item.config – The JSON description of this item.
log_on_set – Indicates whether this item will log SET requests. The default is True.
publish_on_set – Indicates whether this item will publish a new value whenever
perform_set()is successfully invoked. The default is True.
The bulk of mKTL interactions involve the
mktl.Itemclass. In addition to the methods described here anmktl.Iteminstance can be used with Python operators, such as addition/concatenation or multiplication.The behavior of an
mktl.Itemwhen used in this fashion will be aligned with the native Python binary type for the item value; for example, if an item test.BAR has an integer value 12,test.BAR + 5will return the integer value 17. If test.BAR is instead the string value ‘12’, the same operation would raise a TypeError exception; however,test.BAR + '5'would return the string value ‘125’, just like you would expect for string concatenation. In-place operators will set the current value of the item.Three properties allow unified access to getting and setting an item’s value, regardless of whether the local application is authoritative for that specific item. The use of properties implies default behavior for both
get()andset()in a client context, and forpublish()in a daemon context. The use of these properties is encouraged as the preferred approach to getting and setting item values; any functionality beyond the default behavior requires using the methods directly.- property value
Get and set the current value of the item. The caller should use
get()andset()directly for additional control over how these respective calls are handled, the handling invoked here relies on default values for all optional arguments.
- property formatted
Get and set the human-readable representation of the item. For example, the formatted variant of an enumerated type is the string string representation, as opposed to the integer reported as the current item value. These permutations are driven by the JSON configuration of the item. In the absence of any configured formatting the current value will be returned as a string.
This property can also be used to set the new value of the item using the formatted representation.
- property quantity
Get and set the current value of the item as a
pint.Quantityinstance.This property can also be used to set the new value of the item using a valid
pint.Quantityinstance; the provided quantity will be translated to the base units of the item before proceeding.
- get(refresh=False, formatted=False, quantity=False)
Retrieve the current value. Set refresh to True to prompt the daemon responding to the request to return the most up-to-date value available, potentially bypassing any local cache. Set formatted to True to receive the human-readable formatting of the value, if any such formatting is available; similarly, set quantity to true to receive the value as a
pint.Quantityinstance, which will only work if the item is configured to have physical units.Use of the
formatted,quantity, andvalueproperties is encouraged in the case where a synchronous refresh is not required.
- set(new_value, wait=True, reply=True, formatted=False, quantity=False)
Set a new value. Set wait to True to block until the request completes; this is the default behavior. If wait is set to False, the caller will be returned a
mktl.protocol.message.Requestinstance, which has amktl.protocol.message.Request.wait()method that can optionally be invoked to block until completion of the request; the wait will return immediately once the request is satisfied. Set reply to False to disable all error handling and acknowledgements for the request (fire and forget); setting reply to False implies *wait is also False. There is no return value for a blocking request; failed requests will raise exceptions.The optional formatted and quantity options enable calling
set()with either the string-formatted representation or thepint.Quantityrepresentation of the item; the new value is still the first argument, but set one of formatted or quantity to True to indicate it should be interpreted.Use of the
formatted,quantity, andvalueproperties is encouraged in the case where a blocking set operation is desired.
- register(method, prime=False)
Register a callback to be invoked whenever a new value is received from a remote daemon, regardless of how that new value arrived.
subscribe()will automatically be invoked if it has not been invoked for thisIteminstance, the client does not need to call it separately. If prime is set to True the callback will be invoked using the current value of the item, if any, before returning; no priming call will occur if the item has no value.A callback method should expect three arguments: a reference to the
Itemfrom whence the callback originated, the new value for the item, and the timestamp associated with the new value. For example:def my_callback(item, new_value, new_timestamp):
Callback methods should strive to be lightweight in terms of their execution time; any callbacks registered for an item will be called in series, and there are no provisions for shortening the queue if a backlog occurs.
All of the client functionality remains unchanged when an
Itemis used in a daemon context. The following methods have utility when a daemon is authoritative for an item.- from_payload(payload)
Recreate the fundamental Python type of the value from the provided
mktl.protocol.message.Payloadinstance, and return it to the caller.This default handler will interpret the bulk component, if any, of the payload as an N-dimensional numpy array, with the description of the array present in the other fields of the payload.
This is the inverse of
to_payload().
- poll(period)
Poll for a new value every period seconds. Polling will be discontinued if period is set to None or zero. Polling will invoke
req_poll(), and occurs at the requested interval within a background thread unique to this item.
- publish(new_value, timestamp=None, repeat=False)
Publish a new value, which is expected to be the Python native representation of the new value. If timestamp is set it is expected to be a UNIX epoch timestamp; the current time will be used if it is not provided. Newly published values are always cached locally. If repeat is set to True the value will be published regardless of whether it is a repeat of the previously published value.
Note that, for simple cases, an authoritative daemon can set the
valueproperty to publish a new value instead of callingpublish()directly. In other words, these two calls are equivalent:item.value = new_value item.publish(new_value)
- to_payload(value=None, timestamp=None, **kwargs)
Interpret the provided arguments into a
mktl.protocol.message.Payloadinstance; if the value is not specified the current value of thisItemwill be used; if the timestamp is not specified the current time will be used. This is particularly important as a step in a customperform_get()implementation.This is the inverse of
from_payload().
- watch(item)
Register a callback with the referenced item, such that the current item updates itself any time the referenced item changes. This is functionally equivalent to calling:
item.register(self.req_poll)
Some of the daemon-specific methods are intended to be overridden as part of implementing custom, application-specific logic. It may not be necessary to override all of these methods depending on the needs of the application.
- perform_get()
Acquire the most up-to-date value available for this
Itemand return it to the caller. The most common return value is any Python object that can be serialized as JSON; return None if no new value is available.If a
mktl.protocol.message.Payloadinstance is returned it will be used as-is, otherwise the return value will be passed toto_payload()for encapsulation. The primary motivation for returning a Payload instead of a bare value is if the embedded timestamp needs to be set to some value other than the current time.Returning None will not clear the currently known value, that will only occur if the returned Payload instance is assigned None as the ‘value’; this is not expected to be a common occurrence, but if a custom
perform_get()implementation wants that to occur they need to instantiate and return the Payload instance directly rather than useto_payload().
- perform_set(new_value)
Implement any custom behavior that should occur as a result of a set request for this item. No return value is expected. Any subclass implementations should raise an exception in order to trigger an error response.
Any return value, though again none is expected, will be encapsulated via
to_payload(), after the same fashion asperform_get(), and included in the response to the original request.
- validate(value)
A hook for a daemon to validate a new value. The default behavior is a no-op; any checks should raise exceptions if they encounter a problem with the incoming value. The ‘validated’ value must be returned by this method; this allows for the possibility that the incoming value has been translated to a more acceptable format, for example, converting the string ‘123’ to the integer 123 for a numeric item type.
The req_*() set of methods can be overridden, but for nearly all applications their use is strictly internal and further customization should not be necessary.
- req_get(request)
Handle a GET request. The request argument is a
protocol.message.Requestinstance; the value returned fromreq_get()is identical to the value returned byperform_get(), which is where custom handling by subclasses is expected to occur.
- req_poll(repeat=False)
Handle a background poll request, established by calling
poll().perform_get()is where custom handling by subclasses is expected to occur. The payload returned fromreq_poll()is identical to the payload returned byperform_get().A common pattern for custom subclasses involves registering
req_poll()as a callback on other items, so that the value of this item can be refreshed when external events occur. Thewatch()method exists to facilitate that pattern.
- req_set(request)
Handle a SET request. The request argument is a
protocol.message.Requestinstance; the value returned fromreq_set()will be returned to the caller, though no such return value is expected. Any calls toreq_set()are expected to block until completion. Custom handling by subclasses is expected to occur inperform_set().If the publish_on_set attribute is set to True (this is the default) a call to
publish()will occur at the tail end of any successful SET request. Custom subclasses can set this attribute to False to inhibit that behavior.