A TM1py-inspired Python wrapper for the IBM Planning Analytics Workspace (PAW) REST API.
Project description
PAWpy — Planning Analytics Workspace REST API Wrapper
A TM1py-inspired Python wrapper for the PAW REST API.
Install
uv sync --extra dev # installs PAWpy + pytest
uv run python -m pytest # 21 offline tests (no live server needed)
Requires Python ≥3.11 and requests. The URL-builder calls (paw.ui.*,
*.get_embed_url) make no network request and work without a live PAW server.
Releasing
Publishing is automated by .github/workflows/publish.yml via PyPI
Trusted Publishing (OIDC — no API
token stored). To cut a release:
- Bump
versioninpyproject.tomland add aCHANGELOG.mdentry. - One-time on PyPI: add a Trusted Publisher for project
PAWpy→bluestarleo/PAWpy, workflowpublish.yml, environmentpypi. - Tag and push:
git tag v0.1.0 && git push origin v0.1.0
The workflow runs the tests (3.11–3.13), builds, checks the tag matches the package version, and publishes the sdist + wheel to PyPI.
Architecture
PAWService ← top-level entry point (mirrors TM1py's TM1Service)
├── RestService ← session + auth + GET/POST/PATCH/PUT/DELETE core
├── ContentService ← /pacontent/v1/Assets (legacy OData folders / books / assets)
├── ContentV1Service ← /api/v1/content (OAuth-era assets, permissions,
│ bulk ops, asset types — PAW 2.1.21+/3.1.8+)
├── UserGroupService ← /api/v1/content/users|groups (PAW 2.1.21+/3.1.8+)
├── BookService ← books (type=book/dashboard) over ContentService
├── ViewService ← views over ContentService
├── AdminService ← /api/v1/admin (servers, users, groups)
├── UIService ← URL builder for /ui?type=… embed endpoints
└── TM1ProxyService ← /api/v0/tm1/<db>/api/v1/… (TM1 REST via PAW auth;
pass tm1_proxy_base="/api/v1/tm1" on PAW 2.1.21+/3.1.8+)
All base paths (content_base, admin_base) are constructor-overridable, since
they vary across PAW builds (/pacontent/v1 vs /api/v1/content).
Auth Modes
| Mode | How it works |
|---|---|
oauth |
Client-credentials grant against token_url → Authorization: Bearer |
cam |
CAM namespace login via POST /login → x-csrf-token |
native |
TM1 native username/password login via POST /login → x-csrf-token |
passport |
Cognos CAM passport (camid) via POST /login |
session |
Inject an existing csrf_token / session_cookie (dev/test) |
Usage
OAuth (Recommended)
from PAWpy import PAWService
with PAWService(
host="paw.mycompany.com",
auth_mode="oauth",
client_id="my-client-id",
client_secret="my-client-secret",
token_url="https://idp.mycompany.com/oauth2/token", # required for oauth
scope="paw", # optional
database="Global FPA", # optional default TM1 database
) as paw:
# List books in a folder (returns Asset objects)
books = paw.books.get_all("/shared/FP&A")
# Get embed URL for an iframe (no HTTP call)
url = paw.books.get_embed_url("/shared/FP&A/Monthly Report")
# List registered TM1 servers
servers = paw.admin.get_tm1_servers()
# OAuth-era content API (PAW 2.1.21+/3.1.8+): permissions, bulk ops, users
assets = paw.content_v1.list_children("shared")
perms = paw.content_v1.get_effective_permissions(assets[0].id)
users = paw.user_groups.get_users()
# TM1 proxy call (MDX via PAW auth) — returns the raw cellset JSON
tm1 = paw.tm1("Global FPA")
data = tm1.execute_mdx("SELECT {[Account].[Revenue]} ON 0 FROM [Revenue Cube]")
# Embed URL generation (no HTTP call)
embed = paw.ui.cube_viewer_url("Global FPA", "Revenue Cube", view="Monthly View")
Legacy CAM
with PAWService(
host="paw.mycompany.com",
auth_mode="cam",
namespace="LDAP",
username="my-username",
password="secret",
) as paw:
...
Multi-tenant (PAW Cloud)
with PAWService(
host="planning-analytics.cloud.ibm.com",
tenant_id="my-tenant-id",
auth_mode="oauth",
client_id="...",
client_secret="...",
) as paw:
...
Mapping to TM1py
| TM1py | PAWpy |
|---|---|
TM1Service |
PAWService |
CubeService |
TM1ProxyService (via PAW) |
DimensionService |
TM1ProxyService (via PAW) |
ProcessService |
TM1ProxyService (via PAW) |
| (no equivalent) | BookService |
| (no equivalent) | ContentService |
| (no equivalent) | AdminService |
| (no equivalent) | UIService |
Versioning against PAW builds
The PAW REST API is still incomplete and grows with each IBM release, so PAWpy is
versioned against two axes: its own semver (PAWpy.__version__) and the
minimum PAW build each API group requires. Each service declares its
API_GROUP; the per-group minimums live in PAWpy/version_requirements.py
(MIN_PAW_VERSION).
paw = PAWService(host="paw.acme.com", auth_mode="oauth", ..., paw_version="2.1.21")
paw.requires("content") # -> "2.1.21" (min PAW build for Content Services)
paw.supports("content") # -> True / False against the known paw_version
paw.assert_supported("content") # raises PAWVersionError if the build is too old
paw.detect_paw_version() # best-effort probe (overridable path/field)
When paw_version is unknown, gating is a no-op — PAWpy never blocks a call
solely because it couldn't determine the version; the server still rejects
genuinely-unsupported requests. The version pins are reconciled on each PAW
release as part of a maintainer-local workflow.
Coverage & release tracking
PAWpy's endpoint coverage is tracked in a maintainer-local coverage matrix (not
part of this repo). Because the PAW REST API is still growing, it is reconciled
on each PAW release: IBM's endpoint inventory (the IBM-linked Postman collection
or the published API references) is re-pulled and diffed against the matrix to
flag endpoints PAW now exposes that PAWpy doesn't yet wrap, so the wrapper
tracks IBM's cadence instead of drifting. New coverage lands here as Added
entries in CHANGELOG.md and Roadmap items below.
Roadmap (aligned with IBM's "future releases" promise)
- Content API v1 (
/api/v1/content, PAW 2.1.21+/3.1.8+) —ContentV1Service: assets incl. content retrieval, permissions (get/set/effective), bulk copy/move/delete/permissions, asset types -
UserGroupService— PAW users/groups reads (/api/v1/content/users|groups); write endpoints not yet documented by IBM -
ViewService— PAW view CRUD -
EmbedTokenService— generate scoped embed tokens -
MCPService— PAW MCP endpoint integration - Token refresh / OAuth expiry handling
- Async support (
aiohttp) - Pydantic models for Books, Assets, Servers
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pawpy-0.4.0.tar.gz.
File metadata
- Download URL: pawpy-0.4.0.tar.gz
- Upload date:
- Size: 28.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1321f29910e61c360d2341df9832f31daa5809d797c8bd81be284ea94bfc03a8
|
|
| MD5 |
909b611befeaee9f68412c69d4997a07
|
|
| BLAKE2b-256 |
0081ca33fff4b142dc58e1484c5b1e41c4dc7e2ffbfc39b5cd6d3cb7357051c1
|
Provenance
The following attestation bundles were made for pawpy-0.4.0.tar.gz:
Publisher:
publish.yml on bluestarleo/PAWpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pawpy-0.4.0.tar.gz -
Subject digest:
1321f29910e61c360d2341df9832f31daa5809d797c8bd81be284ea94bfc03a8 - Sigstore transparency entry: 2207244957
- Sigstore integration time:
-
Permalink:
bluestarleo/PAWpy@a7c3c846740f8cc0fbc19819c32b4fcda54e6b4e -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/bluestarleo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a7c3c846740f8cc0fbc19819c32b4fcda54e6b4e -
Trigger Event:
push
-
Statement type:
File details
Details for the file pawpy-0.4.0-py3-none-any.whl.
File metadata
- Download URL: pawpy-0.4.0-py3-none-any.whl
- Upload date:
- Size: 31.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c2fb5f38edc1192bacc8f226819f2a071cc186400c5efc510976d37c4ac06f1
|
|
| MD5 |
4ca5ad4c33a3df3f4c7fb8117fb53b6a
|
|
| BLAKE2b-256 |
d34d67ce132a76dba51d6cef13f7de1425598a9913824e7b0cb018bae41d1502
|
Provenance
The following attestation bundles were made for pawpy-0.4.0-py3-none-any.whl:
Publisher:
publish.yml on bluestarleo/PAWpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pawpy-0.4.0-py3-none-any.whl -
Subject digest:
3c2fb5f38edc1192bacc8f226819f2a071cc186400c5efc510976d37c4ac06f1 - Sigstore transparency entry: 2207244967
- Sigstore integration time:
-
Permalink:
bluestarleo/PAWpy@a7c3c846740f8cc0fbc19819c32b4fcda54e6b4e -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/bluestarleo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a7c3c846740f8cc0fbc19819c32b4fcda54e6b4e -
Trigger Event:
push
-
Statement type: