Skip to content

Commit 0bc1b5b

Browse files
authored
FEAT: Connection.closed property (microsoft#398)
### Work Item / Issue Reference <!-- IMPORTANT: Please follow the PR template guidelines below. For mssql-python maintainers: Insert your ADO Work Item ID below (e.g. AB#37452) For external contributors: Insert Github Issue number below (e.g. microsoft#149) Only one reference is required - either GitHub issue OR ADO Work Item. --> <!-- mssql-python maintainers: ADO Work Item --> > [AB#41491](https://sqlclientdrivers.visualstudio.com/c6d89619-62de-46a0-8b46-70b92a84d85e/_workitems/edit/41491) <!-- External contributors: GitHub Issue --> > GitHub Issue: microsoft#394 ------------------------------------------------------------------- ### Summary This pull request introduces a new `closed` property to the connection class in `mssql_python/connection.py`, providing a clear and explicit way to check if a connection has been closed. Comprehensive tests have been added to ensure correct behavior of this property under various scenarios, improving reliability and clarity for users of the connection API. **Connection class enhancements:** * Added a `closed` property to the connection class, which returns `True` if `close()` was called, and `False` otherwise. This property does not indicate connection health, only whether `close()` was explicitly invoked. **Test coverage improvements:** * Added tests to verify the `closed` property reflects the connection state before and after calling `close()`. * Added tests to confirm that calling `close()` multiple times is safe and the `closed` property remains `True` (idempotency). * Added tests to check the `closed` property when using the connection as a context manager, ensuring it is `True` after exiting the block. * Added tests to verify that operations on a closed connection raise appropriate exceptions, and the `closed` property accurately reflects the closed state.
1 parent 9a30068 commit 0bc1b5b

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

mssql_python/connection.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,22 @@ def autocommit(self, value: bool) -> None:
445445
self.setautocommit(value)
446446
logger.info("Autocommit mode set to %s.", value)
447447

448+
@property
449+
def closed(self) -> bool:
450+
"""
451+
Returns True if the connection is closed, False otherwise.
452+
453+
This property indicates whether close() was explicitly called on
454+
the connection. Note that this does not indicate whether the
455+
connection is healthy/alive - if a timeout or network issue breaks
456+
the connection, closed would still be False until close() is
457+
explicitly called.
458+
459+
Returns:
460+
bool: True if the connection is closed, False otherwise.
461+
"""
462+
return self._closed
463+
448464
def setautocommit(self, value: bool = False) -> None:
449465
"""
450466
Set the autocommit mode of the connection.

tests/test_003_connection.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,71 @@ def test_connection_close(conn_str):
362362
temp_conn.close()
363363

364364

365+
def test_connection_closed_property_reflects_state(conn_str):
366+
"""
367+
Test that the closed property correctly reflects the connection state.
368+
369+
This test verifies that:
370+
1. A new connection has closed=False
371+
2. After calling close(), closed=True
372+
"""
373+
temp_conn = connect(conn_str)
374+
# New connection should not be closed
375+
assert temp_conn.closed is False, "New connection should have closed=False"
376+
377+
# Close the connection
378+
temp_conn.close()
379+
380+
# After close(), closed should be True
381+
assert temp_conn.closed is True, "After close(), connection should have closed=True"
382+
383+
384+
def test_connection_closed_property_after_multiple_close_calls(conn_str):
385+
"""
386+
Test that calling close() multiple times is safe and closed remains True.
387+
388+
This test verifies idempotent behavior of close() and the closed property.
389+
"""
390+
temp_conn = connect(conn_str)
391+
assert temp_conn.closed is False
392+
393+
# First close
394+
temp_conn.close()
395+
assert temp_conn.closed is True
396+
397+
# Second close should not raise and closed should still be True
398+
temp_conn.close() # Should not raise
399+
assert temp_conn.closed is True
400+
401+
402+
def test_connection_closed_property_with_context_manager(conn_str):
403+
"""
404+
Test that closed property is True after exiting context manager.
405+
"""
406+
with connect(conn_str) as temp_conn:
407+
assert temp_conn.closed is False, "Connection should be open inside context manager"
408+
409+
# After exiting context manager, connection should be closed
410+
assert temp_conn.closed is True, "Connection should be closed after exiting context manager"
411+
412+
413+
def test_connection_closed_property_operations_after_close(conn_str):
414+
"""
415+
Test that operations on a closed connection raise appropriate exceptions.
416+
417+
This test verifies that attempting to use a closed connection raises
418+
an InterfaceError, and the closed property correctly reflects the state.
419+
"""
420+
temp_conn = connect(conn_str)
421+
temp_conn.close()
422+
423+
assert temp_conn.closed is True
424+
425+
# Attempting to create a cursor on a closed connection should raise InterfaceError
426+
with pytest.raises(InterfaceError):
427+
temp_conn.cursor()
428+
429+
365430
def test_connection_timeout_invalid_password(conn_str):
366431
"""Test that connecting with an invalid password raises an exception quickly (timeout)."""
367432
# Modify the connection string to use an invalid password

0 commit comments

Comments
 (0)