adstoolbox 0.1.0__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.
- adsToolBox/__init__.py +12 -0
- adsToolBox/dataFactory.py +22 -0
- adsToolBox/dbMssql.py +119 -0
- adsToolBox/dbPgsql.py +119 -0
- adsToolBox/demo/_demo.py +63 -0
- adsToolBox/demo/dataset_deduplicate.py +15 -0
- adsToolBox/demo/dataset_file.py +50 -0
- adsToolBox/demo/dataset_join.py +25 -0
- adsToolBox/demo/dataset_sort.py +16 -0
- adsToolBox/demo/dataset_transform.py +19 -0
- adsToolBox/demo/demo.py +0 -0
- adsToolBox/demo/demo_logger_timer.py +62 -0
- adsToolBox/demo/demo_pipeline_1.py +88 -0
- adsToolBox/demo/demo_pipeline_2_tableau.py +86 -0
- adsToolBox/demo/demo_pipeline_3_destinations.py +66 -0
- adsToolBox/demo/demo_pipeline_yield.py +61 -0
- adsToolBox/demo/demo_request_insertion.py +55 -0
- adsToolBox/demo/demo_wait_file.py +38 -0
- adsToolBox/demo/example_data.csv +5 -0
- adsToolBox/demo/log.txt +1490 -0
- adsToolBox/demo/log.txt.2024-10-11 +278 -0
- adsToolBox/global_config.py +10 -0
- adsToolBox/logger.py +166 -0
- adsToolBox/pipeline.py +59 -0
- adsToolBox/timer.py +20 -0
- adsToolBox/to_sort/email.py +39 -0
- adsToolBox/to_sort/env.py +19 -0
- adsToolBox/wait_file.py +14 -0
- adstoolbox-0.1.0.dist-info/METADATA +46 -0
- adstoolbox-0.1.0.dist-info/RECORD +31 -0
- adstoolbox-0.1.0.dist-info/WHEEL +4 -0
adsToolBox/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .logger import Logger
|
|
2
|
+
from .timer import timer, get_timer
|
|
3
|
+
from .global_config import set_timer
|
|
4
|
+
from .dbPgsql import dbPgsql
|
|
5
|
+
from .dbMssql import dbMssql
|
|
6
|
+
from .pipeline import pipeline
|
|
7
|
+
from .wait_file import wait_for_file
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"Logger", "timer", "set_timer", "get_timer", "dbPgsql", "dbMssql", "pipeline", "wait_for_file"
|
|
12
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class data_factory(ABC):
|
|
5
|
+
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def connect(self):
|
|
8
|
+
pass
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def insert(self,table,cols=[],rows=[]):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def insertBulk(self,table,cols=[],rows=[]):
|
|
15
|
+
pass
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def sqlQuery(self,query):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def sqlExec(self, query: str, params=None):
|
|
22
|
+
pass
|
adsToolBox/dbMssql.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
import pymssql
|
|
3
|
+
import timeit
|
|
4
|
+
from .timer import timer, get_timer
|
|
5
|
+
from .dataFactory import data_factory
|
|
6
|
+
|
|
7
|
+
class dbMssql(data_factory):
|
|
8
|
+
|
|
9
|
+
def __init__(self, dictionnary: dict, logger, batch_size=10_000):
|
|
10
|
+
self.connection = None
|
|
11
|
+
self.logger = logger
|
|
12
|
+
self.__database = dictionnary['database']
|
|
13
|
+
self.__user = dictionnary['user']
|
|
14
|
+
self.__password = dictionnary['password']
|
|
15
|
+
self.__port = dictionnary['port']
|
|
16
|
+
self.__host = dictionnary['host']
|
|
17
|
+
self.__batch_size = batch_size
|
|
18
|
+
|
|
19
|
+
@timer
|
|
20
|
+
def connect(self):
|
|
21
|
+
if self.logger is not None: self.logger.info("Tentative de connexion avec la base de données.")
|
|
22
|
+
try:
|
|
23
|
+
self.connection = pymssql.connect(
|
|
24
|
+
server=f"{self.__host}:{self.__port}",
|
|
25
|
+
user=self.__user,
|
|
26
|
+
password=self.__password,
|
|
27
|
+
database=self.__database
|
|
28
|
+
)
|
|
29
|
+
if self.logger is not None: self.logger.info(f"Connexion établie avec la base de données.")
|
|
30
|
+
return self.connection
|
|
31
|
+
except Exception as e:
|
|
32
|
+
if self.logger is not None: self.logger.error(f"Échec de la connexion à la base de données: {e}")
|
|
33
|
+
raise
|
|
34
|
+
|
|
35
|
+
def sqlQuery(self, query):
|
|
36
|
+
self.logger.debug(f"Exécution de la requête de lecture : {query}")
|
|
37
|
+
start_time = datetime.now()
|
|
38
|
+
try:
|
|
39
|
+
timer_start = timeit.default_timer()
|
|
40
|
+
with self.connection.cursor() as cursor:
|
|
41
|
+
cursor.execute(query)
|
|
42
|
+
cols = [desc[0] for desc in cursor.description]
|
|
43
|
+
self.logger.info("Requête exécutée avec succès, début de la lecture des résultats.")
|
|
44
|
+
while True:
|
|
45
|
+
rows = cursor.fetchmany(self.__batch_size)
|
|
46
|
+
if not rows:
|
|
47
|
+
break
|
|
48
|
+
yield from rows
|
|
49
|
+
self.logger.info(f"{len(rows)} lignes lues.")
|
|
50
|
+
end_time = datetime.now()
|
|
51
|
+
self.logger.log_to_db(start_time, end_time, status='success', message="Requête de lecture exécutée.")
|
|
52
|
+
if get_timer():
|
|
53
|
+
elapsed_time = timeit.default_timer() - timer_start
|
|
54
|
+
self.logger.info(f"Temps d'exécution de sqlQuery: {elapsed_time:.4f} secondes")
|
|
55
|
+
except Exception as e:
|
|
56
|
+
end_time = datetime.now()
|
|
57
|
+
self.logger.error(f"Échec de la lecture des données: {e}")
|
|
58
|
+
self.logger.log_to_db(start_time, end_time, status="failure", message=str(e))
|
|
59
|
+
raise
|
|
60
|
+
|
|
61
|
+
@timer
|
|
62
|
+
def sqlExec(self, query):
|
|
63
|
+
try:
|
|
64
|
+
with self.connection.cursor() as cursor:
|
|
65
|
+
cursor.execute(query)
|
|
66
|
+
self.logger.info(f"Requête exécutée avec succès.")
|
|
67
|
+
self.connection.commit()
|
|
68
|
+
except Exception as e:
|
|
69
|
+
self.logger.error(f"Échec de l'exécution de la requête: {e}")
|
|
70
|
+
raise
|
|
71
|
+
|
|
72
|
+
@timer
|
|
73
|
+
def sqlScalaire(self, query):
|
|
74
|
+
try:
|
|
75
|
+
with self.connection.cursor() as cursor:
|
|
76
|
+
cursor.execute(query)
|
|
77
|
+
self.logger.info(f"Requête exécutée avec succès.")
|
|
78
|
+
data = cursor.fetchone()
|
|
79
|
+
return data
|
|
80
|
+
except Exception as e:
|
|
81
|
+
self.logger.error(f"Échec de l'exécution de la requête: {e}")
|
|
82
|
+
raise
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@timer
|
|
86
|
+
def insert(self, table, cols=[], rows=[]):
|
|
87
|
+
start_time = datetime.now()
|
|
88
|
+
try:
|
|
89
|
+
with self.connection.cursor() as cursor:
|
|
90
|
+
placeholders = ", ".join(["%s"] * len(cols))
|
|
91
|
+
query = f"INSERT INTO {table} ({', '.join(cols)}) VALUES ({placeholders})"
|
|
92
|
+
cursor.execute(query, rows)
|
|
93
|
+
self.connection.commit()
|
|
94
|
+
self.logger.info(f"{cursor.rowcount} lignes insérées avec succès dans la table {table}.")
|
|
95
|
+
self.logger.log_to_db(start_time, datetime.now(), status='success', message="Insertion réussie.")
|
|
96
|
+
return ["SUCCESS"]
|
|
97
|
+
except Exception as e:
|
|
98
|
+
self.logger.error(f"Échec de l'insertion des données: {e}")
|
|
99
|
+
self.logger.log_to_db(start_time, datetime.now(), status='failure', message=str(e))
|
|
100
|
+
self.connection.rollback()
|
|
101
|
+
return "ERROR", str(e), rows
|
|
102
|
+
|
|
103
|
+
@timer
|
|
104
|
+
def insertBulk(self, table, cols=[], rows=[]):
|
|
105
|
+
start_time = datetime.now()
|
|
106
|
+
try:
|
|
107
|
+
with self.connection.cursor() as cursor:
|
|
108
|
+
placeholders = ", ".join(["%s"] * len(cols))
|
|
109
|
+
query = f"INSERT INTO {table} ({', '.join(cols)}) VALUES ({placeholders})"
|
|
110
|
+
cursor.executemany(query, rows)
|
|
111
|
+
self.connection.commit()
|
|
112
|
+
self.logger.info(f"{cursor.rowcount} lignes insérées avec succès dans la table {table}.")
|
|
113
|
+
self.logger.log_to_db(start_time, datetime.now(), status='success', message="Insertion réussie.")
|
|
114
|
+
return ["SUCCESS"]
|
|
115
|
+
except Exception as e:
|
|
116
|
+
self.logger.error(f"Échec de l'insertion des données: {e}")
|
|
117
|
+
self.logger.log_to_db(start_time, datetime.now(), status='failure', message=str(e))
|
|
118
|
+
self.connection.rollback()
|
|
119
|
+
return "ERROR", str(e), rows
|
adsToolBox/dbPgsql.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
import psycopg2
|
|
3
|
+
import timeit
|
|
4
|
+
from .timer import timer, get_timer
|
|
5
|
+
from .dataFactory import data_factory
|
|
6
|
+
|
|
7
|
+
class dbPgsql(data_factory):
|
|
8
|
+
|
|
9
|
+
def __init__(self, dictionnary: dict, logger, batch_size=10_000):
|
|
10
|
+
self.connection = None
|
|
11
|
+
self.logger = logger
|
|
12
|
+
self.__database = dictionnary['database']
|
|
13
|
+
self.__user = dictionnary['user']
|
|
14
|
+
self.__password = dictionnary['password']
|
|
15
|
+
self.__port = dictionnary['port']
|
|
16
|
+
self.__host = dictionnary['host']
|
|
17
|
+
self.__batch_size = batch_size
|
|
18
|
+
|
|
19
|
+
@timer
|
|
20
|
+
def connect(self):
|
|
21
|
+
if self.logger is not None: self.logger.info("Tentative de connexion avec la base de données.")
|
|
22
|
+
try:
|
|
23
|
+
self.connection = psycopg2.connect(
|
|
24
|
+
database=self.__database,
|
|
25
|
+
user=self.__user,
|
|
26
|
+
password=self.__password,
|
|
27
|
+
port=self.__port,
|
|
28
|
+
host=self.__host
|
|
29
|
+
)
|
|
30
|
+
if self.logger is not None: self.logger.info(f"Connexion établie avec la base de données.")
|
|
31
|
+
return self.connection
|
|
32
|
+
except Exception as e:
|
|
33
|
+
if self.logger is not None: self.logger.error(f"Échec de la connexion à la base de données.")
|
|
34
|
+
raise
|
|
35
|
+
|
|
36
|
+
def sqlQuery(self, query: str):
|
|
37
|
+
self.logger.debug(f"Exécution de la requête de lecture: {query}")
|
|
38
|
+
start_time = datetime.now()
|
|
39
|
+
try:
|
|
40
|
+
timer_start = timeit.default_timer()
|
|
41
|
+
with self.connection.cursor() as cursor:
|
|
42
|
+
cursor.execute(query)
|
|
43
|
+
cols = [desc for desc in cursor.description]
|
|
44
|
+
self.logger.info("Requête exécutée avec succès, début de la lecture des résultats.")
|
|
45
|
+
while True:
|
|
46
|
+
rows = cursor.fetchmany(self.__batch_size)
|
|
47
|
+
if not rows:
|
|
48
|
+
break
|
|
49
|
+
yield rows
|
|
50
|
+
self.logger.info(f"{len(rows)} ligne(s) lue(s).")
|
|
51
|
+
end_time = datetime.now()
|
|
52
|
+
self.logger.log_to_db(start_time, end_time, status='success', message='Requête de lecture exécutée')
|
|
53
|
+
if get_timer():
|
|
54
|
+
elapsed_time = timeit.default_timer() - timer_start
|
|
55
|
+
self.logger.info(f"Temps d'exécution de sqlQuery: {elapsed_time:.4f} secondes")
|
|
56
|
+
except Exception as e:
|
|
57
|
+
end_time = datetime.now()
|
|
58
|
+
self.logger.error(f"Échec de la lecture des données: {e}")
|
|
59
|
+
self.logger.log_to_db(start_time, end_time, status="failure", message=str(e))
|
|
60
|
+
raise
|
|
61
|
+
|
|
62
|
+
@timer
|
|
63
|
+
def sqlExec(self, query):
|
|
64
|
+
try:
|
|
65
|
+
with self.connection.cursor() as cursor:
|
|
66
|
+
cursor.execute(query)
|
|
67
|
+
self.logger.info(f"Requête exécutée avec succès.")
|
|
68
|
+
self.connection.commit()
|
|
69
|
+
except Exception as e:
|
|
70
|
+
self.logger.error(f"Échec de l'exécution de la requête: {e}")
|
|
71
|
+
raise
|
|
72
|
+
|
|
73
|
+
@timer
|
|
74
|
+
def sqlScalaire(self, query):
|
|
75
|
+
try:
|
|
76
|
+
with self.connection.cursor() as cursor:
|
|
77
|
+
cursor.execute(query)
|
|
78
|
+
self.logger.info(f"Requête exécutée avec succès.")
|
|
79
|
+
data = cursor.fetchone()
|
|
80
|
+
return data
|
|
81
|
+
except Exception as e:
|
|
82
|
+
self.logger.error(f"Échec de l'exécution de la requête: {e}")
|
|
83
|
+
raise
|
|
84
|
+
|
|
85
|
+
@timer
|
|
86
|
+
def insert(self, table, cols=[], rows=[]):
|
|
87
|
+
start_time = datetime.now()
|
|
88
|
+
try:
|
|
89
|
+
with self.connection.cursor() as cursor:
|
|
90
|
+
placeholders = ", ".join(["%s"] * len(cols))
|
|
91
|
+
query = f"INSERT INTO {table} ({', '.join(cols)}) VALUES ({placeholders})"
|
|
92
|
+
cursor.execute(query, rows)
|
|
93
|
+
self.connection.commit()
|
|
94
|
+
self.logger.info(f"{cursor.rowcount} ligne insérée avec succès dans la table {table}.")
|
|
95
|
+
self.logger.log_to_db(start_time, datetime.now(), status='success', message="Insertion réussie.")
|
|
96
|
+
return ["SUCCESS"]
|
|
97
|
+
except Exception as e:
|
|
98
|
+
self.logger.error(f"Échec de l'insertion des données: {e}")
|
|
99
|
+
self.logger.log_to_db(start_time, datetime.now(), status='failure', message=str(e))
|
|
100
|
+
self.connection.rollback()
|
|
101
|
+
return "ERROR", str(e), rows
|
|
102
|
+
|
|
103
|
+
@timer
|
|
104
|
+
def insertBulk(self, table, cols=[], rows=[]):
|
|
105
|
+
start_time = datetime.now()
|
|
106
|
+
try:
|
|
107
|
+
with self.connection.cursor() as cursor:
|
|
108
|
+
placeholders = ", ".join(["%s"] * len(cols))
|
|
109
|
+
query = f"INSERT INTO {table} ({', '.join(cols)}) VALUES ({placeholders})"
|
|
110
|
+
cursor.executemany(query, rows)
|
|
111
|
+
self.connection.commit()
|
|
112
|
+
self.logger.info(f"{cursor.rowcount} lignes insérées avec succès dans la table {table}.")
|
|
113
|
+
self.logger.log_to_db(start_time, datetime.now(), status="success", message="Insertion(s) réussie(s)")
|
|
114
|
+
return ["SUCCESS"]
|
|
115
|
+
except Exception as e:
|
|
116
|
+
self.logger.error(f"Échec de l'insertion des données: {e}")
|
|
117
|
+
self.logger.log_to_db(start_time, datetime.now(), status="failure", message=str(e))
|
|
118
|
+
self.connection.rollback()
|
|
119
|
+
return "ERROR", str(e), rows
|
adsToolBox/demo/_demo.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import adsToolBox as ads
|
|
2
|
+
from to_sort.env import *
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
ads.set_timer(True) # active les timer
|
|
6
|
+
|
|
7
|
+
#--------------------------------------------------------------------------------------
|
|
8
|
+
#--------------------- DATA PIPELINE DB to DB -------------------------
|
|
9
|
+
#--------------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
def pipeline():
|
|
12
|
+
pg_source=ads.dbPgsql({'database':pg_dwh_db
|
|
13
|
+
, 'user':pg_dwh_user
|
|
14
|
+
, 'password':pg_dwh_pwd
|
|
15
|
+
, 'port':pg_dwh_port
|
|
16
|
+
, 'host':pg_dwh_host})
|
|
17
|
+
|
|
18
|
+
mssql_destination=ads.dbMssql({'database': mssql_dwh_db
|
|
19
|
+
, 'user':mssql_dwh_user
|
|
20
|
+
, 'password':mssql_dwh_pwd
|
|
21
|
+
, 'port':mssql_dwh_port
|
|
22
|
+
, 'host':mssql_dwh_host})
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
mypipeline=ads.pipelineBulk({'db_source':pg_source
|
|
26
|
+
,'query_source':'''SELECT tenantname, taille, unite, fichier FROM onyx_qs."diskcheck" LIMIT 10'''
|
|
27
|
+
,'db_destination':mssql_destination
|
|
28
|
+
,'table':'ONYX.diskcheck'
|
|
29
|
+
,'cols':['tenantname', 'taille', 'unite', 'fichier']})
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
mssql_destination=ads.dbMssql({'database': mssql_dwh_db
|
|
33
|
+
, 'user':mssql_dwh_user
|
|
34
|
+
, 'password':mssql_dwh_pwd
|
|
35
|
+
, 'port':mssql_dwh_port
|
|
36
|
+
, 'host':mssql_dwh_host})
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
mypipeline=ads.pipeline({'db_source':pg_source
|
|
40
|
+
,'query_source':'''SELECT tenantname, taille, unite, fichier FROM onyx_qs."diskcheck" LIMIT 10'''
|
|
41
|
+
,'db_destination':mssql_destination
|
|
42
|
+
,'table':'ONYX.diskcheck'
|
|
43
|
+
,'cols':['tenantname', 'taille', 'unite', 'fichier']})
|
|
44
|
+
|
|
45
|
+
mypipeline.run()
|
|
46
|
+
|
|
47
|
+
#--------------------------------------------------------------------------------------
|
|
48
|
+
#---------------------------- FICHIERS --------------------------------
|
|
49
|
+
#--------------------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
def fichier():
|
|
52
|
+
# lister un dossier
|
|
53
|
+
os.listdir()
|
|
54
|
+
|
|
55
|
+
# Copier un fichier
|
|
56
|
+
#shutil.copy("trashcan.py", "../factory")
|
|
57
|
+
|
|
58
|
+
#shutil.copy2() #--> conserve les metadata
|
|
59
|
+
|
|
60
|
+
# Vérifier l'existance d'un fichier
|
|
61
|
+
#os.path.isfile("")
|
|
62
|
+
|
|
63
|
+
pipeline()
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import polars as pl
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
data = [
|
|
6
|
+
("A", 1, 10.5, 'He said "Hello"'),
|
|
7
|
+
("B", 2, 20.1, "NA"),
|
|
8
|
+
("C", 3, 30.7, "NA"),
|
|
9
|
+
("D", "NA", 40.6, "NA")
|
|
10
|
+
]
|
|
11
|
+
df = pl.DataFrame(data, schema=["key", "value1", "value2", "value3"], orient="row")
|
|
12
|
+
|
|
13
|
+
# Écriture dans un fichier csv
|
|
14
|
+
csv_file = "example_data.csv"
|
|
15
|
+
df.write_csv(csv_file, separator=";", quote_char='"', include_header=True)
|
|
16
|
+
|
|
17
|
+
# Lecture à partir d'un fichier csv
|
|
18
|
+
df_csv = pl.read_csv(
|
|
19
|
+
"example_data.csv",
|
|
20
|
+
separator=";", #Utiliser un séparateur précis, par défaut ","
|
|
21
|
+
has_header=True, #Indique si le fichier a une ligne d'en-tête
|
|
22
|
+
null_values=["NA"], #Interpréter ces valeurs comme nulles
|
|
23
|
+
columns=["key", "value1", "value3"], #Lire uniquement certaines colonnes
|
|
24
|
+
quote_char='"' #Le caractère utilisé pour entourer les valeurs est le double guillemet
|
|
25
|
+
)
|
|
26
|
+
print(df_csv)
|
|
27
|
+
|
|
28
|
+
# Lister les fichiers du répertoire courant
|
|
29
|
+
print(os.listdir())
|
|
30
|
+
|
|
31
|
+
# Créer et écrire dans un fichier txt
|
|
32
|
+
with open("file.txt", "w") as file:
|
|
33
|
+
file.write("Your text goes here")
|
|
34
|
+
|
|
35
|
+
# Copier un fichier
|
|
36
|
+
shutil.copy("file.txt", "copy.txt")
|
|
37
|
+
|
|
38
|
+
# Copier les métadonnées
|
|
39
|
+
shutil.copy2("file.txt", "copy2.txt")
|
|
40
|
+
|
|
41
|
+
# Vérifier si un fichier est présent ou non
|
|
42
|
+
if os.path.isfile("copy.txt"):
|
|
43
|
+
print("Le fichier est bien présent.")
|
|
44
|
+
else:
|
|
45
|
+
print("Le fichier n'est pas présent.")
|
|
46
|
+
|
|
47
|
+
# Supprime un fichier
|
|
48
|
+
os.remove("copy.txt")
|
|
49
|
+
os.remove("copy2.txt")
|
|
50
|
+
os.remove("file.txt")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import polars as pl
|
|
2
|
+
|
|
3
|
+
tbl1 = [
|
|
4
|
+
("A", "1"),
|
|
5
|
+
("B", "2"),
|
|
6
|
+
("C", "3"),
|
|
7
|
+
("D", "4")
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
df1 = pl.DataFrame(tbl1, schema=["key", "value1"], orient="row")
|
|
11
|
+
tbl2 = [
|
|
12
|
+
("A", "10"),
|
|
13
|
+
("B", "20"),
|
|
14
|
+
("C", "40"),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
df2 = pl.DataFrame(tbl2, schema=["key", "value2"], orient="row")
|
|
18
|
+
|
|
19
|
+
# Inner join
|
|
20
|
+
df_joined = df1.join(df2, on="key", how="inner")
|
|
21
|
+
print(df_joined)
|
|
22
|
+
|
|
23
|
+
# Left join
|
|
24
|
+
df_left_joined = df1.join(df2, on="key", how="left")
|
|
25
|
+
print(df_left_joined)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import polars as pl
|
|
2
|
+
|
|
3
|
+
tbl = [
|
|
4
|
+
("A", "5"),
|
|
5
|
+
("C", "3"),
|
|
6
|
+
("E", "1"),
|
|
7
|
+
("D", "2"),
|
|
8
|
+
("B", "4")
|
|
9
|
+
]
|
|
10
|
+
df = pl.DataFrame(tbl, schema=["key", "value"], orient="row")
|
|
11
|
+
|
|
12
|
+
df = df.sort("key")
|
|
13
|
+
print(df)
|
|
14
|
+
|
|
15
|
+
df = df.sort("value")
|
|
16
|
+
print(df)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import polars as pl
|
|
2
|
+
|
|
3
|
+
tbl = [
|
|
4
|
+
("A A A A", "1"),
|
|
5
|
+
("B V", "2"),
|
|
6
|
+
("CZZ ZDQS", "3"),
|
|
7
|
+
("CQSD d", "4"),
|
|
8
|
+
("CDAS AZDASD", "5")
|
|
9
|
+
]
|
|
10
|
+
df = pl.DataFrame(tbl, schema=["key", "value"], orient="row")
|
|
11
|
+
print(df)
|
|
12
|
+
|
|
13
|
+
#Suppression des espaces sur une colonne
|
|
14
|
+
df = df.with_columns(pl.col("key").str.replace_all(" ", ""))
|
|
15
|
+
print(df)
|
|
16
|
+
|
|
17
|
+
#Concaténation de 2 champs
|
|
18
|
+
df = df.with_columns(pl.concat_str(["key", "value"], separator="-").alias("value2"))
|
|
19
|
+
print(df)
|
adsToolBox/demo/demo.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from adsToolBox import timer
|
|
2
|
+
from adsToolBox.dbPgsql import dbPgsql
|
|
3
|
+
from adsToolBox.logger import Logger
|
|
4
|
+
from adsToolBox.global_config import set_timer
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
from to_sort.env import *
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
# Établit une connexion pour que le logger puisse écrire en base
|
|
11
|
+
logger_connection = dbPgsql({'database': pg_dwh_db
|
|
12
|
+
, 'user': pg_dwh_user
|
|
13
|
+
, 'password': pg_dwh_pwd
|
|
14
|
+
, 'port': pg_dwh_port
|
|
15
|
+
, 'host': pg_dwh_host},
|
|
16
|
+
None)
|
|
17
|
+
# Ne pas oublier de lancer la connection
|
|
18
|
+
logger_connection.connect()
|
|
19
|
+
|
|
20
|
+
logger = Logger(logger_connection, logging.INFO, "AdsLogger", "LOGS", "LOGS_details")
|
|
21
|
+
logger.info("Début de la démonstration.")
|
|
22
|
+
|
|
23
|
+
# Active le timer, les requêtes seront chronométrées, si le logger n'est pas activé, les temps d'exécutions ne seront pas affichés
|
|
24
|
+
set_timer(True)
|
|
25
|
+
|
|
26
|
+
# On définit une source de connexion à laquelle on affecte notre logger
|
|
27
|
+
source = dbPgsql({'database': pg_dwh_db
|
|
28
|
+
, 'user': pg_dwh_user
|
|
29
|
+
, 'password': pg_dwh_pwd
|
|
30
|
+
, 'port': pg_dwh_port
|
|
31
|
+
, 'host': pg_dwh_host},
|
|
32
|
+
logger)
|
|
33
|
+
|
|
34
|
+
# Cette opération sera loguée et chronométrée
|
|
35
|
+
source.connect()
|
|
36
|
+
|
|
37
|
+
# Celle-ci le sera dès que le flux (générateur) renvoyé par sqlQuery sera consommé
|
|
38
|
+
data1 = source.sqlQuery('''SELECT tenantname, fichier FROM onyx_qs."diskcheck" LIMIT 10''')
|
|
39
|
+
print(f"Première requête: {list(data1)}")
|
|
40
|
+
# Après ce print viennent les notifications d'insertions des logs en base et le temps d'eéxuction
|
|
41
|
+
|
|
42
|
+
# Voici comment désactiver les logs
|
|
43
|
+
logger.disable()
|
|
44
|
+
logger.info("Ceci est un message d'information qui n'est pas censé s'afficher.")
|
|
45
|
+
|
|
46
|
+
data2 = source.sqlQuery('''SELECT tenantname, fichier FROM onyx_qs."diskcheck" LIMIT 10''')
|
|
47
|
+
print(f"Seconde requête: {list(data2)}")
|
|
48
|
+
# Ici pas d'insertions en base de logs non plus, et pas de temps d'exécutions affiché
|
|
49
|
+
|
|
50
|
+
# On peut aussi affecter le décorateur timer à n'importe quelle méthode
|
|
51
|
+
@timer
|
|
52
|
+
def sample_function(duration, logger=None):
|
|
53
|
+
""" Une fonction d'exemple qui simule une tâche en attendant un certain temps. """
|
|
54
|
+
time.sleep(duration)
|
|
55
|
+
return "Done"
|
|
56
|
+
|
|
57
|
+
# Par contre, il faut absolument un argument 'logger' dans la fonction en question
|
|
58
|
+
logger.enable()
|
|
59
|
+
sample_function(0.1, logger=logger)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
logger.info("Fin de la démonstration !")
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from adsToolBox.logger import Logger
|
|
2
|
+
from adsToolBox.dbPgsql import dbPgsql
|
|
3
|
+
from adsToolBox.global_config import set_timer
|
|
4
|
+
from adsToolBox.pipeline import pipeline
|
|
5
|
+
|
|
6
|
+
from to_sort.env import *
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
logger_connection = dbPgsql({'database': pg_dwh_db
|
|
10
|
+
, 'user': pg_dwh_user
|
|
11
|
+
, 'password': pg_dwh_pwd
|
|
12
|
+
, 'port': pg_dwh_port
|
|
13
|
+
, 'host': pg_dwh_host},
|
|
14
|
+
None, 10_000)
|
|
15
|
+
logger_connection.connect()
|
|
16
|
+
logger = Logger(logger_connection, logging.INFO, "AdsLogger", "LOGS", "LOGS_details")
|
|
17
|
+
logger.info("Début de la démonstration...")
|
|
18
|
+
logger.disable()
|
|
19
|
+
set_timer(True)
|
|
20
|
+
|
|
21
|
+
# Déclarons une source base de données
|
|
22
|
+
source = dbPgsql({'database':pg_dwh_db
|
|
23
|
+
, 'user':pg_dwh_user
|
|
24
|
+
, 'password':pg_dwh_pwd
|
|
25
|
+
, 'port':pg_dwh_port
|
|
26
|
+
, 'host':pg_dwh_host}, logger, batch_size=1)
|
|
27
|
+
|
|
28
|
+
# Déclarer une destination, c'est un peu plus complexe
|
|
29
|
+
destination = {
|
|
30
|
+
'name': 'test',
|
|
31
|
+
'db': dbPgsql({'database':pg_dwh_db, 'user':pg_dwh_user, 'password':pg_dwh_pwd, 'port':pg_dwh_port
|
|
32
|
+
, 'host':pg_dwh_host}, logger),
|
|
33
|
+
'table': 'demo_pipeline',
|
|
34
|
+
'cols': ['tenantname', 'taille', 'unite', 'fichier']
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Créons la table de réception de nos données
|
|
38
|
+
destination['db'].connect()
|
|
39
|
+
destination['db'].sqlExec(''' DROP TABLE IF EXISTS demo_pipeline; ''')
|
|
40
|
+
destination['db'].sqlExec('''
|
|
41
|
+
CREATE TABLE IF NOT EXISTS demo_pipeline (
|
|
42
|
+
id SERIAL PRIMARY KEY,
|
|
43
|
+
tenantname VARCHAR(255),
|
|
44
|
+
taille FLOAT(8),
|
|
45
|
+
unite VARCHAR(10),
|
|
46
|
+
fichier VARCHAR(255)
|
|
47
|
+
);
|
|
48
|
+
''')
|
|
49
|
+
|
|
50
|
+
# Voici la requête pour la source
|
|
51
|
+
query = '''
|
|
52
|
+
SELECT tenantname, taille, unite, fichier
|
|
53
|
+
FROM onyx_qs."diskcheck" LIMIT 5
|
|
54
|
+
'''
|
|
55
|
+
logger.enable()
|
|
56
|
+
|
|
57
|
+
# Premier pipeline
|
|
58
|
+
pipeline_1 = pipeline({
|
|
59
|
+
'db_source': source, # La source du pipeline
|
|
60
|
+
'query_source': query, # La requête qui sera exécutée sur cette source
|
|
61
|
+
'db_destinations': destination, # La destination du pipeline
|
|
62
|
+
'batch_size': 1
|
|
63
|
+
}, logger)
|
|
64
|
+
|
|
65
|
+
rejects = pipeline_1.run() # pipeline.run() renvoie les rejets du pipeline, ce sera une liste vide s'il
|
|
66
|
+
# n'y en a pas
|
|
67
|
+
print(f"{len(rejects)} rejets : {rejects}")
|
|
68
|
+
|
|
69
|
+
# Un batch_size à 1, ce insère les lignes une par une, un batch_size plus grand implique un run plus rapide
|
|
70
|
+
# pour le même nombre de lignes, batch_size est à 10 000 par défaut
|
|
71
|
+
# Second pipeline
|
|
72
|
+
source = dbPgsql({'database':pg_dwh_db
|
|
73
|
+
, 'user':pg_dwh_user
|
|
74
|
+
, 'password':pg_dwh_pwd
|
|
75
|
+
, 'port':pg_dwh_port
|
|
76
|
+
, 'host':pg_dwh_host}, logger)
|
|
77
|
+
|
|
78
|
+
pipeline_2 = pipeline({
|
|
79
|
+
'db_source': source, # La source du pipeline
|
|
80
|
+
'query_source': query, # La requête qui sera exécutée sur cette source
|
|
81
|
+
'db_destinations': destination # La destination du pipeline
|
|
82
|
+
}, logger)
|
|
83
|
+
|
|
84
|
+
rejects = pipeline_2.run()
|
|
85
|
+
print(f"{len(rejects)} rejets : {rejects}")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
logger.info("Fin de la démonstration")
|