-
Notifications
You must be signed in to change notification settings - Fork 33
REFACTOR: Clearing init.py file #386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
038ee14
76ea50d
ce5768b
e5b7cba
489593e
ce488bb
588165b
8fa61ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,7 +11,7 @@ | |||||||||||||||
| import weakref | ||||||||||||||||
| from typing import Dict | ||||||||||||||||
|
|
||||||||||||||||
| # Import settings from helpers to avoid circular imports | ||||||||||||||||
| # Import settings from helpers module | ||||||||||||||||
| from .helpers import Settings, get_settings, _settings, _settings_lock | ||||||||||||||||
|
|
||||||||||||||||
| # Driver version | ||||||||||||||||
|
|
@@ -65,7 +65,7 @@ | |||||||||||||||
| from .logging import logger, setup_logging, driver_logger | ||||||||||||||||
|
|
||||||||||||||||
| # Constants | ||||||||||||||||
| from .constants import ConstantsDDBC, GetInfoConstants | ||||||||||||||||
| from .constants import ConstantsDDBC, GetInfoConstants, get_info_constants | ||||||||||||||||
|
|
||||||||||||||||
| # Pooling | ||||||||||||||||
| from .pooling import PoolingManager | ||||||||||||||||
|
|
@@ -116,100 +116,16 @@ def _cleanup_connections(): | |||||||||||||||
| # GLOBALS | ||||||||||||||||
| # Read-Only | ||||||||||||||||
| apilevel: str = "2.0" | ||||||||||||||||
| paramstyle: str = "qmark" | ||||||||||||||||
| paramstyle: str = "pyformat" | ||||||||||||||||
| threadsafety: int = 1 | ||||||||||||||||
|
|
||||||||||||||||
| # Set the initial decimal separator in C++ | ||||||||||||||||
| try: | ||||||||||||||||
| from .ddbc_bindings import DDBCSetDecimalSeparator | ||||||||||||||||
| # Create decimal separator control functions bound to our settings | ||||||||||||||||
| from .decimal_config import create_decimal_separator_functions | ||||||||||||||||
|
|
||||||||||||||||
| DDBCSetDecimalSeparator(_settings.decimal_separator) | ||||||||||||||||
| except ImportError: | ||||||||||||||||
| # Handle case where ddbc_bindings is not available | ||||||||||||||||
| DDBCSetDecimalSeparator = None | ||||||||||||||||
| setDecimalSeparator, getDecimalSeparator = create_decimal_separator_functions(_settings) | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| # New functions for decimal separator control | ||||||||||||||||
| def setDecimalSeparator(separator: str) -> None: | ||||||||||||||||
| """ | ||||||||||||||||
| Sets the decimal separator character used when parsing NUMERIC/DECIMAL values | ||||||||||||||||
| from the database, e.g. the "." in "1,234.56". | ||||||||||||||||
|
|
||||||||||||||||
| The default is to use the current locale's "decimal_point" value when the module | ||||||||||||||||
| was first imported, or "." if the locale is not available. This function overrides | ||||||||||||||||
| the default. | ||||||||||||||||
|
|
||||||||||||||||
| Args: | ||||||||||||||||
| separator (str): The character to use as decimal separator | ||||||||||||||||
|
|
||||||||||||||||
| Raises: | ||||||||||||||||
| ValueError: If the separator is not a single character string | ||||||||||||||||
| """ | ||||||||||||||||
| # Type validation | ||||||||||||||||
| if not isinstance(separator, str): | ||||||||||||||||
| raise ValueError("Decimal separator must be a string") | ||||||||||||||||
|
|
||||||||||||||||
| # Length validation | ||||||||||||||||
| if len(separator) == 0: | ||||||||||||||||
| raise ValueError("Decimal separator cannot be empty") | ||||||||||||||||
|
|
||||||||||||||||
| if len(separator) > 1: | ||||||||||||||||
| raise ValueError("Decimal separator must be a single character") | ||||||||||||||||
|
|
||||||||||||||||
| # Character validation | ||||||||||||||||
| if separator.isspace(): | ||||||||||||||||
| raise ValueError("Whitespace characters are not allowed as decimal separators") | ||||||||||||||||
|
|
||||||||||||||||
| # Check for specific disallowed characters | ||||||||||||||||
| if separator in ["\t", "\n", "\r", "\v", "\f"]: | ||||||||||||||||
| raise ValueError( | ||||||||||||||||
| f"Control character '{repr(separator)}' is not allowed as a decimal separator" | ||||||||||||||||
| ) | ||||||||||||||||
|
|
||||||||||||||||
| # Set in Python side settings | ||||||||||||||||
| _settings.decimal_separator = separator | ||||||||||||||||
|
|
||||||||||||||||
| # Update the C++ side | ||||||||||||||||
| if DDBCSetDecimalSeparator is not None: | ||||||||||||||||
| DDBCSetDecimalSeparator(separator) | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def getDecimalSeparator() -> str: | ||||||||||||||||
| """ | ||||||||||||||||
| Returns the decimal separator character used when parsing NUMERIC/DECIMAL values | ||||||||||||||||
| from the database. | ||||||||||||||||
|
|
||||||||||||||||
| Returns: | ||||||||||||||||
| str: The current decimal separator character | ||||||||||||||||
| """ | ||||||||||||||||
| return _settings.decimal_separator | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| # Export specific constants for setencoding() | ||||||||||||||||
| SQL_CHAR: int = ConstantsDDBC.SQL_CHAR.value | ||||||||||||||||
| SQL_WCHAR: int = ConstantsDDBC.SQL_WCHAR.value | ||||||||||||||||
| SQL_WMETADATA: int = -99 | ||||||||||||||||
|
|
||||||||||||||||
| # Export connection attribute constants for set_attr() | ||||||||||||||||
| # Only include driver-level attributes that the SQL Server ODBC driver can handle directly | ||||||||||||||||
|
|
||||||||||||||||
| # Core driver-level attributes | ||||||||||||||||
| SQL_ATTR_ACCESS_MODE: int = ConstantsDDBC.SQL_ATTR_ACCESS_MODE.value | ||||||||||||||||
| SQL_ATTR_CONNECTION_TIMEOUT: int = ConstantsDDBC.SQL_ATTR_CONNECTION_TIMEOUT.value | ||||||||||||||||
| SQL_ATTR_CURRENT_CATALOG: int = ConstantsDDBC.SQL_ATTR_CURRENT_CATALOG.value | ||||||||||||||||
| SQL_ATTR_LOGIN_TIMEOUT: int = ConstantsDDBC.SQL_ATTR_LOGIN_TIMEOUT.value | ||||||||||||||||
| SQL_ATTR_PACKET_SIZE: int = ConstantsDDBC.SQL_ATTR_PACKET_SIZE.value | ||||||||||||||||
| SQL_ATTR_TXN_ISOLATION: int = ConstantsDDBC.SQL_ATTR_TXN_ISOLATION.value | ||||||||||||||||
|
|
||||||||||||||||
| # Transaction Isolation Level Constants | ||||||||||||||||
| SQL_TXN_READ_UNCOMMITTED: int = ConstantsDDBC.SQL_TXN_READ_UNCOMMITTED.value | ||||||||||||||||
| SQL_TXN_READ_COMMITTED: int = ConstantsDDBC.SQL_TXN_READ_COMMITTED.value | ||||||||||||||||
| SQL_TXN_REPEATABLE_READ: int = ConstantsDDBC.SQL_TXN_REPEATABLE_READ.value | ||||||||||||||||
| SQL_TXN_SERIALIZABLE: int = ConstantsDDBC.SQL_TXN_SERIALIZABLE.value | ||||||||||||||||
|
|
||||||||||||||||
| # Access Mode Constants | ||||||||||||||||
| SQL_MODE_READ_WRITE: int = ConstantsDDBC.SQL_MODE_READ_WRITE.value | ||||||||||||||||
| SQL_MODE_READ_ONLY: int = ConstantsDDBC.SQL_MODE_READ_ONLY.value | ||||||||||||||||
| # Import all module-level constants from constants module | ||||||||||||||||
| from .constants import * # noqa: F401, F403 | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
|
Comment on lines
+127
to
130
|
||||||||||||||||
| # Import all module-level constants from constants module | |
| from .constants import * # noqa: F401, F403 | |
| # Import constants module and re-export its public names defined in __all__ | |
| from . import constants as _constants | |
| for _name in getattr(_constants, "__all__", ()): | |
| setattr(sys.modules[__name__], _name, getattr(_constants, _name)) |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -502,3 +502,111 @@ def get_attribute_set_timing(attribute): | |||||
| # internally. | ||||||
| "packetsize": "PacketSize", | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| def get_info_constants() -> Dict[str, int]: | ||||||
| """ | ||||||
| Returns a dictionary of all available GetInfo constants. | ||||||
|
|
||||||
| This provides all SQLGetInfo constants that can be used with the Connection.getinfo() method | ||||||
| to retrieve metadata about the database server and driver. | ||||||
|
|
||||||
| Returns: | ||||||
| dict: Dictionary mapping constant names to their integer values | ||||||
| """ | ||||||
| return {name: member.value for name, member in GetInfoConstants.__members__.items()} | ||||||
|
|
||||||
|
|
||||||
| # Automatically export selected enum constants as module-level attributes | ||||||
| # This allows: from mssql_python import SQL_VARCHAR | ||||||
| # Instead of: from mssql_python.constants import ConstantsDDBC; ConstantsDDBC.SQL_VARCHAR.value | ||||||
|
|
||||||
| # Define which ConstantsDDBC members should be exported as public API | ||||||
| # Internal/driver-manager-dependent constants are excluded | ||||||
| _DDBC_PUBLIC_API = { | ||||||
| # SQL Type constants | ||||||
| "SQL_CHAR", | ||||||
| "SQL_VARCHAR", | ||||||
| "SQL_LONGVARCHAR", | ||||||
| "SQL_WCHAR", | ||||||
| "SQL_WVARCHAR", | ||||||
| "SQL_WLONGVARCHAR", | ||||||
| "SQL_DECIMAL", | ||||||
| "SQL_NUMERIC", | ||||||
| "SQL_BIT", | ||||||
| "SQL_TINYINT", | ||||||
| "SQL_SMALLINT", | ||||||
| "SQL_INTEGER", | ||||||
| "SQL_BIGINT", | ||||||
| "SQL_REAL", | ||||||
| "SQL_FLOAT", | ||||||
| "SQL_DOUBLE", | ||||||
| "SQL_BINARY", | ||||||
| "SQL_VARBINARY", | ||||||
| "SQL_LONGVARBINARY", | ||||||
| "SQL_DATE", | ||||||
| "SQL_TIME", | ||||||
| "SQL_TIMESTAMP", | ||||||
| "SQL_TYPE_DATE", | ||||||
| "SQL_TYPE_TIME", | ||||||
| "SQL_TYPE_TIMESTAMP", | ||||||
| "SQL_GUID", | ||||||
| "SQL_XML", | ||||||
| # Connection attribute constants (ODBC-standard, driver-independent only) | ||||||
| "SQL_ATTR_ACCESS_MODE", | ||||||
| "SQL_ATTR_CONNECTION_TIMEOUT", | ||||||
| "SQL_ATTR_CURRENT_CATALOG", | ||||||
| "SQL_ATTR_LOGIN_TIMEOUT", | ||||||
| "SQL_ATTR_PACKET_SIZE", | ||||||
| "SQL_ATTR_TXN_ISOLATION", | ||||||
| # Transaction isolation levels | ||||||
| "SQL_TXN_READ_UNCOMMITTED", | ||||||
| "SQL_TXN_READ_COMMITTED", | ||||||
| "SQL_TXN_REPEATABLE_READ", | ||||||
| "SQL_TXN_SERIALIZABLE", | ||||||
| # Access modes | ||||||
| "SQL_MODE_READ_WRITE", | ||||||
| "SQL_MODE_READ_ONLY", | ||||||
| } | ||||||
|
|
||||||
| # Get current module's globals for dynamic export | ||||||
| _module_globals = globals() | ||||||
| _exported_names = [] | ||||||
|
|
||||||
| # Export selected ConstantsDDBC enum members as module-level constants | ||||||
| for _name, _member in ConstantsDDBC.__members__.items(): | ||||||
| if _name in _DDBC_PUBLIC_API: | ||||||
| _module_globals[_name] = _member.value | ||||||
| _exported_names.append(_name) | ||||||
|
|
||||||
| # Export all GetInfoConstants enum members as module-level constants | ||||||
| for _name, _member in GetInfoConstants.__members__.items(): | ||||||
| _module_globals[_name] = _member.value | ||||||
| _exported_names.append(_name) | ||||||
|
|
||||||
| # Export all AuthType enum members as module-level constants | ||||||
| for _name, _member in AuthType.__members__.items(): | ||||||
| _module_globals[_name] = _member.value | ||||||
| _exported_names.append(_name) | ||||||
|
|
||||||
| # SQLTypes is not an Enum, it's a regular class - don't iterate it | ||||||
|
|
||||||
| # Add special constant not in enum | ||||||
| SQL_WMETADATA: int = -99 | ||||||
| _exported_names.append("SQL_WMETADATA") | ||||||
|
|
||||||
| # Define __all__ for controlled exports | ||||||
| __all__ = [ | ||||||
| # Enum classes themselves | ||||||
| "ConstantsDDBC", | ||||||
| "GetInfoConstants", | ||||||
| "AuthType", | ||||||
| "SQLTypes", | ||||||
| # Helper function | ||||||
| "get_info_constants", | ||||||
| # All dynamically exported constants | ||||||
| *_exported_names, | ||||||
| ] | ||||||
|
|
||||||
| # Clean up temporary variables | ||||||
| del _module_globals, _exported_names, _name, _member, _DDBC_PUBLIC_API | ||||||
|
||||||
| del _module_globals, _exported_names, _name, _member, _DDBC_PUBLIC_API | |
| del _module_globals, _exported_names, _name, _member |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The paramstyle is changed from "qmark" to "pyformat", but this is a breaking API change. According to PEP 249, paramstyle indicates which parameter marker format is supported. Changing this from "qmark" (?) to "pyformat" (%(name)s) could break existing code that relies on this value to determine how to format parameters. While the implementation now supports both styles automatically, the paramstyle should reflect the primary/preferred style or be documented as supporting multiple styles. Consider if this should be "pyformat" or remain "qmark" with documentation noting that both are supported.