detquantlib 5.10.0__tar.gz → 5.10.2__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.
- {detquantlib-5.10.0 → detquantlib-5.10.2}/PKG-INFO +1 -1
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/data/databases/azure_client.py +1 -3
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/data/databases/snowflake_client.py +40 -6
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/utils/logging.py +2 -1
- {detquantlib-5.10.0 → detquantlib-5.10.2}/pyproject.toml +1 -1
- {detquantlib-5.10.0 → detquantlib-5.10.2}/LICENSE.txt +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/README.md +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/assets/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/assets/battery.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/assets/wind_turbine.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/converters/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/converters/definitions.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/converters/energy.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/converters/helpers.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/converters/price.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/data/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/data/databases/detdatabase.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/data/databases/helpers.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/data/entsoe/entsoe.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/data/sftp/sftp.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/data/tennet/tennet_client.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/dates/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/dates/dates.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/figures/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/figures/plotly_figures.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/forecasting/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/forecasting/forecasting.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/outputs/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/outputs/outputs_interface.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/README.md +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/cases.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/comparison.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/config.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/errors.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/isolation.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/pytest_plugin.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/recording.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/snapshot_testing/tables.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/stats/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/stats/data_analysis.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/tradable_products/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/tradable_products/tradable_products.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/utils/__init__.py +0 -0
- {detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/utils/utils.py +0 -0
|
@@ -254,7 +254,6 @@ class AzureClient:
|
|
|
254
254
|
database = self._resolve_database(database)
|
|
255
255
|
if database not in self._engines:
|
|
256
256
|
conn_str = self._to_connection_string(self._connection_params(database))
|
|
257
|
-
logger.info("Connecting to Azure SQL database %s on %s", database, self.config.server)
|
|
258
257
|
self._engines[database] = create_engine(
|
|
259
258
|
"mssql+pyodbc://",
|
|
260
259
|
creator=lambda: pyodbc.connect(conn_str),
|
|
@@ -268,9 +267,8 @@ class AzureClient:
|
|
|
268
267
|
|
|
269
268
|
Safe to call multiple times, or when no connection was ever opened.
|
|
270
269
|
"""
|
|
271
|
-
for
|
|
270
|
+
for engine in self._engines.values():
|
|
272
271
|
engine.dispose()
|
|
273
|
-
logger.info("Azure SQL connection to database %s closed", database)
|
|
274
272
|
self._engines = {}
|
|
275
273
|
|
|
276
274
|
def __enter__(self) -> "AzureClient":
|
|
@@ -22,6 +22,7 @@ from snowflake.connector.errors import Error as SnowflakeError
|
|
|
22
22
|
from snowflake.connector.pandas_tools import write_pandas
|
|
23
23
|
|
|
24
24
|
logger = logging.getLogger(__name__)
|
|
25
|
+
logging.getLogger("snowflake.connector").setLevel(logging.WARNING)
|
|
25
26
|
|
|
26
27
|
_IDENTIFIER_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_$]*$")
|
|
27
28
|
|
|
@@ -225,7 +226,6 @@ class SnowflakeClient:
|
|
|
225
226
|
The active Snowflake connection.
|
|
226
227
|
"""
|
|
227
228
|
if self._conn is None or self._conn.is_closed():
|
|
228
|
-
logger.info("Connecting to Snowflake account %s", self.config.account)
|
|
229
229
|
self._conn = snowflake.connector.connect(**self._connection_params())
|
|
230
230
|
return self._conn
|
|
231
231
|
|
|
@@ -237,7 +237,6 @@ class SnowflakeClient:
|
|
|
237
237
|
"""
|
|
238
238
|
if self._conn is not None and not self._conn.is_closed():
|
|
239
239
|
self._conn.close()
|
|
240
|
-
logger.info("Snowflake connection closed")
|
|
241
240
|
self._conn = None
|
|
242
241
|
|
|
243
242
|
def __enter__(self) -> "SnowflakeClient":
|
|
@@ -286,7 +285,9 @@ class SnowflakeClient:
|
|
|
286
285
|
Args:
|
|
287
286
|
sql: The SQL statement to execute.
|
|
288
287
|
params: Values bound to the placeholders in ``sql``: a sequence for positional ``%s``
|
|
289
|
-
placeholders, or a dict for named ``%(name)s`` placeholders.
|
|
288
|
+
placeholders, or a dict for named ``%(name)s`` placeholders. pandas Timestamps
|
|
289
|
+
are converted to Python datetimes (and ``NaT`` to ``None``), since the connector
|
|
290
|
+
cannot bind them.
|
|
290
291
|
lowercase_columns: If ``True``, column names in the result are converted to lowercase
|
|
291
292
|
(Snowflake returns them uppercase by default).
|
|
292
293
|
|
|
@@ -299,7 +300,7 @@ class SnowflakeClient:
|
|
|
299
300
|
conn = self.connect()
|
|
300
301
|
try:
|
|
301
302
|
with conn.cursor() as cur:
|
|
302
|
-
cur.execute(sql, params)
|
|
303
|
+
cur.execute(sql, self._prepare_params(params))
|
|
303
304
|
df = cur.fetch_pandas_all()
|
|
304
305
|
except SnowflakeError as e:
|
|
305
306
|
logger.error("Query failed: %s", e)
|
|
@@ -329,7 +330,7 @@ class SnowflakeClient:
|
|
|
329
330
|
"""
|
|
330
331
|
conn = self.connect()
|
|
331
332
|
with conn.cursor() as cur:
|
|
332
|
-
cur.execute(sql, params)
|
|
333
|
+
cur.execute(sql, self._prepare_params(params))
|
|
333
334
|
for batch in cur.fetch_pandas_batches():
|
|
334
335
|
yield batch
|
|
335
336
|
|
|
@@ -492,7 +493,7 @@ class SnowflakeClient:
|
|
|
492
493
|
conn = self.connect()
|
|
493
494
|
try:
|
|
494
495
|
with conn.cursor() as cur:
|
|
495
|
-
cur.execute(sql, params)
|
|
496
|
+
cur.execute(sql, self._prepare_params(params))
|
|
496
497
|
rowcount = cur.rowcount
|
|
497
498
|
except SnowflakeError as e:
|
|
498
499
|
logger.error("Statement failed: %s", e)
|
|
@@ -500,6 +501,39 @@ class SnowflakeClient:
|
|
|
500
501
|
logger.info("Statement affected %s rows", rowcount)
|
|
501
502
|
return rowcount
|
|
502
503
|
|
|
504
|
+
@staticmethod
|
|
505
|
+
def _prepare_params(
|
|
506
|
+
params: Optional[Union[Sequence[Any], dict[str, Any]]],
|
|
507
|
+
) -> Optional[Union[tuple[Any, ...], dict[str, Any]]]:
|
|
508
|
+
"""
|
|
509
|
+
Converts parameter values that the Snowflake connector cannot bind.
|
|
510
|
+
|
|
511
|
+
The connector picks a converter by type name, so it rejects pandas Timestamps even though
|
|
512
|
+
they are datetime subclasses. They are converted to Python datetimes, and ``NaT`` to
|
|
513
|
+
``None``. Note that Python datetimes only have microsecond precision, so nanoseconds are
|
|
514
|
+
dropped (pandas warns when this happens). Other values are passed through unchanged.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
params: Values bound to the placeholders of a query, as in ``query()``.
|
|
518
|
+
|
|
519
|
+
Returns:
|
|
520
|
+
The converted values, as a dict for named placeholders or a tuple for positional
|
|
521
|
+
ones, or ``None`` if ``params`` is ``None``.
|
|
522
|
+
"""
|
|
523
|
+
if params is None:
|
|
524
|
+
return None
|
|
525
|
+
|
|
526
|
+
def convert(value: Any) -> Any:
|
|
527
|
+
if value is pd.NaT:
|
|
528
|
+
return None
|
|
529
|
+
if isinstance(value, pd.Timestamp):
|
|
530
|
+
return value.to_pydatetime()
|
|
531
|
+
return value
|
|
532
|
+
|
|
533
|
+
if isinstance(params, dict):
|
|
534
|
+
return {k: convert(v) for k, v in params.items()}
|
|
535
|
+
return tuple(convert(v) for v in params)
|
|
536
|
+
|
|
503
537
|
@staticmethod
|
|
504
538
|
def _check_identifier(name: str) -> str:
|
|
505
539
|
"""
|
|
@@ -29,6 +29,7 @@ def setup_logger(log_dir: Path):
|
|
|
29
29
|
fmt=(
|
|
30
30
|
"%(log_color)s%(asctime)-8s%(reset)s "
|
|
31
31
|
"%(log_color)s[%(levelname)s]%(reset)s "
|
|
32
|
+
"%(log_color)s[%(name)s]%(reset)s "
|
|
32
33
|
"%(log_color)s%(message)s"
|
|
33
34
|
),
|
|
34
35
|
datefmt="%Y-%m-%d %H:%M:%S",
|
|
@@ -40,7 +41,7 @@ def setup_logger(log_dir: Path):
|
|
|
40
41
|
|
|
41
42
|
# File handler (plain, no colors)
|
|
42
43
|
file_formatter = logging.Formatter(
|
|
43
|
-
fmt="%(asctime)s [%(levelname)s] %(message)s",
|
|
44
|
+
fmt="%(asctime)s [%(levelname)s] [%(name)s] %(message)s",
|
|
44
45
|
datefmt="%Y-%m-%d %H:%M:%S",
|
|
45
46
|
)
|
|
46
47
|
file_handler = logging.FileHandler(log_dir, mode="a", encoding="utf-8")
|
|
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
|
{detquantlib-5.10.0 → detquantlib-5.10.2}/detquantlib/tradable_products/tradable_products.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|