0.9.4 (Feb 28, 2025)#

Distribution#

The name QuerySession, unused since 0.9.0 (September 13, 2024), makes a come back in this release but, this time, with a different meaning. QuerySession becomes the entry point to create clusters of Atoti applications [6].

atoti.Cube.restrictions has been introduced to secure query sessions. For the sake of symmetry, atoti.Session.security.restrictions has moved to atoti.tables.Tables.restrictions (the old location remains available but is deprecated).

Learn how to Scale with distribution.

Performance#

Client/server communication#

Most components of Session are exposed through mappings such as Cubes or Tables. As a project grows, a lot of mapping lookups will be made to iteratively define the data model or to pass arguments to methods such as atoti.Cube.query(). For instance, the following code will make 3 lookups:

new_measure = tt.agg.sum(
    m["Foo.SUM"], # 1
    scope=tt.OriginScope({
        l["Bar"], # 2
        l["Baz"], # 3
    })
)

Each lookup makes a request to the server to check that the key exists. This is pretty quick but, when thousands of lookups are made, this client/server communication can add up. mapping_lookup() allows skipping these server requests.

Cube queries#

The aggregate cache of a cube can be restricted to a subset of measures [3]. This improvement comes with a new atoti.Cube.aggregate_cache API deprecating the previous atoti.Cube.aggregates_cache (with an “s”) one:

- cube.aggregates_cache.capacity = 200
+ cube.aggregate_cache = tt.AggregateCache(capacity=200)
- cube.aggregates_cache.capacity = -1
+ del cube.aggregate_cache

Hierarchy creation#

Creating hierarchies from columns of a table fully joined (i.e. all their keys are mapped) to the cube’s fact table do not require “rebuilding” the cube anymore [4]. This means that no time will be lost reindexing hierarchies or performing other expensive computations.

Data modeling#

Measures#

atoti.where() was not respecting the order of condition_to_value when the same value was assigned to multiple conditions [2]. For example, in:

m["8"] = 8
m["Test"] = tt.where(
    {
        m["8"] < 5: -1, # False
        m["8"] >= 5: 1, # True
        m["8"] < 10: -1, # True
    },
    default=0,
)

Test was equal to -1 because the first and last conditions, being both assigned to the same value, were merged together and that merged condition became the first one evaluating to True. This incorrect merging of conditions has been removed: m["8"] >= 5 is correctly detected as the first condition evaluating to True and so Test is equal to 1.

Table columns#

Columns with an arrray data type can be made non-nullable. atoti.Column.default_value’s documentation has been updated accordingly.

Data loading#

Transactions#

data_transaction()’s tables parameter allows some data transactions to execute concurrently [1].

CSV#

The atoti.CsvLoad.true_values and atoti.CsvLoad.false_values attributes can be configured to parse more values than "True", "true", "False", and "false" as "boolean" [5].

Dependencies#

  • Atoti Server has been upgraded to 6.1.4.

  • Atoti UI and Atoti Admin UI have been upgraded to 5.2.6.

Internal issue tracker references