modulitiz-micro 3.0.0__py314-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/SerialModule.py +55 -0
- modulitiz_micro/SunUtil.py +22 -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 +112 -0
- modulitiz_micro/database/mysql/ModuloMysql.py +157 -0
- modulitiz_micro/database/mysql/MysqlCommonConverter.py +55 -0
- modulitiz_micro/database/mysql/exceptions/ExceptionMysqlOffline.py +6 -0
- modulitiz_micro/dom/DomModule.py +48 -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/decorators/cacheRam.py +26 -0
- modulitiz_micro/files/git/ModuloGit.py +32 -0
- modulitiz_micro/files/git/decorators/catchAndRaiseGitExceptions.py +19 -0
- modulitiz_micro/files/git/exceptions/ExceptionGit.py +7 -0
- modulitiz_micro/iot/ModuleIotDevice.py +61 -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 +115 -0
- modulitiz_micro/rete/ModuloNetworking.py +71 -0
- modulitiz_micro/rete/ModuloOpenVpn.py +15 -0
- modulitiz_micro/rete/email/EmailBean.py +5 -0
- modulitiz_micro/rete/email/ModuloEmail.py +88 -0
- modulitiz_micro/rete/http/ModuloHttp.py +127 -0
- modulitiz_micro/rete/http/ModuloHttpConnectionSafe.py +96 -0
- modulitiz_micro/rete/http/ModuloHttpUtils.py +68 -0
- modulitiz_micro/rete/http/beans/HttpResponseBean.py +5 -0
- modulitiz_micro/rete/http/decorators/catchAndRaiseHttpExceptions.py +28 -0
- modulitiz_micro/rete/http/ecovacsdeebot/AbstractModuleEcovacsDeebot.py +94 -0
- modulitiz_micro/rete/http/ecovacsdeebot/ModuleEcovacsDeebot.py +43 -0
- modulitiz_micro/rete/http/enums/HttpHeaderNameEnum.py +14 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/ModuleBasicHuaweiFusionSolar.py +114 -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 +11 -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 +29 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/exceptions/ExceptionTooManyLogins.py +7 -0
- modulitiz_micro/rete/http/huawei/fusionsolar/service/AbstractHuaweiFusionSolar.py +77 -0
- modulitiz_micro/rete/http/mapbox/AbstractModuleMapBox.py +36 -0
- modulitiz_micro/rete/http/mapbox/ModuleMapBox.py +12 -0
- modulitiz_micro/rete/http/mapbox/inner/directions/ModuleMapBoxDirections.py +54 -0
- modulitiz_micro/rete/http/mapbox/inner/directions/beans/HighTrafficPointBean.py +7 -0
- modulitiz_micro/rete/ntp/AbstractModuloNtp.py +95 -0
- modulitiz_micro/rete/ntp/ModuloNtpIt.py +8 -0
- modulitiz_micro/rete/socketserver/AbstractBasicGetSocketServer.py +35 -0
- modulitiz_micro/rete/socketserver/AbstractSocketServer.py +268 -0
- modulitiz_micro/rete/ssl/ModuloSsl.py +55 -0
- modulitiz_micro/sistema/ModuloEnvVars.py +34 -0
- modulitiz_micro/sistema/ModuloSystemPipe.py +67 -0
- modulitiz_micro/social/telegram/AbstractModuloTelegram.py +50 -0
- modulitiz_micro/social/telegram/ModuloTelegramSimple.py +26 -0
- modulitiz_micro/social/telegram/bot/AbstractTelegramBotMainService.py +94 -0
- modulitiz_micro/social/telegram/bot/AbstractTelegramBotService.py +47 -0
- modulitiz_micro/social/telegram/bot/enums/TelegramBotCommandEnum.py +10 -0
- modulitiz_micro/social/telegram/bot/util/TelegramBotUtil.py +7 -0
- modulitiz_micro/util/SolarUtil.py +18 -0
- modulitiz_micro/util/beans/CoordinatesBean.py +7 -0
- modulitiz_micro/util/beans/globalvar/AbstractBasicGlobalVarBean.py +15 -0
- modulitiz_micro/util/scheduler/AbstractSchedulerBasicService.py +16 -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/AbstractWeatherBean.py +6 -0
- modulitiz_micro/weather/beans/AbstractWeatherDataBean.py +21 -0
- modulitiz_micro/weather/beans/commons/WeatherBean.py +11 -0
- modulitiz_micro/weather/beans/commons/WeatherCloudsBean.py +6 -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 +25 -0
- modulitiz_micro/weather/beans/current/inners/WeatherSysBean.py +5 -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 +9 -0
- modulitiz_micro/weather/beans/forecast/inners/WeatherSysBean.py +9 -0
- modulitiz_micro/weather/enums/IdWeatherEnum.py +68 -0
- modulitiz_micro-3.0.0.dist-info/METADATA +62 -0
- modulitiz_micro-3.0.0.dist-info/RECORD +98 -0
- modulitiz_micro-3.0.0.dist-info/WHEEL +5 -0
- modulitiz_micro-3.0.0.dist-info/licenses/LICENSE +21 -0
- modulitiz_micro-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import serial
|
|
2
|
+
import serial.tools.list_ports
|
|
3
|
+
|
|
4
|
+
from modulitiz_nano.ModuloColorText import ModuloColorText
|
|
5
|
+
from modulitiz_nano.ModuloDate import ModuloDate
|
|
6
|
+
from modulitiz_nano.sistema.EncodingEnum import EncodingEnum
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SerialModule(object):
|
|
10
|
+
"""
|
|
11
|
+
Utility di gestione della connessione seriale / RS232
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self.conn=None
|
|
16
|
+
|
|
17
|
+
def populate(self,port: str,baudrate: int):
|
|
18
|
+
self.conn=serial.Serial(port,baudrate,timeout=1)
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def findFirstPortConnected()->str|None:
|
|
22
|
+
ports:list|tuple=serial.tools.list_ports.comports()
|
|
23
|
+
if not ports:
|
|
24
|
+
return None
|
|
25
|
+
return min(ports)[0]
|
|
26
|
+
|
|
27
|
+
def isOpen(self)->bool:
|
|
28
|
+
"""
|
|
29
|
+
Controlla se la connessione alla porta è aperta.
|
|
30
|
+
"""
|
|
31
|
+
return self.conn is not None and self.conn.isOpen()
|
|
32
|
+
|
|
33
|
+
def read(self, exitCallback):
|
|
34
|
+
"""
|
|
35
|
+
Reads serial strings and prints it to standard output.
|
|
36
|
+
"""
|
|
37
|
+
try:
|
|
38
|
+
while not exitCallback():
|
|
39
|
+
character=self.conn.read(1).decode(EncodingEnum.UTF8,"replace")
|
|
40
|
+
if character!="\n":
|
|
41
|
+
msg=character
|
|
42
|
+
else:
|
|
43
|
+
msg="\n%s%s >>> %s"%(ModuloDate.dateToString(None,ModuloDate.FORMATO_ORA),ModuloColorText.BLU,ModuloColorText.DEFAULT)
|
|
44
|
+
print(msg,end="",flush=True)
|
|
45
|
+
finally:
|
|
46
|
+
self.close()
|
|
47
|
+
|
|
48
|
+
def close(self):
|
|
49
|
+
"""
|
|
50
|
+
Chiude la connessione alla porta.
|
|
51
|
+
"""
|
|
52
|
+
if not self.isOpen():
|
|
53
|
+
return
|
|
54
|
+
self.conn.close()
|
|
55
|
+
self.conn=None
|
|
@@ -0,0 +1,22 @@
|
|
|
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 ModuloDate.removeTimezoneInfo(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
|
+
dateTime=ModuloDate.plusMinusDays(dateTime,1)
|
|
21
|
+
sun=Sun(lat,long)
|
|
22
|
+
return ModuloDate.removeTimezoneInfo(sun.get_sunset_time(dateTime,ModuloDate.getTimezoneLocal(dateTime)))
|
|
@@ -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_nano.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,112 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from modulitiz_micro.database.mysql.ModuloMysql import ModuloMysql
|
|
4
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
|
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
|
+
with self.lock:
|
|
54
|
+
cursoreDb=self.selectParamByEntries(paramType, paramKey, None, True)
|
|
55
|
+
results=self.fetchAll(cursoreDb)
|
|
56
|
+
if len(results)==0:
|
|
57
|
+
return None
|
|
58
|
+
result=results[0]
|
|
59
|
+
return result['desc1']
|
|
60
|
+
|
|
61
|
+
def selectParamByEntries(self,paramType:str,paramKey:str|None,langCode:str|None,enabled:bool|None):
|
|
62
|
+
addParamKey=ModuloStringhe.isEmpty(paramKey) is False
|
|
63
|
+
addLangCode=ModuloStringhe.isEmpty(langCode) is False
|
|
64
|
+
addEnabled=enabled is not None
|
|
65
|
+
|
|
66
|
+
sql="""
|
|
67
|
+
SELECT *
|
|
68
|
+
FROM tb_params
|
|
69
|
+
WHERE type1=%(paramType)s
|
|
70
|
+
"""+("AND key1=%(paramKey)s" if addParamKey is True else "")+"""
|
|
71
|
+
"""+("AND langCode=%(langCode)s" if addLangCode is True else "")+"""
|
|
72
|
+
"""+("AND enabled=%(enabled)s" 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
|
+
|
|
83
|
+
cursoreDb=self.initCursor()
|
|
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
|
+
cursoreDb.execute(sql,params)
|
|
112
|
+
return cursoreDb
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
import mysql.connector
|
|
4
|
+
|
|
5
|
+
from modulitiz_micro.database.exceptions.ExceptionDbNoData import ExceptionDbNoData
|
|
6
|
+
from modulitiz_micro.database.mysql.MysqlCommonConverter import MysqlCommonConverter
|
|
7
|
+
from modulitiz_nano.ModuloListe import ModuloListe
|
|
8
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
|
9
|
+
from modulitiz_nano.database.AbstractSql import AbstractSql
|
|
10
|
+
from modulitiz_nano.exceptions.ExceptionRuntime import ExceptionRuntime
|
|
11
|
+
from modulitiz_nano.files.ModuloFiles import ModuloFiles
|
|
12
|
+
from modulitiz_nano.sistema.ModuloSystem import ModuloSystem
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ModuloMysql(AbstractSql):
|
|
16
|
+
"""
|
|
17
|
+
select
|
|
18
|
+
count
|
|
19
|
+
insert
|
|
20
|
+
update
|
|
21
|
+
delete
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
DATE_TIME_NOW="NOW()"
|
|
25
|
+
|
|
26
|
+
DEFAULT_PORT=3306
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def __init__(self,host: str,port: int|None,user: str,password: str,nomeDb: str,isDebug: bool):
|
|
30
|
+
super().__init__()
|
|
31
|
+
self.nomeDb=nomeDb
|
|
32
|
+
if port is None:
|
|
33
|
+
port=self.DEFAULT_PORT
|
|
34
|
+
# open connection
|
|
35
|
+
self.connDb=mysql.connector.connect(user=user,password=password,host=host,port=port,
|
|
36
|
+
converter_class=MysqlCommonConverter)
|
|
37
|
+
self.TABLE_OPTIONS=self.getTableOptions(isDebug)
|
|
38
|
+
self.isDbNew=None
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def schema(self):
|
|
42
|
+
"""
|
|
43
|
+
Insert here sql instructions containing table definitions (DDL)
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def initDdl(self):
|
|
47
|
+
#scelgo il db
|
|
48
|
+
try:
|
|
49
|
+
self.connDb.cmd_init_db(self.nomeDb)
|
|
50
|
+
self.isDbNew=False
|
|
51
|
+
except mysql.connector.ProgrammingError:
|
|
52
|
+
sqlCreaDb="CREATE DATABASE %s;"%(self.nomeDb,)
|
|
53
|
+
with self.initCursor() as cursoreDb:
|
|
54
|
+
cursoreDb.execute(sqlCreaDb)
|
|
55
|
+
self.connDb.cmd_init_db(self.nomeDb)
|
|
56
|
+
self.isDbNew=True
|
|
57
|
+
#se il db non esisteva creo le tabelle
|
|
58
|
+
if self.isDbNew:
|
|
59
|
+
sqlStr=ModuloStringhe.normalizzaEol(self.schema())
|
|
60
|
+
for results in self.executeScript(sqlStr):
|
|
61
|
+
yield results
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def getLastIdInserted(cursoreDb):
|
|
65
|
+
return cursoreDb.lastrowid
|
|
66
|
+
|
|
67
|
+
def selectNow(self):
|
|
68
|
+
"""
|
|
69
|
+
Returns current db date and time.
|
|
70
|
+
"""
|
|
71
|
+
sql="SELECT {};".format(self.DATE_TIME_NOW)
|
|
72
|
+
with self.initCursor() as cursoreDb:
|
|
73
|
+
cursoreDb.execute(sql,{})
|
|
74
|
+
output=self.fetchOne(cursoreDb)
|
|
75
|
+
return output
|
|
76
|
+
|
|
77
|
+
def executeScript(self,sqlStr:str):
|
|
78
|
+
sqlCmds=sqlStr.split(";")
|
|
79
|
+
sqlCmds=ModuloListe.eliminaElementiVuoti(sqlCmds)
|
|
80
|
+
numCmds=len(sqlCmds)
|
|
81
|
+
with self.initCursor() as cursoreDb:
|
|
82
|
+
for index,sqlCmd in enumerate(sqlCmds):
|
|
83
|
+
sqlCmd=sqlCmd.strip()
|
|
84
|
+
try:
|
|
85
|
+
if sqlCmd!="":
|
|
86
|
+
cursoreDb.execute(sqlCmd)
|
|
87
|
+
yield index,numCmds
|
|
88
|
+
except Exception as ex:
|
|
89
|
+
raise ExceptionRuntime(sqlCmd) from ex
|
|
90
|
+
|
|
91
|
+
def fetchAll(self,cursoreDb)->list:
|
|
92
|
+
with cursoreDb:
|
|
93
|
+
if cursoreDb.description is None:
|
|
94
|
+
raise ExceptionDbNoData()
|
|
95
|
+
descriptions=cursoreDb.description
|
|
96
|
+
rows=cursoreDb.fetchall()
|
|
97
|
+
self.commit() # mysql mette in cache i risultati, lo risolvo così, è un bug loro...
|
|
98
|
+
columns = [col[0] for col in descriptions]
|
|
99
|
+
rows = [dict(zip(columns, row)) for row in rows]
|
|
100
|
+
return rows
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def backup(cls,percorsoCartella: str,user: str,password: str,dbName: str,
|
|
104
|
+
ignoreTables:list|tuple|None)->list:
|
|
105
|
+
output=[
|
|
106
|
+
cls.backupDdl(percorsoCartella,user,password,dbName,ignoreTables),
|
|
107
|
+
cls.backupData(percorsoCartella,user,password,dbName,ignoreTables)
|
|
108
|
+
]
|
|
109
|
+
return output
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def backupDdl(cls,percorsoCartella: str,user: str,password: str,dbName: str,
|
|
113
|
+
ignoreTables:list|tuple|None)->str:
|
|
114
|
+
return cls.__backup(percorsoCartella,user,password,dbName,ignoreTables,True,False)
|
|
115
|
+
@classmethod
|
|
116
|
+
def backupData(cls,percorsoCartella: str,user: str,password: str,dbName: str,
|
|
117
|
+
ignoreTables:list|tuple|None)->str:
|
|
118
|
+
return cls.__backup(percorsoCartella,user,password,dbName,ignoreTables,False,True)
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def __backup(percorsoCartella:str,user:str,password:str,dbName:str,
|
|
122
|
+
ignoreTables:list|tuple|None,onlyDdl:bool,onlyData:bool)->str:
|
|
123
|
+
if onlyDdl and onlyData:
|
|
124
|
+
raise ExceptionRuntime("valorizzare solo un'opzione alla volta")
|
|
125
|
+
cmdIgnoreTables=""
|
|
126
|
+
if ignoreTables is not None:
|
|
127
|
+
cmdIgnoreTables=" ".join(["--ignore-table=%s.%s"%(dbName,x) for x in ignoreTables])
|
|
128
|
+
nomefileSuffix=""
|
|
129
|
+
cmdOptions=""
|
|
130
|
+
if onlyDdl:
|
|
131
|
+
nomefileSuffix="_ddl"
|
|
132
|
+
cmdOptions="--no-data "+cmdIgnoreTables
|
|
133
|
+
elif onlyData:
|
|
134
|
+
nomefileSuffix="_data"
|
|
135
|
+
cmdOptions="--order-by-primary --no-create-info --quick "+cmdIgnoreTables
|
|
136
|
+
nomefileOutput=dbName+nomefileSuffix+".sql"
|
|
137
|
+
percorsoFileBackup=ModuloFiles.pathJoin(percorsoCartella,nomefileOutput)
|
|
138
|
+
cmd=r'mysqldump -u {} -p{} --databases {} --skip-add-drop-table --skip-comments {} -r "{}"'.format(user,password,dbName,cmdOptions,percorsoFileBackup)
|
|
139
|
+
output=ModuloSystem.systemCallReturnOutput(cmd,None).strip()
|
|
140
|
+
if not ModuloStringhe.isEmpty(output):
|
|
141
|
+
raise ExceptionRuntime(output)
|
|
142
|
+
return percorsoFileBackup
|
|
143
|
+
|
|
144
|
+
@staticmethod
|
|
145
|
+
def getTableOptions(isDebug: bool) -> str:
|
|
146
|
+
return "ENGINE=%s DEFAULT CHARSET=utf8"%("InnoDB" if not isDebug else "MEMORY",)
|
|
147
|
+
|
|
148
|
+
def paginazione(firstResult:int|None,numResults:int|None)->str:
|
|
149
|
+
sql=("LIMIT "+str(numResults) if numResults is not None else "")+\
|
|
150
|
+
(" OFFSET "+str(firstResult) if firstResult is not None else "")
|
|
151
|
+
return sql
|
|
152
|
+
|
|
153
|
+
def add_param_list(lista:list,prefix:str)->dict:
|
|
154
|
+
params={}
|
|
155
|
+
for index,elem in enumerate(lista):
|
|
156
|
+
params[prefix+str(index)]=elem
|
|
157
|
+
return params
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from typing import override
|
|
3
|
+
|
|
4
|
+
from mysql.connector import FieldType
|
|
5
|
+
from mysql.connector.conversion import MySQLConverter
|
|
6
|
+
from mysql.connector.types import DescriptionType
|
|
7
|
+
from mysql.connector.types import MySQLConvertibleType
|
|
8
|
+
from mysql.connector.types import MySQLProducedType
|
|
9
|
+
from mysql.connector.types import PythonProducedType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MysqlCommonConverter(MySQLConverter):
|
|
13
|
+
def __init__(self,charset: str|None = None,
|
|
14
|
+
use_unicode: bool = True,
|
|
15
|
+
str_fallback: bool = False):
|
|
16
|
+
super().__init__(charset,use_unicode,str_fallback)
|
|
17
|
+
|
|
18
|
+
@override
|
|
19
|
+
@classmethod
|
|
20
|
+
def _bit_to_python(cls,value: bytes, dsc: Optional[DescriptionType] = None) -> bool:
|
|
21
|
+
return super()._bit_to_python(value, dsc)==1
|
|
22
|
+
|
|
23
|
+
@override
|
|
24
|
+
def to_mysql(self,value) -> MySQLProducedType:
|
|
25
|
+
value=self.__to_mysql(value)
|
|
26
|
+
# default behavior
|
|
27
|
+
return super().to_mysql(value)
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def __to_mysql(value):
|
|
31
|
+
"""
|
|
32
|
+
Gestione custom, ad esempio per IntEnum e StrEnum
|
|
33
|
+
"""
|
|
34
|
+
if value.__class__ in MySQLConvertibleType.__args__:
|
|
35
|
+
return value
|
|
36
|
+
# inizio gestione custom
|
|
37
|
+
if isinstance(value,int):
|
|
38
|
+
typePrimitive=int
|
|
39
|
+
elif isinstance(value,str):
|
|
40
|
+
typePrimitive=str
|
|
41
|
+
else:
|
|
42
|
+
return value
|
|
43
|
+
value.__class__.__name__=typePrimitive.__name__
|
|
44
|
+
return value
|
|
45
|
+
|
|
46
|
+
@override
|
|
47
|
+
def to_python(
|
|
48
|
+
self,
|
|
49
|
+
vtype: DescriptionType,
|
|
50
|
+
value: Optional[bytes],
|
|
51
|
+
) -> PythonProducedType:
|
|
52
|
+
if vtype[1] == FieldType.BIT:
|
|
53
|
+
return value==b'\x01'
|
|
54
|
+
# default behavior
|
|
55
|
+
return super().to_python(vtype, value)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from bs4 import BeautifulSoup
|
|
2
|
+
from bs4 import ResultSet
|
|
3
|
+
from bs4 import Tag
|
|
4
|
+
|
|
5
|
+
from modulitiz_nano.files.ModuloFiles import ModuloFiles
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DomModule(object):
|
|
9
|
+
def __init__(self, filePath: str|None, htmlString: str|None):
|
|
10
|
+
if filePath is not None:
|
|
11
|
+
self.filePath=filePath
|
|
12
|
+
htmlString=ModuloFiles.readFileText(filePath, True)
|
|
13
|
+
self.htmlString=htmlString
|
|
14
|
+
self.dom=self.__createObj()
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def innerHTML(tag:Tag)->str:
|
|
18
|
+
"""
|
|
19
|
+
dato in input un tag html della classe BeautifulSoup, restituisce il codice html all'interno di questo tag
|
|
20
|
+
"""
|
|
21
|
+
return "".join([str(x) for x in tag.contents])
|
|
22
|
+
|
|
23
|
+
def selector(self,cssSelector:str)->ResultSet[Tag]:
|
|
24
|
+
"""
|
|
25
|
+
estrae tutti gli elementi che corrispondono al css selector
|
|
26
|
+
"""
|
|
27
|
+
return self.dom.select(cssSelector)
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def getAttributeValue(tag:Tag, nomeAttr:str):
|
|
31
|
+
return tag.attrs[nomeAttr]
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def setAttributeValue(tag:Tag, nomeAttr:str, value):
|
|
35
|
+
tag.attrs[nomeAttr]=value
|
|
36
|
+
return tag
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def setInnerHtml(tag:Tag, value):
|
|
40
|
+
tag.string=value
|
|
41
|
+
|
|
42
|
+
def save(self):
|
|
43
|
+
htmlOut=str(self.dom).encode()
|
|
44
|
+
with open(self.filePath, "wb") as file:
|
|
45
|
+
file.write(htmlOut)
|
|
46
|
+
|
|
47
|
+
def __createObj(self)->BeautifulSoup:
|
|
48
|
+
return BeautifulSoup(self.htmlString, features="xml")
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
|
|
3
|
+
from cachetools import TTLCache
|
|
4
|
+
from cachetools import cached
|
|
5
|
+
|
|
6
|
+
from modulitiz_nano.ModuloNumeri import ModuloNumeri
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def cacheRam(minsBeforeExpiry: int|float|None):
|
|
10
|
+
"""
|
|
11
|
+
Usare questo decorator per mettere in cache delle informazioni.
|
|
12
|
+
Alla base usa una libreria di terze parti.
|
|
13
|
+
:param minsBeforeExpiry: se null mantiene i dati in memoria per 1 giorno
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
__secsBeforeExpiry=24*3600 if minsBeforeExpiry is None else ModuloNumeri.decimalNumbersTruncate(minsBeforeExpiry*60,2)
|
|
17
|
+
__cache=cached(TTLCache(20,__secsBeforeExpiry))
|
|
18
|
+
|
|
19
|
+
def decorator(funzione):
|
|
20
|
+
__funzione=__cache(funzione)
|
|
21
|
+
|
|
22
|
+
@wraps(funzione)
|
|
23
|
+
def wrapped(*args,**kwargs):
|
|
24
|
+
return __funzione(*args,**kwargs)
|
|
25
|
+
return wrapped
|
|
26
|
+
return decorator
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import git
|
|
2
|
+
|
|
3
|
+
from modulitiz_micro.files.git.decorators.catchAndRaiseGitExceptions import catchAndRaiseGitExceptions
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ModuloGit(object):
|
|
7
|
+
def __init__(self, repoPath:str):
|
|
8
|
+
self.inner=git.Repo(repoPath)
|
|
9
|
+
|
|
10
|
+
@catchAndRaiseGitExceptions
|
|
11
|
+
def getWorkingCopyRevision(self)->str:
|
|
12
|
+
return self.inner.head.object.hexsha
|
|
13
|
+
|
|
14
|
+
@catchAndRaiseGitExceptions
|
|
15
|
+
def getRemoteRevision(self)->str:
|
|
16
|
+
return self.inner.remotes[0].fetch()[0].ref.object.hexsha
|
|
17
|
+
|
|
18
|
+
@catchAndRaiseGitExceptions
|
|
19
|
+
def addFile(self,filenamePath:str):
|
|
20
|
+
self.inner.index.add(filenamePath)
|
|
21
|
+
|
|
22
|
+
@catchAndRaiseGitExceptions
|
|
23
|
+
def removeFile(self,filenamePath:str):
|
|
24
|
+
self.inner.index.remove(filenamePath,working_tree=True)
|
|
25
|
+
|
|
26
|
+
@catchAndRaiseGitExceptions
|
|
27
|
+
def resetCurrentLocalBranch(self):
|
|
28
|
+
self.inner.head.reset(working_tree=True)
|
|
29
|
+
|
|
30
|
+
@catchAndRaiseGitExceptions
|
|
31
|
+
def update(self)->str:
|
|
32
|
+
return self.inner.remotes[0].pull()[0].ref.object.hexsha
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
|
|
3
|
+
from git import GitCommandError
|
|
4
|
+
|
|
5
|
+
from modulitiz_micro.files.git.exceptions.ExceptionGit import ExceptionGit
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def catchAndRaiseGitExceptions(function):
|
|
9
|
+
"""
|
|
10
|
+
Cattura tutte le eccezioni git di vario tipo e rilancia un'eccezione custom
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@wraps(function)
|
|
14
|
+
def wrapped(*args,**kwargs):
|
|
15
|
+
try:
|
|
16
|
+
return function(*args,**kwargs)
|
|
17
|
+
except (GitCommandError,) as ex:
|
|
18
|
+
raise ExceptionGit() from ex
|
|
19
|
+
return wrapped
|