pydpm_xl 0.2.6__tar.gz → 0.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pydpm_xl-0.2.6/pydpm_xl.egg-info → pydpm_xl-0.2.8}/PKG-INFO +1 -1
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/__init__.py +1 -1
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm/data_dictionary.py +11 -2
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm_xl/ast_generator.py +8 -1
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm_xl/operation_scopes.py +8 -2
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm_xl/semantic.py +8 -2
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/utils.py +43 -7
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8/pydpm_xl.egg-info}/PKG-INFO +1 -1
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/pyproject.toml +2 -2
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/LICENSE +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/README.md +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm/explorer.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm/hierarchical_queries.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm/instance.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm/migration.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm_xl/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm_xl/complete_ast.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/api/dpm_xl/syntax.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/cli/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/cli/commands/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/cli/main.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/migration.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/models.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/queries/base.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/queries/basic_objects.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/queries/explorer_queries.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/queries/filters.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/queries/glossary.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/queries/hierarchical_queries.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm/queries/tables.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/constructor.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/ml_generation.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/module_analyzer.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/module_dependencies.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/nodes.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/operands.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/template.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/visitor.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/ast/where_clause.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/dpm_xlLexer.interp +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/dpm_xlLexer.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/dpm_xlLexer.tokens +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/dpm_xlParser.interp +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/dpm_xlParser.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/dpm_xlParser.tokens +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/dpm_xlParserListener.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/dpm_xlParserVisitor.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/grammar/generated/listeners.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/aggregate.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/arithmetic.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/base.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/boolean.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/clause.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/comparison.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/conditional.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/string.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/operators/time.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/semantic_analyzer.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/symbols.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/types/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/types/promotion.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/types/scalar.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/types/time.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/utils/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/utils/data_handlers.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/utils/operands_mapping.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/utils/operator_mapping.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/utils/scopes_calculator.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/utils/serialization.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/dpm_xl/utils/tokens.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/exceptions/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/exceptions/exceptions.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/exceptions/messages.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/instance/__init__.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/py_dpm/instance/instance.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/pydpm_xl.egg-info/SOURCES.txt +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/pydpm_xl.egg-info/dependency_links.txt +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/pydpm_xl.egg-info/entry_points.txt +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/pydpm_xl.egg-info/requires.txt +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/pydpm_xl.egg-info/top_level.txt +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/setup.cfg +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_cli_semantic.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_data_dictionary_releases.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_db_connection_handling.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_get_table_details.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_get_tables_date_filter.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_get_tables_release_code.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_hierarchical_query.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_query_refactor.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_release_filters_semantic.py +0 -0
- {pydpm_xl-0.2.6 → pydpm_xl-0.2.8}/tests/test_semantic_release.py +0 -0
|
@@ -41,7 +41,7 @@ Available packages:
|
|
|
41
41
|
- pydpm.api: Main APIs for migration, syntax, and semantic analysis
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
|
-
__version__ = "0.2.
|
|
44
|
+
__version__ = "0.2.8"
|
|
45
45
|
__author__ = "MeaningfulData S.L."
|
|
46
46
|
__email__ = "info@meaningfuldata.eu"
|
|
47
47
|
__license__ = "GPL-3.0-or-later"
|
|
@@ -50,7 +50,10 @@ class DataDictionaryAPI:
|
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
52
|
def __init__(
|
|
53
|
-
self,
|
|
53
|
+
self,
|
|
54
|
+
database_path: Optional[str] = None,
|
|
55
|
+
connection_url: Optional[str] = None,
|
|
56
|
+
pool_config: Optional[Dict[str, Any]] = None,
|
|
54
57
|
):
|
|
55
58
|
"""
|
|
56
59
|
Initialize the Data Dictionary API.
|
|
@@ -58,8 +61,14 @@ class DataDictionaryAPI:
|
|
|
58
61
|
Args:
|
|
59
62
|
database_path: Path to SQLite database (optional)
|
|
60
63
|
connection_url: SQLAlchemy connection URL for PostgreSQL (optional)
|
|
64
|
+
pool_config: Connection pool configuration for PostgreSQL/MySQL (optional)
|
|
65
|
+
Supported keys: pool_size, max_overflow, pool_timeout, pool_recycle, pool_pre_ping.
|
|
61
66
|
"""
|
|
62
|
-
engine = get_engine(
|
|
67
|
+
engine = get_engine(
|
|
68
|
+
database_path=database_path,
|
|
69
|
+
connection_url=connection_url,
|
|
70
|
+
pool_config=pool_config
|
|
71
|
+
)
|
|
63
72
|
self.session = get_session()
|
|
64
73
|
|
|
65
74
|
# ==================== Release Query Methods ====================
|
|
@@ -48,6 +48,7 @@ class ASTGeneratorAPI:
|
|
|
48
48
|
|
|
49
49
|
def __init__(self, database_path: Optional[str] = None,
|
|
50
50
|
connection_url: Optional[str] = None,
|
|
51
|
+
pool_config: Optional[Dict[str, Any]] = None,
|
|
51
52
|
compatibility_mode: str = "auto",
|
|
52
53
|
enable_semantic_validation: bool = False):
|
|
53
54
|
"""
|
|
@@ -56,13 +57,19 @@ class ASTGeneratorAPI:
|
|
|
56
57
|
Args:
|
|
57
58
|
database_path: Optional path to SQLite data dictionary database
|
|
58
59
|
connection_url: Optional SQLAlchemy connection URL for PostgreSQL
|
|
60
|
+
pool_config: Connection pool configuration for PostgreSQL/MySQL
|
|
59
61
|
compatibility_mode: "auto", "3.1.0", "4.0.0", or "current"
|
|
60
62
|
enable_semantic_validation: Enable semantic validation (requires database)
|
|
61
63
|
"""
|
|
62
64
|
self.syntax_api = SyntaxAPI()
|
|
63
|
-
self.semantic_api = SemanticAPI(
|
|
65
|
+
self.semantic_api = SemanticAPI(
|
|
66
|
+
database_path=database_path,
|
|
67
|
+
connection_url=connection_url,
|
|
68
|
+
pool_config=pool_config
|
|
69
|
+
) if enable_semantic_validation else None
|
|
64
70
|
self.database_path = database_path
|
|
65
71
|
self.connection_url = connection_url
|
|
72
|
+
self.pool_config = pool_config
|
|
66
73
|
self.compatibility_mode = compatibility_mode
|
|
67
74
|
self.enable_semantic = enable_semantic_validation
|
|
68
75
|
|
|
@@ -100,7 +100,10 @@ class OperationScopesAPI:
|
|
|
100
100
|
"""
|
|
101
101
|
|
|
102
102
|
def __init__(
|
|
103
|
-
self,
|
|
103
|
+
self,
|
|
104
|
+
database_path: Optional[str] = None,
|
|
105
|
+
connection_url: Optional[str] = None,
|
|
106
|
+
pool_config: Optional[Dict[str, Any]] = None,
|
|
104
107
|
):
|
|
105
108
|
"""
|
|
106
109
|
Initialize the Operation Scopes API.
|
|
@@ -109,9 +112,12 @@ class OperationScopesAPI:
|
|
|
109
112
|
database_path (Optional[str]): Path to SQLite database. If None, uses default from environment.
|
|
110
113
|
connection_url (Optional[str]): Full SQLAlchemy connection URL (e.g., postgresql://user:pass@host:port/db).
|
|
111
114
|
Takes precedence over database_path.
|
|
115
|
+
pool_config (Optional[Dict[str, Any]]): Connection pool configuration for PostgreSQL/MySQL.
|
|
116
|
+
Supported keys: pool_size, max_overflow, pool_timeout, pool_recycle, pool_pre_ping.
|
|
112
117
|
"""
|
|
113
118
|
self.database_path = database_path
|
|
114
119
|
self.connection_url = connection_url
|
|
120
|
+
self.pool_config = pool_config
|
|
115
121
|
|
|
116
122
|
if connection_url:
|
|
117
123
|
# Create isolated engine and session for the provided connection URL
|
|
@@ -119,7 +125,7 @@ class OperationScopesAPI:
|
|
|
119
125
|
from py_dpm.dpm.utils import create_engine_from_url
|
|
120
126
|
|
|
121
127
|
# Create engine for the connection URL (supports SQLite, PostgreSQL, MySQL, etc.)
|
|
122
|
-
self.engine = create_engine_from_url(connection_url)
|
|
128
|
+
self.engine = create_engine_from_url(connection_url, pool_config=pool_config)
|
|
123
129
|
session_maker = sessionmaker(bind=self.engine)
|
|
124
130
|
self.session = session_maker()
|
|
125
131
|
|
|
@@ -44,7 +44,10 @@ class SemanticAPI:
|
|
|
44
44
|
"""
|
|
45
45
|
|
|
46
46
|
def __init__(
|
|
47
|
-
self,
|
|
47
|
+
self,
|
|
48
|
+
database_path: Optional[str] = None,
|
|
49
|
+
connection_url: Optional[str] = None,
|
|
50
|
+
pool_config: Optional[Dict[str, Any]] = None,
|
|
48
51
|
):
|
|
49
52
|
"""
|
|
50
53
|
Initialize the Semantic API.
|
|
@@ -53,9 +56,12 @@ class SemanticAPI:
|
|
|
53
56
|
database_path (Optional[str]): Path to SQLite database. If None, uses default from environment.
|
|
54
57
|
connection_url (Optional[str]): Full SQLAlchemy connection URL (e.g., postgresql://user:pass@host:port/db).
|
|
55
58
|
Takes precedence over database_path.
|
|
59
|
+
pool_config (Optional[Dict[str, Any]]): Connection pool configuration for PostgreSQL/MySQL.
|
|
60
|
+
Supported keys: pool_size, max_overflow, pool_timeout, pool_recycle, pool_pre_ping.
|
|
56
61
|
"""
|
|
57
62
|
self.database_path = database_path
|
|
58
63
|
self.connection_url = connection_url
|
|
64
|
+
self.pool_config = pool_config
|
|
59
65
|
# Store last parsed AST for consumers that need it (e.g. complete AST generation)
|
|
60
66
|
self.ast = None
|
|
61
67
|
|
|
@@ -65,7 +71,7 @@ class SemanticAPI:
|
|
|
65
71
|
from py_dpm.dpm.utils import create_engine_from_url
|
|
66
72
|
|
|
67
73
|
# Create engine for the connection URL (supports SQLite, PostgreSQL, MySQL, etc.)
|
|
68
|
-
self.engine = create_engine_from_url(connection_url)
|
|
74
|
+
self.engine = create_engine_from_url(connection_url, pool_config=pool_config)
|
|
69
75
|
session_maker = sessionmaker(bind=self.engine)
|
|
70
76
|
self.session = session_maker()
|
|
71
77
|
|
|
@@ -84,7 +84,7 @@ sessionMakerObject = None
|
|
|
84
84
|
_current_engine_url = None
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
def create_engine_from_url(connection_url):
|
|
87
|
+
def create_engine_from_url(connection_url, pool_config=None):
|
|
88
88
|
"""
|
|
89
89
|
Create SQLAlchemy engine from a connection URL with appropriate pooling parameters.
|
|
90
90
|
|
|
@@ -96,6 +96,12 @@ def create_engine_from_url(connection_url):
|
|
|
96
96
|
|
|
97
97
|
Args:
|
|
98
98
|
connection_url (str): SQLAlchemy connection URL (e.g., 'sqlite:///path.db', 'postgresql://user:pass@host/db')
|
|
99
|
+
pool_config (dict, optional): Custom pool configuration. Supported keys:
|
|
100
|
+
- pool_size (int): Maximum number of connections to maintain in the pool (default: 20)
|
|
101
|
+
- max_overflow (int): Maximum overflow connections beyond pool_size (default: 10)
|
|
102
|
+
- pool_timeout (int): Seconds to wait before giving up on getting a connection (default: 30)
|
|
103
|
+
- pool_recycle (int): Seconds before recycling connections (default: 180)
|
|
104
|
+
- pool_pre_ping (bool): Health check connections before using from pool (default: True)
|
|
99
105
|
|
|
100
106
|
Returns:
|
|
101
107
|
sqlalchemy.engine.Engine: Configured database engine
|
|
@@ -103,12 +109,21 @@ def create_engine_from_url(connection_url):
|
|
|
103
109
|
Examples:
|
|
104
110
|
>>> engine = create_engine_from_url('sqlite:///database.db')
|
|
105
111
|
>>> engine = create_engine_from_url('postgresql://user:pass@localhost/mydb')
|
|
112
|
+
>>> engine = create_engine_from_url('postgresql://user:pass@localhost/mydb',
|
|
113
|
+
... pool_config={'pool_size': 5, 'max_overflow': 10})
|
|
106
114
|
"""
|
|
107
115
|
global engine, sessionMakerObject, _current_engine_url
|
|
108
116
|
|
|
109
117
|
# Detect database type from URL scheme
|
|
110
118
|
is_sqlite = connection_url.startswith("sqlite://")
|
|
111
119
|
|
|
120
|
+
# For PostgreSQL, ensure ISO datestyle if not already set
|
|
121
|
+
# This prevents date parsing errors when PostgreSQL returns dates in locale format
|
|
122
|
+
is_postgres = connection_url.startswith("postgresql://")
|
|
123
|
+
if is_postgres and "datestyle" not in connection_url.lower():
|
|
124
|
+
separator = "&" if "?" in connection_url else "?"
|
|
125
|
+
connection_url = f"{connection_url}{separator}options=-c%20datestyle%3DISO"
|
|
126
|
+
|
|
112
127
|
# For SQLite URLs, always create a fresh engine to avoid
|
|
113
128
|
# surprising cross-test or cross-call state sharing, especially
|
|
114
129
|
# for in-memory databases. For server-based databases, reuse the
|
|
@@ -123,12 +138,22 @@ def create_engine_from_url(connection_url):
|
|
|
123
138
|
engine = create_engine(connection_url, pool_pre_ping=True)
|
|
124
139
|
else:
|
|
125
140
|
# Server-based databases (PostgreSQL, MySQL, etc.) with connection pooling
|
|
141
|
+
# Default pool configuration
|
|
142
|
+
default_pool_config = {
|
|
143
|
+
'pool_size': 20,
|
|
144
|
+
'max_overflow': 10,
|
|
145
|
+
'pool_timeout': 30,
|
|
146
|
+
'pool_recycle': 180,
|
|
147
|
+
'pool_pre_ping': True,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Merge custom pool_config with defaults
|
|
151
|
+
if pool_config:
|
|
152
|
+
default_pool_config.update(pool_config)
|
|
153
|
+
|
|
126
154
|
engine = create_engine(
|
|
127
155
|
connection_url,
|
|
128
|
-
|
|
129
|
-
max_overflow=10,
|
|
130
|
-
pool_recycle=180,
|
|
131
|
-
pool_pre_ping=True,
|
|
156
|
+
**default_pool_config
|
|
132
157
|
)
|
|
133
158
|
|
|
134
159
|
# Initialize global sessionMakerObject
|
|
@@ -149,6 +174,14 @@ def create_engine_object(url):
|
|
|
149
174
|
# Detect database type from URL scheme (not from environment variables)
|
|
150
175
|
is_sqlite = url_str.startswith("sqlite://")
|
|
151
176
|
|
|
177
|
+
# For PostgreSQL, ensure ISO datestyle if not already set
|
|
178
|
+
# This prevents date parsing errors when PostgreSQL returns dates in locale format
|
|
179
|
+
is_postgres = url_str.startswith("postgresql://")
|
|
180
|
+
if is_postgres and "datestyle" not in url_str.lower():
|
|
181
|
+
separator = "&" if "?" in url_str else "?"
|
|
182
|
+
url_str = f"{url_str}{separator}options=-c%20datestyle%3DISO"
|
|
183
|
+
url = url_str # Use modified URL for engine creation
|
|
184
|
+
|
|
152
185
|
# Only reuse engines for non-SQLite URLs. SQLite (especially in-memory)
|
|
153
186
|
# should create independent engines to avoid leaking state between calls.
|
|
154
187
|
if not is_sqlite and engine is not None and _current_engine_url == url_str:
|
|
@@ -170,7 +203,7 @@ def create_engine_object(url):
|
|
|
170
203
|
return engine
|
|
171
204
|
|
|
172
205
|
|
|
173
|
-
def get_engine(owner=None, database_path=None, connection_url=None):
|
|
206
|
+
def get_engine(owner=None, database_path=None, connection_url=None, pool_config=None):
|
|
174
207
|
"""
|
|
175
208
|
Get database engine based on configuration or explicit parameters.
|
|
176
209
|
|
|
@@ -184,13 +217,14 @@ def get_engine(owner=None, database_path=None, connection_url=None):
|
|
|
184
217
|
owner: Owner for SQL Server databases (EBA/EIOPA) - legacy support
|
|
185
218
|
database_path: Explicit SQLite database path
|
|
186
219
|
connection_url: Explicit SQLAlchemy connection URL (e.g., for PostgreSQL)
|
|
220
|
+
pool_config: Connection pool configuration dict (for PostgreSQL/MySQL)
|
|
187
221
|
|
|
188
222
|
Returns:
|
|
189
223
|
SQLAlchemy Engine
|
|
190
224
|
"""
|
|
191
225
|
# Priority 1: If explicit connection URL is provided, use it directly
|
|
192
226
|
if connection_url:
|
|
193
|
-
return create_engine_from_url(connection_url)
|
|
227
|
+
return create_engine_from_url(connection_url, pool_config=pool_config)
|
|
194
228
|
|
|
195
229
|
# Priority 2: If explicit database_path is provided, use SQLite with that path
|
|
196
230
|
if database_path:
|
|
@@ -211,6 +245,7 @@ def get_engine(owner=None, database_path=None, connection_url=None):
|
|
|
211
245
|
port = db_port or "5432"
|
|
212
246
|
connection_url = (
|
|
213
247
|
f"postgresql://{db_user}:{db_password}@{db_host}:{port}/{db_name}"
|
|
248
|
+
"?options=-c%20datestyle%3DISO"
|
|
214
249
|
)
|
|
215
250
|
return create_engine_object(connection_url)
|
|
216
251
|
else:
|
|
@@ -258,6 +293,7 @@ def get_engine(owner=None, database_path=None, connection_url=None):
|
|
|
258
293
|
connection_url = (
|
|
259
294
|
f"postgresql://{postgres_user}:{postgres_pass}@"
|
|
260
295
|
f"{postgres_host}:{postgres_port}/{postgres_db}"
|
|
296
|
+
"?options=-c%20datestyle%3DISO"
|
|
261
297
|
)
|
|
262
298
|
return create_engine_object(connection_url)
|
|
263
299
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pydpm_xl"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.8"
|
|
4
4
|
description = "Python library for DPM-XL data processing and analysis"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "MeaningfulData S.L.", email = "info@meaningfuldata.eu"}
|
|
@@ -52,7 +52,7 @@ exclude = []
|
|
|
52
52
|
|
|
53
53
|
[tool.poetry]
|
|
54
54
|
name = "pydpm_xl"
|
|
55
|
-
version = "0.2.
|
|
55
|
+
version = "0.2.8"
|
|
56
56
|
description = "Python library for DPM-XL data processing and analysis"
|
|
57
57
|
authors = ["MeaningfulData S.L. <info@meaningfuldata.eu>"]
|
|
58
58
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|