|
11 | 11 | import weakref |
12 | 12 | from typing import Dict |
13 | 13 |
|
14 | | -# Import settings from helpers to avoid circular imports |
| 14 | +# Import settings from helpers module |
15 | 15 | from .helpers import Settings, get_settings, _settings, _settings_lock |
16 | 16 |
|
17 | 17 | # Driver version |
|
65 | 65 | from .logging import logger, setup_logging, driver_logger |
66 | 66 |
|
67 | 67 | # Constants |
68 | | -from .constants import ConstantsDDBC, GetInfoConstants |
| 68 | +from .constants import ConstantsDDBC, GetInfoConstants, get_info_constants |
69 | 69 |
|
70 | 70 | # Pooling |
71 | 71 | from .pooling import PoolingManager |
@@ -119,97 +119,13 @@ def _cleanup_connections(): |
119 | 119 | paramstyle: str = "pyformat" |
120 | 120 | threadsafety: int = 1 |
121 | 121 |
|
122 | | -# Set the initial decimal separator in C++ |
123 | | -try: |
124 | | - from .ddbc_bindings import DDBCSetDecimalSeparator |
| 122 | +# Create decimal separator control functions bound to our settings |
| 123 | +from .decimal_config import create_decimal_separator_functions |
125 | 124 |
|
126 | | - DDBCSetDecimalSeparator(_settings.decimal_separator) |
127 | | -except ImportError: |
128 | | - # Handle case where ddbc_bindings is not available |
129 | | - DDBCSetDecimalSeparator = None |
| 125 | +setDecimalSeparator, getDecimalSeparator = create_decimal_separator_functions(_settings) |
130 | 126 |
|
131 | | - |
132 | | -# New functions for decimal separator control |
133 | | -def setDecimalSeparator(separator: str) -> None: |
134 | | - """ |
135 | | - Sets the decimal separator character used when parsing NUMERIC/DECIMAL values |
136 | | - from the database, e.g. the "." in "1,234.56". |
137 | | -
|
138 | | - The default is to use the current locale's "decimal_point" value when the module |
139 | | - was first imported, or "." if the locale is not available. This function overrides |
140 | | - the default. |
141 | | -
|
142 | | - Args: |
143 | | - separator (str): The character to use as decimal separator |
144 | | -
|
145 | | - Raises: |
146 | | - ValueError: If the separator is not a single character string |
147 | | - """ |
148 | | - # Type validation |
149 | | - if not isinstance(separator, str): |
150 | | - raise ValueError("Decimal separator must be a string") |
151 | | - |
152 | | - # Length validation |
153 | | - if len(separator) == 0: |
154 | | - raise ValueError("Decimal separator cannot be empty") |
155 | | - |
156 | | - if len(separator) > 1: |
157 | | - raise ValueError("Decimal separator must be a single character") |
158 | | - |
159 | | - # Character validation |
160 | | - if separator.isspace(): |
161 | | - raise ValueError("Whitespace characters are not allowed as decimal separators") |
162 | | - |
163 | | - # Check for specific disallowed characters |
164 | | - if separator in ["\t", "\n", "\r", "\v", "\f"]: |
165 | | - raise ValueError( |
166 | | - f"Control character '{repr(separator)}' is not allowed as a decimal separator" |
167 | | - ) |
168 | | - |
169 | | - # Set in Python side settings |
170 | | - _settings.decimal_separator = separator |
171 | | - |
172 | | - # Update the C++ side |
173 | | - if DDBCSetDecimalSeparator is not None: |
174 | | - DDBCSetDecimalSeparator(separator) |
175 | | - |
176 | | - |
177 | | -def getDecimalSeparator() -> str: |
178 | | - """ |
179 | | - Returns the decimal separator character used when parsing NUMERIC/DECIMAL values |
180 | | - from the database. |
181 | | -
|
182 | | - Returns: |
183 | | - str: The current decimal separator character |
184 | | - """ |
185 | | - return _settings.decimal_separator |
186 | | - |
187 | | - |
188 | | -# Export specific constants for setencoding() |
189 | | -SQL_CHAR: int = ConstantsDDBC.SQL_CHAR.value |
190 | | -SQL_WCHAR: int = ConstantsDDBC.SQL_WCHAR.value |
191 | | -SQL_WMETADATA: int = -99 |
192 | | - |
193 | | -# Export connection attribute constants for set_attr() |
194 | | -# Only include driver-level attributes that the SQL Server ODBC driver can handle directly |
195 | | - |
196 | | -# Core driver-level attributes |
197 | | -SQL_ATTR_ACCESS_MODE: int = ConstantsDDBC.SQL_ATTR_ACCESS_MODE.value |
198 | | -SQL_ATTR_CONNECTION_TIMEOUT: int = ConstantsDDBC.SQL_ATTR_CONNECTION_TIMEOUT.value |
199 | | -SQL_ATTR_CURRENT_CATALOG: int = ConstantsDDBC.SQL_ATTR_CURRENT_CATALOG.value |
200 | | -SQL_ATTR_LOGIN_TIMEOUT: int = ConstantsDDBC.SQL_ATTR_LOGIN_TIMEOUT.value |
201 | | -SQL_ATTR_PACKET_SIZE: int = ConstantsDDBC.SQL_ATTR_PACKET_SIZE.value |
202 | | -SQL_ATTR_TXN_ISOLATION: int = ConstantsDDBC.SQL_ATTR_TXN_ISOLATION.value |
203 | | - |
204 | | -# Transaction Isolation Level Constants |
205 | | -SQL_TXN_READ_UNCOMMITTED: int = ConstantsDDBC.SQL_TXN_READ_UNCOMMITTED.value |
206 | | -SQL_TXN_READ_COMMITTED: int = ConstantsDDBC.SQL_TXN_READ_COMMITTED.value |
207 | | -SQL_TXN_REPEATABLE_READ: int = ConstantsDDBC.SQL_TXN_REPEATABLE_READ.value |
208 | | -SQL_TXN_SERIALIZABLE: int = ConstantsDDBC.SQL_TXN_SERIALIZABLE.value |
209 | | - |
210 | | -# Access Mode Constants |
211 | | -SQL_MODE_READ_WRITE: int = ConstantsDDBC.SQL_MODE_READ_WRITE.value |
212 | | -SQL_MODE_READ_ONLY: int = ConstantsDDBC.SQL_MODE_READ_ONLY.value |
| 127 | +# Import all module-level constants from constants module |
| 128 | +from .constants import * # noqa: F401, F403 |
213 | 129 |
|
214 | 130 |
|
215 | 131 | def pooling(max_size: int = 100, idle_timeout: int = 600, enabled: bool = True) -> None: |
@@ -249,81 +165,6 @@ def _custom_setattr(name, value): |
249 | 165 | sys.modules[__name__].__setattr__ = _custom_setattr |
250 | 166 |
|
251 | 167 |
|
252 | | -# Export SQL constants at module level |
253 | | -SQL_VARCHAR: int = ConstantsDDBC.SQL_VARCHAR.value |
254 | | -SQL_LONGVARCHAR: int = ConstantsDDBC.SQL_LONGVARCHAR.value |
255 | | -SQL_WVARCHAR: int = ConstantsDDBC.SQL_WVARCHAR.value |
256 | | -SQL_WLONGVARCHAR: int = ConstantsDDBC.SQL_WLONGVARCHAR.value |
257 | | -SQL_DECIMAL: int = ConstantsDDBC.SQL_DECIMAL.value |
258 | | -SQL_NUMERIC: int = ConstantsDDBC.SQL_NUMERIC.value |
259 | | -SQL_BIT: int = ConstantsDDBC.SQL_BIT.value |
260 | | -SQL_TINYINT: int = ConstantsDDBC.SQL_TINYINT.value |
261 | | -SQL_SMALLINT: int = ConstantsDDBC.SQL_SMALLINT.value |
262 | | -SQL_INTEGER: int = ConstantsDDBC.SQL_INTEGER.value |
263 | | -SQL_BIGINT: int = ConstantsDDBC.SQL_BIGINT.value |
264 | | -SQL_REAL: int = ConstantsDDBC.SQL_REAL.value |
265 | | -SQL_FLOAT: int = ConstantsDDBC.SQL_FLOAT.value |
266 | | -SQL_DOUBLE: int = ConstantsDDBC.SQL_DOUBLE.value |
267 | | -SQL_BINARY: int = ConstantsDDBC.SQL_BINARY.value |
268 | | -SQL_VARBINARY: int = ConstantsDDBC.SQL_VARBINARY.value |
269 | | -SQL_LONGVARBINARY: int = ConstantsDDBC.SQL_LONGVARBINARY.value |
270 | | -SQL_DATE: int = ConstantsDDBC.SQL_DATE.value |
271 | | -SQL_TIME: int = ConstantsDDBC.SQL_TIME.value |
272 | | -SQL_TIMESTAMP: int = ConstantsDDBC.SQL_TIMESTAMP.value |
273 | | - |
274 | | -# Export GetInfo constants at module level |
275 | | -# Driver and database information |
276 | | -SQL_DRIVER_NAME: int = GetInfoConstants.SQL_DRIVER_NAME.value |
277 | | -SQL_DRIVER_VER: int = GetInfoConstants.SQL_DRIVER_VER.value |
278 | | -SQL_DRIVER_ODBC_VER: int = GetInfoConstants.SQL_DRIVER_ODBC_VER.value |
279 | | -SQL_DATA_SOURCE_NAME: int = GetInfoConstants.SQL_DATA_SOURCE_NAME.value |
280 | | -SQL_DATABASE_NAME: int = GetInfoConstants.SQL_DATABASE_NAME.value |
281 | | -SQL_SERVER_NAME: int = GetInfoConstants.SQL_SERVER_NAME.value |
282 | | -SQL_USER_NAME: int = GetInfoConstants.SQL_USER_NAME.value |
283 | | - |
284 | | -# SQL conformance and support |
285 | | -SQL_SQL_CONFORMANCE: int = GetInfoConstants.SQL_SQL_CONFORMANCE.value |
286 | | -SQL_KEYWORDS: int = GetInfoConstants.SQL_KEYWORDS.value |
287 | | -SQL_IDENTIFIER_QUOTE_CHAR: int = GetInfoConstants.SQL_IDENTIFIER_QUOTE_CHAR.value |
288 | | -SQL_SEARCH_PATTERN_ESCAPE: int = GetInfoConstants.SQL_SEARCH_PATTERN_ESCAPE.value |
289 | | - |
290 | | -# Catalog and schema support |
291 | | -SQL_CATALOG_TERM: int = GetInfoConstants.SQL_CATALOG_TERM.value |
292 | | -SQL_SCHEMA_TERM: int = GetInfoConstants.SQL_SCHEMA_TERM.value |
293 | | -SQL_TABLE_TERM: int = GetInfoConstants.SQL_TABLE_TERM.value |
294 | | -SQL_PROCEDURE_TERM: int = GetInfoConstants.SQL_PROCEDURE_TERM.value |
295 | | - |
296 | | -# Transaction support |
297 | | -SQL_TXN_CAPABLE: int = GetInfoConstants.SQL_TXN_CAPABLE.value |
298 | | -SQL_DEFAULT_TXN_ISOLATION: int = GetInfoConstants.SQL_DEFAULT_TXN_ISOLATION.value |
299 | | - |
300 | | -# Data type support |
301 | | -SQL_NUMERIC_FUNCTIONS: int = GetInfoConstants.SQL_NUMERIC_FUNCTIONS.value |
302 | | -SQL_STRING_FUNCTIONS: int = GetInfoConstants.SQL_STRING_FUNCTIONS.value |
303 | | -SQL_DATETIME_FUNCTIONS: int = GetInfoConstants.SQL_DATETIME_FUNCTIONS.value |
304 | | - |
305 | | -# Limits |
306 | | -SQL_MAX_COLUMN_NAME_LEN: int = GetInfoConstants.SQL_MAX_COLUMN_NAME_LEN.value |
307 | | -SQL_MAX_TABLE_NAME_LEN: int = GetInfoConstants.SQL_MAX_TABLE_NAME_LEN.value |
308 | | -SQL_MAX_SCHEMA_NAME_LEN: int = GetInfoConstants.SQL_MAX_SCHEMA_NAME_LEN.value |
309 | | -SQL_MAX_CATALOG_NAME_LEN: int = GetInfoConstants.SQL_MAX_CATALOG_NAME_LEN.value |
310 | | -SQL_MAX_IDENTIFIER_LEN: int = GetInfoConstants.SQL_MAX_IDENTIFIER_LEN.value |
311 | | - |
312 | | - |
313 | | -# Also provide a function to get all constants |
314 | | -def get_info_constants() -> Dict[str, int]: |
315 | | - """ |
316 | | - Returns a dictionary of all available GetInfo constants. |
317 | | -
|
318 | | - This provides all SQLGetInfo constants that can be used with the Connection.getinfo() method |
319 | | - to retrieve metadata about the database server and driver. |
320 | | -
|
321 | | - Returns: |
322 | | - dict: Dictionary mapping constant names to their integer values |
323 | | - """ |
324 | | - return {name: member.value for name, member in GetInfoConstants.__members__.items()} |
325 | | - |
326 | | - |
327 | 168 | # Create a custom module class that uses properties instead of __setattr__ |
328 | 169 | class _MSSQLModule(types.ModuleType): |
329 | 170 | @property |
|
0 commit comments