wpipe 2.2.0__tar.gz → 2.3.1__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.
- {wpipe-2.2.0 → wpipe-2.3.1}/PKG-INFO +38 -31
- {wpipe-2.2.0 → wpipe-2.3.1}/README.md +1 -1
- {wpipe-2.2.0 → wpipe-2.3.1}/pyproject.toml +1 -1
- wpipe-2.3.1/setup.cfg +4 -0
- wpipe-2.3.1/setup.py +63 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/__init__.py +51 -15
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/dashboard/main.py +4 -4
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/components/metrics.py +5 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/resource_monitor/monitor.py +5 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/sqlite/tables_dto/tracker_models.py +11 -11
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/tracking/tracker.py +5 -1
- wpipe-2.3.1/wpipe.egg-info/PKG-INFO +635 -0
- wpipe-2.3.1/wpipe.egg-info/SOURCES.txt +80 -0
- wpipe-2.3.1/wpipe.egg-info/dependency_links.txt +1 -0
- wpipe-2.3.1/wpipe.egg-info/requires.txt +25 -0
- wpipe-2.3.1/wpipe.egg-info/top_level.txt +2 -0
- wpipe-2.2.0/.gitignore +0 -178
- wpipe-2.2.0/examples/01_basic_pipeline/01_simple_function/README.md +0 -76
- wpipe-2.2.0/examples/01_basic_pipeline/01_simple_function/example.py +0 -84
- wpipe-2.2.0/examples/01_basic_pipeline/02_class_steps/README.md +0 -75
- wpipe-2.2.0/examples/01_basic_pipeline/02_class_steps/example.py +0 -93
- wpipe-2.2.0/examples/01_basic_pipeline/03_mixed_steps/README.md +0 -75
- wpipe-2.2.0/examples/01_basic_pipeline/03_mixed_steps/example.py +0 -87
- wpipe-2.2.0/examples/01_basic_pipeline/04_default_values/README.md +0 -70
- wpipe-2.2.0/examples/01_basic_pipeline/04_default_values/example.py +0 -72
- wpipe-2.2.0/examples/01_basic_pipeline/05_args_kwargs/README.md +0 -70
- wpipe-2.2.0/examples/01_basic_pipeline/05_args_kwargs/example.py +0 -78
- wpipe-2.2.0/examples/01_basic_pipeline/06_dict_processing/README.md +0 -75
- wpipe-2.2.0/examples/01_basic_pipeline/06_dict_processing/example.py +0 -100
- wpipe-2.2.0/examples/01_basic_pipeline/07_multiple_runs/README.md +0 -71
- wpipe-2.2.0/examples/01_basic_pipeline/07_multiple_runs/example.py +0 -95
- wpipe-2.2.0/examples/01_basic_pipeline/08_data_aggregation/README.md +0 -81
- wpipe-2.2.0/examples/01_basic_pipeline/08_data_aggregation/example.py +0 -106
- wpipe-2.2.0/examples/01_basic_pipeline/09_empty_data/README.md +0 -71
- wpipe-2.2.0/examples/01_basic_pipeline/09_empty_data/example.py +0 -76
- wpipe-2.2.0/examples/01_basic_pipeline/10_lambda_steps/README.md +0 -77
- wpipe-2.2.0/examples/01_basic_pipeline/10_lambda_steps/example.py +0 -34
- wpipe-2.2.0/examples/01_basic_pipeline/11_decorator_steps/README.md +0 -74
- wpipe-2.2.0/examples/01_basic_pipeline/11_decorator_steps/example.py +0 -91
- wpipe-2.2.0/examples/01_basic_pipeline/12_context_manager/README.md +0 -72
- wpipe-2.2.0/examples/01_basic_pipeline/12_context_manager/example.py +0 -73
- wpipe-2.2.0/examples/01_basic_pipeline/13_async_pipeline/README.md +0 -76
- wpipe-2.2.0/examples/01_basic_pipeline/13_async_pipeline/example.py +0 -80
- wpipe-2.2.0/examples/01_basic_pipeline/14_pipeline_chaining/README.md +0 -70
- wpipe-2.2.0/examples/01_basic_pipeline/14_pipeline_chaining/example.py +0 -53
- wpipe-2.2.0/examples/01_basic_pipeline/15_pipeline_clone/README.md +0 -70
- wpipe-2.2.0/examples/01_basic_pipeline/15_pipeline_clone/example.py +0 -53
- wpipe-2.2.0/examples/01_basic_pipeline/16_LogGestor/example.py +0 -19
- wpipe-2.2.0/examples/01_basic_pipeline/README.md +0 -166
- wpipe-2.2.0/examples/15_export/01_json/export_json.py +0 -77
- wpipe-2.2.0/examples/15_export/README.md +0 -110
- wpipe-2.2.0/wpipe/README.md +0 -241
- wpipe-2.2.0/wpipe/checkpoint/README.md +0 -67
- wpipe-2.2.0/wpipe/composition/README.md +0 -163
- wpipe-2.2.0/wpipe/dashboard/static/dashboard.js +0 -1384
- wpipe-2.2.0/wpipe/dashboard/static/styles.css +0 -1969
- wpipe-2.2.0/wpipe/dashboard/templates/base.html +0 -268
- wpipe-2.2.0/wpipe/dashboard/templates/tabs/alerts.html +0 -20
- wpipe-2.2.0/wpipe/dashboard/templates/tabs/analytics.html +0 -36
- wpipe-2.2.0/wpipe/dashboard/templates/tabs/data.html +0 -42
- wpipe-2.2.0/wpipe/dashboard/templates/tabs/events.html +0 -15
- wpipe-2.2.0/wpipe/dashboard/templates/tabs/graph.html +0 -110
- wpipe-2.2.0/wpipe/dashboard/templates/tabs/pipelines.html +0 -29
- wpipe-2.2.0/wpipe/dashboard/templates/tabs/states.html +0 -29
- wpipe-2.2.0/wpipe/dashboard/templates/tabs/timeline.html +0 -22
- wpipe-2.2.0/wpipe/decorators/README.md +0 -245
- wpipe-2.2.0/wpipe/export/README.md +0 -102
- wpipe-2.2.0/wpipe/parallel/README.md +0 -106
- wpipe-2.2.0/wpipe/resource_monitor/README.md +0 -104
- wpipe-2.2.0/wpipe/timeout/README.md +0 -81
- wpipe-2.2.0/wpipe/type_hinting/README.md +0 -94
- {wpipe-2.2.0 → wpipe-2.3.1}/LICENSE +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_api_pipeline.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_async.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_background.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_basic_pipeline.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_checkpoint.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_core.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_dashboard_and_monitor.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_export.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_misc.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_nested_pipelines.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_pipe.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_pipe_async.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_pipeline_config.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_sqlite.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_tracking.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_util.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/test/test_yaml_config.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/api_client/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/api_client/api_client.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/checkpoint/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/checkpoint/checkpoint.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/composition/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/composition/pipeline_step.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/dashboard/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/dashboard/__main__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/decorators/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/decorators/step.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/exception/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/exception/api_error.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/export/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/export/exporter.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/log/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/log/log.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/parallel/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/parallel/executor.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/components/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/components/constants.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/components/logic_blocks.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/components/logic_blocks_async.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/components/progress.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/components/reporting.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/pipe.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/pipe_async.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/pipe/pipe_async_minimal.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/ram/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/ram/ram.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/resource_monitor/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/sqlite/Sqlite.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/sqlite/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/sqlite/tables_dto/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/sqlite/tables_dto/log_gestor_model.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/sqlite/tables_dto/records.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/timeout/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/timeout/timeout.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/tracking/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/tracking/alerts.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/tracking/analysis.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/tracking/queries.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/type_hinting/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/type_hinting/validators.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/util/__init__.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/util/transform.py +0 -0
- {wpipe-2.2.0 → wpipe-2.3.1}/wpipe/util/utils.py +0 -0
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wpipe
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.1
|
|
4
4
|
Summary: Pipeline library with API integration for task orchestration and execution tracking
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Project-URL: Repository, https://github.com/wisrovi/wpipe
|
|
8
|
-
Project-URL: Issues, https://github.com/wisrovi/wpipe/issues
|
|
9
|
-
Project-URL: Changelog, https://github.com/wisrovi/wpipe/blob/main/CHANGELOG.md
|
|
5
|
+
Home-page: https://github.com/wisrovi/wpipe
|
|
6
|
+
Author: William Steve Rodriguez Villamizar
|
|
10
7
|
Author-email: William Steve Rodriguez Villamizar <wisrovi.rodriguez@gmail.com>
|
|
11
8
|
License: MIT License
|
|
12
9
|
|
|
@@ -42,46 +39,56 @@ License: MIT License
|
|
|
42
39
|
🌐 Website: https://wisrovi.github.io/wpipe/
|
|
43
40
|
|
|
44
41
|
¡Gracias por usar WPipe!
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
|
|
43
|
+
Project-URL: Homepage, https://github.com/wisrovi/wpipe
|
|
44
|
+
Project-URL: Documentation, https://wpipe.readthedocs.io/en/latest/
|
|
45
|
+
Project-URL: Repository, https://github.com/wisrovi/wpipe
|
|
46
|
+
Project-URL: Issues, https://github.com/wisrovi/wpipe/issues
|
|
47
|
+
Project-URL: Changelog, https://github.com/wisrovi/wpipe/blob/main/CHANGELOG.md
|
|
48
|
+
Keywords: pipeline,workflow,tasks,orchestration,api,worker
|
|
51
49
|
Classifier: Programming Language :: Python :: 3
|
|
52
50
|
Classifier: Programming Language :: Python :: 3.9
|
|
53
51
|
Classifier: Programming Language :: Python :: 3.10
|
|
54
52
|
Classifier: Programming Language :: Python :: 3.11
|
|
55
53
|
Classifier: Programming Language :: Python :: 3.12
|
|
56
54
|
Classifier: Programming Language :: Python :: 3.13
|
|
55
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
56
|
+
Classifier: Operating System :: OS Independent
|
|
57
57
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
Classifier: Intended Audience :: Developers
|
|
59
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
60
|
+
Requires-Python: >=3.6
|
|
61
|
+
Description-Content-Type: text/markdown
|
|
62
|
+
License-File: LICENSE
|
|
63
|
+
Requires-Dist: requests>=2.31.0
|
|
60
64
|
Requires-Dist: loguru>=0.7.0
|
|
61
65
|
Requires-Dist: pandas>=2.0.0
|
|
62
|
-
Requires-Dist: pydantic>=2.0.0
|
|
63
66
|
Requires-Dist: pyyaml>=6.0.1
|
|
64
|
-
Requires-Dist: requests>=2.31.0
|
|
65
|
-
Requires-Dist: rich>=13.7.0
|
|
66
67
|
Requires-Dist: tqdm>=4.66.0
|
|
68
|
+
Requires-Dist: rich>=13.7.0
|
|
69
|
+
Requires-Dist: pydantic>=2.0.0
|
|
70
|
+
Requires-Dist: fastapi>=0.100.0
|
|
67
71
|
Requires-Dist: uvicorn>=0.23.0
|
|
68
72
|
Requires-Dist: wsqlite>=0.1.0
|
|
69
73
|
Provides-Extra: dev
|
|
70
|
-
Requires-Dist:
|
|
71
|
-
Requires-Dist:
|
|
72
|
-
Requires-Dist:
|
|
73
|
-
Requires-Dist:
|
|
74
|
-
Requires-Dist:
|
|
74
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
75
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
76
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
77
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
78
|
+
Requires-Dist: mypy>=1.7.0; extra == "dev"
|
|
75
79
|
Provides-Extra: docs
|
|
76
|
-
Requires-Dist:
|
|
77
|
-
Requires-Dist: sphinx-
|
|
78
|
-
Requires-Dist: sphinx-
|
|
79
|
-
Requires-Dist:
|
|
80
|
-
Requires-Dist: sphinx-sitemap>=2.5.0; extra ==
|
|
81
|
-
Requires-Dist: sphinx>=
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
Requires-Dist: sphinx>=7.2.0; extra == "docs"
|
|
81
|
+
Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "docs"
|
|
82
|
+
Requires-Dist: sphinx-copybutton>=0.5.0; extra == "docs"
|
|
83
|
+
Requires-Dist: myst-parser>=2.0.0; extra == "docs"
|
|
84
|
+
Requires-Dist: sphinx-sitemap>=2.5.0; extra == "docs"
|
|
85
|
+
Requires-Dist: sphinx-design>=0.5.0; extra == "docs"
|
|
86
|
+
Dynamic: author
|
|
87
|
+
Dynamic: home-page
|
|
88
|
+
Dynamic: license-file
|
|
89
|
+
Dynamic: requires-python
|
|
90
|
+
|
|
91
|
+
# 🚀 WPipe v2.3.0
|
|
85
92
|
|
|
86
93
|
**El motor de orquestación de pipelines más rápido, resiliente y puro para Python.**
|
|
87
94
|
|
wpipe-2.3.1/setup.cfg
ADDED
wpipe-2.3.1/setup.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Setup configuration for the wpipe package.
|
|
3
|
+
|
|
4
|
+
This module handles the packaging and distribution of the wpipe library,
|
|
5
|
+
a tool for creating pipelines connected to an API.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import List
|
|
10
|
+
from setuptools import setup, find_packages
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_long_description() -> str:
|
|
14
|
+
"""
|
|
15
|
+
Retrieve the long description from the README.md file.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
str: The content of the README.md file.
|
|
19
|
+
"""
|
|
20
|
+
this_directory: Path = Path(__file__).parent
|
|
21
|
+
readme_path: Path = this_directory / "README.md"
|
|
22
|
+
if readme_path.exists():
|
|
23
|
+
return readme_path.read_text(encoding="utf-8")
|
|
24
|
+
return "Libreria para crear pipelines conectados a una API"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def run_setup() -> None:
|
|
28
|
+
"""
|
|
29
|
+
Execute the setup process for the package.
|
|
30
|
+
"""
|
|
31
|
+
install_requires: List[str] = [
|
|
32
|
+
"requests",
|
|
33
|
+
"loguru",
|
|
34
|
+
"pandas",
|
|
35
|
+
"pyyaml",
|
|
36
|
+
"rich",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
setup(
|
|
40
|
+
name="wpipe",
|
|
41
|
+
version="2.3.1",
|
|
42
|
+
description="Library for creating pipelines connected to an API",
|
|
43
|
+
author="William Steve Rodriguez Villamizar",
|
|
44
|
+
author_email="wisrovi.rodriguez@gmail.com",
|
|
45
|
+
packages=find_packages(),
|
|
46
|
+
install_requires=install_requires,
|
|
47
|
+
classifiers=[
|
|
48
|
+
"Programming Language :: Python :: 3",
|
|
49
|
+
"License :: OSI Approved :: MIT License",
|
|
50
|
+
"Operating System :: OS Independent",
|
|
51
|
+
"Topic :: Software Development :: Build Tools",
|
|
52
|
+
"Intended Audience :: Developers",
|
|
53
|
+
],
|
|
54
|
+
python_requires=">=3.6",
|
|
55
|
+
long_description_content_type="text/markdown",
|
|
56
|
+
long_description=get_long_description(),
|
|
57
|
+
license="MIT",
|
|
58
|
+
url="https://github.com/wisrovi/wpipe",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
run_setup()
|
|
@@ -12,16 +12,14 @@ from typing import Any, Dict
|
|
|
12
12
|
|
|
13
13
|
from wsqlite import WSQLite as Wsqlite_original
|
|
14
14
|
|
|
15
|
+
import wsqlite.core.connection as wconn
|
|
16
|
+
|
|
15
17
|
# Connection pooling for performance optimization
|
|
16
18
|
_db_connections: Dict[str, sqlite3.Connection] = {}
|
|
17
19
|
_db_lock = threading.RLock()
|
|
18
20
|
|
|
19
|
-
def
|
|
21
|
+
def patched_get_shared_connection(db_path: str) -> sqlite3.Connection:
|
|
20
22
|
"""Obtain a shared database connection to improve performance."""
|
|
21
|
-
db_path = getattr(self, 'db_path', None) or self.__dict__.get('db_path')
|
|
22
|
-
if db_path is None:
|
|
23
|
-
raise AttributeError(f"WSQLite object has no attribute 'db_path'.")
|
|
24
|
-
|
|
25
23
|
with _db_lock:
|
|
26
24
|
if db_path in _db_connections:
|
|
27
25
|
try:
|
|
@@ -38,41 +36,79 @@ def patched_get_connection(self) -> sqlite3.Connection:
|
|
|
38
36
|
_db_connections[db_path] = conn
|
|
39
37
|
return _db_connections[db_path]
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
# Redirect wsqlite's internal connection getter to our shared pool
|
|
40
|
+
wconn._get_connection = patched_get_shared_connection
|
|
41
|
+
|
|
42
|
+
# Also patch ConnectionPool to use our shared connection
|
|
43
|
+
from wsqlite.core.pool import ConnectionPool
|
|
44
|
+
ConnectionPool._create_connection = lambda self: patched_get_shared_connection(self.db_path)
|
|
45
|
+
|
|
46
|
+
def _patched_return(self, conn):
|
|
47
|
+
"""Patched return_connection that releases semaphore but avoids rollback."""
|
|
48
|
+
try:
|
|
49
|
+
if self._is_healthy(conn):
|
|
50
|
+
try:
|
|
51
|
+
self._pool.put_nowait(conn)
|
|
52
|
+
except:
|
|
53
|
+
pass
|
|
54
|
+
finally:
|
|
55
|
+
self._semaphore.release()
|
|
56
|
+
|
|
57
|
+
ConnectionPool.return_connection = _patched_return
|
|
42
58
|
|
|
43
|
-
def patched_insert(self, data: Any) ->
|
|
44
|
-
"""Insert a new record and return the generated ID."""
|
|
45
|
-
|
|
46
|
-
data_dict = data.model_dump() if hasattr(data, "model_dump") else data
|
|
59
|
+
def patched_insert(self, data: Any) -> Any:
|
|
60
|
+
"""Insert a new record and return the generated ID without committing immediately."""
|
|
61
|
+
self._call_hook(data, "pre_save")
|
|
47
62
|
|
|
63
|
+
data_dict = self._dump(data)
|
|
64
|
+
# Filter out None values to allow SQLite autoincrement
|
|
48
65
|
columns = [k for k, v in data_dict.items() if v is not None]
|
|
49
66
|
placeholders = ["?" for _ in columns]
|
|
50
67
|
values = [data_dict[k] for k in columns]
|
|
51
68
|
|
|
52
|
-
query = f"INSERT INTO {table_name} ({', '.join(columns)}) VALUES ({', '.join(placeholders)})"
|
|
69
|
+
query = f"INSERT INTO {self.table_name} ({', '.join(columns)}) VALUES ({', '.join(placeholders)})"
|
|
53
70
|
|
|
54
71
|
with _db_lock:
|
|
55
|
-
conn = self.
|
|
72
|
+
conn = patched_get_shared_connection(self.db_path)
|
|
56
73
|
cursor = conn.cursor()
|
|
57
74
|
try:
|
|
58
75
|
cursor.execute(query, values)
|
|
59
|
-
|
|
60
|
-
|
|
76
|
+
result = cursor.lastrowid
|
|
77
|
+
self._call_hook(data, "post_save")
|
|
78
|
+
return result
|
|
61
79
|
except Exception as e:
|
|
62
|
-
|
|
80
|
+
# Only rollback if we are in a transaction
|
|
81
|
+
try:
|
|
82
|
+
conn.rollback()
|
|
83
|
+
except:
|
|
84
|
+
pass
|
|
63
85
|
raise e
|
|
64
86
|
|
|
65
87
|
Wsqlite_original.insert = patched_insert
|
|
66
88
|
|
|
67
89
|
@atexit.register
|
|
68
90
|
def _close_connections():
|
|
91
|
+
"""Cleanup connections and threads on exit."""
|
|
69
92
|
with _db_lock:
|
|
70
93
|
for path, conn in list(_db_connections.items()):
|
|
71
94
|
try:
|
|
95
|
+
# Force commit before closing if possible
|
|
96
|
+
conn.commit()
|
|
72
97
|
conn.close()
|
|
73
98
|
except:
|
|
74
99
|
pass
|
|
75
100
|
_db_connections.clear()
|
|
101
|
+
|
|
102
|
+
# Final attempt to silence lingering daemon threads in environments like Binder/Jupyter
|
|
103
|
+
import threading
|
|
104
|
+
for thread in threading.enumerate():
|
|
105
|
+
if thread.daemon and thread is not threading.current_thread():
|
|
106
|
+
if "_RefreshThread" in str(thread):
|
|
107
|
+
try:
|
|
108
|
+
# Give it a very short window to finish or just ignore it
|
|
109
|
+
thread.join(timeout=0.01)
|
|
110
|
+
except:
|
|
111
|
+
pass
|
|
76
112
|
|
|
77
113
|
# Lazy loading map
|
|
78
114
|
_LAZY_MAP = {
|
|
@@ -143,8 +143,8 @@ def create_app(
|
|
|
143
143
|
"""Get the YAML configuration for a pipeline execution."""
|
|
144
144
|
tracker = PipelineTracker(db_path=db_path, config_dir=config_dir)
|
|
145
145
|
pipeline = tracker.get_pipeline(pipeline_id)
|
|
146
|
-
if pipeline and pipeline.get("
|
|
147
|
-
yaml_path = Path(pipeline["
|
|
146
|
+
if pipeline and pipeline.get("yaml_path"):
|
|
147
|
+
yaml_path = Path(pipeline["yaml_path"])
|
|
148
148
|
if not yaml_path.exists() and config_dir:
|
|
149
149
|
yaml_path = Path(config_dir) / f"{pipeline_id}.yaml"
|
|
150
150
|
if not yaml_path.exists() and config_dir:
|
|
@@ -190,13 +190,13 @@ def create_app(
|
|
|
190
190
|
return tracker.get_top_slow_steps(limit=limit)
|
|
191
191
|
|
|
192
192
|
@app.get("/api/analysis/states")
|
|
193
|
-
async def get_states_analysis() ->
|
|
193
|
+
async def get_states_analysis() -> Dict[str, Any]:
|
|
194
194
|
"""Get analysis of pipeline states."""
|
|
195
195
|
tracker = PipelineTracker(db_path=db_path, config_dir=config_dir)
|
|
196
196
|
return tracker.get_states_analysis()
|
|
197
197
|
|
|
198
198
|
@app.get("/api/analysis/pipelines")
|
|
199
|
-
async def get_pipelines_analysis() ->
|
|
199
|
+
async def get_pipelines_analysis() -> Dict[str, Any]:
|
|
200
200
|
"""Get analysis of pipeline performance."""
|
|
201
201
|
tracker = PipelineTracker(db_path=db_path, config_dir=config_dir)
|
|
202
202
|
return tracker.get_pipelines_analysis()
|
|
@@ -77,6 +77,11 @@ class SystemMetricsCollector:
|
|
|
77
77
|
def stop(self) -> None:
|
|
78
78
|
"""Stop the background collection thread."""
|
|
79
79
|
self._stop_event.set()
|
|
80
|
+
if self._thread and self._thread.is_alive():
|
|
81
|
+
try:
|
|
82
|
+
self._thread.join(timeout=1.0)
|
|
83
|
+
except:
|
|
84
|
+
pass
|
|
80
85
|
|
|
81
86
|
def _collect_loop(self) -> None:
|
|
82
87
|
"""Continuous collection loop executed in the background thread."""
|
|
@@ -133,6 +133,11 @@ class ResourceMonitor:
|
|
|
133
133
|
return
|
|
134
134
|
|
|
135
135
|
self._monitoring = False
|
|
136
|
+
if self._monitor_thread and self._monitor_thread.is_alive():
|
|
137
|
+
try:
|
|
138
|
+
self._monitor_thread.join(timeout=1.0)
|
|
139
|
+
except:
|
|
140
|
+
pass
|
|
136
141
|
|
|
137
142
|
self.end_time = time.time()
|
|
138
143
|
try:
|
|
@@ -70,7 +70,7 @@ class StepModel(BaseModel):
|
|
|
70
70
|
error_traceback (Optional[str]): Full traceback if the step failed.
|
|
71
71
|
"""
|
|
72
72
|
|
|
73
|
-
id: Optional[int] = Field(None, description="
|
|
73
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
74
74
|
pipeline_id: str
|
|
75
75
|
step_order: int
|
|
76
76
|
step_name: str
|
|
@@ -103,7 +103,7 @@ class StepHistoryModel(BaseModel):
|
|
|
103
103
|
recorded_at (Optional[str]): ISO timestamp of the record.
|
|
104
104
|
"""
|
|
105
105
|
|
|
106
|
-
id: Optional[int] = Field(None, description="
|
|
106
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
107
107
|
pipeline_id: str
|
|
108
108
|
step_name: str
|
|
109
109
|
duration_ms: float
|
|
@@ -135,7 +135,7 @@ class PerformanceStatsModel(BaseModel):
|
|
|
135
135
|
created_at (Optional[str]): ISO timestamp of the record creation.
|
|
136
136
|
"""
|
|
137
137
|
|
|
138
|
-
id: Optional[int] = Field(None, description="
|
|
138
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
139
139
|
entity_type: str
|
|
140
140
|
entity_name: str
|
|
141
141
|
period_start: str
|
|
@@ -169,7 +169,7 @@ class AlertConfigModel(BaseModel):
|
|
|
169
169
|
enabled (int): Whether the alert is enabled (1) or disabled (0).
|
|
170
170
|
"""
|
|
171
171
|
|
|
172
|
-
id: Optional[int] = Field(None, description="
|
|
172
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
173
173
|
name: str
|
|
174
174
|
metric: str
|
|
175
175
|
condition: str
|
|
@@ -196,7 +196,7 @@ class AlertFiredModel(BaseModel):
|
|
|
196
196
|
fired_at (Optional[str]): ISO timestamp of when the alert fired.
|
|
197
197
|
"""
|
|
198
198
|
|
|
199
|
-
id: Optional[int] = Field(None, description="
|
|
199
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
200
200
|
alert_config_id: int
|
|
201
201
|
pipeline_id: str
|
|
202
202
|
step_id: Optional[int] = None
|
|
@@ -224,7 +224,7 @@ class EventModel(BaseModel):
|
|
|
224
224
|
created_at (Optional[str]): ISO timestamp of event creation.
|
|
225
225
|
"""
|
|
226
226
|
|
|
227
|
-
id: Optional[int] = Field(None, description="
|
|
227
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
228
228
|
pipeline_id: str
|
|
229
229
|
step_id: Optional[int] = None
|
|
230
230
|
event_type: str
|
|
@@ -250,7 +250,7 @@ class PipelineRelationModel(BaseModel):
|
|
|
250
250
|
created_at (Optional[str]): ISO timestamp of relation creation.
|
|
251
251
|
"""
|
|
252
252
|
|
|
253
|
-
id: Optional[int] = Field(None, description="
|
|
253
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
254
254
|
parent_pipeline_id: str
|
|
255
255
|
child_pipeline_id: str
|
|
256
256
|
relation_type: str = "triggered"
|
|
@@ -276,7 +276,7 @@ class SystemMetricsModel(BaseModel):
|
|
|
276
276
|
recorded_at (Optional[str]): ISO timestamp of the measurement.
|
|
277
277
|
"""
|
|
278
278
|
|
|
279
|
-
id: Optional[int] = Field(None, description="
|
|
279
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
280
280
|
pipeline_id: str
|
|
281
281
|
cpu_percent: Optional[float] = None
|
|
282
282
|
memory_percent: Optional[float] = None
|
|
@@ -304,7 +304,7 @@ class ResourceMetricsModel(BaseModel):
|
|
|
304
304
|
created_at (Optional[str]): ISO timestamp of record creation.
|
|
305
305
|
"""
|
|
306
306
|
|
|
307
|
-
id: Optional[int] = Field(None, description="
|
|
307
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
308
308
|
task_name: str
|
|
309
309
|
start_ram_mb: Optional[float] = None
|
|
310
310
|
peak_ram_mb: Optional[float] = None
|
|
@@ -330,7 +330,7 @@ class CheckpointModel(BaseModel):
|
|
|
330
330
|
created_at (Optional[str]): ISO timestamp of checkpoint creation.
|
|
331
331
|
"""
|
|
332
332
|
|
|
333
|
-
id: Optional[int] = Field(None, description="
|
|
333
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
334
334
|
pipeline_id: str
|
|
335
335
|
step_order: int
|
|
336
336
|
step_name: str
|
|
@@ -356,7 +356,7 @@ class ComparisonModel(BaseModel):
|
|
|
356
356
|
created_at (Optional[str]): ISO timestamp of comparison creation.
|
|
357
357
|
"""
|
|
358
358
|
|
|
359
|
-
id: Optional[int] = Field(None, description="
|
|
359
|
+
id: Optional[int] = Field(None, description="primary key autoincrement")
|
|
360
360
|
comparison_uuid: str
|
|
361
361
|
pipeline_a_id: str
|
|
362
362
|
pipeline_b_id: str
|
|
@@ -334,7 +334,11 @@ class PipelineTracker:
|
|
|
334
334
|
if not pipeline_records:
|
|
335
335
|
return []
|
|
336
336
|
model = pipeline_records[0]
|
|
337
|
-
|
|
337
|
+
started_at = model.started_at
|
|
338
|
+
if started_at is None:
|
|
339
|
+
started = datetime.now()
|
|
340
|
+
else:
|
|
341
|
+
started = datetime.fromisoformat(str(started_at))
|
|
338
342
|
duration_ms = (datetime.now() - started).total_seconds() * 1000
|
|
339
343
|
model.status = "error" if error_message else "completed"
|
|
340
344
|
model.completed_at = datetime.now().isoformat()
|