Skip to content

Commit 16a41f5

Browse files
authored
RELEASE:1.13.0 (microsoft#707)
### Work Item / Issue Reference > [AB#47087](https://sqlclientdrivers.visualstudio.com/c6d89619-62de-46a0-8b46-70b92a84d85e/_workitems/edit/47087) ------------------------------------------------------------------- ### Summary Release mssql-python v1.13.0. Version bump to 1.13.0. Updates `mssql_python/__init__.py`, `setup.py`, `PyPI_Description.md`, and the README "Important Note" section. Bundled `mssql_py_core` bumped from 0.1.7 to 0.1.8 (no source/API changes — dev-nightly to stable pin). #### Enhancements - **ODBC driver ships exclusively via `mssql-python-odbc` (Phase 2)** — The `libs/` fallback introduced in v1.12.0 has been removed. `mssql-python` now hard-depends on `mssql-python-odbc==18.6.2.1`; `pip install mssql-python` still pulls the driver package transparently. Smaller wheels; driver binaries managed independently (microsoft#693). - **Apache Arrow bulk copy** — New `Cursor.bulkcopy_arrow(table_name, source)` method for high-performance bulk loading from `pyarrow.Table` / `RecordBatch` / Arrow C Data Interface sources; classic `bulkcopy()` now raises `TypeError` for Arrow inputs and steers users to the new method (microsoft#665). - **`token_provider=` parameter for Azure Identity credentials** — `connect()` accepts any credential with a `.get_token(scope)` method (`DefaultAzureCredential`, `AzureCliCredential`, `ManagedIdentityCredential`, …). Mutually exclusive with `Authentication=` in the connection string (microsoft#603, issue microsoft#577). - **Identity-aware connection pooling with token-expiry refresh** — Pool now keys on security context, preventing cross-identity connection leaks; token acquisition deferred to pool-misses; connections with near-expiry tokens refreshed automatically (microsoft#660, issues microsoft#651, microsoft#659). #### Bug Fixes - **Silent zero-row `executemany` batches on late NULLs** — Fixed numeric array parameter binding paths (`TINYINT`/`SMALLINT`/`INT`/`FLOAT`) that left indicator slots uninitialized when a NULL appeared partway through the batch (microsoft#702, issue microsoft#670). - **`SQL_WVARCHAR` output converter applied as catch-all to non-string columns** — Fallback now gated on `str`/`bytes` mapped types (microsoft#692, issue microsoft#691). - **Integer-keyed output converters silently never fired** — `add_output_converter(SQL_DECIMAL, ...)` and other integer SQL type code keys now dispatch correctly (pyodbc parity) (microsoft#690, issue microsoft#684). - **`RecordBatchReader.Close()` for Arrow result sets** — `Cursor.arrow_reader()` now returns a wrapper whose `.close()` releases server-side resources and leaves the parent cursor usable (microsoft#644, issue microsoft#643). - **`AttributeError` in `Cursor.__del__` on partially-initialized cursor** — `__init__` sets `closed`/`hstmt` before any raise; `__del__` uses correct `sys.is_finalizing()` guard (microsoft#646, issue microsoft#642). #### Version Bump - `mssql_python/__init__.py`: `__version__ = "1.13.0"` - `setup.py`: `version="1.13.0"` - `PyPI_Description.md`: `## What's new in v1.13.0` section refreshed - `README.md`: "Important Note" updated for Phase 2 (no more `libs/` fallback, `mssql-python-odbc==18.6.2.1`)
1 parent a6a7c93 commit 16a41f5

4 files changed

Lines changed: 16 additions & 12 deletions

File tree

PyPI_Description.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,22 @@ PyBind11 provides:
3535
- Memory-safe bindings
3636
- Clean and Pythonic API, while performance-critical logic remains in robust, maintainable C++.
3737

38-
## What's new in v1.12.0
38+
## What's new in v1.13.0
3939

4040
### Enhancements
4141

42-
- **Standalone `mssql-python-odbc` Package** - The bundled ODBC driver binaries are now also published as a separate, pure-data package `mssql-python-odbc` (import name `mssql_python_odbc`, version 18.6.2). `mssql-python` now depends on `mssql-python-odbc==18.6.2` and prefers the external package at import time, falling back to the still-bundled `libs/` tree so existing installs keep working (#663, #687).
42+
- **ODBC Driver Now Ships Exclusively via `mssql-python-odbc`** - The `libs/` fallback introduced in v1.12.0 has been removed. `mssql-python` now hard-depends on `mssql-python-odbc==18.6.2.1`; `pip install mssql-python` still Just Works and transparently pulls the driver package. Wheels are smaller and driver binaries are managed independently (#693).
43+
- **Apache Arrow Bulk Copy** - New `Cursor.bulkcopy_arrow(table_name, source)` method for high-performance bulk loading from `pyarrow.Table`, `RecordBatch`, or any object exposing the Arrow C Data Interface, avoiding Python row materialization. The classic `bulkcopy()` now raises `TypeError` for Arrow inputs and steers users to the new method (#665).
44+
- **`token_provider=` Parameter for Azure Identity** - `connect()` now accepts a `token_provider` object with a `.get_token(scope)` method, enabling `DefaultAzureCredential`, `AzureCliCredential`, `ManagedIdentityCredential`, and any custom credential from `azure-identity`. Bulk copy re-acquires a fresh token per operation. Mutually exclusive with `Authentication=` in the connection string (#603).
45+
- **Identity-Aware Connection Pooling with Token-Expiry Refresh** - The pool now keys on the security context (connection string + identity discriminator) so a connection authenticated as user A can never be handed to user B. Token acquisition is deferred to pool misses, and pooled connections whose token is within 5 minutes of expiry are refreshed automatically (#660).
4346

4447
### Bug Fixes
4548

46-
- **Bulk Copy Connection Timeout** - `cursor.bulkcopy()` now forwards the cursor's connection timeout (from `connect(timeout=X)`) into the underlying `mssql_py_core` connection, instead of always using the hardcoded 15s default (#650).
47-
- **Bulk Copy of Custom CLR UDT Columns** - Fixed a `Protocol Error: Unsupported TDS type for bulk copy: 0xF0` that prevented `cursor.bulkcopy()` from loading rows into custom (non-spatial) CLR UDT columns; UDT columns are now mapped to `varbinary(max)` on the wire and the supplied bytes are streamed as the UDT's serialized form (#688, via `mssql_py_core` 0.1.7).
49+
- **Silent Zero-Row `executemany` Batches on Late NULLs** - Fixed numeric array parameter binding paths (`TINYINT` / `SMALLINT` / `INT` / `FLOAT`) that left indicator slots uninitialized when a NULL appeared partway through the batch, causing the batch to insert zero rows without raising (#702, issue #670).
50+
- **`SQL_WVARCHAR` Output Converter Applied to Non-String Columns** - The legacy `SQL_WVARCHAR` catch-all no longer runs against `INT` / `DECIMAL` / `DATE` columns. Registering a single `SQL_WVARCHAR` converter used to mangle every non-string column value; the fallback is now gated on `str`/`bytes` mapped types, matching `Row._apply_output_converters` (#692, issue #691).
51+
- **Integer-Keyed Output Converters Now Fire** - `Connection.add_output_converter(SQL_DECIMAL, ...)` and any other integer ODBC SQL type code as a key now dispatch correctly. Previously the converter dictionary was keyed only by Python type, so integer-keyed registrations were silently stored but never invoked, diverging from `pyodbc` and from the driver's own documentation. Integer keys take precedence over Python-type keys, and `SQL_DECIMAL` vs `SQL_NUMERIC` are dispatched distinctly (#690, issue #684).
52+
- **`RecordBatchReader.Close()` for Arrow Result Sets** - `Cursor.arrow_reader()` now returns a wrapped reader whose `.close()` stops fetching, releases the server-side cursor, resets cursor state, and leaves the parent cursor usable. Supports idempotent close and context-manager usage (#644, issue #643).
53+
- **`AttributeError` on Partially-Initialized `Cursor` Cleanup** - `Cursor.__init__` now sets `self.closed = False` and `self.hstmt = None` before any code that can raise, `close()` defends with `getattr(self, "closed", True)`, and `__del__` uses the correct `sys.is_finalizing()` guard, so half-constructed cursors no longer emit unraisable exceptions during garbage collection (#646, issue #642).
4854

4955
For more information, please visit the project link on Github: https://github.com/microsoft/mssql-python
5056

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,15 @@ The driver is compatible with all the Python versions >= 3.10
1212
> **Important Note:**
1313
>
1414
> ### ODBC Driver Distribution
15-
> The ODBC driver binaries used by `mssql-python` are now distributed through a dedicated companion package:
15+
> The ODBC driver binaries used by `mssql-python` are distributed exclusively through a dedicated companion package:
1616
>
1717
> - Package: `mssql-python-odbc`
1818
> - Import name: `mssql_python_odbc`
19-
> - Current version: **18.6.2**
19+
> - Current version: **18.6.2.1**
2020
>
21-
> When installed, `mssql-python` automatically depends on and loads the ODBC driver binaries from `mssql-python-odbc`.
21+
> `mssql-python` depends on `mssql-python-odbc==18.6.2.1` and loads the ODBC driver binaries from it at import time. `pip install mssql-python` transparently pulls the companion package alongside it — no separate install step is required.
2222
>
23-
> To ensure a smooth transition, the current release retains the bundled binaries within the `libs/` directory and uses them as a fallback if the external package is unavailable. Existing installations will continue to work without modification.
24-
>
25-
> **Note:** The bundled `libs/` fallback is deprecated and will be removed in a future release. Beginning with a subsequent release, the ODBC binaries will be supplied exclusively through the `mssql-python-odbc` package. We recommend validating environments against the standalone package ahead of this change.
23+
> Starting with v1.13.0, the bundled `libs/` fallback that shipped in v1.12.0 has been removed. `mssql-python` will fail to import if `mssql-python-odbc` is not installed. If you install `mssql-python` from a private index or with `--no-deps`, make sure `mssql-python-odbc==18.6.2.1` is installed alongside it.
2624
2725
## Installation
2826

mssql_python/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from .helpers import Settings, get_settings, _settings, _settings_lock
1515

1616
# Driver version
17-
__version__ = "1.12.0"
17+
__version__ = "1.13.0"
1818

1919
# Exceptions
2020
# https://www.python.org/dev/peps/pep-0249/#exceptions

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ def run(self):
197197

198198
setup(
199199
name="mssql-python",
200-
version="1.12.0",
200+
version="1.13.0",
201201
description="A Python library for interacting with Microsoft SQL Server",
202202
long_description=open("PyPI_Description.md", encoding="utf-8").read(),
203203
long_description_content_type="text/markdown",

0 commit comments

Comments
 (0)