modulitiz-micro 2.60.0__py312-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.
- modulitiz_micro/ModuloSeriale.py +70 -0
- modulitiz_micro/SunUtil.py +21 -0
- modulitiz_micro/database/AbstractDatabaseService.py +13 -0
- modulitiz_micro/database/AbstractSql.py +69 -0
- modulitiz_micro/database/ModuloSqlOracle.py +19 -0
- modulitiz_micro/database/ModuloSqlServer.py +43 -0
- modulitiz_micro/database/exceptions/ExceptionDbNoData.py +7 -0
- modulitiz_micro/database/mysql/AbstractBasicMysql.py +114 -0
- modulitiz_micro/database/mysql/ModuloMysql.py +162 -0
- modulitiz_micro/database/mysql/MysqlCommonConverter.py +47 -0
- modulitiz_micro/database/mysql/exceptions/ExceptionMysqlOffline.py +6 -0
- modulitiz_micro/database/sqlite/AbstractBasicSQLite.py +114 -0
- modulitiz_micro/database/sqlite/ModuloSQLite.py +82 -0
- modulitiz_micro/dom/DomModule.py +49 -0
- modulitiz_micro/exceptions/ExceptionCtrlC.py +7 -0
- modulitiz_micro/exceptions/ExceptionScheduler.py +7 -0
- modulitiz_micro/exceptions/http/ExceptionHttp.py +8 -0
- modulitiz_micro/exceptions/http/ExceptionHttp404.py +7 -0
- modulitiz_micro/exceptions/http/ExceptionHttpGeneric.py +7 -0
- modulitiz_micro/exceptions/http/ExceptionHttpRetriesExceeded.py +7 -0
- modulitiz_micro/files/cache/DatabaseCache.py +91 -0
- modulitiz_micro/files/cache/decorators/cacheRam.py +26 -0
- modulitiz_micro/files/git/ModuloGit.py +28 -0
- modulitiz_micro/files/git/decorators/catchAndRaiseGitExceptions.py +19 -0
- modulitiz_micro/files/git/exceptions/ExceptionGit.py +7 -0
- modulitiz_micro/iot/ModuleIotDevice.py +62 -0
- modulitiz_micro/iot/beans/IotDeviceBean.py +13 -0
- modulitiz_micro/iot/enums/IotOSEnum.py +12 -0
- modulitiz_micro/iot/espurna/ModuleEspurna.py +3 -0
- modulitiz_micro/keylogger/ExceptionKeyLogger.py +7 -0
- modulitiz_micro/keylogger/ModuloKeylogger.py +73 -0
- modulitiz_micro/rete/ModuleAndroidTVRemote.py +112 -0
- modulitiz_micro/rete/ModuloNetworking.py +91 -0
- modulitiz_micro/rete/ModuloOpenVpn.py +15 -0
- modulitiz_micro/rete/email/EmailBean.py +5 -0
- modulitiz_micro/rete/email/ModuloEmail.py +90 -0
- modulitiz_micro/rete/http/ModuloHttp.py +124 -0
- modulitiz_micro/rete/http/ModuloHttpConnectionSafe.py +95 -0
- modulitiz_micro/rete/http/ModuloHttpUtils.py +69 -0
- modulitiz_micro/rete/http/beans/HttpResponseBean.py +5 -0
- modulitiz_micro/rete/http/decorators/catchAndRaiseHttpExceptions.py +24 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/ModuleBasicHuaweiFusionSolar.py +13 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/ModuleHuaweiFusionSolar.py +94 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/TokenBean.py +28 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/DeviceBean.py +8 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/DeviceDataBattery.py +29 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/DeviceDataPowerSensor.py +49 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/DeviceDataResidentialInverter.py +46 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/batteryunitinfo/BatteryUnitInfo.py +9 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/batteryunitinfo/BatteryUnitInfoUnit.py +9 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/enums/BatteryStatusEnum.py +11 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/enums/DevTypeIdEnum.py +21 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/exceptions/ExceptionTooManyLogins.py +7 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/service/AbstractHuaweiFusionSolar.py +72 -0
- modulitiz_micro/rete/ntp/AbstractModuloNtp.py +73 -0
- modulitiz_micro/rete/ntp/ModuloNtpIt.py +8 -0
- modulitiz_micro/rete/socketserver/AbstractBasicGetSocketServer.py +35 -0
- modulitiz_micro/rete/socketserver/AbstractSocketServer.py +267 -0
- modulitiz_micro/rete/ssl/ModuloSsl.py +56 -0
- modulitiz_micro/sistema/ModuloEnvVars.py +34 -0
- modulitiz_micro/sistema/ModuloSystemPipe.py +67 -0
- modulitiz_micro/social/telegram/AbstractModuloTelegram.py +53 -0
- modulitiz_micro/social/telegram/ModuloTelegramSimple.py +26 -0
- modulitiz_micro/util/beans/globalvar/AbstractBasicGlobalVarBean.py +15 -0
- modulitiz_micro/util/scheduler/AbstractSchedulerBasicService.py +26 -0
- modulitiz_micro/util/scheduler/SchedulerBasicService.py +64 -0
- modulitiz_micro/util/scheduler/enums/ExecutorEnum.py +7 -0
- modulitiz_micro/util/scheduler/enums/TriggerEnum.py +9 -0
- modulitiz_micro/weather/AbstractModuleWeather.py +58 -0
- modulitiz_micro/weather/ModuleWeather.py +25 -0
- modulitiz_micro/weather/beans/AbstractWeatherDataBean.py +7 -0
- modulitiz_micro/weather/beans/commons/WeatherBean.py +11 -0
- modulitiz_micro/weather/beans/commons/WeatherCloudsBean.py +6 -0
- modulitiz_micro/weather/beans/commons/WeatherCoordBean.py +7 -0
- modulitiz_micro/weather/beans/commons/WeatherMainBean.py +13 -0
- modulitiz_micro/weather/beans/commons/WeatherRainBean.py +5 -0
- modulitiz_micro/weather/beans/commons/WeatherWindBean.py +8 -0
- modulitiz_micro/weather/beans/current/WeatherCurrentDataBean.py +30 -0
- modulitiz_micro/weather/beans/current/inners/WeatherSysBean.py +10 -0
- modulitiz_micro/weather/beans/forecast/WeatherForecastDataBean.py +12 -0
- modulitiz_micro/weather/beans/forecast/inners/WeatherCityBean.py +13 -0
- modulitiz_micro/weather/beans/forecast/inners/WeatherForecastBean.py +31 -0
- modulitiz_micro/weather/beans/forecast/inners/WeatherMainForecastBean.py +8 -0
- modulitiz_micro/weather/beans/forecast/inners/WeatherSysBean.py +9 -0
- modulitiz_micro/weather/enums/IdWeatherEnum.py +68 -0
- modulitiz_micro-2.60.0.dist-info/METADATA +61 -0
- modulitiz_micro-2.60.0.dist-info/RECORD +90 -0
- modulitiz_micro-2.60.0.dist-info/WHEEL +5 -0
- modulitiz_micro-2.60.0.dist-info/licenses/LICENSE +21 -0
- modulitiz_micro-2.60.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import serial
|
|
2
|
+
|
|
3
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
|
4
|
+
from modulitiz_nano.sistema.ModuloSystem import ModuloSystem
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ModuloSeriale(object):
|
|
8
|
+
"""
|
|
9
|
+
Utility di gestione dela connessione seriale RS232
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
COM_PORTS=[]
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self.connessione=None
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def populate(cls):
|
|
19
|
+
"""
|
|
20
|
+
Popola le variabili di classe.
|
|
21
|
+
"""
|
|
22
|
+
if ModuloSystem.isWindows():
|
|
23
|
+
COM_PORTS=cls.__generaElencoPorte("COM",1)
|
|
24
|
+
else:
|
|
25
|
+
COM_PORTS=cls.__generaElencoPorte("/dev/tty",0)
|
|
26
|
+
COM_PORTS.extend(cls.__generaElencoPorte("/dev/ttyS",0))
|
|
27
|
+
COM_PORTS.extend(cls.__generaElencoPorte("/dev/ttyUSB",0))
|
|
28
|
+
cls.COM_PORTS=COM_PORTS
|
|
29
|
+
|
|
30
|
+
def apriPrimaPortaDisponibile(self):
|
|
31
|
+
"""
|
|
32
|
+
Prova ad aprire la prima porta disponibile che trova.
|
|
33
|
+
"""
|
|
34
|
+
for port in self.COM_PORTS:
|
|
35
|
+
try:
|
|
36
|
+
connessioneSeriale=serial.Serial(port=port, baudrate=9600, rtscts=True, dsrdtr=True, exclusive=True)
|
|
37
|
+
connessioneSeriale.dtr=True
|
|
38
|
+
connessioneSeriale.dtr=False
|
|
39
|
+
self.connessione=connessioneSeriale
|
|
40
|
+
return
|
|
41
|
+
except OSError:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def isOpen(self)->bool:
|
|
45
|
+
"""
|
|
46
|
+
Controlla se la connessione alla porta è aperta.
|
|
47
|
+
"""
|
|
48
|
+
return self.connessione is not None and self.connessione.isOpen()
|
|
49
|
+
|
|
50
|
+
def read(self, port: str,baudrate: int,exitCallback):
|
|
51
|
+
"""
|
|
52
|
+
Reads serial strings and prints it to standard output.
|
|
53
|
+
"""
|
|
54
|
+
self.connessione=serial.Serial(port,baudrate,timeout=1)
|
|
55
|
+
while not exitCallback():
|
|
56
|
+
print(self.connessione.readline().decode(ModuloStringhe.CODIFICA_UTF8,"replace"),end="")
|
|
57
|
+
self.close()
|
|
58
|
+
|
|
59
|
+
def close(self):
|
|
60
|
+
"""
|
|
61
|
+
Chiude la connessione alla porta.
|
|
62
|
+
"""
|
|
63
|
+
if not self.isOpen():
|
|
64
|
+
return
|
|
65
|
+
self.connessione.close()
|
|
66
|
+
self.connessione=None
|
|
67
|
+
|
|
68
|
+
@staticmethod
|
|
69
|
+
def __generaElencoPorte(prefisso:str,inizio:int)->list:
|
|
70
|
+
return [prefisso+str(i) for i in range(inizio,16)]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from suntime import Sun
|
|
4
|
+
|
|
5
|
+
from modulitiz_nano.ModuloDate import ModuloDate
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SunUtil(object):
|
|
9
|
+
@staticmethod
|
|
10
|
+
def getLocalSunrise(lat: float,long: float,dateTime: datetime|None = None) -> datetime:
|
|
11
|
+
if dateTime is None:
|
|
12
|
+
dateTime=ModuloDate.now()
|
|
13
|
+
sun=Sun(lat,long)
|
|
14
|
+
return sun.get_sunrise_time(dateTime,ModuloDate.getTimezoneLocal(dateTime))
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def getLocalSunset(lat: float,long: float,dateTime: datetime|None = None) -> datetime:
|
|
18
|
+
if dateTime is None:
|
|
19
|
+
dateTime=ModuloDate.now()
|
|
20
|
+
sun=Sun(lat,long)
|
|
21
|
+
return sun.get_sunset_time(dateTime,ModuloDate.getTimezoneLocal(dateTime))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
from abc import ABC
|
|
3
|
+
|
|
4
|
+
from modulitiz_nano.files.ModuloLogging import ModuloLogging
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AbstractDatabaseService(ABC):
|
|
8
|
+
|
|
9
|
+
def __init__(self,logger:ModuloLogging):
|
|
10
|
+
self._logger=logger
|
|
11
|
+
self.lock=threading.Lock()
|
|
12
|
+
|
|
13
|
+
self.database=None
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
from abc import ABC
|
|
3
|
+
|
|
4
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AbstractSql(ABC):
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self.connDb=None
|
|
10
|
+
self.lock=threading.Lock()
|
|
11
|
+
|
|
12
|
+
def commit(self):
|
|
13
|
+
"""
|
|
14
|
+
Use to make modifications permanents.
|
|
15
|
+
"""
|
|
16
|
+
with self.lock:
|
|
17
|
+
self.commitNoLock()
|
|
18
|
+
|
|
19
|
+
def commitNoLock(self):
|
|
20
|
+
"""
|
|
21
|
+
Use only if lock is made externally.
|
|
22
|
+
"""
|
|
23
|
+
self.connDb.commit()
|
|
24
|
+
|
|
25
|
+
def rollback(self):
|
|
26
|
+
"""
|
|
27
|
+
Undo last uncommitted operations.
|
|
28
|
+
"""
|
|
29
|
+
with self.lock:
|
|
30
|
+
self.connDb.rollback()
|
|
31
|
+
|
|
32
|
+
def initCursor(self):
|
|
33
|
+
"""
|
|
34
|
+
Creates cursor objects, it's needed to read/write database.
|
|
35
|
+
"""
|
|
36
|
+
with self.lock:
|
|
37
|
+
cursoreDb=self.connDb.cursor()
|
|
38
|
+
return cursoreDb
|
|
39
|
+
|
|
40
|
+
def fetchOne(self,cursoreDb):
|
|
41
|
+
"""
|
|
42
|
+
Retrieve first row of query
|
|
43
|
+
"""
|
|
44
|
+
with cursoreDb:
|
|
45
|
+
with self.lock:
|
|
46
|
+
result=cursoreDb.fetchone()
|
|
47
|
+
if not result:
|
|
48
|
+
return None
|
|
49
|
+
return result[0]
|
|
50
|
+
|
|
51
|
+
def count(self,cursoreDb)->int:
|
|
52
|
+
with cursoreDb:
|
|
53
|
+
with self.lock:
|
|
54
|
+
result=cursoreDb.fetchone()
|
|
55
|
+
if not result:
|
|
56
|
+
return 0
|
|
57
|
+
return result[0]
|
|
58
|
+
|
|
59
|
+
def close(self):
|
|
60
|
+
with self.lock:
|
|
61
|
+
if self.connDb is not None:
|
|
62
|
+
self.connDb.close()
|
|
63
|
+
self.connDb=None
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def ifEmptyThenNull(testo:str|None)->str|None:
|
|
67
|
+
if ModuloStringhe.isEmpty(testo) or testo=="NULL":
|
|
68
|
+
return None
|
|
69
|
+
return testo
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import oracledb
|
|
2
|
+
|
|
3
|
+
from modulitiz_micro.database.ModuloSqlServer import ModuloSqlServer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ModuloSqlOracle(ModuloSqlServer):
|
|
7
|
+
DEFAULT_PORT=1521
|
|
8
|
+
|
|
9
|
+
def __init__(self,port:int|None,*args,**kwargs):
|
|
10
|
+
super().__init__(*args,**kwargs)
|
|
11
|
+
if port is None:
|
|
12
|
+
port=self.DEFAULT_PORT
|
|
13
|
+
self.port=port
|
|
14
|
+
|
|
15
|
+
def connessione(self):
|
|
16
|
+
dsn="{}/{}@{}:{}/xe".format(self.username,self.password,self.host,self.port)
|
|
17
|
+
self.connDb=oracledb.connect(dsn)
|
|
18
|
+
self.connDb=dsn
|
|
19
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import pypyodbc
|
|
2
|
+
|
|
3
|
+
from modulitiz_micro.database.AbstractSql import AbstractSql
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ModuloSqlServer(AbstractSql):
|
|
7
|
+
ERROR_CODE__UNIQUE_INDEX=23000
|
|
8
|
+
|
|
9
|
+
def __init__(self,host:str,nome_db:str,username:str,password:str):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.host=host
|
|
12
|
+
self.nome_db=nome_db
|
|
13
|
+
self.username=username
|
|
14
|
+
self.password=password
|
|
15
|
+
|
|
16
|
+
def connessione(self):
|
|
17
|
+
connDb=pypyodbc.connect("Driver={SQL Server};Server="+self.host+";Database="+self.nome_db+";uid="+self.username+";pwd="+self.password+";")
|
|
18
|
+
self.connDb=connDb
|
|
19
|
+
|
|
20
|
+
def select(self,sql:str,params:list):
|
|
21
|
+
with self.initCursor() as cursoreDb:
|
|
22
|
+
cursoreDb.execute(sql,params)
|
|
23
|
+
results=list(cursoreDb)
|
|
24
|
+
return results
|
|
25
|
+
|
|
26
|
+
def select_count(self,cursoreDb,sql:str,params:list)->int:
|
|
27
|
+
with cursoreDb:
|
|
28
|
+
cursoreDb.execute(sql,params)
|
|
29
|
+
output=self.count(cursoreDb)
|
|
30
|
+
return output
|
|
31
|
+
|
|
32
|
+
def modifica(self,cursoreDb,sql:str,params:list,ignore_unique_index:bool):
|
|
33
|
+
"""
|
|
34
|
+
Use it for data modifications like: insert, update, delete
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
cursoreDb.execute(sql,params)
|
|
38
|
+
except pypyodbc.IntegrityError as ie:
|
|
39
|
+
if ignore_unique_index:
|
|
40
|
+
error_code=int(ie.value[0])
|
|
41
|
+
if error_code!=self.ERROR_CODE__UNIQUE_INDEX:
|
|
42
|
+
raise ie
|
|
43
|
+
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
|
4
|
+
from modulitiz_micro.database.mysql.ModuloMysql import ModuloMysql
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AbstractBasicMysql(ModuloMysql):
|
|
8
|
+
|
|
9
|
+
def __init__(self,*args,**kwargs):
|
|
10
|
+
super().__init__(*args,**kwargs)
|
|
11
|
+
|
|
12
|
+
def initDdlBasicTables(self):
|
|
13
|
+
if not self.isDbNew:
|
|
14
|
+
return
|
|
15
|
+
sqlStr=ModuloStringhe.normalizzaEol(self.schemaBasicTables())
|
|
16
|
+
for results in self.executeScript(sqlStr):
|
|
17
|
+
yield results
|
|
18
|
+
sqlInsertBasicTables=self.insertBasicTables()
|
|
19
|
+
if not ModuloStringhe.isEmpty(sqlInsertBasicTables):
|
|
20
|
+
sqlInsertBasicTables=ModuloStringhe.normalizzaEol(sqlInsertBasicTables)
|
|
21
|
+
for results in self.executeScript(sqlInsertBasicTables):
|
|
22
|
+
yield results
|
|
23
|
+
self.commit()
|
|
24
|
+
|
|
25
|
+
def schemaBasicTables(self):
|
|
26
|
+
return """
|
|
27
|
+
|
|
28
|
+
CREATE TABLE tb_params(
|
|
29
|
+
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
|
|
30
|
+
type1 CHAR(30) NOT NULL,
|
|
31
|
+
key1 CHAR(30) NOT NULL,
|
|
32
|
+
desc1 CHAR(100) NOT NULL,
|
|
33
|
+
enabled BOOLEAN NOT NULL,
|
|
34
|
+
lang_code CHAR(2) NULL,
|
|
35
|
+
data_insert DATETIME NOT NULL
|
|
36
|
+
)"""+self.TABLE_OPTIONS+""";
|
|
37
|
+
CREATE UNIQUE INDEX PARAMS__UK1 ON tb_params(type1,key1,lang_code);
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def insertBasicTables(self):
|
|
43
|
+
"""
|
|
44
|
+
Inserire le istruzioni sql che vanno eseguite alla fine di tutto
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
#############################################################################################################################
|
|
50
|
+
#############################################################################################################################
|
|
51
|
+
#############################################################################################################################
|
|
52
|
+
def selectParamDescByEntries(self,paramType:str,paramKey:str|None)->str|None:
|
|
53
|
+
cursoreDb=self.selectParamByEntries(paramType, paramKey, None, True)
|
|
54
|
+
results=self.fetchAll(cursoreDb)
|
|
55
|
+
if len(results)==0:
|
|
56
|
+
return None
|
|
57
|
+
result=results[0]
|
|
58
|
+
return result['desc1']
|
|
59
|
+
|
|
60
|
+
def selectParamByEntries(self,paramType:str,paramKey:str|None,langCode:str|None,enabled:bool|None):
|
|
61
|
+
addParamKey=ModuloStringhe.isEmpty(paramKey) is False
|
|
62
|
+
addLangCode=ModuloStringhe.isEmpty(langCode) is False
|
|
63
|
+
addEnabled=enabled is not None
|
|
64
|
+
|
|
65
|
+
sql="""
|
|
66
|
+
SELECT *
|
|
67
|
+
FROM tb_params
|
|
68
|
+
WHERE type1=%(paramType)s
|
|
69
|
+
"""+("AND key1=%(paramKey)s" if addParamKey is True else "")+"""
|
|
70
|
+
"""+("AND langCode=%(langCode)s" if addLangCode is True else "")+"""
|
|
71
|
+
"""+("AND enabled=%(enabled)s" if addEnabled is True else "")+"""
|
|
72
|
+
;
|
|
73
|
+
"""
|
|
74
|
+
params= {'paramType': paramType}
|
|
75
|
+
if addParamKey is True:
|
|
76
|
+
params['paramKey']=paramKey
|
|
77
|
+
if addLangCode is True:
|
|
78
|
+
params['langCode']=langCode
|
|
79
|
+
if addEnabled is True:
|
|
80
|
+
params['enabled']=enabled
|
|
81
|
+
|
|
82
|
+
cursoreDb=self.initCursor()
|
|
83
|
+
with self.lock:
|
|
84
|
+
cursoreDb.execute(sql,params)
|
|
85
|
+
return cursoreDb
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def updateParamDesc(self,paramType:str,paramKey:str|None,newDesc:str|None):
|
|
89
|
+
addParamKey=ModuloStringhe.isEmpty(paramKey) is False
|
|
90
|
+
addNewDesc=ModuloStringhe.isEmpty(newDesc) is False
|
|
91
|
+
|
|
92
|
+
sqlSet=[]
|
|
93
|
+
if addNewDesc is True:
|
|
94
|
+
sqlSet.append("desc1=%(newDesc)s")
|
|
95
|
+
sqlSet=", ".join(sqlSet)
|
|
96
|
+
|
|
97
|
+
sql="""
|
|
98
|
+
UPDATE tb_params
|
|
99
|
+
SET """+sqlSet+"""
|
|
100
|
+
WHERE type1=%(paramType)s
|
|
101
|
+
"""+("AND key1=%(paramKey)s" if addParamKey is True else "")+"""
|
|
102
|
+
;
|
|
103
|
+
"""
|
|
104
|
+
params={}
|
|
105
|
+
if addNewDesc is True:
|
|
106
|
+
params['newDesc']=newDesc
|
|
107
|
+
params['paramType']=paramType
|
|
108
|
+
if addParamKey is True:
|
|
109
|
+
params['paramKey']=paramKey
|
|
110
|
+
cursoreDb=self.initCursor()
|
|
111
|
+
with self.lock:
|
|
112
|
+
cursoreDb.execute(sql,params)
|
|
113
|
+
return cursoreDb
|
|
114
|
+
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
import mysql.connector
|
|
4
|
+
|
|
5
|
+
from modulitiz_micro.database.AbstractSql import AbstractSql
|
|
6
|
+
from modulitiz_micro.database.exceptions.ExceptionDbNoData import ExceptionDbNoData
|
|
7
|
+
from modulitiz_micro.database.mysql.MysqlCommonConverter import MysqlCommonConverter
|
|
8
|
+
from modulitiz_nano.ModuloListe import ModuloListe
|
|
9
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
|
10
|
+
from modulitiz_nano.exceptions.ExceptionRuntime import ExceptionRuntime
|
|
11
|
+
from modulitiz_nano.exceptions.ExceptionUtil import ExceptionUtil
|
|
12
|
+
from modulitiz_nano.files.ModuloFiles import ModuloFiles
|
|
13
|
+
from modulitiz_nano.sistema.ModuloSystem import ModuloSystem
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ModuloMysql(AbstractSql):
|
|
17
|
+
"""
|
|
18
|
+
select
|
|
19
|
+
count
|
|
20
|
+
insert
|
|
21
|
+
update
|
|
22
|
+
delete
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
DATE_TIME_NOW="NOW()"
|
|
26
|
+
|
|
27
|
+
DEFAULT_PORT=3306
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def __init__(self,host: str,port: int|None,user: str,password: str,nomeDb: str,isDebug: bool):
|
|
31
|
+
super().__init__()
|
|
32
|
+
self.nomeDb=nomeDb
|
|
33
|
+
if port is None:
|
|
34
|
+
port=self.DEFAULT_PORT
|
|
35
|
+
# apro la connessione col server
|
|
36
|
+
self.connDb=mysql.connector.connect(user=user,password=password,host=host,port=port,
|
|
37
|
+
converter_class=MysqlCommonConverter)
|
|
38
|
+
self.TABLE_OPTIONS=self.getTableOptions(isDebug)
|
|
39
|
+
self.isDbNew=None
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def schema(self):
|
|
43
|
+
"""
|
|
44
|
+
Insert here sql instructions containing table definitions (DDL)
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def initDdl(self):
|
|
48
|
+
#scelgo il db
|
|
49
|
+
try:
|
|
50
|
+
self.connDb.cmd_init_db(self.nomeDb)
|
|
51
|
+
self.isDbNew=False
|
|
52
|
+
except mysql.connector.ProgrammingError:
|
|
53
|
+
sqlCreaDb="CREATE DATABASE %s;"%(self.nomeDb,)
|
|
54
|
+
with self.initCursor() as cursoreDb:
|
|
55
|
+
with self.lock:
|
|
56
|
+
cursoreDb.execute(sqlCreaDb)
|
|
57
|
+
self.connDb.cmd_init_db(self.nomeDb)
|
|
58
|
+
self.isDbNew=True
|
|
59
|
+
#se il db non esisteva creo le tabelle
|
|
60
|
+
if self.isDbNew:
|
|
61
|
+
sqlStr=ModuloStringhe.normalizzaEol(self.schema())
|
|
62
|
+
for results in self.executeScript(sqlStr):
|
|
63
|
+
yield results
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def getLastIdInserted(cursoreDb):
|
|
67
|
+
return cursoreDb.lastrowid
|
|
68
|
+
|
|
69
|
+
def selectNow(self):
|
|
70
|
+
"""
|
|
71
|
+
Returns current db date and time.
|
|
72
|
+
"""
|
|
73
|
+
sql="SELECT {};".format(self.DATE_TIME_NOW)
|
|
74
|
+
with self.initCursor() as cursoreDb:
|
|
75
|
+
with self.lock:
|
|
76
|
+
cursoreDb.execute(sql,{})
|
|
77
|
+
output=self.fetchOne(cursoreDb)
|
|
78
|
+
return output
|
|
79
|
+
|
|
80
|
+
def executeScript(self,sqlStr:str):
|
|
81
|
+
sqlCmds=sqlStr.split(";")
|
|
82
|
+
sqlCmds=ModuloListe.eliminaElementiVuoti(sqlCmds)
|
|
83
|
+
numCmds=len(sqlCmds)
|
|
84
|
+
with self.initCursor() as cursoreDb:
|
|
85
|
+
for index,sqlCmd in enumerate(sqlCmds):
|
|
86
|
+
sqlCmd=sqlCmd.strip()
|
|
87
|
+
try:
|
|
88
|
+
if sqlCmd!="":
|
|
89
|
+
with self.lock:
|
|
90
|
+
cursoreDb.execute(sqlCmd)
|
|
91
|
+
yield index,numCmds
|
|
92
|
+
except Exception as ex:
|
|
93
|
+
raise ExceptionRuntime(sqlCmd+"\n\n"+ExceptionUtil.toString(ex))
|
|
94
|
+
|
|
95
|
+
def fetchAll(self,cursoreDb)->list:
|
|
96
|
+
with self.lock:
|
|
97
|
+
with cursoreDb:
|
|
98
|
+
if cursoreDb.description is None:
|
|
99
|
+
raise ExceptionDbNoData()
|
|
100
|
+
descriptions=cursoreDb.description
|
|
101
|
+
rows=cursoreDb.fetchall()
|
|
102
|
+
self.commitNoLock() # mysql mette in cache i risultati, lo risolvo così, è un bug loro...
|
|
103
|
+
columns = [col[0] for col in descriptions]
|
|
104
|
+
rows = [dict(zip(columns, row)) for row in rows]
|
|
105
|
+
return rows
|
|
106
|
+
|
|
107
|
+
@classmethod
|
|
108
|
+
def backup(cls,percorsoCartella: str,user: str,password: str,dbName: str,
|
|
109
|
+
ignoreTables:list|tuple|None)->list:
|
|
110
|
+
output=[
|
|
111
|
+
cls.backupDdl(percorsoCartella,user,password,dbName,ignoreTables),
|
|
112
|
+
cls.backupData(percorsoCartella,user,password,dbName,ignoreTables)
|
|
113
|
+
]
|
|
114
|
+
return output
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def backupDdl(cls,percorsoCartella: str,user: str,password: str,dbName: str,
|
|
118
|
+
ignoreTables:list|tuple|None)->str:
|
|
119
|
+
return cls.__backup(percorsoCartella,user,password,dbName,ignoreTables,True,False)
|
|
120
|
+
@classmethod
|
|
121
|
+
def backupData(cls,percorsoCartella: str,user: str,password: str,dbName: str,
|
|
122
|
+
ignoreTables:list|tuple|None)->str:
|
|
123
|
+
return cls.__backup(percorsoCartella,user,password,dbName,ignoreTables,False,True)
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def __backup(percorsoCartella:str,user:str,password:str,dbName:str,
|
|
127
|
+
ignoreTables:list|tuple|None,onlyDdl:bool,onlyData:bool)->str:
|
|
128
|
+
if onlyDdl and onlyData:
|
|
129
|
+
raise ExceptionRuntime("valorizzare solo un'opzione alla volta")
|
|
130
|
+
cmdIgnoreTables=""
|
|
131
|
+
if ignoreTables is not None:
|
|
132
|
+
cmdIgnoreTables=" ".join(["--ignore-table=%s.%s"%(dbName,x) for x in ignoreTables])
|
|
133
|
+
nomefileSuffix=""
|
|
134
|
+
cmdOptions=""
|
|
135
|
+
if onlyDdl:
|
|
136
|
+
nomefileSuffix="_ddl"
|
|
137
|
+
cmdOptions="--no-data "+cmdIgnoreTables
|
|
138
|
+
elif onlyData:
|
|
139
|
+
nomefileSuffix="_data"
|
|
140
|
+
cmdOptions="--order-by-primary --no-create-info --quick "+cmdIgnoreTables
|
|
141
|
+
nomefileOutput=dbName+nomefileSuffix+".sql"
|
|
142
|
+
percorsoFileBackup=ModuloFiles.pathJoin(percorsoCartella,nomefileOutput)
|
|
143
|
+
cmd=r'mysqldump -u {} -p{} --databases {} --skip-add-drop-table --skip-comments {} -r "{}"'.format(user,password,dbName,cmdOptions,percorsoFileBackup)
|
|
144
|
+
output=ModuloSystem.systemCallReturnOutput(cmd,None).strip()
|
|
145
|
+
if not ModuloStringhe.isEmpty(output):
|
|
146
|
+
raise ExceptionRuntime(output)
|
|
147
|
+
return percorsoFileBackup
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def getTableOptions(isDebug: bool) -> str:
|
|
151
|
+
return "ENGINE=%s DEFAULT CHARSET=utf8"%("InnoDB" if not isDebug else "MEMORY",)
|
|
152
|
+
|
|
153
|
+
def paginazione(firstResult:int,numResults:int)->str:
|
|
154
|
+
sql=("LIMIT "+str(numResults) if numResults is not None else "")+\
|
|
155
|
+
(" OFFSET "+str(firstResult) if firstResult is not None else "")
|
|
156
|
+
return sql
|
|
157
|
+
|
|
158
|
+
def add_param_list(lista:list,prefix:str)->dict:
|
|
159
|
+
params={}
|
|
160
|
+
for index,elem in enumerate(lista):
|
|
161
|
+
params[prefix+str(index)]=elem
|
|
162
|
+
return params
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from mysql.connector import FieldType
|
|
4
|
+
from mysql.connector.conversion import MySQLConverter
|
|
5
|
+
from mysql.connector.types import DescriptionType
|
|
6
|
+
from mysql.connector.types import MySQLConvertibleType
|
|
7
|
+
from mysql.connector.types import MySQLProducedType
|
|
8
|
+
from mysql.connector.types import PythonProducedType
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MysqlCommonConverter(MySQLConverter):
|
|
12
|
+
def __init__(self,charset: str|None = None,
|
|
13
|
+
use_unicode: bool = True,
|
|
14
|
+
str_fallback: bool = False):
|
|
15
|
+
super().__init__(charset,use_unicode,str_fallback)
|
|
16
|
+
|
|
17
|
+
def to_mysql(self,value) -> MySQLProducedType:
|
|
18
|
+
value=self.__to_mysql(value)
|
|
19
|
+
# default behavior
|
|
20
|
+
return super().to_mysql(value)
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def __to_mysql(value):
|
|
24
|
+
"""
|
|
25
|
+
Gestione custom, ad esempio per IntEnum e StrEnum
|
|
26
|
+
"""
|
|
27
|
+
if value.__class__ in MySQLConvertibleType.__args__:
|
|
28
|
+
return value
|
|
29
|
+
# inizio gestione custom
|
|
30
|
+
if isinstance(value,int):
|
|
31
|
+
typePrimitive=int
|
|
32
|
+
elif isinstance(value,str):
|
|
33
|
+
typePrimitive=str
|
|
34
|
+
else:
|
|
35
|
+
return value
|
|
36
|
+
value.__class__.__name__=typePrimitive.__name__
|
|
37
|
+
return value
|
|
38
|
+
|
|
39
|
+
def to_python(
|
|
40
|
+
self,
|
|
41
|
+
vtype: DescriptionType,
|
|
42
|
+
value: Optional[bytes],
|
|
43
|
+
) -> PythonProducedType:
|
|
44
|
+
if vtype[1] == FieldType.BIT:
|
|
45
|
+
return value==b'\x01'
|
|
46
|
+
# default behavior
|
|
47
|
+
return super().to_python(vtype, value)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
|
4
|
+
from modulitiz_micro.database.sqlite.ModuloSQLite import AbstractSqlite
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AbstractBasicSqlite(AbstractSqlite):
|
|
8
|
+
|
|
9
|
+
def __init__(self,*args,**kwargs):
|
|
10
|
+
super().__init__(*args,**kwargs)
|
|
11
|
+
if not self.isDbNew:
|
|
12
|
+
return
|
|
13
|
+
sql_str=ModuloStringhe.normalizzaEol(self.schemaBasicTables())
|
|
14
|
+
with self.initCursor() as cursoreDb:
|
|
15
|
+
with self.lock:
|
|
16
|
+
cursoreDb.executescript(sql_str)
|
|
17
|
+
sql_insertBasicTables=self.insertBasicTables()
|
|
18
|
+
if not ModuloStringhe.isEmpty(sql_insertBasicTables):
|
|
19
|
+
sql_insertBasicTables=ModuloStringhe.normalizzaEol(sql_insertBasicTables)
|
|
20
|
+
with self.lock:
|
|
21
|
+
cursoreDb.executescript(sql_insertBasicTables)
|
|
22
|
+
self.commit()
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def insertBasicTables(self):
|
|
26
|
+
"""
|
|
27
|
+
Inserire le istruzioni sql che vanno eseguite alla fine di tutto
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def schemaBasicTables(self):
|
|
31
|
+
return """
|
|
32
|
+
|
|
33
|
+
CREATE TABLE tb_params(
|
|
34
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
35
|
+
type TEXT NOT NULL,
|
|
36
|
+
key TEXT NULL,
|
|
37
|
+
desc TEXT NOT NULL,
|
|
38
|
+
enabled INTEGER NOT NULL,
|
|
39
|
+
lang_code TEXT NULL,
|
|
40
|
+
data_insert TIMESTAMP NOT NULL
|
|
41
|
+
);
|
|
42
|
+
CREATE UNIQUE INDEX PARAMS__UK1 ON tb_params(
|
|
43
|
+
type,
|
|
44
|
+
IFNULL(key, 0),
|
|
45
|
+
IFNULL(lang_code, 0)
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
#############################################################################################################################
|
|
52
|
+
#############################################################################################################################
|
|
53
|
+
#############################################################################################################################
|
|
54
|
+
def selectParamDescByEntries(self,paramType,paramKey)->str|None:
|
|
55
|
+
with self.selectParamByEntries(paramType, paramKey, None, True) as cursoreDb:
|
|
56
|
+
results=cursoreDb.fetchall()
|
|
57
|
+
if len(results)==0:
|
|
58
|
+
return None
|
|
59
|
+
return results[0]['desc']
|
|
60
|
+
|
|
61
|
+
def selectParamByEntries(self,paramType,paramKey,langCode,enabled):
|
|
62
|
+
addParamKey=ModuloStringhe.isEmpty(paramKey) is False
|
|
63
|
+
addLangCode=ModuloStringhe.isEmpty(langCode) is False
|
|
64
|
+
addEnabled=ModuloStringhe.isEmpty(enabled) is False
|
|
65
|
+
|
|
66
|
+
sql="""
|
|
67
|
+
SELECT *
|
|
68
|
+
FROM tb_params
|
|
69
|
+
WHERE type=:paramType
|
|
70
|
+
"""+("AND key=:paramKey" if addParamKey is True else "")+"""
|
|
71
|
+
"""+("AND langCode=:langCode" if addLangCode is True else "")+"""
|
|
72
|
+
"""+("AND enabled=:enabled" if addEnabled is True else "")+"""
|
|
73
|
+
;
|
|
74
|
+
"""
|
|
75
|
+
params={'paramType':paramType}
|
|
76
|
+
if addParamKey is True:
|
|
77
|
+
params['paramKey']=paramKey
|
|
78
|
+
if addLangCode is True:
|
|
79
|
+
params['langCode']=langCode
|
|
80
|
+
if addEnabled is True:
|
|
81
|
+
params['enabled']=enabled
|
|
82
|
+
cursoreDb=self.initCursor()
|
|
83
|
+
with self.lock:
|
|
84
|
+
cursoreDb.execute(sql,params)
|
|
85
|
+
return cursoreDb
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def updateParamDesc(self,paramType,paramKey,newDesc):
|
|
89
|
+
addParamKey=ModuloStringhe.isEmpty(paramKey) is False
|
|
90
|
+
addNewDesc=ModuloStringhe.isEmpty(newDesc) is False
|
|
91
|
+
|
|
92
|
+
sql_set=[]
|
|
93
|
+
if addNewDesc is True:
|
|
94
|
+
sql_set.append("desc=:newDesc")
|
|
95
|
+
sql_set=", ".join(sql_set)
|
|
96
|
+
|
|
97
|
+
sql="""
|
|
98
|
+
UPDATE tb_params
|
|
99
|
+
SET """+sql_set+"""
|
|
100
|
+
WHERE type=:paramType
|
|
101
|
+
"""+("AND key=:paramKey" if addParamKey is True else "")+"""
|
|
102
|
+
;
|
|
103
|
+
"""
|
|
104
|
+
params={}
|
|
105
|
+
if addNewDesc is True:
|
|
106
|
+
params['newDesc']=newDesc
|
|
107
|
+
params['paramType']=paramType
|
|
108
|
+
if addParamKey is True:
|
|
109
|
+
params['paramKey']=paramKey
|
|
110
|
+
cursoreDb=self.initCursor()
|
|
111
|
+
with self.lock:
|
|
112
|
+
cursoreDb.execute(sql,params)
|
|
113
|
+
return cursoreDb
|
|
114
|
+
|