Skip to content

Conversation

@jahnvi480
Copy link
Contributor

@jahnvi480 jahnvi480 commented Aug 4, 2025

Work Item / Issue Reference

AB#38074

GitHub Issue: #23


Summary

This pull request introduces context manager support for the Connection and Cursor classes in the mssql_python module, aligning their behavior with pyodbc. It also adds extensive tests to ensure correct functionality, covering various scenarios such as normal exits, exceptions, nested transactions, and manual commit/rollback. The key changes are grouped below:

Context Manager Support

  • Added __enter__ and __exit__ methods to the Connection class to enable usage with the with statement. The connection commits transactions on normal exit and rolls back on exceptions, without closing the connection.
  • Added __enter__ and __exit__ methods to the Cursor class to allow usage with the with statement. The cursor commits transactions on normal exit but does not close itself, aligning with pyodbc behavior.

Logging Enhancements

  • Enhanced the Connection.close method to log when uncommitted changes are rolled back before closing.

Test Coverage

  • Added new tests in tests/test_003_connection.py to verify context manager behavior for connections, including:
    • Committing transactions on normal exit.
    • Rolling back transactions on exceptions.
    • Handling autocommit mode.
    • Ensuring connections remain open after context exit.
    • Supporting nested context managers.
    • Testing manual commit/rollback within a context manager.
  • Added a test for using contextlib.closing with connections to ensure proper closure after context exit.
  • Updated tests/test_004_cursor.py to include contextlib.closing for cursor tests.

@github-actions github-actions bot added the pr-size: large Substantial code update label Aug 4, 2025
@LarnuUK
Copy link

LarnuUK commented Aug 4, 2025

Why, out of interest @jahnvi480 , should the context managers not close the connection/cursor? I am aware that you state that this aligns with pyodbc but is that the right choice? The behaviour, honestly, feels more like a "gotcha", as often it would be expected that the connection/cursor would be disposed of when the context manage is closed. Look, for example, at Psycopg 3 which changed their default behaviour to close to the connection. I actually think that the context managers closing the objects implicitly would be far better. If people don't want them closed like that, then they (likely) wouldn't use a context manager.

@jahnvi480 jahnvi480 changed the base branch from jahnvi/connection_pyodbc to main August 6, 2025 08:33
Copilot AI review requested due to automatic review settings August 6, 2025 09:27
@github-actions github-actions bot added pr-size: large Substantial code update and removed pr-size: large Substantial code update labels Aug 6, 2025
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 pull request adds context manager support (__enter__ and __exit__ methods) to both the Connection and Cursor classes, enabling their use with Python's with statement. The implementation follows pyodbc behavior where context managers commit transactions on normal exit and rollback on exceptions, but do not close the connection/cursor itself.

Key changes:

  • Context manager methods added to both Connection and Cursor classes with transaction management
  • Enhanced logging in Connection.close method to track rollback operations
  • Comprehensive test coverage for various context manager scenarios including autocommit modes, exceptions, and nested usage

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
mssql_python/connection.py Adds __enter__ and __exit__ methods with transaction commit/rollback logic and enhanced logging
mssql_python/cursor.py Adds __enter__ and __exit__ methods that delegate transaction management to the connection
tests/test_003_connection.py Comprehensive context manager tests for connections including edge cases and contextlib.closing usage
tests/test_004_cursor.py Extensive cursor context manager tests covering various scenarios and error conditions

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-actions github-actions bot added pr-size: large Substantial code update and removed pr-size: large Substantial code update labels Aug 6, 2025
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-actions github-actions bot added pr-size: large Substantial code update and removed pr-size: large Substantial code update labels Aug 6, 2025
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-actions github-actions bot added pr-size: large Substantial code update and removed pr-size: large Substantial code update labels Aug 6, 2025
@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Aug 13, 2025
sumitmsft
sumitmsft previously approved these changes Aug 26, 2025
Copy link
Contributor

@sumitmsft sumitmsft left a comment

Choose a reason for hiding this comment

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

Good PR, we have had several discussions on this over a period of time and this has come out nicely.

In totality, following are the scenarios captured and their corresponding outcome:

Feature/Scenario and Outcomes:
Connection as Context Manager
Begins transaction on enter. On exit: commit if no error, rollback if error, always closes connection.

Cursor as Context Manager
Opens cursor on enter. On exit: closes cursor and releases resources. Does not close connection/transaction.

Automatic Commit/Rollback
Commits or rolls back transaction on context exit depending on success/error.

Resource Cleanup/No Leaks
All cursors and connections closed on exit or error, even if explicit close not called.

Nested Usage (multiple cursors from same connection)
Multiple cursors can be opened in nested/parallel contexts. Connection is reused until explicitly closed.

Destructor Safety Net
Cursor/connection resources are cleaned up even if not closed explicitly.

No Transaction/Connection Closure on Cursor Close
Closing a cursor only affects that cursor; connection/transaction remain open/active.

All Cursors Closed on Connection Close
When connection is closed, all open cursors are closed automatically.

Idempotency and Safety on Multiple Close Calls
Closing connection or cursor multiple times is safe and does not cause errors.

Compliance with Python DB-API 2.0 (PEP 249) context manager pattern
Both Connection and Cursor implement enter/exit as per DB-API best practices.

@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Aug 26, 2025
@jahnvi480 jahnvi480 requested a review from sumitmsft August 26, 2025 22:28
gargsaumya
gargsaumya previously approved these changes Aug 27, 2025
@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Aug 27, 2025
@jahnvi480 jahnvi480 requested a review from gargsaumya August 27, 2025 11:28
sumitmsft
sumitmsft previously approved these changes Aug 27, 2025
@github-actions github-actions bot added pr-size: medium Moderate update size and removed pr-size: medium Moderate update size labels Aug 27, 2025
@jahnvi480 jahnvi480 requested a review from sumitmsft August 27, 2025 12:16
@jahnvi480 jahnvi480 merged commit f4c899e into main Aug 27, 2025
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-size: medium Moderate update size

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants