wpipe 0.0.1__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.
- wpipe/__init__.py +5 -0
- wpipe/api_client/__init__.py +1 -0
- wpipe/api_client/api_client.py +87 -0
- wpipe/log/__init__.py +1 -0
- wpipe/log/log.py +31 -0
- wpipe/pipe/__init__.py +1 -0
- wpipe/pipe/pipe.py +224 -0
- wpipe/ram/__init__.py +1 -0
- wpipe/ram/ram.py +52 -0
- wpipe/sqlite/Sqlite.py +207 -0
- wpipe/sqlite/Wsqlite.py +54 -0
- wpipe/sqlite/__init__.py +1 -0
- wpipe/util/__init__.py +1 -0
- wpipe/util/utils.py +26 -0
- wpipe-0.0.1.dist-info/LICENSE +21 -0
- wpipe-0.0.1.dist-info/METADATA +782 -0
- wpipe-0.0.1.dist-info/RECORD +19 -0
- wpipe-0.0.1.dist-info/WHEEL +5 -0
- wpipe-0.0.1.dist-info/top_level.txt +1 -0
wpipe/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .api_client import APIClient
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# pip install requests
|
|
2
|
+
import requests
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class APIClient:
|
|
7
|
+
def __init__(self, base_url: str = None, token: str = None):
|
|
8
|
+
"""
|
|
9
|
+
Inicializa el cliente API con la URL base y el token de autorización.
|
|
10
|
+
"""
|
|
11
|
+
self.base_url = base_url
|
|
12
|
+
self.headers = {
|
|
13
|
+
"Authorization": f"Bearer {token}",
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def send_post(self, endpoint: str, data: dict):
|
|
18
|
+
"""
|
|
19
|
+
Envía una solicitud POST a un endpoint específico.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
if not self.base_url:
|
|
23
|
+
raise Exception("No 'base_url' defined.")
|
|
24
|
+
|
|
25
|
+
url = f"{self.base_url}{endpoint}"
|
|
26
|
+
try:
|
|
27
|
+
response = requests.post(url, headers=self.headers, data=json.dumps(data))
|
|
28
|
+
response.raise_for_status() # Lanza una excepción si el código de estado indica un error
|
|
29
|
+
return response.json()
|
|
30
|
+
except requests.exceptions.RequestException as e:
|
|
31
|
+
print(f"Error en la solicitud POST a {url}: {e}")
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
def send_get(self, endpoint: str):
|
|
35
|
+
"""
|
|
36
|
+
Envía una solicitud GET a un endpoint específico.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
if not self.base_url:
|
|
40
|
+
raise Exception("No 'base_url' defined.")
|
|
41
|
+
|
|
42
|
+
url = f"{self.base_url}{endpoint}"
|
|
43
|
+
try:
|
|
44
|
+
response = requests.get(url, headers=self.headers)
|
|
45
|
+
response.raise_for_status()
|
|
46
|
+
return response.json()
|
|
47
|
+
except requests.exceptions.RequestException as e:
|
|
48
|
+
print(f"Error en la solicitud GET a {url}: {e}")
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
# Métodos específicos para cada endpoint
|
|
52
|
+
|
|
53
|
+
def register_worker(self, data: dict):
|
|
54
|
+
return self.send_post("/matricula", data)
|
|
55
|
+
|
|
56
|
+
def healthcheck_worker(self, data: dict):
|
|
57
|
+
return self.send_post("/healthchecker", data)
|
|
58
|
+
|
|
59
|
+
def register_process(self, data: dict):
|
|
60
|
+
return self.send_post("/newprocess", data)
|
|
61
|
+
|
|
62
|
+
def end_process(self, data: dict):
|
|
63
|
+
return self.send_post("/endprocess", data)
|
|
64
|
+
|
|
65
|
+
def update_task(self, data: dict):
|
|
66
|
+
return self.send_post("/actualizar_task", data)
|
|
67
|
+
|
|
68
|
+
def get_dashboard_workers(self):
|
|
69
|
+
return self.send_get("/dashboard_workers")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Ejemplo de uso
|
|
73
|
+
if __name__ == "__main__":
|
|
74
|
+
# Configura la URL base y el token de autorización
|
|
75
|
+
client = APIClient(base_url="http://192.168.1.60:8418", token="mysecrettoken")
|
|
76
|
+
|
|
77
|
+
# Ejemplo de cómo registrar un trabajador
|
|
78
|
+
data = {
|
|
79
|
+
# Llena con los datos necesarios para la solicitud
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Llama al método para obtener el dashboard de trabajadores
|
|
83
|
+
workers_info = client.get_dashboard_workers()
|
|
84
|
+
print(workers_info)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# pip install requests
|
wpipe/log/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .log import new_logger
|
wpipe/log/log.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This program has a functions that returns
|
|
3
|
+
a logger object.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
from loguru import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def new_logger(process_name: str, path_file: str = "/logs/file_{time}.log"):
|
|
11
|
+
|
|
12
|
+
# for print in console
|
|
13
|
+
logger.add(
|
|
14
|
+
sys.stderr,
|
|
15
|
+
format="{time} {level} {message}",
|
|
16
|
+
filter=f"{process_name}",
|
|
17
|
+
level="INFO",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# for save in file
|
|
21
|
+
logger.add(
|
|
22
|
+
path_file,
|
|
23
|
+
colorize=True,
|
|
24
|
+
format="<green>{time:YYYY-MM-DD at HH:mm:ss}</green>"
|
|
25
|
+
+ "| <level>{level}</level> | <blue>{message}</blue>",
|
|
26
|
+
rotation="50 MB",
|
|
27
|
+
compression="zip",
|
|
28
|
+
retention="10 days",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
return logger
|
wpipe/pipe/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .pipe import Pipeline
|
wpipe/pipe/pipe.py
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
from wpipe.api_client.api_client import APIClient
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# Definición de la clase
|
|
5
|
+
class Pipeline(APIClient):
|
|
6
|
+
worker_id: str = None
|
|
7
|
+
process_id: str = None
|
|
8
|
+
send_to_api: bool = False
|
|
9
|
+
api_config: dict = None
|
|
10
|
+
tasks_list: list = [] # Inicializa un atributo lista vacío
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self, worker_id: str = None, api_config: dict = None, verbose: bool = False
|
|
14
|
+
):
|
|
15
|
+
if api_config:
|
|
16
|
+
# invoca el constructor de APIClient
|
|
17
|
+
super().__init__(
|
|
18
|
+
base_url=api_config.get("base_url"), token=api_config.get("token")
|
|
19
|
+
)
|
|
20
|
+
self.api_config = api_config
|
|
21
|
+
|
|
22
|
+
if worker_id:
|
|
23
|
+
self.set_worker_id(worker_id)
|
|
24
|
+
|
|
25
|
+
self.verbose = verbose
|
|
26
|
+
|
|
27
|
+
def set_worker_id(self, id: str):
|
|
28
|
+
if id and isinstance(id, str):
|
|
29
|
+
if len(id) > 5:
|
|
30
|
+
if self.api_config and not self.worker_id:
|
|
31
|
+
self.send_to_api = True
|
|
32
|
+
print("[INFO] worker_id defined correct")
|
|
33
|
+
|
|
34
|
+
self.worker_id = id
|
|
35
|
+
else:
|
|
36
|
+
self.worker_id = None
|
|
37
|
+
else:
|
|
38
|
+
raise Exception(f"[ERROR] {id} is not correct, have to be a string")
|
|
39
|
+
|
|
40
|
+
def worker_register(self, name: str, version: str):
|
|
41
|
+
data = {
|
|
42
|
+
"name": name,
|
|
43
|
+
"version": version,
|
|
44
|
+
"tasks": [
|
|
45
|
+
{
|
|
46
|
+
"name": name,
|
|
47
|
+
"version": version,
|
|
48
|
+
}
|
|
49
|
+
for func, name, version, _id in self.tasks_list
|
|
50
|
+
],
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if self.api_config:
|
|
54
|
+
worker_id = self.register_worker(data)
|
|
55
|
+
|
|
56
|
+
if worker_id and "id" in worker_id:
|
|
57
|
+
self.set_worker_id(worker_id.get("id"))
|
|
58
|
+
|
|
59
|
+
return worker_id
|
|
60
|
+
|
|
61
|
+
def _decorator_task_report(func):
|
|
62
|
+
"""Decorador para reportar la ejecución de cada tarea."""
|
|
63
|
+
|
|
64
|
+
def wrapper(self, *args, **kwargs):
|
|
65
|
+
|
|
66
|
+
if self.send_to_api:
|
|
67
|
+
task_updated = self.update_task(
|
|
68
|
+
{"task_id": self.task_id, "status": "start"}
|
|
69
|
+
)
|
|
70
|
+
if self.verbose:
|
|
71
|
+
print(
|
|
72
|
+
"\t" * 2,
|
|
73
|
+
f"[INFO] [START] task '{self.task_name}': {task_updated}",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
resultado = {}
|
|
77
|
+
try:
|
|
78
|
+
resultado = func(self, *args, **kwargs)
|
|
79
|
+
|
|
80
|
+
if self.send_to_api:
|
|
81
|
+
task_updated = self.update_task(
|
|
82
|
+
{"task_id": self.task_id, "status": "success"}
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if not task_updated:
|
|
86
|
+
raise Exception("Problem task")
|
|
87
|
+
|
|
88
|
+
if self.verbose:
|
|
89
|
+
print(
|
|
90
|
+
"\t" * 2,
|
|
91
|
+
f"[INFO] [END] task '{self.task_name}': {task_updated}",
|
|
92
|
+
)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
details = str(e)
|
|
95
|
+
resultado["error"] = details
|
|
96
|
+
|
|
97
|
+
if self.send_to_api:
|
|
98
|
+
task_updated = self.update_task(
|
|
99
|
+
{"task_id": self.task_id, "status": "error"}
|
|
100
|
+
)
|
|
101
|
+
print(
|
|
102
|
+
"\t" * 2,
|
|
103
|
+
f"[ERROR] [END] task '{self.task_name}': {task_updated}",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return resultado
|
|
107
|
+
|
|
108
|
+
return wrapper
|
|
109
|
+
|
|
110
|
+
def _decorator_pipeline_report(func):
|
|
111
|
+
"""Decorador para reportar la ejecución del pipeline completo."""
|
|
112
|
+
|
|
113
|
+
def wrapper(self, *args, **kwargs):
|
|
114
|
+
|
|
115
|
+
worker_id = self.worker_id
|
|
116
|
+
|
|
117
|
+
if self.verbose:
|
|
118
|
+
print("\n", "\t", "*" * 50)
|
|
119
|
+
print("\n", f"\t [WORKER] {self.worker_id}")
|
|
120
|
+
print("\n\t", "*" * 50)
|
|
121
|
+
|
|
122
|
+
if self.send_to_api:
|
|
123
|
+
process_registed = self.register_process({"id": worker_id})
|
|
124
|
+
|
|
125
|
+
if process_registed:
|
|
126
|
+
self.tasks_list = [
|
|
127
|
+
(rta[0], rta[1], rta[2], son["id"])
|
|
128
|
+
for son, rta in zip(process_registed["sons"], self.tasks_list)
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
self.process_id = process_registed["father"]
|
|
132
|
+
|
|
133
|
+
if self.verbose:
|
|
134
|
+
print(
|
|
135
|
+
"\t",
|
|
136
|
+
f"[INFO] [START] pipeline: new process ({self.process_id})",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
resultado = {}
|
|
140
|
+
try:
|
|
141
|
+
resultado = func(self, *args, **kwargs)
|
|
142
|
+
|
|
143
|
+
if self.send_to_api:
|
|
144
|
+
status = self.end_process({"id": self.process_id, "details": ""})
|
|
145
|
+
if not status:
|
|
146
|
+
raise Exception("API problem")
|
|
147
|
+
|
|
148
|
+
if self.verbose:
|
|
149
|
+
print("\t", f"[INFO] [END] pipeline: {status}")
|
|
150
|
+
|
|
151
|
+
except Exception as e:
|
|
152
|
+
details = str(e)
|
|
153
|
+
resultado["error"] = details
|
|
154
|
+
|
|
155
|
+
if self.send_to_api:
|
|
156
|
+
status = self.end_process(
|
|
157
|
+
{"id": self.process_id, "details": details}
|
|
158
|
+
)
|
|
159
|
+
print("\t", f"[ERROR] [END] pipeline: {status}")
|
|
160
|
+
|
|
161
|
+
return resultado
|
|
162
|
+
|
|
163
|
+
return wrapper
|
|
164
|
+
|
|
165
|
+
def set_steps(self, lista):
|
|
166
|
+
"""
|
|
167
|
+
Define los pasos del pipeline, verificando que cada elemento sea una tupla
|
|
168
|
+
compuesta por una función y un nombre en string.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
new_list = []
|
|
172
|
+
|
|
173
|
+
for item in lista:
|
|
174
|
+
if not (
|
|
175
|
+
isinstance(item, tuple)
|
|
176
|
+
and len(item) == 3
|
|
177
|
+
and callable(item[0])
|
|
178
|
+
and isinstance(item[1], str)
|
|
179
|
+
):
|
|
180
|
+
raise ValueError(
|
|
181
|
+
"Cada elemento de la lista debe ser una tupla (función, nombre)."
|
|
182
|
+
)
|
|
183
|
+
else:
|
|
184
|
+
new_list.append((item[0], item[1], item[2], ""))
|
|
185
|
+
|
|
186
|
+
self.tasks_list = new_list
|
|
187
|
+
|
|
188
|
+
@_decorator_task_report
|
|
189
|
+
def _task_invoke(self, func, name, *args, **kwargs):
|
|
190
|
+
return func(*args, **kwargs)
|
|
191
|
+
|
|
192
|
+
@_decorator_pipeline_report
|
|
193
|
+
def run(self, *args, **kwargs):
|
|
194
|
+
"""
|
|
195
|
+
Ejecuta el pipeline completo, pasando los resultados de una función como
|
|
196
|
+
entrada a la siguiente.
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
resultado = None
|
|
200
|
+
data = {}
|
|
201
|
+
# TODO: poner un tqdm para ver como van avanzando el progreso de las tareas
|
|
202
|
+
for i, (func, name, version, _id) in enumerate(self.tasks_list):
|
|
203
|
+
self.task_name = name
|
|
204
|
+
self.task_id = _id
|
|
205
|
+
|
|
206
|
+
data.update(args[0])
|
|
207
|
+
|
|
208
|
+
if i == 0:
|
|
209
|
+
resultado = self._task_invoke(func, name, *(data,), **kwargs)
|
|
210
|
+
else:
|
|
211
|
+
resultado = self._task_invoke(func, name, *(data,), **kwargs)
|
|
212
|
+
|
|
213
|
+
data.update(resultado)
|
|
214
|
+
|
|
215
|
+
if self.verbose:
|
|
216
|
+
print()
|
|
217
|
+
|
|
218
|
+
if "error" in data:
|
|
219
|
+
break
|
|
220
|
+
|
|
221
|
+
if "error" in data:
|
|
222
|
+
raise Exception(f"[{self.task_name}] Fail the pipeline:{data['error']}")
|
|
223
|
+
|
|
224
|
+
return data
|
wpipe/ram/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .ram import memory
|
wpipe/ram/ram.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import resource
|
|
2
|
+
import platform
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def memory_limit(percentage: float):
|
|
7
|
+
"""
|
|
8
|
+
只在linux操作系统起作用
|
|
9
|
+
"""
|
|
10
|
+
if platform.system() != "Linux":
|
|
11
|
+
print("Only works on linux!")
|
|
12
|
+
return
|
|
13
|
+
soft, hard = resource.getrlimit(resource.RLIMIT_AS)
|
|
14
|
+
resource.setrlimit(resource.RLIMIT_AS, (get_memory() * 1024 * percentage, hard))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_memory():
|
|
18
|
+
with open("/proc/meminfo", "r") as mem:
|
|
19
|
+
free_memory = 0
|
|
20
|
+
for i in mem:
|
|
21
|
+
sline = i.split()
|
|
22
|
+
if str(sline[0]) in ("MemFree:", "Buffers:", "Cached:"):
|
|
23
|
+
free_memory += int(sline[1])
|
|
24
|
+
return free_memory
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
Este es el decorador
|
|
29
|
+
|
|
30
|
+
example:
|
|
31
|
+
|
|
32
|
+
@memory(percentage=0.8)
|
|
33
|
+
def main():
|
|
34
|
+
print('My memory is limited to 80%.')
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def memory(percentage=0.8):
|
|
39
|
+
def decorator(function):
|
|
40
|
+
def wrapper(*args, **kwargs):
|
|
41
|
+
memory_limit(percentage)
|
|
42
|
+
try:
|
|
43
|
+
return function(*args, **kwargs)
|
|
44
|
+
except MemoryError:
|
|
45
|
+
mem = get_memory() / 1024 / 1024
|
|
46
|
+
print("Remain: %.2f GB" % mem)
|
|
47
|
+
sys.stderr.write("\n\nERROR: Memory Exception\n")
|
|
48
|
+
sys.exit(1)
|
|
49
|
+
|
|
50
|
+
return wrapper
|
|
51
|
+
|
|
52
|
+
return decorator
|
wpipe/sqlite/Sqlite.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import sqlite3
|
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
+
from typing import Literal
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SQLite:
|
|
11
|
+
def __init__(self, db_name: str = "register.db"):
|
|
12
|
+
# nombre absoluto de db_name
|
|
13
|
+
# self.db_name = os.path.basename(db_name)
|
|
14
|
+
self.db_name = db_name
|
|
15
|
+
self._create_table_if_not_exists()
|
|
16
|
+
|
|
17
|
+
self.executor = ThreadPoolExecutor(max_workers=10)
|
|
18
|
+
|
|
19
|
+
def _create_table_if_not_exists(self):
|
|
20
|
+
if not self.db_name:
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
with sqlite3.connect(self.db_name) as conn:
|
|
24
|
+
cursor = conn.cursor()
|
|
25
|
+
cursor.execute(
|
|
26
|
+
"""CREATE TABLE IF NOT EXISTS records
|
|
27
|
+
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
28
|
+
input TEXT,
|
|
29
|
+
output TEXT,
|
|
30
|
+
details TEXT DEFAULT NULL,
|
|
31
|
+
datetime TEXT DEFAULT CURRENT_TIMESTAMP)"""
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def async_write(
|
|
35
|
+
self, input: str = None, output: str = None, details: str = None, id: int = None
|
|
36
|
+
):
|
|
37
|
+
self.executor.submit(self.write, input, output, details, id)
|
|
38
|
+
|
|
39
|
+
def write(
|
|
40
|
+
self,
|
|
41
|
+
input: str = None,
|
|
42
|
+
output: Literal["str", "dict"] = None,
|
|
43
|
+
details: str = None,
|
|
44
|
+
id: int = None,
|
|
45
|
+
):
|
|
46
|
+
if not self.check_table_exists():
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
if isinstance(input, dict):
|
|
50
|
+
input = json.dumps(input)
|
|
51
|
+
|
|
52
|
+
if isinstance(output, dict):
|
|
53
|
+
output["datetime"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
54
|
+
output = json.dumps(output)
|
|
55
|
+
|
|
56
|
+
elif isinstance(output, str):
|
|
57
|
+
output = json.dumps(
|
|
58
|
+
{
|
|
59
|
+
"output": output,
|
|
60
|
+
"datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if isinstance(details, dict):
|
|
65
|
+
details = json.dumps(details)
|
|
66
|
+
|
|
67
|
+
with sqlite3.connect(self.db_name) as conn:
|
|
68
|
+
cursor = conn.cursor()
|
|
69
|
+
|
|
70
|
+
if not id:
|
|
71
|
+
# insert
|
|
72
|
+
cursor.execute(
|
|
73
|
+
"INSERT INTO records (input, output, details) VALUES (?, ?, ?)",
|
|
74
|
+
(input, output, details),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
id = cursor.lastrowid
|
|
78
|
+
else:
|
|
79
|
+
# update
|
|
80
|
+
if not self.read_by_id(id):
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
if not input and not details and output:
|
|
84
|
+
cursor.execute(
|
|
85
|
+
"UPDATE records SET output = ? WHERE id = ?",
|
|
86
|
+
(output, id),
|
|
87
|
+
)
|
|
88
|
+
elif not input and output and details:
|
|
89
|
+
cursor.execute(
|
|
90
|
+
"UPDATE records SET output = ?, details = ? WHERE id = ?",
|
|
91
|
+
(output, details, id),
|
|
92
|
+
)
|
|
93
|
+
elif input and output and details:
|
|
94
|
+
cursor.execute(
|
|
95
|
+
"UPDATE records SET input = ?, output = ?, details = ? WHERE id = ?",
|
|
96
|
+
(input, output, details, id),
|
|
97
|
+
)
|
|
98
|
+
elif input and output and not details:
|
|
99
|
+
cursor.execute(
|
|
100
|
+
"UPDATE records SET input = ?, output = ? WHERE id = ?",
|
|
101
|
+
(input, output, id),
|
|
102
|
+
)
|
|
103
|
+
conn.commit()
|
|
104
|
+
|
|
105
|
+
return id
|
|
106
|
+
|
|
107
|
+
def read_by_id(self, id: int) -> list:
|
|
108
|
+
if not self.check_table_exists():
|
|
109
|
+
return []
|
|
110
|
+
|
|
111
|
+
results = []
|
|
112
|
+
|
|
113
|
+
with sqlite3.connect(self.db_name) as conn:
|
|
114
|
+
cursor = conn.cursor()
|
|
115
|
+
cursor.execute("SELECT * FROM records WHERE id = ?", (id,))
|
|
116
|
+
|
|
117
|
+
results = cursor.fetchall()
|
|
118
|
+
|
|
119
|
+
if cursor.rowcount == 0:
|
|
120
|
+
# print("No records found for the specified id")
|
|
121
|
+
pass
|
|
122
|
+
|
|
123
|
+
return results
|
|
124
|
+
|
|
125
|
+
def _view_records(self) -> pd.DataFrame:
|
|
126
|
+
with sqlite3.connect(self.db_name) as conn:
|
|
127
|
+
return pd.read_sql_query("SELECT * FROM records", conn)
|
|
128
|
+
|
|
129
|
+
def export_to_dataframe(
|
|
130
|
+
self, save_csv: bool = False, csv_name: str = "records.csv"
|
|
131
|
+
) -> pd.DataFrame:
|
|
132
|
+
if not self.check_table_exists():
|
|
133
|
+
return pd.DataFrame()
|
|
134
|
+
|
|
135
|
+
df = self._view_records()
|
|
136
|
+
|
|
137
|
+
if save_csv:
|
|
138
|
+
df.to_csv(csv_name, index=False)
|
|
139
|
+
|
|
140
|
+
return df
|
|
141
|
+
|
|
142
|
+
def get_records_by_date_range(self, start_date: str, end_date: str) -> list:
|
|
143
|
+
if not self.check_table_exists():
|
|
144
|
+
return []
|
|
145
|
+
|
|
146
|
+
with sqlite3.connect(self.db_name) as conn:
|
|
147
|
+
cursor = conn.cursor()
|
|
148
|
+
cursor.execute(
|
|
149
|
+
"SELECT * FROM records WHERE datetime BETWEEN ? AND ?",
|
|
150
|
+
(start_date, end_date),
|
|
151
|
+
)
|
|
152
|
+
return cursor.fetchall()
|
|
153
|
+
|
|
154
|
+
def count_records(self) -> int:
|
|
155
|
+
if not self.check_table_exists():
|
|
156
|
+
return 0
|
|
157
|
+
|
|
158
|
+
with sqlite3.connect(self.db_name) as conn:
|
|
159
|
+
cursor = conn.cursor()
|
|
160
|
+
cursor.execute("SELECT COUNT(*) FROM records")
|
|
161
|
+
return cursor.fetchone()[0]
|
|
162
|
+
|
|
163
|
+
def delete_by_id(self, id_saved: int):
|
|
164
|
+
if not self.check_table_exists():
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
with sqlite3.connect(self.db_name) as conn:
|
|
168
|
+
cursor = conn.cursor()
|
|
169
|
+
cursor.execute("DELETE FROM records WHERE id = ?", (id_saved,))
|
|
170
|
+
conn.commit()
|
|
171
|
+
|
|
172
|
+
def check_table_exists(self) -> bool:
|
|
173
|
+
if not self.db_name:
|
|
174
|
+
return False
|
|
175
|
+
|
|
176
|
+
if len(os.path.dirname(self.db_name)) > 0:
|
|
177
|
+
if not os.path.exists(os.path.dirname(self.db_name)):
|
|
178
|
+
os.makedirs(os.path.dirname(self.db_name))
|
|
179
|
+
|
|
180
|
+
self._create_table_if_not_exists()
|
|
181
|
+
|
|
182
|
+
return True
|
|
183
|
+
|
|
184
|
+
def __enter__(self):
|
|
185
|
+
return self
|
|
186
|
+
|
|
187
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
188
|
+
if self.executor:
|
|
189
|
+
self.executor.shutdown(wait=True)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if __name__ == "__main__":
|
|
193
|
+
import uuid
|
|
194
|
+
|
|
195
|
+
my_uuid = str(uuid.uuid4().hex)
|
|
196
|
+
|
|
197
|
+
with SQLite() as registro:
|
|
198
|
+
registro.write(topic="topic 1", type_data="image", value=my_uuid)
|
|
199
|
+
registro.write(topic="topic 2", type_data="image", value=my_uuid)
|
|
200
|
+
registro.write(topic="topic 3", type_data="image", value=my_uuid)
|
|
201
|
+
registro.write(topic="topic 4", type_data="image", value=my_uuid)
|
|
202
|
+
|
|
203
|
+
print(registro.read_by_id(str(uuid.uuid4().hex)))
|
|
204
|
+
|
|
205
|
+
print(registro.export_to_dataframe().head())
|
|
206
|
+
|
|
207
|
+
print("total", registro.count_records())
|
wpipe/sqlite/Wsqlite.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from wpipe.sqlite.Sqlite import SQLite
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Wsqlite:
|
|
5
|
+
|
|
6
|
+
id: str = None
|
|
7
|
+
|
|
8
|
+
output_db: dict = {}
|
|
9
|
+
details_db: dict = {}
|
|
10
|
+
input_db: dict = {}
|
|
11
|
+
|
|
12
|
+
def __init__(self, db_name: str = "register.db") -> None:
|
|
13
|
+
self.db_name = db_name
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def _input(self):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@_input.setter
|
|
20
|
+
def input(self, input: dict):
|
|
21
|
+
self._create(input=input)
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def _output(self):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@_output.setter
|
|
28
|
+
def output(self, output: dict):
|
|
29
|
+
self.output_db = output
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def _details(self):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
@_details.setter
|
|
36
|
+
def details(self, details: dict):
|
|
37
|
+
self.details_db = details
|
|
38
|
+
|
|
39
|
+
def _create(self, input: dict):
|
|
40
|
+
id = None
|
|
41
|
+
with SQLite(self.db_name) as conection_db:
|
|
42
|
+
id = conection_db.async_write(input=input)
|
|
43
|
+
|
|
44
|
+
self.id = str(id)
|
|
45
|
+
|
|
46
|
+
def _update(self, output: dict, details: dict = {}):
|
|
47
|
+
with SQLite(self.db_name) as conection_db:
|
|
48
|
+
conection_db.async_write(output=output, details=details, id=self.id)
|
|
49
|
+
|
|
50
|
+
def __enter__(self):
|
|
51
|
+
return self
|
|
52
|
+
|
|
53
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
54
|
+
self._update(output=self.output_db, details=self.details_db)
|
wpipe/sqlite/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .Wsqlite import Wsqlite
|
wpipe/util/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .utils import leer_yaml, escribir_yaml
|