sibi-dst 2025.9.10__py3-none-any.whl → 2025.9.12__py3-none-any.whl

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.
@@ -1,19 +1,22 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime as dt
2
4
  from typing import Any, Dict, Iterable, Optional
3
- from sibi_dst.utils import Logger
5
+
6
+ import dask.dataframe as dd
4
7
  import numpy as np
5
8
  import pandas as pd
6
- import dask.dataframe as dd
9
+
10
+ from sibi_dst.utils import Logger
7
11
 
8
12
 
9
13
  # ---------------- Vectorized helpers (used by Dask map_partitions) ----------------
10
14
 
11
15
  def _to_np_days(series: pd.Series) -> np.ndarray:
12
16
  """Coerce to numpy datetime64[D] with NaT-safe conversion."""
13
- # Use pandas for robust parsing, then cast to date-days
14
17
  s = pd.to_datetime(series, errors="coerce")
15
- # Convert to numpy datetime64[D] (day precision)
16
- return s.values.astype("datetime64[D]")
18
+ # Return day precision array directly
19
+ return s.dt.floor("D").to_numpy(dtype="datetime64[D]")
17
20
 
18
21
 
19
22
  def _vectorized_busday_count(
@@ -24,8 +27,8 @@ def _vectorized_busday_count(
24
27
  weekmask: Optional[str],
25
28
  inclusive: bool,
26
29
  ) -> pd.Series:
27
- start = _to_np_days(part[begin_col]) # numpy datetime64[D]
28
- end = _to_np_days(part[end_col]) # numpy datetime64[D]
30
+ start = _to_np_days(part[begin_col])
31
+ end = _to_np_days(part[end_col])
29
32
 
30
33
  kwargs: Dict[str, Any] = {}
31
34
  if holidays:
@@ -38,7 +41,7 @@ def _vectorized_busday_count(
38
41
  with np.errstate(invalid="ignore"):
39
42
  end_adj = end + np.timedelta64(1, "D")
40
43
 
41
- valid = (~pd.isna(start)) & (~pd.isna(end)) # numpy bool mask
44
+ valid = (~pd.isna(start)) & (~pd.isna(end))
42
45
  result = np.full(part.shape[0], np.nan, dtype="float64")
43
46
  if valid.any():
44
47
  counts = np.busday_count(
@@ -59,8 +62,8 @@ def _vectorized_busday_offset(
59
62
  weekmask: Optional[str],
60
63
  roll: str,
61
64
  ) -> pd.Series:
62
- start = _to_np_days(part[start_col]) # numpy datetime64[D]
63
- n_days = pd.to_numeric(part[n_days_col], errors="coerce").to_numpy() # numpy float -> cast later
65
+ start = _to_np_days(part[start_col])
66
+ n_days = pd.to_numeric(part[n_days_col], errors="coerce").to_numpy()
64
67
 
65
68
  kwargs: Dict[str, Any] = {"roll": roll}
66
69
  if holidays:
@@ -68,7 +71,7 @@ def _vectorized_busday_offset(
68
71
  if weekmask:
69
72
  kwargs["weekmask"] = weekmask
70
73
 
71
- valid = (~pd.isna(start)) & (~pd.isna(n_days)) # numpy bool mask
74
+ valid = (~pd.isna(start)) & (~pd.isna(n_days))
72
75
  out = np.full(part.shape[0], np.datetime64("NaT", "ns"), dtype="datetime64[ns]")
73
76
  if valid.any():
74
77
  offs = np.busday_offset(
@@ -86,26 +89,6 @@ def _vectorized_busday_offset(
86
89
  class BusinessDays:
87
90
  """
88
91
  Business day calculations with custom holidays and optional weekmask.
89
-
90
- Features
91
- - Scalar helpers:
92
- - get_business_days_count(begin, end, inclusive=False) -> int
93
- - add_business_days(start_date, n_days, roll='forward') -> np.datetime64
94
- - Dask DataFrame helpers (vectorized via map_partitions):
95
- - calc_business_days_from_df(df, begin_col, end_col, result_col='business_days', inclusive=False)
96
- - calc_sla_end_date(df, start_date_col, n_days_col, result_col='sla_end_date', roll='forward')
97
-
98
- Parameters
99
- ----------
100
- holiday_list : dict[str, list[str]] | Iterable[str]
101
- Either a mapping of year -> [YYYY-MM-DD, ...] or a flat iterable of YYYY-MM-DD strings.
102
- logger : Any
103
- Logger with .debug/.info/.warning/.error.
104
- weekmask : str | None
105
- A numpy business day weekmask like '1111100' (Mon–Fri). None means default Mon–Fri.
106
- Examples:
107
- '1111100' -> Mon-Fri
108
- '1111110' -> Mon-Sat
109
92
  """
110
93
 
111
94
  def __init__(
@@ -119,12 +102,11 @@ class BusinessDays:
119
102
  self.logger = logger or Logger.default_logger(logger_name=self.__class__.__name__)
120
103
  self.weekmask = weekmask
121
104
 
122
- # Normalize holidays to a flat, sorted tuple of 'YYYY-MM-DD'
123
105
  if isinstance(holiday_list, dict):
124
106
  flat = [d for _, days in sorted(holiday_list.items()) for d in days]
125
107
  else:
126
108
  flat = list(holiday_list)
127
- # Deduplicate while preserving order
109
+
128
110
  seen = set()
129
111
  flat_unique = []
130
112
  for d in flat:
@@ -142,7 +124,6 @@ class BusinessDays:
142
124
  *,
143
125
  inclusive: bool = False,
144
126
  ) -> int:
145
- """Business days between two dates. If inclusive=True, include the end date."""
146
127
  b = pd.to_datetime(begin_date).date()
147
128
  e = pd.to_datetime(end_date).date()
148
129
 
@@ -153,11 +134,11 @@ class BusinessDays:
153
134
  kwargs["weekmask"] = self.weekmask
154
135
 
155
136
  if inclusive:
156
- e_np = np.datetime64(e) + np.timedelta64(1, "D")
137
+ e_np = np.datetime64(e, "D") + np.timedelta64(1, "D")
157
138
  else:
158
- e_np = np.datetime64(e)
139
+ e_np = np.datetime64(e, "D")
159
140
 
160
- val = int(np.busday_count(np.datetime64(b), e_np, **kwargs))
141
+ val = int(np.busday_count(np.datetime64(b, "D"), e_np, **kwargs))
161
142
  return val
162
143
 
163
144
  def add_business_days(
@@ -167,11 +148,6 @@ class BusinessDays:
167
148
  *,
168
149
  roll: str = "forward",
169
150
  ) -> np.datetime64:
170
- """
171
- Add (or subtract) business days to a date. Returns numpy datetime64[D].
172
- roll: {'forward','backward','following','preceding','modifiedfollowing',
173
- 'modifiedpreceding','nat'}
174
- """
175
151
  s = pd.to_datetime(start_date).date()
176
152
  kwargs: Dict[str, Any] = {"roll": roll}
177
153
  if self.holidays:
@@ -179,7 +155,7 @@ class BusinessDays:
179
155
  if self.weekmask:
180
156
  kwargs["weekmask"] = self.weekmask
181
157
 
182
- return np.busday_offset(np.datetime64(s), int(n_days), **kwargs)
158
+ return np.busday_offset(np.datetime64(s, "D"), int(n_days), **kwargs)
183
159
 
184
160
  # -------- Dask API --------
185
161
 
@@ -192,10 +168,6 @@ class BusinessDays:
192
168
  *,
193
169
  inclusive: bool = False,
194
170
  ) -> dd.DataFrame:
195
- """
196
- Vectorized business-day difference between two date columns.
197
- Produces float64 (NaN where either side is missing).
198
- """
199
171
  missing = {begin_date_col, end_date_col} - set(df.columns)
200
172
  if missing:
201
173
  self.logger.error(f"Missing columns: {missing}")
@@ -224,10 +196,6 @@ class BusinessDays:
224
196
  *,
225
197
  roll: str = "forward",
226
198
  ) -> dd.DataFrame:
227
- """
228
- Vectorized business-day offset for SLA end date.
229
- Produces datetime64[ns] with NaT where invalid.
230
- """
231
199
  missing = {start_date_col, n_days_col} - set(df.columns)
232
200
  if missing:
233
201
  self.logger.error(f"Missing columns: {missing}")
@@ -1,7 +1,10 @@
1
+ from __future__ import annotations
2
+
1
3
  import asyncio
2
4
  from typing import List, Any, Dict
3
5
 
4
6
  import dask
7
+ #dask.config.set({"distributed.worker.daemon": False})
5
8
  import dask.dataframe as dd
6
9
 
7
10
  def _to_int_safe(x) -> int:
@@ -58,4 +61,124 @@ class UniqueValuesExtractor:
58
61
  return col, await self.compute_to_list(ser)
59
62
 
60
63
  pairs = await asyncio.gather(*(one(c) for c in columns))
61
- return dict(pairs)
64
+ return dict(pairs)
65
+
66
+ from contextlib import suppress
67
+ from dask.distributed import Client, LocalCluster, get_client
68
+ import os
69
+
70
+ class DaskClientMixin:
71
+ """
72
+ Provides shared Dask client lifecycle management.
73
+ Ensures reuse of an existing client if available,
74
+ or creates a local in-process Dask cluster for fallback.
75
+ """
76
+
77
+ def _init_dask_client(
78
+ self,
79
+ dask_client=None,
80
+ logger=None,
81
+ *,
82
+ n_workers: int = 1,
83
+ threads_per_worker: int = 1,
84
+ processes: bool = False,
85
+ asynchronous: bool = False,
86
+ memory_limit: str = "auto",
87
+ #dashboard_address: str | None = None,
88
+ local_directory: str | None = None,
89
+ silence_logs: str = "info",
90
+ resources: dict | None = None,
91
+ timeout: int = 30,
92
+ ):
93
+ self.dask_client = dask_client
94
+ self.own_dask_client = False
95
+ self.logger = logger
96
+
97
+ if self.dask_client is None:
98
+ with suppress(ValueError, RuntimeError):
99
+ # Try to attach to an existing client (common in shared Dask setups)
100
+ self.dask_client = get_client()
101
+
102
+ if self.dask_client is None:
103
+ # Default to half of logical cores if not specified
104
+ n_workers = n_workers or max(2, os.cpu_count() // 2)
105
+
106
+ cluster = LocalCluster(
107
+ n_workers=n_workers,
108
+ threads_per_worker=threads_per_worker,
109
+ processes=processes,
110
+ asynchronous=asynchronous,
111
+ memory_limit=memory_limit,
112
+ local_directory=local_directory,
113
+ silence_logs=silence_logs,
114
+ resources=resources,
115
+ timeout=timeout,
116
+ )
117
+
118
+ self.dask_client = Client(cluster)
119
+ self.own_dask_client = True
120
+
121
+ if self.logger:
122
+ self.logger.info(
123
+ f"Started local Dask cluster with {n_workers} workers × {threads_per_worker} threads "
124
+ f"({memory_limit} memory per worker). Dashboard: {self.dask_client.dashboard_link}"
125
+ )
126
+ else:
127
+ if self.logger:
128
+ self.logger.debug(
129
+ f"Using existing Dask client: {self.dask_client.dashboard_link}"
130
+ )
131
+
132
+ def _close_dask_client(self):
133
+ """Close the Dask client if this instance created it."""
134
+ if getattr(self, "own_dask_client", False) and self.dask_client is not None:
135
+ try:
136
+ cluster = getattr(self.dask_client, "cluster", None)
137
+ self.dask_client.close()
138
+ if cluster is not None:
139
+ cluster.close()
140
+ if self.logger:
141
+ self.logger.info("Closed local Dask client and cluster.")
142
+ except Exception as e:
143
+ if self.logger:
144
+ self.logger.warning(f"Error while closing Dask client: {e}")
145
+
146
+ # from contextlib import suppress
147
+ # from dask.distributed import Client, get_client
148
+ #
149
+ # class DaskClientMixin:
150
+ # """
151
+ # Provides shared Dask client lifecycle management.
152
+ # Ensures reuse of existing client when available, otherwise creates a lightweight local one.
153
+ # """
154
+ #
155
+ # def _init_dask_client(self, dask_client=None, logger=None):
156
+ # self.dask_client = dask_client
157
+ # self.own_dask_client = False
158
+ # self.logger = logger
159
+ #
160
+ # if self.dask_client is None:
161
+ # with suppress(ValueError, RuntimeError):
162
+ # # Try to attach to an existing active client if running inside a Dask context
163
+ # self.dask_client = get_client()
164
+ #
165
+ # if self.dask_client is None:
166
+ # # Start a local in-process scheduler for fallback
167
+ # self.dask_client = Client(processes=False)
168
+ # self.own_dask_client = True
169
+ # if self.logger:
170
+ # self.logger.info(f"Started local Dask client: {self.dask_client.dashboard_link}")
171
+ # else:
172
+ # if self.logger:
173
+ # self.logger.debug(f"Using existing Dask client: {self.dask_client.dashboard_link}")
174
+ #
175
+ # def _close_dask_client(self):
176
+ # """Close client only if this instance created it."""
177
+ # if getattr(self, "own_dask_client", False) and self.dask_client is not None:
178
+ # try:
179
+ # self.dask_client.close()
180
+ # if self.logger:
181
+ # self.logger.info("Closed local Dask client.")
182
+ # except Exception as e:
183
+ # if self.logger:
184
+ # self.logger.warning(f"Error while closing Dask client: {e}")
@@ -87,17 +87,6 @@ class DataWrapper(ManagedResource):
87
87
  "dataclass": self.dataclass.__name__
88
88
  })
89
89
 
90
- # --------------------- Context Management ---------------------
91
- def __exit__(self, exc_type, exc_val, exc_tb):
92
- """Ensure manifest is saved and resources are cleaned up on context exit."""
93
- if self.mmanifest:
94
- try:
95
- self.mmanifest.save()
96
- except Exception as e:
97
- self.logger.error(f"Failed to save manifest in __exit__: {e}", extra=self.logger_extra)
98
- # Call parent's __exit__ which triggers _cleanup
99
- return super().__exit__(exc_type, exc_val, exc_tb)
100
-
101
90
  # --------------------- Cleanup ---------------------
102
91
  def _cleanup(self) -> None:
103
92
  """Signal shutdown during class-specific cleanup."""
@@ -160,160 +160,7 @@ class FilePathGenerator:
160
160
  # For local file, return absolute-like path without scheme or keep 'file://'? Keep scheme for consistency.
161
161
  return f"{self._protocol}://{path}"
162
162
 
163
- # import datetime
164
- # import re
165
- #
166
- # import fsspec
167
- #
168
- # from .log_utils import Logger
169
- #
170
- #
171
- # class FilePathGenerator:
172
- # """
173
- # Dynamically generates file paths by scanning directories starting from the base path
174
- # and determining the innermost directory structure.
175
- #
176
- # Now supports generating appropriate paths for both pandas and Dask.
177
- # """
178
- #
179
- # def __init__(self, base_path='', fs=None, logger=None, **kwargs):
180
- # """
181
- # Initialize the FilePathGenerator.
182
- #
183
- # Parameters:
184
- # base_path (str): Base directory path where data files are stored.
185
- # fs (fsspec.AbstractFileSystem, optional): Filesystem object to use for file operations.
186
- # logger (Logger, optional): Logger instance for logging information.
187
- # **kwargs: Additional keyword arguments.
188
- # - debug (bool): If True, enables debug logging.
189
- # - storage_options (dict): Options for the filesystem (e.g., credentials, tokens).
190
- # - exclude_patterns (list): List of regex patterns to exclude from file paths.
191
- # - file_extension (str): File extension to look for (default: 'parquet').
192
- # """
193
- # self.base_path = base_path.rstrip('/')
194
- # self.fs = fs # Filesystem object
195
- # self.logger = logger or Logger.default_logger(logger_name=self.__class__.__name__)
196
- # self.debug = kwargs.get('debug', False)
197
- # self.storage_options = kwargs.get('storage_options', {})
198
- # self.exclude_patterns = kwargs.get('exclude_patterns', [])
199
- # self.file_extension = kwargs.get('file_extension', 'parquet').lstrip('.')
200
- #
201
- # # If fs is not provided, initialize it based on base_path and storage_options
202
- # if self.fs is None:
203
- # self.fs, _ = fsspec.core.url_to_fs(self.base_path, **self.storage_options)
204
- #
205
- # def generate_file_paths(self, start_date, end_date, engine='dask'):
206
- # """
207
- # Generate paths dynamically for files within the date range by scanning directories.
208
- # Returns a list of file paths compatible with the specified engine.
209
- #
210
- # Parameters:
211
- # start_date (str or datetime): Start date in 'YYYY-MM-DD' format or datetime object.
212
- # end_date (str or datetime): End date in 'YYYY-MM-DD' format or datetime object.
213
- # engine (str): 'pandas' or 'dask' to specify which library the paths are intended for.
214
- #
215
- # Returns:
216
- # list: List of file paths.
217
- # """
218
- # start_date = self._convert_to_datetime(start_date)
219
- # end_date = self._convert_to_datetime(end_date)
220
- #
221
- # paths = []
222
- # curr_date = start_date
223
- #
224
- # while curr_date <= end_date:
225
- # year, month, day = curr_date.year, curr_date.month, curr_date.day
226
- # day_paths = self._collect_paths(year, month, day, engine)
227
- # if day_paths:
228
- # paths.extend(day_paths)
229
- # curr_date += datetime.timedelta(days=1)
230
- #
231
- # return paths
232
- #
233
- # def _collect_paths(self, year, month, day, engine):
234
- # """
235
- # Collect appropriate paths for a given date, depending on the engine.
236
- #
237
- # Parameters:
238
- # year (int): Year component of the date.
239
- # month (int): Month component of the date.
240
- # day (int): Day component of the date.
241
- # engine (str): 'pandas' or 'dask'.
242
- #
243
- # Returns:
244
- # list: List of file or directory paths.
245
- # """
246
- # base_dir = f"{self.base_path}/{year}/{str(month).zfill(2)}/{str(day).zfill(2)}"
247
- #
248
- # if not self.fs.exists(base_dir):
249
- # if self.debug:
250
- # self.logger.debug(f"Directory does not exist: {base_dir}")
251
- # return []
252
- #
253
- # if engine == 'dask':
254
- # # Collect individual file paths
255
- # file_pattern = f"{base_dir}/**/*.{self.file_extension}"
256
- # all_paths = self.fs.glob(file_pattern)
257
- #
258
- # if not all_paths and self.debug:
259
- # self.logger.debug(f"No files found with pattern: {file_pattern}")
260
- #
261
- # # Exclude unwanted files and directories
262
- # filtered_paths = self._exclude_unwanted_paths(all_paths)
263
- #
264
- # # Filter out directories
265
- # file_paths = [path for path in filtered_paths if not self.fs.isdir(path)]
266
- #
267
- # elif engine == 'pandas':
268
- # # Collect dataset directories
269
- # # Assume that the base_dir is a Parquet dataset
270
- # if self.fs.isdir(base_dir):
271
- # file_paths = [base_dir]
272
- # else:
273
- # file_paths = []
274
- #
275
- # else:
276
- # raise ValueError("Engine must be 'pandas' or 'dask'.")
277
- #
278
- # protocol = self.fs.protocol if isinstance(self.fs.protocol, str) else self.fs.protocol[0]
279
- #
280
- # # Ensure the protocol is included in the paths
281
- # file_paths = [
282
- # f"{protocol}://{path}" if not path.startswith(f"{protocol}://") else path
283
- # for path in file_paths
284
- # ]
285
- #
286
- # if self.debug:
287
- # self.logger.debug(f"Collected {len(file_paths)} paths from {base_dir} for engine '{engine}'")
288
- #
289
- # return file_paths
290
- #
291
- # def _exclude_unwanted_paths(self, paths):
292
- # """
293
- # Exclude paths that match any of the exclusion patterns.
294
- # """
295
- # # Combine default patterns with user-provided patterns
296
- # exclude_patterns = self.exclude_patterns
297
- #
298
- # # Compile regex patterns for efficiency
299
- # compiled_patterns = [re.compile(pattern) for pattern in exclude_patterns]
300
- #
301
- # # Filter out paths matching any of the exclude patterns
302
- # filtered_paths = [
303
- # path for path in paths
304
- # if not any(pattern.match(path) for pattern in compiled_patterns)
305
- # ]
306
- #
307
- # return filtered_paths
308
- #
309
- # @staticmethod
310
- # def _convert_to_datetime(date):
311
- # """Convert a date string or datetime object into a datetime object."""
312
- # if isinstance(date, str):
313
- # return datetime.datetime.strptime(date, '%Y-%m-%d')
314
- # return date
315
- #
316
- #
163
+
317
164
  # """
318
165
  # Usage:
319
166
  # # Initialize the generator
@@ -1,34 +1,31 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: sibi-dst
3
- Version: 2025.9.10
4
- Summary: Data Science Toolkit
5
- Author: Luis Valverde
6
- Author-email: lvalverdeb@gmail.com
7
- Requires-Python: >=3.11,<4.0
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.11
10
- Classifier: Programming Language :: Python :: 3.12
11
- Classifier: Programming Language :: Python :: 3.13
12
- Requires-Dist: clickhouse-connect (>=0.8.18,<0.9.0)
13
- Requires-Dist: clickhouse-driver (>=0.2.9,<0.3.0)
14
- Requires-Dist: dask[complete] (>=2025.9.0,<2026.0.0)
15
- Requires-Dist: distributed (>=2025.9.1,<2026.0.0)
16
- Requires-Dist: mysqlclient (>=2.2.7,<3.0.0)
17
- Requires-Dist: opentelemetry-exporter-otlp (>=1.35.0,<2.0.0)
18
- Requires-Dist: opentelemetry-sdk (>=1.35.0,<2.0.0)
19
- Requires-Dist: pandas (>=2.3.1,<3.0.0)
20
- Requires-Dist: psycopg2 (>=2.9.10,<3.0.0)
21
- Requires-Dist: pyarrow (>=20.0.0,<21.0.0)
22
- Requires-Dist: pydantic (>=2.11.7,<3.0.0)
23
- Requires-Dist: pyiceberg[hive,s3fs] (>=0.9.1,<0.10.0)
24
- Requires-Dist: pymysql (>=1.1.1,<2.0.0)
25
- Requires-Dist: pyrosm (>=0.6.2,<0.7.0)
26
- Requires-Dist: s3fs (>=2025.5.1,<2026.0.0)
27
- Requires-Dist: sqlalchemy (>=2.0.41,<3.0.0)
28
- Requires-Dist: sse-starlette (>=3.0.2,<4.0.0)
29
- Requires-Dist: tqdm (>=4.67.1,<5.0.0)
30
- Requires-Dist: webdav4 (>=0.10.0,<0.11.0)
3
+ Version: 2025.9.12
4
+ Summary: A data science toolkit for scalable data processing and analysis.
5
+ Requires-Python: >=3.11
31
6
  Description-Content-Type: text/markdown
7
+ Requires-Dist: clickhouse-connect>=0.9.2
8
+ Requires-Dist: clickhouse-driver>=0.2.9
9
+ Requires-Dist: dask>=2025.9.1
10
+ Requires-Dist: distributed>=2025.9.1
11
+ Requires-Dist: fastapi>=0.118.0
12
+ Requires-Dist: folium>=0.20.0
13
+ Requires-Dist: mysqlclient>=2.2.7
14
+ Requires-Dist: opentelemetry-api>=1.37.0
15
+ Requires-Dist: opentelemetry-exporter-otlp>=1.37.0
16
+ Requires-Dist: opentelemetry-sdk>=1.37.0
17
+ Requires-Dist: pandas>=2.3.3
18
+ Requires-Dist: psycopg2>=2.9.10
19
+ Requires-Dist: pyarrow>=21.0.0
20
+ Requires-Dist: pydantic>=2.11.10
21
+ Requires-Dist: pymysql>=1.1.2
22
+ Requires-Dist: redis>=6.4.0
23
+ Requires-Dist: s3fs>=2025.9.0
24
+ Requires-Dist: sqlalchemy>=2.0.43
25
+ Requires-Dist: tqdm>=4.67.1
26
+ Requires-Dist: uvicorn>=0.37.0
27
+ Requires-Dist: webdav4>=0.10.0
28
+ Requires-Dist: wheel>=0.45.1
32
29
 
33
30
  ### SIBI-DST
34
31
 
@@ -60,4 +57,3 @@ pip install sibi-dst[dev,test,geospatial] # Install all optional dependencies
60
57
 
61
58
 
62
59
  ```
63
-
@@ -1,6 +1,6 @@
1
- sibi_dst/__init__.py,sha256=D4TMsAMGRl54J5PNYMDf_z0NcCnS_lZK1YHze2eJvpc,464
2
- sibi_dst/df_helper/__init__.py,sha256=aOQFmWpLeSq-7O8IYEKaxR1nvuIe9F7SJsOsgwj1ECg,579
3
- sibi_dst/df_helper/_artifact_updater_async.py,sha256=0VBwGMIQXKagr4MpshvfuhplwePD2VQbN2MOUTgQyJs,9992
1
+ sibi_dst/__init__.py,sha256=QQVT3Xlj8iZN17sSMfRQFSb_DHr8A7giJP8hn02K2Oo,585
2
+ sibi_dst/df_helper/__init__.py,sha256=7rUdMybgCNZhQL_J7IFTTHz_xtFin81xavi5-PUExkA,463
3
+ sibi_dst/df_helper/_artifact_updater_async.py,sha256=AZp0vM3vji0tjiaScr8a9SUMH15NjPIKYPdRQ7SJe3Y,11372
4
4
  sibi_dst/df_helper/_artifact_updater_threaded.py,sha256=M5GNZismOqMmBrcyfolP1DPv87VILQf_P18is_epn50,7238
5
5
  sibi_dst/df_helper/_df_helper.py,sha256=rgVP4ggiCW6tTHmUz2UqUvLznwOtY5IyoVS3WSlg73U,17005
6
6
  sibi_dst/df_helper/_parquet_artifact.py,sha256=UXkhDSAVRNKp9DykVhJd3agnryCZT0Sj2qhdhUZomuM,19421
@@ -9,7 +9,7 @@ sibi_dst/df_helper/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
9
9
  sibi_dst/df_helper/backends/http/__init__.py,sha256=d1pfgYxbiYg7E0Iw8RbJ7xfqIfJShqqTBQQGU_S6OOo,105
10
10
  sibi_dst/df_helper/backends/http/_http_config.py,sha256=eGPFdqZ5M3Tscqx2P93B6XoBEEzlmdt7yNg7PXUQnNQ,4726
11
11
  sibi_dst/df_helper/backends/parquet/__init__.py,sha256=0A6BGHZLwiLBmuBBaUvEHfeWTcInvy2NbymlrI_nuXE,104
12
- sibi_dst/df_helper/backends/parquet/_parquet_options.py,sha256=KlzmTMVHME5kmhEBRzWdWPcih-jYaslkyhHOZdQ1gLA,11802
12
+ sibi_dst/df_helper/backends/parquet/_parquet_options.py,sha256=OeeWWFhrolayg8MGZxbbAVNIC9zZB9cCXxTGGLPX0og,11746
13
13
  sibi_dst/df_helper/backends/sqlalchemy/__init__.py,sha256=LjWm9B7CweTvlvFOgB90XjSe0lVLILAIYMWKPkFXFm8,265
14
14
  sibi_dst/df_helper/backends/sqlalchemy/_db_connection.py,sha256=6705rABdh0RY0JisxD7sE62m6890hMCAv_cpyHOMSvM,8729
15
15
  sibi_dst/df_helper/backends/sqlalchemy/_db_gatekeeper.py,sha256=GQwDy2JwPUx37vpwxPM5hg4ZydilPIP824y5C_clsl0,383
@@ -22,59 +22,58 @@ sibi_dst/df_helper/core/_defaults.py,sha256=9UMEMu2wXznO5UzEhnQ82f_ZazZ20JRyRXIi
22
22
  sibi_dst/df_helper/core/_filter_handler.py,sha256=9C30zrT8wSGy1X8ryiTWc0XfnbpeoHndHgoOcHKOPOo,19309
23
23
  sibi_dst/df_helper/core/_params_config.py,sha256=DYx2drDz3uF-lSPzizPkchhy-kxRrQKE5FQRxcEWsac,6736
24
24
  sibi_dst/df_helper/core/_query_config.py,sha256=1ApqmuSGXTC3CdF-xMsSbCa3V2Z5hOP3Wq5huhzZwqY,439
25
- sibi_dst/df_helper/data_cleaner.py,sha256=lkxQoXLvGzXCicFUimnA5nen5qkrO1oxgl_p2Be2o8w,5183
26
25
  sibi_dst/geopy_helper/__init__.py,sha256=Q1RJiUZIOlV0QNNLjxZ_2IZS5LqIe5jRbeQkfD1Vm60,112
27
26
  sibi_dst/geopy_helper/geo_location_service.py,sha256=1ArI980QF_gRw096ZsABHwJt-m55jrfOlB8tPwL1BvY,2959
28
27
  sibi_dst/geopy_helper/utils.py,sha256=Sb7qfSqIyWh-AZ4GBdB9-z5FrQPWtrdtQLLcNjph0yw,3351
29
- sibi_dst/osmnx_helper/__init__.py,sha256=On2_pD13HmzZjP-YrXV9BA9uFK-z26QkQE-MliGdv5w,134
28
+ sibi_dst/osmnx_helper/__init__.py,sha256=hTv1uCnN35MSUEYNWk30OHHSflDb1qidwfLDXhUU8cE,243
30
29
  sibi_dst/osmnx_helper/base_osm_map.py,sha256=L7g3VBiayHX41BcCBTOCS0iJOKzp2ZZYcrp8N-mnU90,19392
30
+ sibi_dst/osmnx_helper/route_path_builder.py,sha256=XJJyu4YXegAkCRjE-knyQncwXaxDVXZhalYacLcb7e0,3557
31
+ sibi_dst/osmnx_helper/utils.py,sha256=7-lFVhGn4rHjGz6FvpXtC2jY8UzGIVyKR3MVyEfB7nw,14407
31
32
  sibi_dst/osmnx_helper/basemaps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
33
  sibi_dst/osmnx_helper/basemaps/calendar_html.py,sha256=UArt6FDgoCgoRte45Xo3IHqd-RNzW0YgitgZYfOFasY,4031
33
34
  sibi_dst/osmnx_helper/basemaps/route_map_plotter.py,sha256=rsJidieojcqIoe0kBanZbrxcelrS6nWoAyWoQXWdPiQ,11849
34
35
  sibi_dst/osmnx_helper/basemaps/router_plotter.py,sha256=UAiijn-J-jjX4YnL0_P9SFqTadrxMx-YK4djYhqPqfQ,10941
35
- sibi_dst/osmnx_helper/route_path_builder.py,sha256=XJJyu4YXegAkCRjE-knyQncwXaxDVXZhalYacLcb7e0,3557
36
- sibi_dst/osmnx_helper/utils.py,sha256=7-lFVhGn4rHjGz6FvpXtC2jY8UzGIVyKR3MVyEfB7nw,14407
37
36
  sibi_dst/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
37
  sibi_dst/tests/test_baseclass.py,sha256=5huAwjWo_SOEZR2_0y5w9qUmw5G7pVdm8X1OTG87JK0,11562
39
38
  sibi_dst/tests/test_data_wrapper_class.py,sha256=6uFmZR2DxnxQz49L5jT2ehlKvlLnpUHMLFB_PqqUq7k,3336
40
- sibi_dst/utils/__init__.py,sha256=vShNCOMPw8KKwlb4tq5XGrpjqakJ_OE8YDc_xDAWAxI,1302
39
+ sibi_dst/utils/__init__.py,sha256=eoW7iROrCUVYjNT1owMgGvW6U7lolbNy3FrBb_wInPs,1304
41
40
  sibi_dst/utils/async_utils.py,sha256=53aywfgq1Q6-0OVr9qR1Sf6g7Qv3I9qunAAR4fjFXBE,351
42
41
  sibi_dst/utils/base.py,sha256=sFngliI7Ku8bZMz0YdVhppuaPNZ0dvqRwCsPe9XdF1A,16256
43
- sibi_dst/utils/boilerplate/__init__.py,sha256=89oepkDCnjegnhzd6Kgga71AH17KSvNMlgD83CAAmg8,582
44
- sibi_dst/utils/boilerplate/base_attacher.py,sha256=iZftWNUx8y370OJP_kGCs5v3t2RgPuARIK_jQeFfbAU,2089
45
- sibi_dst/utils/boilerplate/base_data_cube.py,sha256=ErKTM2kT8LsSXADcyYvT436O_Mp0J2hm8xs1IUircb4,2760
46
- sibi_dst/utils/boilerplate/base_parquet_artifact.py,sha256=oqPbjHFfChA9j1WL-eDAh7XLA3zmf-Rq7s_kzITVniA,3753
47
- sibi_dst/utils/boilerplate/base_parquet_reader.py,sha256=3kN9_bbxyX-WuJLMBWejeApW2V_BDArSljhSUOAOhVU,692
48
- sibi_dst/utils/boilerplate/base_pipeline.py,sha256=LQZBACksqHO3tQ8OhWShfqjiGyda7UhrmllRq3eWQfU,5690
49
- sibi_dst/utils/boilerplate/base_pipeline_template.py,sha256=D5HFA4odsR2wlTY6iLg1tm57Tsh91QkoYjjX8eUgrjU,1574
50
- sibi_dst/utils/boilerplate/hybrid_data_loader.py,sha256=Tazn7QL3FmWKVMXxzkvxPrG_2ucsPHvSotIW9dBLoNc,6018
51
- sibi_dst/utils/business_days.py,sha256=dP0Xj4FhTBIvZZrZYLOHZl5zOpDAgWkD4p_1a7BOT7I,8461
42
+ sibi_dst/utils/business_days.py,sha256=DPZExTXTt7n3IbAaEuVacm-vZgbR_Ug2bJTPBUaoP3g,6694
52
43
  sibi_dst/utils/clickhouse_writer.py,sha256=8W_dTEOKQp4pXANznVSxRqFA2H5oD8UJifiBAONpXWY,17001
53
44
  sibi_dst/utils/credentials.py,sha256=cHJPPsmVyijqbUQIq7WWPe-lIallA-mI5RAy3YUuRME,1724
54
- sibi_dst/utils/dask_utils.py,sha256=QhFcmpH4fXAy6b3DugIX5JvH4h-P3M3hXKnBYTLRkq0,1991
45
+ sibi_dst/utils/dask_utils.py,sha256=UA8Bp0Qm7n8WSyjFmxNSrWdJ5TG_v6NCrmgLxPbnXlA,6692
55
46
  sibi_dst/utils/data_from_http_source.py,sha256=AcpKNsqTgN2ClNwuhgUpuNCx62r5_DdsAiKY8vcHEBA,1867
56
47
  sibi_dst/utils/data_utils.py,sha256=7bLidEjppieNoozDFb6OuRY0W995cxg4tiGAlkGfePI,7768
57
- sibi_dst/utils/data_wrapper.py,sha256=-a5LkkjBVXUPwDYngn5K98oSNYsQf87zNaih9IJxs-I,18543
48
+ sibi_dst/utils/data_wrapper.py,sha256=9HTuDXgvfhmFAOyNG_GEOaHuojxE3639yyzOoBt7Unc,18000
58
49
  sibi_dst/utils/date_utils.py,sha256=hBVWu9_cqiZ-XsLR7QY9Iek09DQKLwrY1ZlYxWlXj7g,31101
59
50
  sibi_dst/utils/df_utils.py,sha256=bQGromLOEdRTvbVVcuHq0vQ0fIgqhwOoD_eIp5v7VEY,10899
60
51
  sibi_dst/utils/file_age_checker.py,sha256=44B3lwH_PLwzMfiKkgvJKjKx-qSgITIXxKfNbdf_VeA,11552
61
52
  sibi_dst/utils/file_utils.py,sha256=cm__02IKCfEOzAKAZwdNIjnRL8H4XtPa6hKcj510pto,1310
62
- sibi_dst/utils/filepath_generator.py,sha256=Ke_OwBjLJkNMeOP0QjbLIZpSMkzhAIxKyf4hZ5P5re0,12916
53
+ sibi_dst/utils/filepath_generator.py,sha256=Nt6JGEM01_bPCMuWs8_TnTm0CqV5Hv9o1zu9QvN4WFk,6774
63
54
  sibi_dst/utils/iceberg_saver.py,sha256=l1UWJWrLqe2OxCdP1mRyXlG9It1-F3MN_ZvHPmxqRJ4,5253
64
55
  sibi_dst/utils/log_utils.py,sha256=1xXTDfwMwWIdj37hjyXSpHx3ft2GMiXsAfxq9AArMTY,11588
65
56
  sibi_dst/utils/manifest_manager.py,sha256=9y4cV-Ig8O-ekhApp_UObTY-cTsl-bGnvKIThItEzg4,7394
66
57
  sibi_dst/utils/parquet_saver.py,sha256=Itctsf8UnBCnD6NrP00FK0y9KzZgKYfjUk1CC-0x-F0,20486
67
58
  sibi_dst/utils/periods.py,sha256=8eTGi-bToa6_a8Vwyg4fkBPryyzft9Nzy-3ToxjqC8c,1434
68
59
  sibi_dst/utils/phone_formatter.py,sha256=oeM22nLjhObENrpItCNeVpkYS4pXRm5hSxdk0M4nvwU,4580
69
- sibi_dst/utils/progress/__init__.py,sha256=VELVxzo2cePN_-LL0veel8-F3po6tokY5MOOpu6pz1A,92
70
- sibi_dst/utils/progress/jobs.py,sha256=nE58ng9GPCPZhnaCDltr1tQgu3AJVqBJ1dWbGcCH4xo,3089
71
- sibi_dst/utils/progress/sse_runner.py,sha256=NttASZH_ayXo1Zi6I4tSwYnWySLxexOYQGlqzOZiXlI,4965
72
60
  sibi_dst/utils/storage_config.py,sha256=DLtP5jKVM0mdFdgRw6LQfRqyavMjJcCVU7GhsUCRH78,4427
73
61
  sibi_dst/utils/storage_hive.py,sha256=eZ3nq2YWLUUG-06iJubSC15cwSHEbKKdKIwoVhD_I_E,8568
74
62
  sibi_dst/utils/storage_manager.py,sha256=La1NY79bhRAmHWXp7QcXJZtbHoRboJMgoXOSXbIl1SA,6643
75
63
  sibi_dst/utils/update_planner.py,sha256=1UOh4MjZSfaA_ZO-nKailOGal5EY-xVR8KSCJzo7p_g,16834
76
64
  sibi_dst/utils/webdav_client.py,sha256=D9J5d1f1qQwHGm5FE5AMVpOPwcU5oD7K8JZoKGP8NpM,5811
77
65
  sibi_dst/utils/write_gatekeeper.py,sha256=V8sY9YMO-JuN8Ps7prqwVSjP4f1HGH9KiVV-aTPCC_k,569
66
+ sibi_dst/utils/boilerplate/__init__.py,sha256=89oepkDCnjegnhzd6Kgga71AH17KSvNMlgD83CAAmg8,582
67
+ sibi_dst/utils/boilerplate/base_attacher.py,sha256=iZftWNUx8y370OJP_kGCs5v3t2RgPuARIK_jQeFfbAU,2089
68
+ sibi_dst/utils/boilerplate/base_data_cube.py,sha256=ErKTM2kT8LsSXADcyYvT436O_Mp0J2hm8xs1IUircb4,2760
69
+ sibi_dst/utils/boilerplate/base_parquet_artifact.py,sha256=oqPbjHFfChA9j1WL-eDAh7XLA3zmf-Rq7s_kzITVniA,3753
70
+ sibi_dst/utils/boilerplate/base_parquet_reader.py,sha256=3kN9_bbxyX-WuJLMBWejeApW2V_BDArSljhSUOAOhVU,692
71
+ sibi_dst/utils/boilerplate/base_pipeline.py,sha256=cPVvjGxd0tDDvP_c27MNDHNuNnM6k3yx5bivN5ZFgrQ,5587
72
+ sibi_dst/utils/boilerplate/base_pipeline_template.py,sha256=D5HFA4odsR2wlTY6iLg1tm57Tsh91QkoYjjX8eUgrjU,1574
73
+ sibi_dst/utils/boilerplate/hybrid_data_loader.py,sha256=Tazn7QL3FmWKVMXxzkvxPrG_2ucsPHvSotIW9dBLoNc,6018
74
+ sibi_dst/utils/progress/__init__.py,sha256=VELVxzo2cePN_-LL0veel8-F3po6tokY5MOOpu6pz1A,92
75
+ sibi_dst/utils/progress/jobs.py,sha256=nE58ng9GPCPZhnaCDltr1tQgu3AJVqBJ1dWbGcCH4xo,3089
76
+ sibi_dst/utils/progress/sse_runner.py,sha256=NttASZH_ayXo1Zi6I4tSwYnWySLxexOYQGlqzOZiXlI,4965
78
77
  sibi_dst/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
78
  sibi_dst/v2/df_helper/__init__.py,sha256=XuH6jKYAPg2DdRbsxxBSxp9X3x-ARyaT0xe27uILrVo,99
80
79
  sibi_dst/v2/df_helper/_df_helper.py,sha256=9pED3bjQ2Z81zqzJrZ9e7SguoO4-hBmNTJK4WOKrr4M,9297
@@ -95,6 +94,7 @@ sibi_dst/v2/df_helper/core/_params_config.py,sha256=DYx2drDz3uF-lSPzizPkchhy-kxR
95
94
  sibi_dst/v2/df_helper/core/_query_config.py,sha256=Y8LVSyaKuVkrPluRDkQoOwuXHQxner1pFWG3HPfnDHM,441
96
95
  sibi_dst/v2/utils/__init__.py,sha256=6H4cvhqTiFufnFPETBF0f8beVVMpfJfvUs6Ne0TQZNY,58
97
96
  sibi_dst/v2/utils/log_utils.py,sha256=rfk5VsLAt-FKpv6aPTC1FToIPiyrnHAFFBAkHme24po,4123
98
- sibi_dst-2025.9.10.dist-info/METADATA,sha256=Sy1u7f-x3I_Ap-n2NklwyhAPWk1cluc0vX5Qn_BgS7c,2761
99
- sibi_dst-2025.9.10.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
100
- sibi_dst-2025.9.10.dist-info/RECORD,,
97
+ sibi_dst-2025.9.12.dist-info/METADATA,sha256=6WESOFkRannoMbUj_V-dDpti2qQ5XIxUgHSTfaqKAHA,2413
98
+ sibi_dst-2025.9.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
99
+ sibi_dst-2025.9.12.dist-info/top_level.txt,sha256=g3Cj4R-rciuNyJgcxuxNgw5nhN0n4TCB0ujcTEjZNiU,9
100
+ sibi_dst-2025.9.12.dist-info/RECORD,,
@@ -1,4 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
+