0.7.0 (August 16, 2022)#
Added#
DirectQuery plugins.
Ability to change the
default_valueof aColumn.AggregateProviderto speed up queries by pre-aggregating some measures on specified levels.
Functions#
User interface#
Ability to hide and show table columns.
Changed#
Tableis automatically partitioned for improved default performance.
User interface#
Upgraded Atoti UI to 5.0.15.
Functions and methods#
The following changes are BREAKING.
The signature of the
atoti.aggfunctions have been clarified:The signature of functions creating measures in the
atoti,atoti.array, andatoti.mathmodules and of the methodsSession.read_*()andTable.load_*()have been changed to make more parameters positional-only.read_csv()andload_csv()’s separator and process_quotes parameters default to","andTrue(respectively).Nonecan still be passed to force the inference of these arguments in a preliminary partial read of the CSV file.read_csv()andload_csv()attempt to parse dates in the ISO 8601 format only. To parse dates in other formats, specify their pattern in the date_patterns argument.date_shift()results are not impacted by conditions and filters when executing a query (same behavior asshift()).atoti.scope.cumulative()with a time period window matches pandas and Excel’s behavior (issue #396).scope=tt.scope.cumulative( l["datetime"], - window=("-1D", None), + window=("-2D", None) )
delete_scenario()’s scenario parameter has been renamed name.
Other#
The following changes are BREAKING.
Different
TablewithColumnwith the same name can be joined (issue #655).Saved drillthrough widgets must be recreated as their MDX query has changed to use both the table and column names to uniquely reference a field.
atoti_plus.security.Restrictionsmust specify both the table and column names using a tuple.
The
DataTypeclass has been replaced with aLiteraltype. The main data types still have constants inatoti.type. Nullable types have been removed, set thedefault_valuetoNoneinstead for non-numeric types:- session.create_table("Example", types={"String": tt.type.NULLABLE_STRING}) + session.create_table("Example", types={"String": tt.STRING}, default_values={"String": None})
Default values for temporal
Columnhave been changed from"N/A"to actual temporal values. Seedefault_valuefor an exhaustive list.Passing a
UserContentStorageConfigpointing to a local H2 database will not automatically migrate the database to H2 v2 format during session startup anymore. Downgrade to Atoti 0.6.6 and start a session configured to use this local H2 database to migrate it to v2 format to be able to use the database with Atoti 0.7.0.
Deprecated#
Scope factory functions
atoti.scope.cumulative(),atoti.scope.origin(), andatoti.scope.siblings(). Instantiate their corresponding class instead:CumulativeScope,OriginScope, andSiblingsScope(respectively).value()function. Useatoti.agg.single_value()instead:- m["City.VALUE"] = tt.value(table["City"]) + m["City.VALUE"] = tt.agg.single_value(table["City"])
date_shift()’s offset andatoti.scope.cumulative()’s window values missing a duration designator ("P").atoti.Cube.query(),atoti_query.QueryCube.query()andexplain_query()’s condition parameter has been deprecated and renamed filter.Passing a
Leveltoshift()’s on parameter. Pass aHierarchyinstead.
Removed#
The following removals are BREAKING.
Ability to create a
Hierarchyon a nullableColumn. Set the column’sdefault_valueto something different thanNonebefore creating theHierarchyinstead.Implicit required levels. Measures created from
value(),Level, or conditions implicitly added aOriginScopeon the corresponding level(s) in subsequent calls toatoti.aggfunctions. This undocumented behavior has been removed so these implicit scopes will have to be defined explicitly. For example:table = session.create_table( "example", types={ "Product": tt.STRING, "Date": tt.LOCAL_DATE, "Price": tt.INT, }, keys=["Product", "Date"], ) cube = session.create_cube(table) l, m = cube.levels, cube.measures price_column = table["Price"] - m["Price"] = tt.agg.sum(tt.value(price_column)) + m["Price"] = tt.agg.sum( + tt.agg.single_value(price_column), + # Levels corresponding to the key columns of `price_column`'s table. + scope=tt.OriginScope(l["Product"], l["Date"]), + )
Note: The example above illustrates the required changes but is contrived:
tt.agg.sum(price_column)would be better in both cases.Set the
ATOTI_REQUIRED_LEVELS_WARNINGenvironment variable to"True"to be warned of the creation of measures that used to have required levels.value()’s levels parameter. Use a combination ofatoti.agg.single_value()andwhere()instead:- m["City.VALUE"] = tt.value(table["City"], levels=[l["Country"]]) + m["City.VALUE"] = tt.where( + l["Country"] != None, + tt.agg.single_value(table["City"]), + )
Parameter hierarchized_columns of table creation methods (
create_table(),read_pandas(),read_spark(),read_csv(),read_parquet(),read_numpy()andread_sql()). Create hierarchies in batch withatoti.hierarchies.Hierarchies.updateinstead:table = session.create_table( "Product", types={"Date": tt.LOCAL_DATE, "Product": tt.STRING, "Quantity": tt.DOUBLE}, keys=["Date"], - hierarchized_columns=["Date", "Product"], ) cube = session.create_cube(table, mode="manual") + cube.hierarchies.update({name: {name: table[name]} for name in ["Date", "Product"]})
atoti.__version__. Useimportlib.metadata’sversion()like for any other library instead:import atoti as tt + from importlib.metadata import version - atoti_version = tt.__version__ + atoti_version = version(tt.__name__)
date_shift()’s offset andatoti.scope.cumulative()’s window support of quarter units. Use"3M"instead of"1Q".Support for remote content servers. Configure the user content storage with a JDBC
urlinstead.The custom
Exceptionclasses have been made private.atoti.Table.loading_reporthas been made private.
Previously deprecated#
create_session()andopen_query_session(). InstantiateSessionandQuerySession(respectively) instead.QuerySession’s name attribute.atoti.querymodule. Instead, import functions and classes fromatotiif installed or fromatoti-queryotherwise.atoti.query.create_basic_authenticationandatoti.query.create_token_authentication. UseBasicAuthenticationandTokenAuthenticationinstead.atoti.level.Level.comparator.instead of
atoti.comparator.ASCENDINGandatoti.comparator.DESCENDING, useNaturalOrder.instead of
atoti.comparator.first_members(), useCustomOrder.
Passing timeouts as instances of
int. Usedatetime.timedeltainstead.create_parameter_simulation()measure_name and default_value parameters. Use the measures parameter instead.Context value keys
queriesResultLimit.intermediateSizeandqueriesResultLimit.transientSizeinshared_context,query(), andquery_mdx(). UsequeriesResultLimit.intermediateLimitandqueriesResultLimit.transientLimit(respectively) instead.atoti_kafka.create_deserializer()andload_kafka()’s deserializer parameter. Only supported records are JSON objects with keys matchingTable’s columns.
Config#
atoti.config.session_config.SessionConfig.awsandatoti.config.session_config.SessionConfig.azure. Useread_csv(),load_csv(),read_parquet(), orload_parquet()’s client_side_encryption parameter instead.atoti_aws.create_aws_key_pair()andatoti_aws.create_aws_kms_config(). InstantiateAwsKeyPairandAwsKmsConfig(respectively) instead.atoti_azure.create_azure_key_pair(). InstantiateAzureKeyPairinstead.Session’s certificate_authority parameter. UseHttpsConfig’s certificate_authority parameter instead.atoti.LdapConfig.role_mappingandatoti.OidcConfig.role_mapping. Useatoti_plus.security.LdapSecurity.role_mappingandatoti_plus.security.OidcSecurity.role_mapping(respectively) instead.atoti.LoggingConfig.file_path. Useatoti.LoggingConfig.destinationinstead.
Fixed#
drop()’s deletion ofNonevalues (issue #610).