From c9add73de9241b2a3cf8f5e51b488f0528f078fd Mon Sep 17 00:00:00 2001 From: Darshan Date: Sat, 31 Jan 2026 16:03:01 +0530 Subject: [PATCH] fix: close file descriptors in Requests-style file tuples When users pass files using the Requests API format {'key': ('filename', fileobj, ...)}, the inner fileobj was not being closed by _close_file_descriptors. This could lead to resource leaks in uploads. - Extend _close_file_descriptors to detect and close file objects inside file-tuple values. - Add unit test to verify the behavior. --- src/RequestsLibrary/RequestsKeywords.py | 18 ++++++++++++------ utests/test_RequestsOnSessionKeywords.py | 12 ++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/RequestsLibrary/RequestsKeywords.py b/src/RequestsLibrary/RequestsKeywords.py index c74bf83..711fdc5 100644 --- a/src/RequestsLibrary/RequestsKeywords.py +++ b/src/RequestsLibrary/RequestsKeywords.py @@ -59,19 +59,25 @@ def _close_file_descriptors(files, data): """ Helper method that closes any open file descriptors. """ - + if is_list_or_tuple(files): files_descriptor_to_close = filter( is_file_descriptor, [file[1][1] for file in files] + [data] ) else: - files_descriptor_to_close = filter( - is_file_descriptor, list(files.values()) + [data] - ) - + files_descriptor_to_close = [] + for value in (files or {}).values(): + if is_file_descriptor(value): + files_descriptor_to_close.append(value) + elif is_list_or_tuple(value) and len(value) >= 2 and is_file_descriptor(value[1]): + files_descriptor_to_close.append(value[1]) + + if is_file_descriptor(data): + files_descriptor_to_close.append(data) + for file_descriptor in files_descriptor_to_close: file_descriptor.close() - + @staticmethod def _merge_url(session, uri): """ diff --git a/utests/test_RequestsOnSessionKeywords.py b/utests/test_RequestsOnSessionKeywords.py index ed82091..6c6acc7 100644 --- a/utests/test_RequestsOnSessionKeywords.py +++ b/utests/test_RequestsOnSessionKeywords.py @@ -32,6 +32,18 @@ def test_common_request_files_descriptor_closing_when_passed_as_files_param(): assert f2.closed is True +def test_common_request_files_descriptor_closing_when_passed_as_file_tuple(): + session, m_common_request = build_mocked_session_common_request() + with open(os.path.join(SCRIPT_DIR, '../atests/randombytes.bin'), 'rb') as f: + m_common_request( + 'get', + session, + 'http://mocking.rules', + files={'randombytes': ('randombytes.bin', f)}, + ) + assert f.closed is True + + def test_common_request_verify_override_true(): session, m_common_request = build_mocked_session_common_request(verify=False) m_common_request('get', session, '/', verify=True)