Add async/await support to ottu-py SDK#22
Merged
jerinpetergeorge merged 6 commits intomainfrom Jun 23, 2025
Merged
Conversation
- Add OttuAsync class with full async/await support - Add AsyncSession and AsyncCard classes for async operations - Add AsyncRequestResponseHandler for async HTTP operations - Support async context manager pattern with proper cleanup - Maintain identical API signatures between sync and async versions - Add comprehensive documentation and examples in README - All async operations support the same features as sync versions - Add pytest-asyncio dependency for async testing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
## Major Improvements ### Clean Architecture with sync_to_async - Replaced duplicate async implementation with Django's sync_to_async wrapper - Ensures 100% behavioral consistency between sync and async versions - Zero code duplication - single source of truth for all logic - Uses proven, battle-tested approach from Django ecosystem ### Dependencies and Installation - Added asgiref as optional async dependency: `pip install 'ottu-py[async]'` - Works with FastAPI, Django async views, aiohttp, and any async framework - Graceful import error handling with helpful installation message ### Simplified Test Suite - Completely rewritten tests using httpx_mock (no more unittest.mock.patch) - Tests follow same patterns as sync tests for consistency - Comprehensive coverage of all async functionality - 193 tests passing with 97.91% coverage ### Enhanced Documentation - Updated README with sync_to_async approach explanation - Clear installation instructions for async support - Framework integration examples (FastAPI, Django, aiohttp) - Emphasis on 100% API consistency between sync and async ### Code Quality Fixes - Fixed all GitHub PR review comments - Removed complex async request handlers - not needed with sync_to_async - Clean async context manager support - Proper error handling maintaining sync behavior ### Benefits - **Zero Maintenance Overhead**: No separate async code to maintain - **Perfect Consistency**: Identical behavior guaranteed - **Framework Agnostic**: Works with any async Python framework - **Battle Tested**: Uses Django's proven sync_to_async approach - **Type Safety**: All type hints and signatures preserved 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Integrate async support with Django and FastAPI dependencies - Remove separate async installation requirement - Update pyproject.toml to include asgiref with Django/FastAPI extras - Fix f-string parsing error in example_async.py - Remove unused typing import from async_ottu.py - Fix long lines in test files to comply with flake8 - Add proper file endings and formatting - Update README to reflect integrated async approach 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove FastAPI-specific installation method - Restore async extra in pyproject.toml for clean separation - Update import error message to guide users to [async] extra - Simplify README to focus on 2 installation methods: - ottu-py[async] for async support with any framework - ottu-py[django] for Django integration (includes async) - Remove FastAPI references since async works universally 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull Request Overview
This PR introduces full async/await support to the ottu-py SDK via a new OttuAsync wrapper while preserving the existing synchronous API.
- Add
OttuAsync,AsyncSessionWrapper, andAsyncCardWrapperusingsync_to_asyncfor seamless async compatibility - Refactor
RequestResponseHandlerinto a sharedBaseRequestResponseHandlerand enhance logging - Provide comprehensive async test suite, update installation extras, examples, and documentation
Reviewed Changes
Copilot reviewed 10 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_ottu/test_async_ottu.py | New async tests covering auto debit, checkout, core, cards, sessions |
| src/ottu/request.py | Split handler into BaseRequestResponseHandler, add logging methods |
| src/ottu/async_ottu.py | Implement OttuAsync, session and card async wrappers |
| src/ottu/init.py | Export OttuAsync in __all__ |
| pyproject.toml | Define async extra, add asgiref dependency |
| example_async.py | Add demo script for async usage |
| README.md | Document async support, install extras, and usage examples |
| CLAUDE.md | Update project guidance including async section |
| .flake8 | Exclude example_async.py from lint |
Comments suppressed due to low confidence (5)
README.md:509
- [nitpick] sync_to_async is provided by asgiref, not Django. Consider updating the description to reference asgiref.sync_to_async for clarity.
The SDK provides full asynchronous support through the `OttuAsync` class using Django's `sync_to_async` wrapper. This ensures 100% identical behavior between sync and async versions while providing proper async/await support.
CLAUDE.md:79
- The documentation refers to a non-existent src/ottu/async_session.py. Async session functionality is implemented within src/ottu/async_ottu.py as AsyncSessionWrapper. Update the path and class name accordingly.
- **RequestResponseHandler**: Synchronous HTTP requests using httpx.Client
tests/test_ottu/test_async_ottu.py:294
- [nitpick] test_session_operations only covers capture. Other session methods (refund, void, cancel, expire, delete, update, refresh) added in AsyncSessionWrapper are not tested. Consider expanding this test or adding new ones to cover all session operations.
async def test_session_operations(self, httpx_mock, auth_api_key):
src/ottu/request.py:25
- BaseRequestResponseHandler.init accepts **kwargs but never assigns self.kwargs, causing AttributeError in _log_request and _log_response. Add self.kwargs = kwargs in the initializer.
**kwargs,
src/ottu/request.py:2
- httpx is referenced in type hints (httpx.Client, httpx.AsyncClient) and used in RequestResponseHandler, but there is no import httpx at the top of the file. Add import httpx.
import typing
- Remove duplicate files with weird \!21xxx\! names - Fix README reference to use asgiref.sync.sync_to_async instead of Django's - Update CLAUDE.md to reference correct async wrapper classes and paths - Expand async session test coverage to include all operations: refund, void, cancel, expire (in addition to existing capture test) - All async tests passing (21 passed, 2 skipped) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds comprehensive asynchronous support to the ottu-py SDK while maintaining full backward compatibility with the existing synchronous API.
Key Features
async withpatternImplementation Details
Testing
Documentation
Test plan
🤖 Generated with Claude Code