Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
feat: `Client` can be used as a context manager and closed explicitly with `close()` to release pooled HTTP connections (#87)

## [2.0.1][2.0.1] - 2026-03-09
feat: Added Support for cancel token
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ client = razorpay.Client(auth=("<YOUR_API_KEY>", "<YOUR_API_SECRET>"))
client.enable_retry(True) # Enable retry mechanism for failed API calls
```

The client keeps a pooled HTTP session open. Close it when you are done, or use the client as a context manager:

```py
with razorpay.Client(auth=("<YOUR_API_KEY>", "<YOUR_API_SECRET>")) as client:
client.payment.fetch("pay_XXXXXXXXXXXXXX")
# the session is closed here

client = razorpay.Client(auth=("<YOUR_API_KEY>", "<YOUR_API_SECRET>"))
...
client.close()
```

## App Details

After setting up client, you can set your app details before making any request
Expand Down
13 changes: 13 additions & 0 deletions razorpay/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ def set_app_details(self, app_details):
def get_app_details(self):
return self.app_details

def close(self):
"""
Close the underlying HTTP session and release its pooled connections.
The client should not be used for further requests after this.
"""
self.session.close()

def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, traceback):
self.close()

def enable_retry(self, retry_enabled=False):
self.retry_enabled = retry_enabled

Expand Down
34 changes: 34 additions & 0 deletions tests/test_client_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import unittest
from unittest import mock

import razorpay


class TestClientSession(unittest.TestCase):

def test_close_closes_session(self):
session = mock.Mock()
client = razorpay.Client(session=session, auth=('key_id', 'key_secret'))
client.close()
session.close.assert_called_once_with()

def test_context_manager_returns_client_and_closes_on_exit(self):
session = mock.Mock()
with razorpay.Client(session=session, auth=('key_id', 'key_secret')) as client:
self.assertIsInstance(client, razorpay.Client)
session.close.assert_not_called()
session.close.assert_called_once_with()

def test_context_manager_closes_on_exception(self):
session = mock.Mock()
with self.assertRaises(RuntimeError):
with razorpay.Client(session=session, auth=('key_id', 'key_secret')):
raise RuntimeError('boom')
session.close.assert_called_once_with()

def test_default_session_is_closed(self):
client = razorpay.Client(auth=('key_id', 'key_secret'))
with mock.patch.object(client.session, 'close') as close:
with client:
pass
close.assert_called_once_with()