atoti.experimental.distributed.session module

class atoti.experimental.distributed.session.DistributedSession(name, *, config, detached_process)

Holds a connection to the Java gateway.

close()

Close this session and free all the associated resources.

Return type

None

property closed: bool

Return whether the session is closed or not.

Return type

bool

create_cube(name)

Create a distributed cube.

Parameters

name (str) – The name of the created cube.

Return type

DistributedCube

property cubes: atoti.experimental.distributed.cubes.DistributedCubes

Cubes of the session.

Return type

DistributedCubes

endpoint(route, *, method='GET')

Create a custom endpoint at /atoti/pyapi/{route}".

This is useful to reuse atoti’s built-in server instead of adding a FastAPI or Flask server to the project. This way, when deploying the project in a container or a VM, only one port (the one of the atoti server) can be exposed instead of two. Since custom endpoints are exposed by atoti’s server, they automatically inherit from the configured atoti.config.session_config.SessionConfig.authentication and atoti.config.session_config.SessionConfig.https parameters.

The decorated function must take three parameters with types User, HttpRequest, and Session and return a response body as a Python data structure that can be converted to JSON.

Parameters
  • route (str) –

    The path suffix after /atoti/pyapi/. For instance, if custom/search is passed, a request to /atoti/pyapi/custom/search?query=test#results will match. The route should not contain the query (?) or fragment (#).

    Path parameters can be configured by wrapping their name in curly braces in the route.

  • method (Literal[‘POST’, ‘GET’, ‘PUT’, ‘DELETE’]) – The HTTP method the request must be using to trigger this endpoint. DELETE, POST, and PUT requests can have a body but it must be JSON.

Example

>>> import requests
>>> df = pd.DataFrame(
...     columns=["Year", "Month", "Day", "Quantity"],
...     data=[
...         (2019, 7, 1, 15),
...         (2019, 7, 2, 20),
...     ],
... )
>>> table = session.read_pandas(df, table_name="Quantity")
>>> table.head()
Year  Month  Day  Quantity
0  2019      7    1        15
1  2019      7    2        20
>>> endpoints_base_url = f"http://localhost:{session.port}/atoti/pyapi"
>>> @session.endpoint("tables/{table_name}/size", method="GET")
... def get_table_size(request, user, session):
...     table_name = request.path_parameters["table_name"]
...     return len(session.tables[table_name])
>>> requests.get(f"{endpoints_base_url}/tables/Quantity/size").json()
2
>>> @session.endpoint("tables/{table_name}/rows", method="POST")
... def append_rows_to_table(request, user, session):
...     rows = request.body
...     table_name = request.path_parameters["table_name"]
...     session.tables[table_name].append(*rows)
>>> requests.post(
...     f"{endpoints_base_url}/tables/Quantity/rows",
...     json=[
...         {"Year": 2021, "Month": 5, "Day": 19, "Quantity": 50},
...         {"Year": 2021, "Month": 5, "Day": 20, "Quantity": 6},
...     ],
... ).status_code
200
>>> requests.get(f"{endpoints_base_url}/tables/Quantity/size").json()
4
>>> table.head()
Year  Month  Day  Quantity
0  2019      7    1        15
1  2019      7    2        20
2  2021      5   19        50
3  2021      5   20         6
Return type

Any

explain_mdx_query(mdx, *, timeout=30)

Run the query but return an explanation of how the query was executed instead of its result.

See also

query_mdx() for the roles of the parameters.

Return type

QueryAnalysis

Returns

An explanation containing a summary, global timings, and the query plan with all the retrievals.

export_translations_template(path)

Export a template containing all translatable values in the session’s cubes.

Parameters

path (Union[str, Path]) – The path at which to write the template.

Display a link to this session.

Clicking on the link will open it in a new browser tab.

Note

This method requires the atoti-jupyterlab plugin.

