Basic Usage

Container Objects

As a simple application example, we generate and store a list of random integer numbers. Parameters are quantity and range of the numbers. At first, we import the Python package random module and the class Container from the package scidatacontainer:

>>> import random
>>> from scidatacontainer import Container

Then we generate a parameter dictionary and the actual test data:

>>> p = {"quantity": 8, "minValue": 1, "maxValue": 6}
>>> data = [random.randint(p["minValue"], p["maxValue"]) for i in range(p["quantity"])]
>>> data
[2, 5, 1, 3, 1, 4, 4, 4]

If a default author name and e-mail address was made available as explained in the Configuration section, there are just two additional attributes, which you must provide. One is the type of the container and the other a title of the dataset. Together with the raw data and the dictionary of parameters, we can now build the dictionary of container items:

>>> items = {
...          "content.json": {
...                           "containerType": {"name": "myRandInt"},
...                          },
...          "meta.json": {
...                        "title": "My first set of random numbers",
...                       },
...          "sim/dice.json": data,
...          "data/parameter.json": p,
...         }

Now we are ready to build the container, store it in a local file and get a short description of its content:

>>> dc = Container(items=items)
>>> dc.write("random.zdc")
>>> print(dc)
Complete Container
        type:        myRandInt
        uuid:        306e2c2d-a9f6-4306-8851-1ee0fceeb852
        created:     2023-02-28T10:03:44+0100
        storageTime: 2023-02-28T10:03:44+0100
        author:      Reinhard Caspary

Feel free to check the content of the file random.zdc now by opening it on the operating system level. Be reminded that the Windows Explorer requires the file extension .zdc to be registered first as in the Configuration section. Recovering the dataset from the local file as a new container object works straight forward:

>>> dc = Container(file="random.zdc")
>>> dc["sim/dice.json"]
[2, 5, 1, 3, 1, 4, 4, 4]

Server Storage

Container files can be stored on and retrieved from a specific data storage server. If the server name and an API key was made available as explained in the Configuration section, upload and download of a container is as simple as:

>>> dc.upload()
>>> dc = Container(uuid="306e2c2d-a9f6-4306-8851-1ee0fceeb852")

The server makes sure that UUIDs are unique. Once uploaded, a container can never be modified on a server. The only exemption are incomplete containers.

In the rare case that a certain container needs to be replaced, the attribute replaces may be used in content.json. Once uploaded, the server will always deliver the new container, even if the container with the old UUID is requested. Only the owner of a container is allowed to replace it.

Timestamps

You may use the function timestamp() to generate a timestamp in the format required by the Container class:

>>> from scidatacontainer import timestamp
>>> timestamp()
2023-03-24T21:50:34+0100

Incomplete Containers

As already mentioned, incomplete containers are a container variant which is intended for long running measurements or simulations. As long as the attribute complete in content.json has the value False, a container may be uploaded repeatedly, each time replacing the container with the same UUID on the server:

>>> items["content.json"]["complete"] = False
>>> dc = Container(items=items)
>>> dc.upload()
>>> dc["content.json"]["uuid"]
'306e2c2d-a9f6-4306-8851-1ee0fceeb852'

The server will only accept containers with increasing modification timestamps. Since the resolution of the internal timestamps is a second, you must wait at least one second before the next upload:

>>> dc = Container(uuid="306e2c2d-a9f6-4306-8851-1ee0fceeb852")
>>> dc["meas/newdata.json"] = newdata
>>> dc.upload()

For the final upload, the container must be marked as being complete. This makes this container immutable:

>>> dc = Container(uuid="306e2c2d-a9f6-4306-8851-1ee0fceeb852")
>>> dc["meas/finaldata.json"] = finaldata
>>> dc["content.json"]["complete"] = True
>>> dc.upload()

Static Containers

A static container is generated by calling the method freeze() of the container object. It is intended for static parameters in contrast to measurement or simulation data:

>>> dc = Container(items=items)
>>> dc.freeze()
>>> print(dc)
Static Container
        type:        myRandInt
        uuid:        2a7eb1c5-5fe8-4c92-be1d-2f1207b0d855
        hash:        bafc6813d92bd23b06b63eed035ba9b33415acc770c9128f47775ab2d55cc152
        created:     2023-03-01T21:01:20+0100
        storageTime: 2023-03-01T21:01:20+0100
        author:      Reinhard Caspary

Freezing a container will set the attribute static in content.json to True, which makes this container immutable and it calculates an SHA256 hash of the container content. When you try to upload a static container and there is another static container with the same attributes containerType.name and hash, the content of the current container object is silently replaced by the original one from the server.