Skip to content

feat(python): add __repr__ and to_dict to all SDK types#38

Open
johnpmitsch wants to merge 1 commit into
mainfrom
dx-5563-sdk-the-python-classes-dont-have-repr-or-str-methods
Open

feat(python): add __repr__ and to_dict to all SDK types#38
johnpmitsch wants to merge 1 commit into
mainfrom
dx-5563-sdk-the-python-classes-dont-have-repr-or-str-methods

Conversation

@johnpmitsch

Copy link
Copy Markdown
Collaborator

Summary

Adds __repr__ and to_dict() to every PyO3-exposed type in the Python SDK so they print readably (Endpoint { id: \"abc\", ... } instead of <builtins.Endpoint object at 0x...>) and convert cleanly to a native Python dict for JSON serialization, comparison, and logging.

  • New python_repr_dict! macro in crates/core/src/python_macros.rs emits both methods. Each pyclass module gets a python_repr_impls block listing one call per type (~160 types).

  • Workspace pyo3 gains multiple-pymethods so the macro can attach its own #[pymethods] impl beside any existing one.

  • __repr__ delegates to Rust Debug; to_dict uses pythonize over the type's Serialize impl.

  • Sensitive fields stay redacted in both repr() and to_dict():

    • SdkFullConfig.api_key (closes a latent leak — the derived Debug previously printed the raw key)
    • EndpointToken.token
    • EndpointJwt.public_key

    Per-type hand-rolled #[pymethods] blocks mirror the manual Debug redaction by overwriting the sensitive key with \"[redacted]\" after pythonize.

  • Per-language wrapper types (StreamWebhookDestination / StreamS3Destination / StreamAzureDestination / StreamPostgresDestination / StreamKafkaDestination, the 8 webhook template wrappers, PyStream, PyListStreamsResponse) all expose the same surface.

Docs: CLAUDE.md gains a Python __repr__ and to_dict subsection that documents the macro and the redaction workflow for credential-bearing types; python/README.md mentions both methods in Language conventions.

Closes DX-5563

Test plan

  • cargo check — all crates compile (python, node, ruby features)
  • just lintcargo clippy --workspace --lib --tests -- -D warnings clean
  • cargo test -p quicknode-sdk --lib — 204 tests pass, including a new sdk_full_config_debug_redacts_api_key regression test
  • just python-build — wheel + stubs regenerate; def __repr__ and def to_dict each appear 182 times in python/quicknode_sdk/_core/__init__.pyi
  • just node-build and just ruby-build — unaffected (macro is gated behind feature = \"python\")
  • Smoke-tested in Python:
    • repr(SdkFullConfig(api_key=\"x\")) contains \"[redacted]\", not \"x\"
    • SdkFullConfig(...).to_dict()[\"api_key\"] == \"[redacted]\"
    • Nested config round-trips through json.dumps
    • Wrapper types (StreamWebhookDestination) show inner attributes in repr and to_dict
  • Run python/examples/admin.py end-to-end against a real API key to verify the new repr / to_dict demo block prints as expected

Python classes previously printed as `<builtins.Endpoint object at 0x...>`
and had no built-in way to convert to a plain dict for JSON serialization
or comparison. Every PyO3-exposed type now implements:

- `__repr__()` delegating to Rust `Debug` for readable REPL/print output
- `to_dict()` returning a native Python dict via `pythonize` from the
  type's `Serialize` impl, so `json.dumps(obj.to_dict())` round-trips

Implementation:
- New `python_repr_dict!` macro (crates/core/src/python_macros.rs) emits
  both methods with one call per type; applied to ~160 pyclass types
- Workspace pyo3 gains the `multiple-pymethods` feature so the macro can
  attach a second `#[pymethods]` block alongside existing ones
- Per-language wrapper types (streams destinations, webhook templates,
  PyStream, PyListStreamsResponse) get hand-rolled equivalents because
  they hold non-Serialize fields

Redaction policy preserved: `SdkFullConfig.api_key`, `EndpointToken.token`,
and `EndpointJwt.public_key` show `"[redacted]"` in both repr() and
to_dict(). `SdkFullConfig` gets a manual `Debug` impl that mirrors the
existing pattern on internal `SdkConfig`, closing a latent leak where
the derived `Debug` would print the raw API key.

Docs: CLAUDE.md gains a "Python __repr__ and to_dict" subsection
documenting the macro and the redaction workflow; python/README.md
mentions both methods in the Language conventions section.

Closes DX-5563
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant