Python: the shell module

Every Python notebook has the Shell scope in scope as the module shell. The notebook runs from shell import * before the first cell, so the names below are available as written. This page lists them as of this release, and describes how a name, an argument and a result map between C# and Python.

For guides with examples, see Python notebooks.

Not the `curiosity` Python SDK

The Python SDK is a pip package that connects to a workspace from outside, with a token. The shell module exists only inside a Python notebook and has no connection to configure: it is the scope of the administrator who opened the notebook.

The module is generated when the first Python notebook opens, by reflection over the scope class, and kept for later notebooks. A member added to the scope appears in the module without a change here; the list below is what exists today. Its docstring lists the same members: print(shell.__doc__).

Names

Values

Evaluated once, when the notebook starts.

Name Type Description
graph ScopedGraph The graph, with the full access of a Shell script. In a sandboxed notebook it is a ReadOnlyGraph.
current_user UID128 The UID of the administrator who opened the notebook. Pass it to calls that take a user, q(current_user), to see what that user sees.
chat_ai ChatAI Helper for chat AI operations.
agent_ai AgentAI Helper for running agents.
structured_ai StructuredAI Helper for structured AI calls.
tracker QueryTracker The performance tracker shared by every query created in the scope.
progress_reporter IUserProgressReporter Reports progress to the UI. A notebook has none attached, so it does nothing visible.

Functions

Signature Returns Description
q() IQuery A new query. The members of the query are the graph query language in snake_case.
q(user_uid) IQuery A new query that sees what that user sees.
query() IQuery Same as q().
query(user_uid) IQuery Same as q(user_uid).
is_cancellation_requested() bool Whether the running cell was asked to stop. A function, not a value, because the answer changes while a cell runs.
throw_if_cancellation_requested() None Ends the cell as stopped if it was asked to stop.
dataframe(query, *fields) pandas DataFrame The query's nodes as a DataFrame. Added for notebooks. See below.
query_rows(query, *fields) list[dict] The same rows as dictionaries. Added for notebooks.

The notebook also imports the flint module.

Not available from Python

A name is left out of the module, and listed at the end of its docstring, when Python cannot call it:

C# member Python name Why
CancellationToken cancellation_token A .NET struct, not a Studio type. Use is_cancellation_requested().
RunEndpointAsync<T> run_endpoint_async Takes a type argument.
RunToolAsync<T> run_tool_async Takes a type argument.
RunTaskAsync(…) run_task_async Takes a delegate.
GetSecretAsync(SecretUID) get_secret_async Takes a SecretUID, which Python cannot build.
CreateHttpClient() create_http_client Returns a .NET HttpClient, which Python cannot use.

The two secrets and HTTP names are in the Shell scope of a C# notebook; in a sandboxed scope they do not exist.

Naming

Python names are snake_case. The module and every object it returns use the same rule, so completion, dir() and error messages show Python names, and the C# spelling is still accepted when you type it.

C# Python
Q q
StartAt start_at
CurrentUser current_user
AsUIDEnumerable as_uid_enumerable
RunEndpointAsync run_endpoint_async
Parameter userUID Keyword user_uid

A word boundary is a lower-case letter or digit followed by an upper-case letter (StartAt, Base64Encode), and the last capital of an acronym before a word (UIDEnumerable). Keyword arguments match without regard to case or underscores, so q(user_uid=x) and q(userUID=x) are the same call. Names that end in _async keep the suffix and still wait for the result.

Objects

A value of a Studio type, such as the result of q(), is a host object. Reading an attribute reads a property; calling an attribute calls a method.

  • Reach. Only members declared by a Studio type are reachable. The members of object and the .NET framework (GetType(), GetHashCode()) are not, and Internals is not reachable on any type. Reading a name that is not reachable raises AttributeError.
  • Overloads. When a method has several overloads, each is tried in order, fewest parameters first, and the first one every argument converts to is called. When none fits, the call raises TypeError listing each overload and why it did not fit.
  • Optional parameters take their default. Keywords name parameters.
  • Not callable from Python: methods that take a delegate or a type argument, and indexers.
  • Iteration. An object that is a collection can be used in a for loop, in list(...) and with len(...).
  • Text. print(obj) shows the object's text form, <Query> when it has none.

Arguments

Python Converts to
None null
bool bool
int Any integer type, or float, double, decimal; an int that does not fit moves on to the next overload
float double, float, decimal
str string; an enum member, by name; a Guid; any type that reads from text, such as a UID
bytes byte[]
list, tuple An array, a List<T> or an IEnumerable<T>, converting each item
dict A Dictionary<K, V> or an IDictionary<K, V>
A host object The object itself, where the parameter accepts its type
Anything for object The natural .NET value: long, double, string, bool, List<object>

Results

From the scope In Python
bool, numbers, string, char bool, int or float, str
Task, Task<T>, ValueTask<T> The result, after waiting for it
An enum str, the member name
A UID, a Guid, a date or time, a Type str, its text form
byte[] bytes
A dictionary dict
A list or array of any other type list, up to 1,000,000 items; more raises MemoryError
An object of a Studio type A host object
Any other type str, its text form

Waiting for results

A method that returns a task is waited for before Python sees its result, by blocking the thread that runs the cell. That is safe because each cell runs on a thread of its own. The wait honors a stop: the cell's token is the scope's CancellationToken.

Errors

Raised in the scope Python
ArgumentException, FormatException ValueError
KeyNotFoundException KeyError
UnauthorizedAccessException PermissionError
NotSupportedException, NotImplementedException NotImplementedError
OperationCanceledException Not catchable: the cell ends as stopped (KeyboardInterrupt)
Any other exception RuntimeError: <Type>: <message>

dataframe and query_rows

dataframe(query, *fields)
query_rows(query, *fields)

query is a query, or a list of nodes such as list(q().start_at("Ticket").as_enumerable()). With no fields, the columns are UID, Type, then every field in the order it is first seen. With fields, only those columns, in that order; "Timestamp" can be named. A node without a field has None there.

  • Fields hidden by the schema are not included.
  • Node types that never leave the server, such as secrets and tokens, are dropped from a query, as emit drops them.
  • Values are int, float, str, bool and list. A time or a UID is its text.
  • More than 100,000 nodes raises RuntimeError with A table takes at most 100000 rows. Narrow the query first. Nothing is cut silently.

dataframe imports pandas when it is called. query_rows returns the same rows without it.

df = dataframe(q().start_at("Ticket"), "Status", "Priority")
df.groupby("Status").size()