Package: katsdptelstate
MeerKAT Science Data Processor Telescope StateThis is a client package that allows connection to a database that
stores telescope state information for the Science Data Processor of the
MeerKAT radio telescope. This database is colloquially known astelstate.The telescope state is a key-value store. There are three types of keys:immutables (akaattributes)Stores a single value that is not allowed to change once set.mutables (akasensors)Stores multiple timestamped values organised into an ordered set.indexedStores a dictionary of key-value pairs, each of which behaves like an
immutable. This is useful to avoid the main key-space becoming too large.
It also supports some patterns like incrementally storing values but
fetching all values in a single operation. Furthermore, it allows more
general keys than just strings.The keys are strings and the values (and the sub-keys of indexed keys) are
Python objects serialised viaMessagePack, which has been extended to support
tuples, complex numbers and NumPy arrays. Older versions of the database stored
the values as pickles, and the package warns the user if that’s the case. Keys
can be retrieved from the telstate object using attribute syntax or dict
syntax.Databases can be accessed via one of two backends: a Redis client backend
that allows shared access to an actual Redis server over the network (or a
simulated server via fakeredis) and a simplified in-memory backend for
stand-alone access. Both backends support loading and saving a Redis snapshot
in the form of an RDB dump file.It is possible to have multipleviewson the same database (one per telstate
instance). A view is defined as a list ofprefixesacting as namespaces that
group keys. When reading from the database, each prefix is prepended to the key
in turn until a match is found. When writing to the database, the first prefix
is prepended to the key. The first prefix therefore serves as the primary
namespace while the rest are supplementary read-only namespaces.WarningWARNING: The standard warning about Python pickles applies. Never
retrieve data from an untrusted telstate database with values encoded as
pickles, or connect to such a database over an untrusted network. Pickle
support is disabled by default, but can be enabled for trusted databases
by setting the environment variable KATSDPTELSTATE_ALLOW_PICKLE=1.Getting StartedThe simplest way to test outkatsdptelstateis to use the in-memory backend.
If you want to run a real Redis server you will need to install Redis (version
4.0 or newer) on a suitable machine on the network. For example, do this:macOS:brew install redisUbuntu:apt-getinstallredis-serverThenpip install katsdptelstateand run a localredis-server. If you
also want to load RDB files, dopip install katsdptelstate[rdb].A Simple Exampleimporttimeimportkatsdptelstate# Connect to an actual Redis server via an endpoint or an URLtelstate=katsdptelstate.TelescopeState('localhost:6379')telstate=katsdptelstate.TelescopeState('redis://localhost')# Or use the in-memory backend (useful for testing)telstate=katsdptelstate.TelescopeState()# Load RDB file into Redis if katsdptelstate is installed with [rdb] optiontelstate.load_from_file('dump.rdb')# Attribute / dict style access returns the latest valuetelstate.add('n_chans',32768)print(telstate.n_chans)# -> 32768print(telstate['n_chans'])# -> 32768# List all keys (attributes and sensors)print(telstate.keys())# -> ['n_chans']# Sensors are timestamped underneathst=time.time()telstate.add('n_chans',4096)et=time.time()telstate.add('n_chans',16384)# Time ranges can be used and are really fasttelstate.get_range('n_chans',st=st,et=et)# -> [(4096, 1556112474.453495)]# Add an item 10 seconds backtelstate.add('n_chans',1024,ts=time.time()-10)# Attributes cannot be changed (only deleted)telstate.add('no_change',1234,immutable=True)# Adding it again is OK as long as the value doesn't changetelstate.add('no_change',1234,immutable=True)# Simpler notation for setting attributestelstate['no_change']=1234# Will raise katsdptelstate.ImmutableKeyErrortelstate['no_change']=456# Create a new view with namespace 'ns' and standard underscore separatorview=telstate.view('ns')# Insert a new attribute in this namespace and retrieve itview['x']=1print(view['x'])# -> 1print(view.prefixes)# -> ('ns_', '')print(view.keys())# -> ['n_chans', 'no_change', 'ns_x']Asynchronous interfaceThere is also an interface that works with asyncio. Usekatsdptelstate.aio.TelescopeStateinstead ofkatsdptelstate.TelescopeState. Functions that interact with the database are now
coroutines. Python 3.6+ is required.There are a few differences from the synchronous version, partly necessary due
to the nature of asyncio and partly to streamline and modernise the code:The constructor only takes a backend, not an endpoint. See below for an
example of how to construct a redis backend.There is currently no support for reading or writing RDB files; you’ll need
to create a synchronous telescope state client that connects to the same
storage.There is no support for attribute-style access.Item-style access is supported for read (awaitts.get('key')), but not
for write. Useawaitts.set('key','value')instead to set immutable
keys.Instead ofkey in ts, useawait ts.exists(key).Thewait_keyandwait_indexedmethods do not take a timeout or a
cancellation future. They can be used with asyncio’s cancellation machinery.
Theasync-timeoutpackage is useful for timeouts.The backend should be closed when no longer needed to avoid warnings.Examplefromkatsdptelstate.aioimportTelescopeStatefromkatsdptelstate.aio.redisimportRedisBackend# Create a connection to localhost redis serverbackend=awaitRedisBackend.from_url('redis://localhost')ts=TelescopeState(backend)# Store and retrieve some dataawaitts.set('key','value')print(awaitts.get('key'))# Close the connections (do not try to use ts after this)ts.backend.close()awaitts.backend.wait_closed()History0.14 (2024-02-28)Improvements to internal type hints (#133)Get lupa version (for testing) from katsdpdockerbase (#134)Fix variables referenced before use in exception path (#135)Improve error message when opening old files containing pickles (#136)0.13 (2023-03-15)Upgrade to redis-py>=4.2 and fakeredis>=2, fix test warnings (#132)This now requires at least Python 3.7 and no more aioredis0.12 (2023-03-13)Switch to aioredis 2.x (#124)Add async (and synchronous)RedisBackend.from_urlconstructor (#125, #126)Switch from nose to pytest (#129)RemoveEndpoint.multicast_subscribeandnetifacesdependency (#130)Fix Lua script forset_indexedso thatwait_indexedactually works (#127)Make aiowait_keymore robust (#128)General cleanup (#122, #123)0.11 (2021-05-07)Add asynchronous RDBWriter class (#108)Use a transaction for get_range instead of Lua: faster on server side (#110)Multiplex aio pubsubs over pool’s standard connection (#113)Require hiredis for speed and aioredis<2 for compatibility (#114, #118)Improvewait_keysresponsiveness forMemoryBackend(#111, #116)Avoid blocking the Redis server on telstate.clear (#112)Update Docker image to use Redis 6.x instead of 4.x (#109)Support older HMSET Redis command in unit tests (#107)Requirements cleanup (#115, #117, #119, #120)0.10 (2020-05-25)Remove Python 2 support. At least Python 3.5 is required.Remove support for old versions of redis-py (#100)Use redis-py health checks to improve robustness (#99)Add “indexed” keys (#98)Add an asyncio interface (#103)No longer throw InvalidKeyError when setting a key that shadows a method (#102)Add type annotations for mypy (#101)0.9 (2020-05-25)Deprecate Python 2 support: this is the last release that will support Python 2 (#94)Removeget_messageandsend_message, which were never used (#89)Publish the documentation onhttps://katsdptelstate.readthedocs.io(#90)Disable pickles by default for security (#92)0.8 (2019-05-06)The default encoding is now msgpack; warn on loading pickles (#75, #79)The default backend is now in-memory (#76)Add the ability to dump in-memory backend to an RDB file (#77)Construct from RDB file-like objects and Redis URLs (#80, #82)Report keys and prefixes to the user as strings (#73)Add IPython tab completion (#83)RDB reader and writer cleanup (#85, #86)0.7 (2019-02-12)Introduce encodings and add msgpack encoding as alternative to pickle (#64, #65)Introduce backends and add in-memory backend as alternative to redis (#71, #72)Simplify setting attributes via__setitem__(#68)Let keys be bytes internally, but allow specification as unicode strings (#63)The GitHub repository is now public as well0.6 (2018-05-10)Initial release of katsdptelstate