pysisense is a Python SDK designed for seamless and structured interaction with the Sisense API.
It simplifies complex API operations and allows you to automate and manage users, groups, dashboards, data models, and more.
β Built for automation, debugging, and extensibility.
pysisense is not an official Sisense product or SDK. It is a community project built and maintained by members of the Sisense Field Engineering team on a best-effort basis.
Please note:
- No SLA or official support β this project is not covered by any Sisense Service Level Agreement or support contract. Do not open Sisense Support tickets for issues with this SDK; use the GitHub issue tracker instead.
- Not part of Sisense's product processes β the SDK does not go through Sisense's official product QA, security review, or release lifecycle.
- No compatibility guarantees β the REST APIs wrapped here may change between Sisense versions without notice, and SDK methods may break as a result.
- Use at your own risk β always validate behavior in a non-production environment before running anything against production, especially write operations (migrations, ownership changes, deletions).
- Best-effort maintenance β issues and pull requests are welcome and reviewed as time permits, with no guaranteed response times.
You can install pysisense from PyPI:
pip install pysisenseFor local development, install in editable mode:
pip install -e .2.0 contains breaking changes. pysisense follows semantic versioning, so pinning
pysisense>=1,<2 keeps you on 1.x until you choose to move.
π Full upgrade guide β every change mapped old-to-new, with a symptom β cause β fix table. Complete detail in the changelog.
The user row is additive β ROLE_NAME and GROUPS keep their 1.x names and meanings,
so role comparisons and group reads keep working. New fields (ROLE_DISPLAY_NAME,
ROLE_RAW_NAME, GROUP_IDS) sit alongside them. What needs action:
GROUPSnow includesEveryone, whichget_users_all()used to strip out. The key and its meaning are unchanged; only this value was added.- Detect failures with
result.get("ok") is Falseβ every failure dict now carries that marker, and methods that used to fail with[],Noneor an"Error: ..."string now return the standard error dict. An empty list always means a genuinely empty result. get_unused_columns_bulkreturns a dict, not a list β readresult["results"].get_connectionswas removed β useget_connections_all.
Check what you are running with python -c "import pysisense; print(pysisense.__version__)".
If you search for pysisense and find a different package, or if you mistyped the package name, PyPI has redirect stub packages registered:
sisense-pyβ redirects topysisensepysisense-sdkβ redirects topysisensesisense-sdkβ redirects topysisense
These packages raise an error with a clear message if you try to import them, pointing you to the correct pysisense package. The canonical package name is always pysisense.
Create one or more config files (use the templates in examples/ as reference only):
config.yamlβ for single-environment operationssource.yamlandtarget.yamlβ for migration scenarios
Each file should follow this structure:
domain: "your-domain.com"
is_ssl: true
token: "<your_api_token>"The same settings can come from a JSON file (config.json) or a plain Python dict, wherever a config is accepted:
client = SisenseClient(config_file="config.json")
client = SisenseClient(config_file={"domain": "your-domain.com", "is_ssl": True, "token": "<your_api_token>"})
migration = Migration(source_config="source.yaml", target_config={"domain": "...", "token": "..."})For non-SSL connections (is_ssl: false), HTTP requests use port 30845 by default. You can override it with an optional port field (ignored when is_ssl is true):
domain: "192.168.1.100"
is_ssl: false
port: 30845 # optional, omit to use the default 30845
token: "<your_api_token>"See config.yaml.example for the template.
verify_ssl: false) for trusted internal networks with self-signed certificates; doing so exposes your API token to on-path interception.
If your Sisense server uses a self-signed or internal-CA certificate and you still want verification enabled, point ssl_path at the CA bundle file (or directory) instead of disabling verification:
domain: "your-domain.com"
is_ssl: true
token: "<your_api_token>"
ssl_path: "/path/to/ca-bundle.pem"ssl_path takes precedence over verify_ssl when both are set, unless verify_ssl is explicitly false, in that case verification stays fully disabled and ssl_path is ignored.
The SDK works with any Sisense user's API token β admin access is not a general requirement. Permissions are enforced by Sisense itself: every API call runs with the role and access rights of the user whose token you configure, so each method can only see and do what that user could see and do in the Sisense UI.
This means the same method can return different results depending on the token. For example, fetching dashboards with an admin token may return every dashboard on the instance, while the same call with a viewer's token returns only the dashboards shared with that user.
Some operations, however, are inherently administrative and will fail or behave inconsistently without full admin privileges β for these, use a dedicated Sisense admin user's token in your config.yaml:
- Folder and dashboard ownership changes
- Granting or modifying permissions across environments
- System-wide migrations (users, groups, data models, dashboards)
- Instance-wide listings and admin exports (e.g., methods using
adminAccess=true)
The examples/ folder contains Markdown guides. Each guide explains common workflows and includes copy-pasteable code snippets you can adapt in your own project:
-
access_management_example.md
Identity & Governance β manage users, groups, folder access, and governance tasks (e.g., unused assets). -
datamodel_example.md
Data Modeling β work with datasets, tables, columns, and schema within Sisense data models. -
dashboard_example.md
Dashboard Lifecycle β retrieve, update, reassign ownership, and manage shares of dashboards. -
folder_example.md
Folder Management β create, list, update, and delete Sisense dashboard folders. -
migration_example.md
Environment Migration β migrate users, dashboards, and data models across environments (e.g., dev β prod). -
wellcheck_example.md
Data Health & Complexity β run structural checks on dashboards and data models (widget counts, pivot fields, island tables, RLS datatypes, import queries, many-to-many relationships, and unused columns).
Note: These guides are not meant to be executed end-to-end. Copy the relevant snippets into your own Python files or notebooks, update configuration (YAML paths, IDs, etc.), and run them in your environment.
All logs are saved automatically to a local folder:
logs/pysisense.log
You donβt need to create this folder manually β it will be created at runtime in the same directory where you run your scripts.
Logs rotate automatically at midnight and keep 7 days of history. The active file is always named pysisense.log; each day's log is renamed to pysisense.log.YYYY-MM-DD at rotation time, and once more than 7 dated backups exist, the oldest one is deleted. The active log file's name never changes and it is never overwritten mid-rotation β only rotated out at day's end.
- π₯ User & Group Management β Create, update, delete, and fetch users or groups
- π Dashboard Management β Export, share, duplicate, and migrate dashboards; find every dashboard on a data model, change the datasource a dashboard queries, and check that every widget still answers
- π¦ Data Models β Explore, describe, and update schemas and security
- π Perspectives β List, create, and delete metadata-only views over a data model, and analyze what a perspective must keep for the model's dashboards to keep working
- π Permissions β Resolve and apply share rules (users & groups)
- π Cross-Environment Migrations β Move dashboards, models, and users
- β WellCheck β Analyze dashboard and data model health (structure complexity, widget density, pivot fields, island tables, RLS datatypes, import queries, many-to-many relationships, and unused columns)
- π§ Smart Logging & Data Helpers β Auto log capture, CSV export, and DataFrame conversion
- β And many more β Refer to the documentation for full details
- Pythonic SDK with class-based structure (
Dashboard,DataModel,AccessManagement,Migration) - Additional analysis module:
WellCheckβ Run dashboard and data model health checks (structure, complexity, and best-practice validations) - Modular YAML-based authentication
- Built-in logging and exception handling
- Designed for end-to-end automation and real-world use
Tools that generate schemas by introspecting this package (agents, MCP servers, code generators) can rely on the following as stable public API:
pysisense.FACADES is an explicit tuple of the tool-bearing facade classes (AccessManagement, DataModel, Dashboard, β¦). Iterate it to discover the SDK's operational surface β do not iterate __all__, which also contains TypedDict payload types and utility functions. SisenseClient is intentionally excluded (it is the shared HTTP/auth client, not an operation facade).
Failure returns follow one shape across the SDK:
{"ok": False, "error": "<human-readable message>", "status_code": <int>} # status_code present only when an HTTP status existsDetect failure by the explicit "ok": False marker (payload.get("ok") is False) β the forward-compatible check β or by the presence of the "error" key. Never match an exact key set. The failure dict may gain additive keys in minor releases (status_code arrived in 1.1.0; some methods add context keys), so a consumer checking keys() == {"error"} will silently misclassify failures as successes. Renaming or removing "error"/"status_code" is treated as a breaking change; adding keys is not.
Since 2.0, "error" is always a clean sentence: either the recognised Sisense reason (from the body's detail/message/title/error key) or an honest label like "unrecognized error body". When the body could not be recognized, the redacted, 300-char-truncated dump travels separately in an additive "raw_body" key, so consumers with different trust boundaries can relay or drop it independently of the sentence.
Two adjacent guarantees:
- Redaction is part of the contract, not a courtesy: credential-shaped values are stripped by
redact_secrets()before the message is built, so the"error"string is safe to relay verbatim across trust boundaries (e.g. privacy modes where the failure reason is the only data that reaches a model). - Resolver envelopes are their own stable shape:
resolve_dashboard_referenceandresolve_datamodel_referencereturn{"success", "status_code", "<entity>_id", "<entity>_title", "error"}on both success and failure. Detect their outcome viasuccess, not via error-key matching β they carry payload keys alongside"error", and they will not be folded into the generic error dict.
Connection-level failures carry "error" without "status_code" (no HTTP status exists; the absence is itself signal).
All live methods follow the contract. The pre-2.0 failure-shape exceptions ([], "Error: ..." strings, None, list-wrapped error dicts) were converged onto the error dict in 2.0 β an empty list from a read method now always means a genuinely empty result, never a swallowed failure. Two footnotes:
- Deprecated aliases are fossils: methods carrying
__deprecated__(e.g.get_user_with_role_and_group_names,users_per_group_all,get_unused_columns) keep their old, frozen shapes β including old failure shapes β until removal. Skip them via the__deprecated__marker. - Write methods return dicts on success too:
add_dashboard_script/add_widget_scriptreturn{"success": True, "message": ...};add_dashboard_sharesreturns{"success": True, "message": ..., "new_shares": n, "updated_shares": n};get_unused_columns_bulkalways returns{"results": [...], "errors": [{"ref", "error"}]}(with"ok": False+ top-level"error"added when nothing could be processed).
Dict parameters are typed with TypedDicts from pysisense/payloads.py (also exported at package root). Required vs. optional fields introspect via __required_keys__ / __optional_keys__; annotations resolve at runtime (inspect.signature(..., eval_str=True)). Deprecated method aliases are decorated with @typing_extensions.deprecated(...) (PEP 702), so __deprecated__ is introspectable. Enum-valued string parameters use typing.Literal.
π Documentation
Comprehensive module-level documentation is available in the docs/ folder:
- Index β Overview of the SDK structure and modules
- Sisense Client β Base API wrapper for all HTTP operations
- Access Management β Manage users, groups, roles, and permissions
- Data Model β Handle datasets, tables, schemas, security, and deployment
- Dashboard β Retrieve, modify, and share Sisense dashboards
- Migration β Migrate users, dashboards, and models between environments
- Utils β Helper functions for export, formatting, and data operations
- WellCheck β Run health checks on dashboards and data models (structure, complexity, and best-practice validations)
You can also explore:
- Inline method docstrings using
help()in Python or directly within your IDE.
This project is licensed under the Sisense End User License Agreement (EULA). See the LICENSE file for the full text.
Β© 2026 Sisense Ltd. βSisenseβ and related marks are trademarks of Sisense Ltd.