Skip to content
13 changes: 13 additions & 0 deletions docs/reference/adapters/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ exports a typed config class and a driver implementation.

Sync + Async SQL Server via Microsoft's official mssql-python driver.

.. grid-item-card:: pymssql
:link: pymssql
:link-type: doc

Sync SQL Server via pymssql / FreeTDS.

Feature Comparison
==================

Expand Down Expand Up @@ -235,6 +241,12 @@ Feature Comparison
- Yes
-
-
* - pymssql
- Yes
-
- Yes
-
-

.. toctree::
:hidden:
Expand All @@ -257,3 +269,4 @@ Feature Comparison
adbc
arrow_odbc
mssql_python
pymssql
57 changes: 57 additions & 0 deletions docs/reference/adapters/pymssql.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
========
pymssql
========

Sync SQL Server adapter using `pymssql <https://pypi.org/project/pymssql/>`_
and FreeTDS. It uses pyformat parameters (``%s`` and ``%(name)s``) and exposes
sync SQLSpec config, driver, pooling, data dictionary, migration, and extension
store integrations.

Configuration
=============

.. autoclass:: sqlspec.adapters.pymssql.PymssqlConfig
:members:
:show-inheritance:

Connection Parameters
=====================

.. autoclass:: sqlspec.adapters.pymssql.config.PymssqlConnectionParams
:members:
:show-inheritance:

Driver Features
===============

.. autoclass:: sqlspec.adapters.pymssql.config.PymssqlDriverFeatures
:members:
:show-inheritance:

Driver
======

.. autoclass:: sqlspec.adapters.pymssql.PymssqlDriver
:members:
:show-inheritance:

Connection Pool
===============

.. autoclass:: sqlspec.adapters.pymssql.PymssqlConnectionPool
:members:
:show-inheritance:

Data Dictionary
===============

.. autoclass:: sqlspec.adapters.pymssql.data_dictionary.PymssqlSyncDataDictionary
:members:
:show-inheritance:

Migrations
==========

.. autoclass:: sqlspec.adapters.pymssql.migrations.PymssqlSyncMigrationTracker
:members:
:show-inheritance:
1 change: 1 addition & 0 deletions docs/usage/drivers_and_querying.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Supported Drivers (High Level)
- **PostgreSQL**: asyncpg, psycopg (sync/async), psqlpy, ADBC
- **SQLite**: sqlite3, aiosqlite, ADBC
- **MySQL**: asyncmy, mysql-connector, pymysql
- **SQL Server**: mssql-python, pymssql, arrow-odbc
- **Analytics / Cloud**: DuckDB, BigQuery, Spanner, Oracle, ADBC

Core Execution Pattern
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ module = [
"asyncmy.*",
"mssql_python",
"mssql_python.*",
"pymssql",
"pymssql.*",
"pyarrow",
"pyarrow.*",
"opentelemetry.*",
Expand Down
26 changes: 26 additions & 0 deletions sqlspec/adapters/pymssql/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""pymssql adapter for SQLSpec."""

from sqlspec.adapters.pymssql._typing import PymssqlConnection, PymssqlCursor
from sqlspec.adapters.pymssql.config import (
PymssqlConfig,
PymssqlConnectionParams,
PymssqlDriverFeatures,
PymssqlPoolParams,
)
from sqlspec.adapters.pymssql.core import default_statement_config, driver_profile
from sqlspec.adapters.pymssql.driver import PymssqlDriver, PymssqlExceptionHandler
from sqlspec.adapters.pymssql.pool import PymssqlConnectionPool

__all__ = (
"PymssqlConfig",
"PymssqlConnection",
"PymssqlConnectionParams",
"PymssqlConnectionPool",
"PymssqlCursor",
"PymssqlDriver",
"PymssqlDriverFeatures",
"PymssqlExceptionHandler",
"PymssqlPoolParams",
"default_statement_config",
"driver_profile",
)
97 changes: 97 additions & 0 deletions sqlspec/adapters/pymssql/_typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"""pymssql adapter type definitions.

This module contains type aliases and classes that are excluded from mypyc
compilation to avoid ABI boundary issues.
"""

import contextlib
from typing import TYPE_CHECKING, Any

import pymssql as _pymssql # pyright: ignore[reportMissingTypeStubs]
from pymssql import Connection as _PymssqlConnection # pyright: ignore[reportMissingTypeStubs]
from pymssql import Cursor as _PymssqlRawCursor # pyright: ignore[reportMissingTypeStubs]

PYMSSQL_MODULE = _pymssql

if TYPE_CHECKING:
from collections.abc import Callable
from types import TracebackType
from typing import TypeAlias

from sqlspec.adapters.pymssql.driver import PymssqlDriver
from sqlspec.core import StatementConfig

PymssqlConnection: TypeAlias = _PymssqlConnection
PymssqlRawCursor: TypeAlias = _PymssqlRawCursor

if not TYPE_CHECKING:
PymssqlConnection = _PymssqlConnection
PymssqlRawCursor = _PymssqlRawCursor

__all__ = ("PYMSSQL_MODULE", "PymssqlConnection", "PymssqlCursor", "PymssqlRawCursor", "PymssqlSessionContext")


class PymssqlCursor:
"""Context manager for pymssql cursor operations."""

__slots__ = ("connection", "cursor")

def __init__(self, connection: "PymssqlConnection") -> None:
self.connection = connection
self.cursor: PymssqlRawCursor | None = None

def __enter__(self) -> "PymssqlRawCursor":
self.cursor = self.connection.cursor()
return self.cursor

def __exit__(self, *_: Any) -> None:
if self.cursor is not None:
with contextlib.suppress(Exception):
self.cursor.close()


class PymssqlSessionContext:
"""Sync context manager for pymssql sessions."""

__slots__ = (
"_acquire_connection",
"_connection",
"_driver",
"_driver_features",
"_prepare_driver",
"_release_connection",
"_statement_config",
)

def __init__(
self,
acquire_connection: "Callable[[], Any]",
release_connection: "Callable[[Any], Any]",
statement_config: "StatementConfig",
driver_features: "dict[str, Any]",
prepare_driver: "Callable[[PymssqlDriver], PymssqlDriver]",
) -> None:
self._acquire_connection = acquire_connection
self._release_connection = release_connection
self._statement_config = statement_config
self._driver_features = driver_features
self._prepare_driver = prepare_driver
self._connection: Any = None
self._driver: PymssqlDriver | None = None

def __enter__(self) -> "PymssqlDriver":
from sqlspec.adapters.pymssql.driver import PymssqlDriver

self._connection = self._acquire_connection()
self._driver = PymssqlDriver(
connection=self._connection, statement_config=self._statement_config, driver_features=self._driver_features
)
return self._prepare_driver(self._driver)

def __exit__(
self, exc_type: "type[BaseException] | None", exc_val: "BaseException | None", exc_tb: "TracebackType | None"
) -> "bool | None":
if self._connection is not None:
self._release_connection(self._connection)
self._connection = None
return None
10 changes: 10 additions & 0 deletions sqlspec/adapters/pymssql/adk/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""pymssql ADK extension."""

from sqlspec.adapters.pymssql.adk.store import (
PymssqlADKConfig,
PymssqlADKMemoryStore,
PymssqlADKStore,
PymssqlSyncADKStore,
)

__all__ = ("PymssqlADKConfig", "PymssqlADKMemoryStore", "PymssqlADKStore", "PymssqlSyncADKStore")
Loading
Loading