Pygrister API reference.¶
Pygrister: a Python client for the Grist API.¶
Grist is a relational spreadsheet with tons of batteries included. The Grist API allows you to programmatically retrieve/update your data stored on Grist, and manipulate most of the basic Grist objects, such as workspaces, documents, user permissions and so on.
Pygrister is a basic Grist client, wrapping all the documented APIs. Pygrister keeps track of some configuration for you, remembering your team site, workspace, working document, so that you don’t have to type in the boring stuff every time. Apart from that and little else, Pygrister is rather low-level: it will call the api and retrieve the response “as is”. If the api call is malformed, you will simply receive a bad HTTP status code.
Pygrister will not attempt to convert sent and received data types: however, it will execute custom converter functions, if provided.
Basic usage goes as follows:
from pygrister.api import GristApi
grist = GristApi()
# list users/permissions for the current document
status_code, response = grist.list_doc_users()
# fetch all rows in a table
status_code, response = grist.see_records('Table1')
# add a column to a table
cols = [{'id': 'age', 'fields': {'label':'age', 'type': 'Int'}}]
status_code, response = grist.add_cols('Table1', cols)
You should read the documentation first, to learn about the basic Pygrister concepts, patterns and configurations. However, the api call functions themselves are not documented in Pygrister: see the Grist API reference documentation for details about each api signature, and browse the Pygrister test suite for more usage examples.
- pygrister.api.get_config() dict[str, str]¶
the global, “static” configuration
- pygrister.api.check_safemode(funct)¶
If Pygrister is in safemode, no writing API call will pass through.
- class pygrister.api.Paginator(provider, start, items, lenname, res_transform, **query_args)¶
A simple iterable object to wrap Api calls that needs pagination.
The main GristApi class.¶
- class pygrister.api.GristApi(config: dict[str, str] | None = None, in_converter: dict | None = None, out_converter: dict | None = None, custom_configurator: Configurator | None = None, custom_apicaller: ApiCaller | None = None)¶
- in_converter¶
converters for input data
- out_converter¶
converters for output data
- reconfig(config: dict[str, str] | None = None) None¶
Reload the configuration options.
A shortcut for
self.configurator.recongif(config).
- update_config(config: dict[str, str]) None¶
Edit the configuration options.
A shortcut for
self.configurator.update_config(config).
- make_server(team_name: str = '') str¶
Construct the “server” part of the API url, up to “/api”.
A shortcut for
self.configurator.make_server(team_name).
- open_session() None¶
Open a Requests sessions for all subsequent Api calls.
A shortcut for
self.apicaller.open_session().
- close_session() None¶
Close an open session, if any.
A shortcut for
self.apicaller.close_session().
- property ok: bool¶
Falseif a HTTP error occurred in the response.If no response was retrieved,
okwill beFalseby default. A shortcut forself.apicaller.ok.
- inspect(sep: str = '\n', max_content: int = 1000) str¶
Collect info on the last api call that was requested (and possibly responded to) by the server.
Use
septo set a custom separator between elements, andmax_contentto limit the response content size.A shortcut for
self.caller.inspect().
- list_service_accounts() tuple[int, Any]¶
Implement GET
/service-accounts.If successful, response will be a
list[dict]of account details.
- add_service_account(expire: str, label: str = '', description: str = '') tuple[int, Any]¶
Implement POST
/service-accounts.If successful, response will be a tuple of service id and key.
- see_service_account(service_id: int) tuple[int, Any]¶
Implement GET
/service-accounts/{saId}.If successful, response will be a
dictof service details.
- update_service_account(service_id: int, expire: str = '', label: str = '', description: str = '') tuple[int, Any]¶
Implement PATCH
/service-accounts/{saId}.If successful, response will be
None.
- delete_service_account(service_id: int) tuple[int, Any]¶
Implement DELETE
/service-accounts/{saId}.If successful, response will be
None.
- update_service_account_key(service_id: int) tuple[int, Any]¶
Implement POST
/service-accounts/{saId}/apikey.If successful, response will be the new key as
str.
- delete_service_account_key(service_id: int) tuple[int, Any]¶
Implement DELETE
/service-accounts/{saId}/apikey.If successful, response will be
None.
- see_user(user_id: int) tuple[int, Any]¶
Implement GET
/scim/v2/Users/{userId}.If successful, response will be a
dictof user details. If scim is not enabled, will return Http 501.
- see_myself() tuple[int, Any]¶
Implement GET
/scim/v2/Me.If successful, response will be a
dictof logged-in user’s details. If scim is not enabled, will return Http 501.
- see_profile() tuple[int, Any]¶
Implement GET
/profile/user.If successful, response will be a
dictof current user profile data.
- update_profile_name(name: str) tuple[int, Any]¶
Implement POST
/profile/user/name.If successful, response will be
None.
- update_profile_locale(locale: str) tuple[int, Any]¶
Implement POST
/profile/user/locale.If successful, response will be
None.
- see_apikey() tuple[int, Any]¶
Implement GET
/profile/apikey.If successful, response will be the key as
str.
- new_apikey(force: bool = True) tuple[int, Any]¶
Implement POST
/profile/apikey.If successful, response will be the key as
str.
- delete_apikey() tuple[int, Any]¶
Implement DELETE
/profile/apikey.If successful, response will be
None.
- see_session() tuple[int, Any]¶
Implement GET
/session/access/active.If successful, response will be a
dictof session info.
- see_session_users() tuple[int, Any]¶
Implement GET
/session/access/all.If successful, response will be a
dictof session and users info.
- update_session_user(email: str, team_id: str = '') tuple[int, Any]¶
Implement POST
/session/access/active.If successful, response will be
None.
- list_users(start: int = 1, chunk: int = 10, filter: str = '') Paginator¶
Implement GET
/scim/v2/Users.This is a paginated api: return an iterable object which, in turn, will retrieve
chunkusers at a time, as alist[dict].
- list_users_raw(start: int = 1, chunk: int = 10, filter: str = '') tuple[int, Any]¶
Implement GET
/scim/v2/Users.If successful, response will be a
dictof user data. If scim is not enabled, will return Http 501.
- add_user(username: str, emails: list[str], formatted_name: str = '', display_name: str = '', lang: str = 'en', locale: str = 'en', photos: list[str] | None = None, schemas: list[str] | None = None) tuple[int, Any]¶
Implement POST
/scim/v2/Users.Note:
schemasdefaults to['urn:ietf:params:scim:schemas:core:2.0:User']If successful, response will be the user id as an
int. If scim is not enabled, will return Http 501.
- update_user_override(user_id: int, username: str, emails: list[str], formatted_name: str = '', display_name: str = '', lang: str = 'en', locale: str = 'en', photos: list[str] | None = None, schemas: list[str] | None = None) tuple[int, Any]¶
Implement PUT
/scim/v2/Users/{userId}.Note:
schemasdefaults to['urn:ietf:params:scim:schemas:core:2.0:User']If successful, response will be
None. If scim is not enabled, will return Http 501.
- update_user(user_id: int, operations: list[dict], schemas: list[str] | None = None) tuple[int, Any]¶
Implement PATCH
/scim/v2/Users/{userId}.Note:
schemasdefaults to['urn:ietf:params:scim:api:messages:2.0:PatchOp']If successful, response will be
None. If scim is not enabled, will return Http 501.
- enable_user(user_id: int, enable: bool = True)¶
Implement POST
/users/{userId}/enableand POST/users/{userId}/disable(accessible to admins only).If successful, response will be
None.
- delete_user(user_id: int)¶
Implement DELETE
/scim/v2/Users/{userId}.If successful, response will be
None. If scim is not enabled, will return Http 501.
- delete_myself(user: str, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement DELETE
/users/{userId}.Note: since this is the only /users endpoint implemented by Grist right now, and since it is of little help (you can only delete your own account), we choose not to implement this one, and leave it here as a stub.
- search_users(start: int = 1, chunk: int = 10, sort: str = '', asc: bool = True, filter: str = '', attrib: list[str] | None = None, no_attrib: list[str] | None = None, schemas: list[str] | None = None) Paginator¶
Implement POST
/scim/v2/Users/.search.Note:
schemasdefaults to['urn:ietf:params:scim:api:messages:2.0:BulkRequest']This is a paginated api: return an iterable object which, in turn, will retrieve
chunkusers at a time, as alist[dict].
- search_users_raw(start: int = 1, chunk: int = 10, sort: str = '', asc: bool = True, filter: str = '', attrib: list[str] | None = None, no_attrib: list[str] | None = None, schemas: list[str] | None = None) tuple[int, Any]¶
Implement POST
/scim/v2/Users/.search.Note:
schemasdefaults to['urn:ietf:params:scim:api:messages:2.0:BulkRequest']If successful, response will be a
dictof user data. If scim is not enabled, will return Http 501.
- bulk_users(operations: list[dict], schemas: list[str] | None = None) tuple[int, Any]¶
Implement POST
/scim/v2/Bulk.Note:
schemasdefaults to['urn:ietf:params:scim:api:messages:2.0:BulkRequest']If successful, response will be a
list[int]of status codes for each operation (inspectGristApi.resp_contentfor details, if any operations resulted in a bad status code). If scim is not enabled, will return Http 501.
- see_scim_schemas() tuple[int, Any]¶
Implement GET
/scim/v2/Schemas.If successful, response will a
dictof scim schemas. If scim is not enabled, will return Http 501.
- see_scim_config() tuple[int, Any]¶
Implement GET
/scim/v2/ServiceProviderConfig.If successful, response will a
dictof scim provider configuration. If scim is not enabled, will return Http 501.
- see_scim_resources() tuple[int, Any]¶
Implement GET
/scim/v2/ResourceTypes.If successful, response will a
dictof scim resources. If scim is not enabled, will return Http 501.
- see_group(group_id: int) tuple[int, Any]¶
Implement GET
/scim/v2/Groups/{groupId}.If successful, response will be a
dictof group details. If scim is not enabled, will return Http 501.
- list_groups(start: int = 1, chunk: int = 10, filter: str = '') Paginator¶
Implement GET
/scim/v2/Groups.This is a paginated api: return an iterable object which, in turn, will retrieve
chunkgroups at a time, as alist[dict].
- list_groups_raw(start: int = 1, chunk: int = 10, filter: str = '') tuple[int, Any]¶
Implement GET
/scim/v2/Groups.If successful, response will be a
dictof groups data. If scim is not enabled, will return Http 501.
- add_group(name: str, members: list | None = None, schemas: list[str] | None = None) tuple[int, Any]¶
Implement POST
/scim/v2/Groups.Note:
schemasdefaults to['urn:ietf:params:scim:schemas:core:2.0:Group']If successful, response will be the group id as an
int. If scim is not enabled, will return Http 501.
- update_group_override(group_id: int, name: str, members: list | None = None, schemas: list[str] | None = None) tuple[int, Any]¶
Implement PUT
/scim/v2/Groups/{userId}.Note:
schemasdefaults to['urn:ietf:params:scim:schemas:core:2.0:Group']If successful, response will be
None. If scim is not enabled, will return Http 501.
- update_group(group_id: int, operations: list[dict], schemas: list[str] | None = None) tuple[int, Any]¶
Implement PATCH
/scim/v2/Groups/{userId}.Note:
schemasdefaults to['urn:ietf:params:scim:api:messages:2.0:PatchOp']If successful, response will be
None. If scim is not enabled, will return Http 501.
- delete_group(group_id: int)¶
Implement DELETE
/scim/v2/Groups/{groupId}.If successful, response will be
None. If scim is not enabled, will return Http 501.
- search_groups(start: int = 1, chunk: int = 10, sort: str = '', asc: bool = True, filter: str = '', attrib: list[str] | None = None, no_attrib: list[str] | None = None, schemas: list[str] | None = None) Paginator¶
Implement POST
/scim/v2/Groups/.search.Note:
schemasdefaults to['urn:ietf:params:scim:api:messages:2.0:SearchRequest']This is a paginated api: return an iterable object which, in turn, will retrieve
chunkgroups at a time, as alist[dict].
- search_groups_raw(start: int = 1, chunk: int = 10, sort: str = '', asc: bool = True, filter: str = '', attrib: list[str] | None = None, no_attrib: list[str] | None = None, schemas: list[str] | None = None) tuple[int, Any]¶
Implement POST
/scim/v2/Users/.search.Note:
schemasdefaults to['urn:ietf:params:scim:api:messages:2.0:SearchRequest']If successful, response will be a
dictof group data. If scim is not enabled, will return Http 501.
- see_role(role_id: int) tuple[int, Any]¶
Implement GET
/scim/v2/Roles/{roleId}.If successful, response will be a
dictof group details. If scim is not enabled, will return Http 501.
- list_roles(start: int = 1, chunk: int = 10, filter: str = '') Paginator¶
Implement GET
/scim/v2/Roles.This is a paginated api: return an iterable object which, in turn, will retrieve
chunkgroups at a time, as alist[dict].
- list_roles_raw(start: int = 1, chunk: int = 10, filter: str = '') tuple[int, Any]¶
Implement GET
/scim/v2/Roles.If successful, response will be a
dictof groups data. If scim is not enabled, will return Http 501.
- update_role_override(role_id: int, members: list | None = None, schemas: list[str] | None = None) tuple[int, Any]¶
Implement PUT
/scim/v2/Roles/{rolesId}.Note:
schemasdefaults to['urn:ietf:params:scim:schemas:Grist:1.0:Role']If successful, response will be
None. If scim is not enabled, will return Http 501.
- update_role(role_id: int, operations: list[dict], schemas: list[str] | None = None) tuple[int, Any]¶
Implement PATCH
/scim/v2/Roles/{roleId}.Note:
schemasdefaults to['urn:ietf:params:scim:api:messages:2.0:PatchOp']If successful, response will be
None. If scim is not enabled, will return Http 501.
- list_team_sites() tuple[int, Any]¶
Implement GET
/orgs.If successful, response will be a
list[dict]of site details.
- see_team(team_id: str = '') tuple[int, Any]¶
Implement GET
/orgs/{orgId}.If successful, response will be a
dictof site details.
- see_team_usage(team_id: str = '') tuple[int, Any]¶
Implement GET
/orgs/{orgId}/usage.If successful, response will be a
dictof usage details.
- update_team(new_name: str, team_id: str = '') tuple[int, Any]¶
Implement PATCH
/orgs/{orgId}.If successful, response will be
None. Note that renaming a team will not change the subdomain too!
- delete_team_old(team_id: str = '') tuple[int, Any]¶
Implement DELETE
/orgs/{orgId}.If successful, response will be
None. Note: disabled in Grist 1.7.4, will return Http 410 instead.
- delete_team(team_id: str = '') tuple[int, Any]¶
Implement DELETE
/orgs/{orgId}/{name}.If successful, response will be
None.
- list_team_users(team_id: str = '') tuple[int, Any]¶
Implement GET
/orgs/{orgId}/access.If successful, response will be a
list[dict]of users.
- update_team_users(users: dict[str, str], team_id: str = '') tuple[int, Any]¶
Implement PATCH
/orgs/{orgId}/access.If successful, response will be
None.
- list_workspaces(team_id: str = '') tuple[int, Any]¶
Implement GET
/{orgId}/workspaces.If successful, response will be a
list[dict]of workspaces.
- add_workspace(name: str, team_id: str = '') tuple[int, Any]¶
Implement POST
/{orgId}/workspaces.If successful, response will be the workspace id as an
int.
- see_workspace(ws_id: int = 0) tuple[int, Any]¶
Implement GET
/workspaces/{workspaceId}.If successful, response will be a
dictof workspace details.
- update_workspace(new_name: str, ws_id: int = 0) tuple[int, Any]¶
Implement PATCH
/workspaces/{workspaceId}.If successful, response will be
None.
- delete_workspace(ws_id: int = 0) tuple[int, Any]¶
Implement DELETE
/workspaces/{workspaceId}.If successful, response will be
None.
- trash_workspace(remove: bool = True, permanent: bool = False, ws_id: int = 0) tuple[int, Any]¶
Implement POST
/workspaces/{workspaceId}/removeand POST/workspaces/{workspaceId}/unremove.If
removeandpermanent, ws will be deleted instead. Ifremove=False,permanentis ignored and ws will be recovered.If successful, response will be
None.
- list_workspace_users(ws_id: int = 0) tuple[int, Any]¶
Implement GET
/workspaces/{workspaceId}/access.If successful, response will be a
list[dict]of users.
- update_workspace_users(users: dict[str, str], ws_id: int = 0) tuple[int, Any]¶
Implement PATCH
/workspaces/{workspaceId}/access.If successful, response will be
None.
- add_doc(name: str, pinned: bool = False, ws_id: int = 0) tuple[int, Any]¶
Implement POST
/workspaces/{workspaceId}/docs.If successful, response will be the doc id as a
str.
- see_doc(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}.If successful, response will be a
dictof doc details.
- update_doc(new_name: str = '', pinned: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PATCH
/docs/{docId}.If successful, response will be
None.
- delete_doc(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement DELETE
/docs/{docId}.If successful, response will be
None.
- trash_doc(remove: bool = True, permanent: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/removeand POST/docs/{docId}/unremove.If
removeandpermanent, doc will be deleted instead. Ifremove=False,permanentis ignored and doc will be recovered.If successful, response will be
None.
- list_doc_history(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/states.If successful, response will be a
list[dict]of history states.
- compare_doc_history(left: str = '', right: str = '', max_rows: int = 10, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/compare.left,right, if left empty, default toHEAD. If successful, response will be adictof comparision results.
- delete_doc_history(keep: int = 1, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/states/remove.If successful, response will be
None.
- fork_doc(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/fork.If successful, response will be a
dictof fork identifiers.
- compare_docs(other: str, details: bool = False, max_rows: int = 10, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/compare/{docId2}.If successful, response will be a
dictof comparision results.
- list_proposals(outgoing: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/proposals.Note: if
outgoing=False, list change proposals todoc_idfrom its forks, which should make more sense in Pygrister. If successful, response will be alistof proposals.
- add_proposal(retracted: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/propose.Note that
doc_idmust be a fork for this to work. If successful, response will be the proposal Id as anint.
- apply_proposal(proposal_id: int, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/proposals/{proposalId}/apply.If successful, response will be a
dictof applied changes.
- move_doc(ws_id: int, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PATCH
/docs/{docId}/move.If successful, response will be
None.
- copy_doc(target_ws: int, target_name: str, template: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/copy.If successful, response will be the
strid of the copied doc.
- replace_doc(source_doc: str = '', source_snapshot: str = '', reset_tutorial: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/replace.If successful, response will be
None.
- reload_doc(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/force-reload.If successful, response will be
None.
- flush_doc(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/flush.If successful, response will be a
boolof the flush outcome.
- assign_doc(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/assign.If successful, response will be a
boolof the outcome.
- enable_doc(enable: bool = True, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/enableand POST/docs/{docId}/disable(accessible to admins only).If successful, response will be
None.
- pin_doc(pin: bool = True, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PATCH
/docs/{docId}/pinand PATCH/docs/{docId}/unpin.If successful, response will be
None.
- set_recovery_mode(mode: bool = True, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/recover.If successful, response will be
None.
- list_doc_users(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/access.If successful, response will be a
list[dict]of users.
- list_viewas_users(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/usersForViewAs.If successful, response will be a
dictwith ``list``s of users divided by category.
- update_doc_users(users: dict[str, str], max: str = 'owners', doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PATCH
/docs/{docId}/access.If successful, response will be
None.
- download_sqlite(filename: Path, nohistory: bool = False, template: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/download.If successful, response will be
None.
- upload_sqlite(filename: Path, target_docname: str, ws_id: int = 0) tuple[int, Any]¶
Implement POST
/workspaces/{workspaceId}/import.If successful, response will be the imported doc Id as
str.
- download_table(filename: Path, table_id: str, header: str = 'label', format: str = 'csv', doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/download/csv|tsv|dsv|xlsx.formatmust be one of csv, tsv, dsv, xlsx. If successful, response will beNone.
- download_excel(filename: Path, table_id: str, header: str = 'label', doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Deprecated, will be removed soon. Use
download_tableinstead.
- download_csv(filename: Path, table_id: str, header: str = 'label', doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Deprecated, will be removed soon. Use
download_tableinstead.
- download_schema(table_id: str, header: str = 'label', filename: Path | None = None, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/download/table-schema.If successful, schema will be returned as json; pass the filename param to have it downloaded as a json file instead.
- list_snapshots(raw: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/snapshots.If successful, response will be a
list[dict]of snapshot data.
- delete_snapshots(snapshot_ids: list[str], doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/snapshots/remove.If successful, response will be
None.
- see_timing(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/timing.If successful, response will be a
dictof formula timing data.
- start_timing(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/timing/start.If successful, response will be
None.
- stop_timing(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/timing/stop.If successful, response will be a
dictof formula timing data.
- list_records(table_id: str, filter: dict | None = None, sort: str = '', limit: int = 0, hidden: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/tables/{tableId}/records.If a converter is found for this table, data conversion will be attempted. If successful, response will be a list of “Pygrister records with id” (see docs).
- add_records(table_id: str, records: list[dict], noparse: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/tables/{tableId}/records.records: a list of “Pygrister records without id” (see docs). If a converter is found for this table, data conversion will be attempted. If successful, response will be alist[int]of added record ids.
- update_records(table_id: str, records: list[dict], noparse: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PATCH
/docs/{docId}/tables/{tableId}/records.records: a list of “Pygrister records with id” (see docs). If a converter is found for this table, data conversion will be attempted. If successful, response will beNone.
- add_update_records(table_id: str, records: list[dict], noparse: bool = False, onmany: str = 'first', noadd: bool = False, noupdate: bool = False, allow_empty_require: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PUT
/docs/{docId}/tables/{tableId}/records.If a converter is found for this table, data conversion will be attempted. If successful, response will be
None.
- list_tables(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/tables.If successful, response will be a
list[dict]of tables.
- add_tables(tables: list[dict], doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/tables.If successful, response will be a
list[str]of added table ids.
- update_tables(tables: list[dict], doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PATCH
/docs/{docId}/tables.If successful, response will be
None.
- list_cols(table_id: str, hidden: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/tables/{tableId}/columns.If successful, response will be a
list[dict]of columns.
- add_cols(table_id: str, cols: list[dict], doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/tables/{tableId}/columns.If successful, response will be a
list[str]of added col ids.
- update_cols(table_id: str, cols: list[dict], doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PATCH
/docs/{docId}/tables/{tableId}/columns.If successful, response will be
None.
- add_update_cols(table_id: str, cols: list[dict], noadd: bool = True, noupdate: bool = True, replaceall: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PUT
/docs/{docId}/tables/{tableId}/columns.If successful, response will be
None.
- delete_column(table_id: str, col_id: str, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement DELETE
/docs/{docId}/tables/{tableId}/columns/{colId}.If successful, response will be
None.
- delete_rows(table_id: str, rows: list[int], doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/tables/{tableId}/data/delete.If successful, response will be
None.
- list_attachments(filter: dict | None = None, sort: str = '', limit: int = 0, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/attachments.If successful, response will be a
list[dict]of attachments.
- upload_attachment(filename: Path, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/attachmentsfor one file only.This is deprecated and redirects to
upload_attachmentswhich you should use instead.
- upload_attachments(filenames: list[Path], doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/attachments.If successful, response will be a
list[int]of attachments ids.
- upload_restore_attachments(filename: Path, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/attachments/archive.filename: must be a tar file. If successful, response will be a summarydictof attachments used.
- see_attachment(attachment_id: int, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/attachments/{attachmentId}.If successful, response will be a
dictof attachment metadata.
- download_attachment(filename: Path, attachment_id: int, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/attachments/{attachmentId}/download.If successful, response will be
None.
- download_attachments(filename: Path | None = None, format: str = 'tar', doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/attachments/archive.filename: must be a file name matching withformatand defaults todoc_<doc_id>_attachments.<format>. If successful, response will beNone.
- delete_unused_attachments(expired_only: bool = False, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/attachments/removeUnused.If successful, response will be
None.
- see_attachment_store(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/attachments/store.If successful, response will be either
externalorinternal.
- update_attachment_store(internal_store: bool = True, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/attachments/store.Pass
internal_store=Trueto set internal storage,Falseto set external storage. If successful, response will beNone. PassingFalsewill return Http 400 if external storage is not configured.
- list_store_settings(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/attachments/stores.If successful, response will be a
listof external storage settings.
- transfer_attachments(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/attachments/transferAll.If successful, response will be a
dictof transfer details. If external storage is not configured, will return Http 404.
- see_transfer_status(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/attachments/transferStatus.If successful, response will be a
dictof transfer details. If external storage is not configured, will return Http 404.
- verify_attachment_usage(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/attachments/updateUsed.If successful, response will be
None.
- verify_attachment_files(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/attachments/verifyFiles.If successful, response will be
None.
- list_webhooks(doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement
GET /docs/{docId}/webhooks.If successful, response will be a
list[dict]of webhooks.
- add_webhooks(webhooks: list[dict], doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/webhooks.If successful, response will be a
list[str]of added webhook ids.
- update_webhook(webhook_id: str, webhook: dict, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement PATCH
/docs/{docId}/webhooks/{webhookId}.If successful, response will be
None.
- delete_webhook(webhook_id: str, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement DELETE
/docs/{docId}/webhooks/{webhookId}.If successful, response will be
None.
- empty_payloads_queue(webhook_id: str = '', doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement DELETE
/docs/{docId}/webhooks/queueand DELETE/docs/{docId}/webhooks/queue/{webhookId}.Clear all pending payloads, or pass
webhook_idto clear queue for a specific webhook. If successful, response will beNone.
- list_templates() tuple[int, Any]¶
Implement GET
/templates.If successful, response will be a
list[dict]of workspaces with templates.
- see_template(template_id: str) tuple[int, Any]¶
Implement GET
/templates/{templateId}.If successful, response will be a
dictof template details.
- list_widgets() tuple[int, Any]¶
Implement GET
/widgets.If successful, response will be a
list[dict]of widgets data.
- see_form(section_id: int, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/forms/{viewSectionId}.If successful, response will be a
dictof form details.
- run_sql(sql: str, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement GET
/docs/{docId}/sql.If a converter named “sql” is found, data conversion will be attempted. If successful, response will be a list of “Pygrister records” (see docs) with or without id, depending on the query.
- run_sql_with_args(sql: str, qargs: list, timeout: int = 1000, doc_id: str = '', team_id: str = '') tuple[int, Any]¶
Implement POST
/docs/{docId}/sql.If a converter named “sql” is found, data conversion will be attempted. If successful, response will be a list of “Pygrister records” (see docs) with or without id, depending on the query.
Configuration mechanism.¶
Pygrister configuration engine.¶
The Configurator class here is responsible for parsing, applying and
changing configuration at runtime. The main GristApi class will create
and load its own default instance of Configurator at instantiation time.
However, you may subclass Configurator and provide your own custom
mechanism:
>>> from pygrister.api import GristApi
>>> from pygrister.config import Configurator
>>> class MyConfig(Configurator):
... pass # do your thing here
...
>>> cfg = MyConfig()
>>> grist = GristApi(custom_configurator=cfg)
- pygrister.config.apikey2output(apikey: str) str¶
Obfuscate the secret Grist API key for output printing.
Api call engine.¶
Pygrister Api call engine.¶
The ApiCaller class here is responsible for actually posting a Grist
Api call. The main GristApi class will create and load its own default
instance of ApiCaller at instantiation time.
However, you may subclass ApiCaller and provide your own custom
mechanism:
>>> from pygrister.api import GristApi
>>> from pygrister.apicaller import ApiCaller
>>> class MyCaller(ApiCaller):
... pass # do your thing here
...
>>> apicall = MyCaller()
>>> grist = GristApi(custom_apicaller=apicall)
- pygrister.apicaller.Apiresp¶
the return type of all api call functions
alias of
tuple[int,Any]
- class pygrister.apicaller.ApiCaller(configurator: Configurator | None = None, request_options: dict | None = None)¶
The engine for posting a call to the Grist Apis.
- session¶
Requests session object, or None
- request_options¶
other options to pass to Requests
- apicalls: int¶
total number of API calls
- dry_run: bool¶
prepare, do not post request
- request: PreparedRequest | None¶
last request posted
- response: Response | None¶
last response retrieved
- property ok: bool¶
Falseif a HTTP error occurred in the response.Also, if no response was retrieved, will be
Falseby default.
- open_session() None¶
Open a Requests sessions for all subsequent Api calls.
- close_session() None¶
Close an open session, if any.
- response_as_json() str¶
Return the response content as (unicode) parsable json.
- apicall(url: str, method: str = 'GET', headers: dict | None = None, params: dict | None = None, json: dict | None = None, filename: Path | None = None, upload_files: list | dict | None = None) tuple[int, Any]¶
The engine responsible for actually calling the Apis.
Return a
Apiresp-type tuple (status_code, resp_content) where “resp_content” is a Json-decoded Python object (usually adict, but that depends on the the specific Grist Api return value and status code).May throw any
requests.RequestExceptionthat is not HTTP- or Json- related, if a server problem occurred. Will throwrequests.HTTPErrorif the status code is >=300 and the config keyGRIST_RAISE_ERRORis set (default). Should never throwrequests.JsonDecodeError.The
okproperty will beFalseif errors occurred.
- inspect(sep: str = '\n', max_content: int = 1000) str¶
Collect info on the last api call that was requested (and possibly responded to) by the server.
Use
septo set a custom separator between elements, andmax_contentto limit request/response body’s content size.Intended for debug: add a
print(self.inspect())right after the call to inspect. Works even if the server returned a “bad” status code. If server did not respond, only request data will be recorded.
Pygrister exceptions.¶
Pygrister exception hierarchy.¶
Exceptions listed here can be raised by Pygrister, and they concern its internal functioning. Note that Grist API calls themselves, however, are delegated to Requests, and will (much more frequently!) throw the exceptions provided by Requests.
- exception pygrister.exceptions.GristApiException¶
The base GristApi exception.
- exception pygrister.exceptions.GristApiNotConfigured¶
A configuration error occurred.
- exception pygrister.exceptions.GristApiNotImplemented¶
This API is not yet implemented by Pygrister.
- exception pygrister.exceptions.GristApiInSafeMode¶
Pygrister is in safe mode, no writing to the db is possible.