The extension will try to access the session through (in that order):

  1. Jupyter Server Proxy if it is enabled.

  2. f"{session_protocol}//{jupyter_server_hostname}:{session.port}" for Session and session.url for QuerySession.

Parameters

path (str) – The path to append to the session base URL. Defaults to the session home page.

Example

Pointing directly to an existing dashboard:

dashboard_id = "92i"
session.link(path=f"#/dashboard/{dashboard_id}")
Return type

Any

property logs_path: pathlib.Path

Path to the session logs file.

Return type

Path

property name: str

Name of the session.

Return type

str

property port: int

Port on which the session is exposed.

Can be configured with port.

Return type

int

query_mdx(mdx, *, keep_totals=False, timeout=30)

Execute an MDX query and return its result as a pandas DataFrame.

Parameters
  • mdx (str) – The MDX SELECT query to execute. Regardless of the axes on which levels and measures appear in the MDX, the returned DataFrame will have all levels on rows and measures on columns.

  • keep_totals (bool) – Whether the resulting DataFrame should contain, if they are present in the query result, the grand total and subtotals. Totals can be useful but they make the DataFrame harder to work with since its index will have some empty values.

  • timeout (int) – The query timeout in seconds.

Example

>>> from datetime import date
>>> df = pd.DataFrame(
...     columns=["Country", "Date", "Price"],
...     data=[
...         ("China", date(2020, 3, 3), 410.0),
...         ("China", date(2020, 4, 4), 350.0),
...         ("France", date(2020, 1, 1), 480.0),
...         ("France", date(2020, 2, 2), 500.0),
...         ("France", date(2020, 3, 3), 400.0),
...         ("France", date(2020, 4, 4), 420.0),
...         ("India", date(2020, 1, 1), 360.0),
...         ("India", date(2020, 2, 2), 400.0),
...         ("UK", date(2020, 2, 2), 960.0),
...     ],
... )
>>> table = session.read_pandas(
...     df, keys=["Country", "Date"], table_name="Prices"
... )
>>> _ = session.create_cube(table)

This MDX:

>>> mdx = (
...     "SELECT"
...     "  NON EMPTY Hierarchize("
...     "    DrilldownLevel("
...     "      [Prices].[Country].[ALL].[AllMember]"
...     "    )"
...     "  ) ON ROWS,"
...     "  NON EMPTY Crossjoin("
...     "    [Measures].[Price.SUM],"
...     "    Hierarchize("
...     "      DrilldownLevel("
...     "        [Prices].[Date].[ALL].[AllMember]"
...     "      )"
...     "    )"
...     "  ) ON COLUMNS"
...     "  FROM [Prices]"
... )

would display this pivot table:

Country

Price.sum

Total

2020-01-01

2020-02-02

2020-03-03

2020-04-04

Total

2,280.00

840.00

1,860.00

810.00

770.00

China

760.00

410.00

350.00

France

1,800.00

480.00

500.00

400.00

420.00

India

760.00

360.00

400.00

UK

960.00

960.00

but will return this DataFrame:

>>> session.query_mdx(mdx).sort_index()
                    Price.SUM
Date       Country
2020-01-01 France       480.0
           India        360.0
2020-02-02 France       500.0
           India        400.0
           UK           960.0
2020-03-03 China        410.0
           France       400.0
2020-04-04 China        350.0
           France       420.0
Return type

QueryResult

property security: atoti_plus.security.Security
Return type

Security

visualize(name=None)

Display an atoti widget to explore the session interactively.

Note

This method requires the atoti-jupyterlab plugin.

The widget state will be stored in the cell metadata. This state should not have to be edited but, if desired, it can be found in JupyterLab by opening the “Notebook tools” sidebar and expanding the the “Advanced Tools” section.

Parameters

name (Optional[str]) – The name to give to the widget.

wait()

Wait for the underlying server subprocess to terminate.

This will prevent the Python process to exit.

Return type

None