Skip to content

Conversation

@omercnet
Copy link
Member

@omercnet omercnet commented Dec 23, 2025

Summary

Add verbose mode to DescopeClient and HTTPClient to capture HTTP response metadata (headers, status codes, etc.) for debugging failed requests with Descope support.

Key Changes

  • DescopeResponse wrapper class: Provides dict-like interface while exposing HTTP metadata (headers, status_code, text, etc.)
  • Verbose parameter: Added to DescopeClient and HTTPClient (defaults to False for backward compatibility)
  • get_last_response() methods: Access captured response data for debugging
  • Thread-safe: Uses threading.local() so each thread gets its own response when sharing a client
  • Full backward compatibility: Zero overhead when disabled (default behavior unchanged)
  • Comprehensive testing: All 386 tests passing (including thread safety tests)
  • Documentation & examples: Added usage examples and README documentation

Use Case

This enables customers to capture cf-ray headers and other HTTP metadata when troubleshooting issues with Descope support:

client = DescopeClient(project_id, management_key, verbose=True)
try:
    client.mgmt.user.create(login_id="test@example.com")
except AuthException:
    resp = client.get_last_response()
    if resp:
        print(f"cf-ray: {resp.headers.get('cf-ray')}")  # For support tickets
        print(f"Status: {resp.status_code}")

Thread Safety

The verbose mode is thread-safe - each thread sees its own response even when sharing a client instance:

# Safe to use across threads
client = DescopeClient(project_id, mgmt_key, verbose=True)

def worker():
    client.mgmt.user.load(...)
    resp = client.get_last_response()  # Returns THIS thread's response
    print(resp.headers.get('cf-ray'))  # Correct cf-ray for this thread

Testing

  • ✅ All 386 tests passing
  • ✅ Added 15 new tests for verbose mode functionality
  • ✅ Thread safety tests verify concurrent access works correctly
  • ✅ Backward compatibility verified (default behavior unchanged)
  • ✅ Pre-commit hooks passing

Files Changed

  • descope/http_client.py - Core implementation (DescopeResponse class, verbose mode, thread-local storage)
  • descope/descope_client.py - Client-level verbose mode support
  • descope/__init__.py - Export DescopeResponse
  • tests/test_http_client.py - Unit tests for DescopeResponse, HTTPClient verbose mode, and thread safety
  • tests/test_descope_client.py - Integration tests for DescopeClient verbose mode
  • samples/verbose_mode_example.py - Usage examples (new file)
  • README.md - Documentation added

Fixes https://github.com/descope/etc/issues/12957

Copilot AI review requested due to automatic review settings December 23, 2025 13:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an opt-in verbose mode to capture HTTP response metadata (headers, status codes, etc.) for debugging failed requests with Descope support. The implementation introduces a DescopeResponse wrapper class that maintains backward compatibility while exposing HTTP metadata, and adds verbose parameters to both DescopeClient and HTTPClient that default to False.

Key Changes:

  • New DescopeResponse wrapper providing dict-like interface plus HTTP metadata access
  • Opt-in verbose parameter added to client constructors (defaults to False)
  • Response capture logic in HTTP methods when verbose mode is enabled

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
descope/http_client.py Core implementation with DescopeResponse class and verbose mode capture logic
descope/descope_client.py Added verbose parameter forwarding and get_last_response() method
descope/__init__.py Exported DescopeResponse for public API access
tests/test_http_client.py Unit tests for DescopeResponse wrapper and HTTPClient verbose mode
tests/test_descope_client.py Integration tests for DescopeClient verbose mode functionality
samples/verbose_mode_example.py Example demonstrating verbose mode usage for debugging
README.md Documentation for verbose mode feature and usage examples
.pre-commit-config.yaml Updated pre-commit hook versions and reorganized poetry-export hook

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add verbose mode to DescopeClient and HTTPClient to capture HTTP response
metadata (headers, status codes, etc.) for debugging failed requests.

Key changes:
- Add DescopeResponse wrapper class providing dict-like interface while
  exposing HTTP metadata (headers, status_code, text, etc.)
- Add verbose parameter to DescopeClient and HTTPClient (defaults to False)
- Add get_last_response() methods to access captured response data
- Maintain full backward compatibility (zero overhead when disabled)
- Add comprehensive tests (366 total tests passing)
- Add usage examples and documentation

This enables customers to capture cf-ray headers and other HTTP metadata
when troubleshooting issues with Descope support.

Fixes descope/etc#12957
@omercnet omercnet force-pushed the feature/verbose-mode-http-metadata branch from cddbdfe to 81060f7 Compare December 23, 2025 13:18
@github-actions
Copy link

github-actions bot commented Dec 23, 2025

Coverage report

The coverage rate went from 98.14% to 98.22% ⬆️

100% of new lines are covered.

Diff Coverage details (click to unfold)

descope/descope_client.py

100% of new lines are covered (97.89% of the complete file).

descope/http_client.py

100% of new lines are covered (100% of the complete file).

descope/init.py

100% of new lines are covered (100% of the complete file).

@omercnet omercnet enabled auto-merge (squash) December 23, 2025 13:21
@dorsha
Copy link
Member

dorsha commented Dec 23, 2025

Coverage report

The coverage rate went from 98.14% to 97.72% ⬇️

83.75% of new lines are covered.

Diff Coverage details (click to unfold)

@omercnet check the coverage issue

omercnet and others added 2 commits December 23, 2025 16:52
…esponse

- Fix: Move verbose capture before error raising so failed responses are captured
- Add: Tests for all DescopeResponse dict-like methods and properties
- Add: Tests for verbose mode capturing GET, POST, PATCH, DELETE responses
- Add: Tests for error handling paths (AuthException, RateLimitException)
- Add: Tests for header parsing and retry-after edge cases
- Coverage: Achieves 98% overall, 100% for http_client.py
@omercnet
Copy link
Member Author

Coverage report

The coverage rate went from 98.14% to 97.72% ⬇️

83.75% of new lines are covered.

Diff Coverage details (click to unfold)

@omercnet check the coverage issue

Fixed

@dorsha
Copy link
Member

dorsha commented Dec 23, 2025

Looks good to me.
@ruvenzx please test this and approve.

@ruvenzx
Copy link
Contributor

ruvenzx commented Dec 25, 2025

LGTM, i've tested with threading and multiprocessing, with threading it seems like the same cf-ray is returned if the same client instance is used.
we need to document that users should either use separate client instances per thread if threading is being used in their code.

Use thread-local storage for _last_response so each thread sees its own
response when sharing a DescopeClient instance. Prevents race condition
where concurrent requests would overwrite each other's cf-ray headers.
@omercnet
Copy link
Member Author

Good catch! 🧵

Fixed in 61593d8 - the verbose mode is now thread-safe using threading.local() storage.

Each thread now gets its own _last_response, so you can safely share a single client instance across threads and still get the correct cf-ray for each thread's request.

# This now works correctly - each thread sees its own cf-ray
client = DescopeClient(project_id, mgmt_key, verbose=True)

def worker():
    client.mgmt.user.load(...)
    resp = client.get_last_response()  # Thread-safe!
    print(resp.headers.get('cf-ray'))  # Correct cf-ray for this thread

Added tests to verify thread safety in tests/test_http_client.py::TestVerboseModeThreadSafety.

@ruvenzx ruvenzx self-requested a review December 25, 2025 08:18
@omercnet omercnet merged commit 91b364a into main Dec 25, 2025
29 checks passed
@omercnet omercnet deleted the feature/verbose-mode-http-metadata branch December 25, 2025 09:24
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.

4 participants