lbxtoolkit 2.4.2__tar.gz → 2.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/PKG-INFO +1 -1
- lbxtoolkit-2.4.4/lbxtoolkit/backup_NewModuleMode_2.4.3.zip +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/postgresql.py +45 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/service.py +9 -4
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/service_windows.py +41 -13
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/pyproject.toml +1 -1
- lbxtoolkit-2.4.2/lbxtoolkit/lbxtoolkit.zip +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/README.md +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/__init__.py +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/api_rest.py +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/auth_entra_id.py +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/chrome_session.py +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/config_manager.py +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/lbx_logger.py +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/locators.py +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/misc.py +0 -0
- {lbxtoolkit-2.4.2 → lbxtoolkit-2.4.4}/lbxtoolkit/webdrive_handler.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lbxtoolkit
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.4
|
|
4
4
|
Summary: Caixa ferramentas da LBX para automações de processos (RPA), integrações, utilitários Windows e componentes reutilizáveis.
|
|
5
5
|
Author: Cristiano P. Ferrari
|
|
6
6
|
Author-email: cristiano.ferrari@lbx.com.br
|
|
Binary file
|
|
@@ -290,3 +290,48 @@ conexao.close()
|
|
|
290
290
|
raise
|
|
291
291
|
#
|
|
292
292
|
#
|
|
293
|
+
def db_execute(self, Query, Fetch=False): # Executa comandos SQL complexos, inclusive DML com CTE
|
|
294
|
+
"""
|
|
295
|
+
Executa comandos SQL de manipulação de dados que não se enquadram nos métodos
|
|
296
|
+
db_select(), db_update() ou db_insert_df().
|
|
297
|
+
|
|
298
|
+
Use este método para comandos DML complexos, especialmente UPDATE/INSERT/DELETE
|
|
299
|
+
com CTE (WITH), subqueries ou RETURNING.
|
|
300
|
+
|
|
301
|
+
Por segurança, comandos de DDL e execução dinâmica não são permitidos.
|
|
302
|
+
|
|
303
|
+
Parâmetros:
|
|
304
|
+
- Query: Comando SQL a executar.
|
|
305
|
+
- Fetch: Quando True, retorna os dados do cursor e os nomes das colunas
|
|
306
|
+
se o comando produzir resultset (ex: RETURNING).
|
|
307
|
+
|
|
308
|
+
Retorno:
|
|
309
|
+
- Se Fetch=True e houver resultset: (Dados, Colunas)
|
|
310
|
+
- Caso contrário: quantidade de linhas afetadas
|
|
311
|
+
"""
|
|
312
|
+
UpdRows = 0
|
|
313
|
+
BlackList = ['CREATE ', 'DROP ', 'ALTER ', 'TRUNCATE ', 'REPLACE ', 'CALL ', 'EXECUTE ']
|
|
314
|
+
|
|
315
|
+
if any(element in Query.upper() for element in BlackList):
|
|
316
|
+
BlackListed = [element for element in BlackList if element in Query.upper()]
|
|
317
|
+
self.logger.erro(f'{__name__}: Este método não permite comandos DDL ou execução dinâmica. A query informada possui as seguintes palavras reservadas não aceitas: {BlackListed} e não foi executada!')
|
|
318
|
+
return None
|
|
319
|
+
else:
|
|
320
|
+
try:
|
|
321
|
+
self.Cursor = self.Conexao.cursor()
|
|
322
|
+
self.Cursor.execute(Query)
|
|
323
|
+
UpdRows = self.Cursor.rowcount
|
|
324
|
+
|
|
325
|
+
if Fetch and self.Cursor.description:
|
|
326
|
+
Dados = self.Cursor.fetchall()
|
|
327
|
+
Colunas = [Col[0] for Col in self.Cursor.description]
|
|
328
|
+
self.Conexao.commit()
|
|
329
|
+
self.Cursor.close()
|
|
330
|
+
return Dados, Colunas
|
|
331
|
+
|
|
332
|
+
self.Conexao.commit()
|
|
333
|
+
self.Cursor.close()
|
|
334
|
+
return UpdRows
|
|
335
|
+
except Exception as Err:
|
|
336
|
+
self.Conexao.rollback()
|
|
337
|
+
raise
|
|
@@ -62,8 +62,8 @@ from pathlib import Path
|
|
|
62
62
|
from lbxtoolkit import Servicer, ServicoWindows, lbx_logger
|
|
63
63
|
|
|
64
64
|
class ServicerConfig(Servicer):
|
|
65
|
-
def __init__(self, Log=None, piddir=None): ## Log e piddir são parametros mandatórios. outros parametros posicionais ou nominais (*args e **kwargs) pode ser adicionados aqui para serem utilizados pelos métodos locais
|
|
66
|
-
super().__init__(Log=Log, piddir=piddir) ## provoca a inicialização da classe pai
|
|
65
|
+
def __init__(self, Log=None, piddir=None, NewModuleMode=False): ## Log e piddir são parametros mandatórios. outros parametros posicionais ou nominais (*args e **kwargs) pode ser adicionados aqui para serem utilizados pelos métodos locais
|
|
66
|
+
super().__init__(Log=Log, piddir=piddir, NewModuleMode=NewModuleMode) ## provoca a inicialização da classe pai
|
|
67
67
|
## complete o código de instanciamento da classe aqui, se necessário
|
|
68
68
|
## os métodos on_init(), on_init_pre() e on_init_pos()
|
|
69
69
|
## SOBRECARGA DOS MÉTODOS DA CLASSE PAI
|
|
@@ -141,7 +141,8 @@ class ServicerConfig(Servicer):
|
|
|
141
141
|
argparse_opt=ArgparseOpt,
|
|
142
142
|
ambiente=Ambiente
|
|
143
143
|
)
|
|
144
|
-
|
|
144
|
+
NewModuleMode = misc.to_bool(os.getenv('NEW_MODULE_MODE'), False)
|
|
145
|
+
Daemon = ServicerConfig(DirRetorno, Log=LogDaemon, piddir=DirPIDDaemons, NewModuleMode=NewModuleMode)
|
|
145
146
|
ConfigManager.set('daemon',Daemon)
|
|
146
147
|
|
|
147
148
|
if __name__ == "__main__":
|
|
@@ -149,7 +150,7 @@ class ServicerConfig(Servicer):
|
|
|
149
150
|
Daemon.main()
|
|
150
151
|
```
|
|
151
152
|
"""
|
|
152
|
-
def __init__(self, Log=None, piddir=None):#TODO: ao criar uma classe padrão usar args/kwargs para lidar como parametros variáveis no instanciamento
|
|
153
|
+
def __init__(self, Log=None, piddir=None, NewModuleMode: bool = False):#TODO: ao criar uma classe padrão usar args/kwargs para lidar como parametros variáveis no instanciamento
|
|
153
154
|
"""
|
|
154
155
|
variáveis abaixo são mandatórias e precisa inicializadas no ConfigManager.inicialize() do módulo principal/pai:
|
|
155
156
|
- log
|
|
@@ -173,6 +174,10 @@ class ServicerConfig(Servicer):
|
|
|
173
174
|
raise ValueError(f'Argumento "argparse_opt" é mandatório e deve ser uma lista de dicionários ao mínimo as chaves: [short, long, action, help] para tratamento dos argumentos recebidos da linha de comando')
|
|
174
175
|
if self.ambiente is None or self.ambiente not in ['Linux', 'Windows', 'Serviço']:
|
|
175
176
|
raise ValueError(f'Argumento "ambiente" é mandatório e deve ser uma string com um dos seguintes valores: [Linux, Windows, Serviço]')
|
|
177
|
+
if not isinstance(NewModuleMode, bool):
|
|
178
|
+
raise ValueError(f'Argumento "NewModuleMode" deve ser booleano [True ou False]')
|
|
179
|
+
|
|
180
|
+
self.NewModuleMode = NewModuleMode
|
|
176
181
|
|
|
177
182
|
self.on_init_pre() ## método opcional a ser definito por sobrecarga na função local
|
|
178
183
|
|
|
@@ -98,13 +98,18 @@ O objetos mandatórios a serem inicilizados pelo **ConfigManager** são:
|
|
|
98
98
|
_svc_display_name_ = config['display_name']
|
|
99
99
|
_svc_description_ = config['description']
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
python_path =
|
|
101
|
+
NewModuleMode = getattr(daemon, 'NewModuleMode', False)
|
|
102
|
+
|
|
103
|
+
if NewModuleMode:
|
|
104
|
+
## Novo padrão de execução por módulo.
|
|
105
|
+
## Usa exatamente o interpretador que executou o comando "install",
|
|
106
|
+
## independentemente de onde o ambiente virtual esteja armazenado.
|
|
107
|
+
python_path = Path(sys.executable).resolve()
|
|
108
|
+
if not python_path.is_file():
|
|
109
|
+
raise FileNotFoundError(
|
|
110
|
+
f'Interpretador Python não encontrado: {python_path}'
|
|
111
|
+
)
|
|
112
|
+
|
|
108
113
|
wrapper = Path(raiz_projeto, f'wrapper_servico_{modulo}.bat') ## tem que ser igual a SvcRemove. Mudou lá, muda aqui.
|
|
109
114
|
wrapper_content = f"""
|
|
110
115
|
@echo off
|
|
@@ -113,16 +118,39 @@ REM !!!!NÃO TOQUE NESSE ARQUIVO. NÃO O APAQUE NEM O MODIFIQUE.!!!!
|
|
|
113
118
|
REM O serviço do windows [{config['display_name']}] que roda nesta máquina depende do conteúdo deste arquivo de lotes.
|
|
114
119
|
REM ==================================================================================================================
|
|
115
120
|
set PYTHONPATH=%~dp0
|
|
116
|
-
"
|
|
117
|
-
"""
|
|
121
|
+
"{python_path}" -m {modulo} %*
|
|
122
|
+
"""
|
|
118
123
|
with open(wrapper, "w", encoding="utf-8") as file:
|
|
119
124
|
file.write(wrapper_content)
|
|
120
125
|
service_cmd = f'{wrapper}'
|
|
121
126
|
|
|
122
|
-
else:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
else:
|
|
128
|
+
## Comportamento anterior preservado integralmente para compatibilidade com o legado.
|
|
129
|
+
## Suporta tanto a criação de execução direta do .py como por módulo.
|
|
130
|
+
## A lógica é que raiz_projeto e modulo só sejam definidos se o projeto foi estruturado
|
|
131
|
+
## para execução por módulo/entrypoint (python -m ou poetry run).
|
|
132
|
+
if raiz_projeto and modulo: ## execução por módulo no padrão anterior
|
|
133
|
+
service_path = None
|
|
134
|
+
python_path = None
|
|
135
|
+
wrapper = Path(raiz_projeto, f'wrapper_servico_{modulo}.bat') ## tem que ser igual a SvcRemove. Mudou lá, muda aqui.
|
|
136
|
+
wrapper_content = f"""
|
|
137
|
+
@echo off
|
|
138
|
+
REM ==================================================================================================================
|
|
139
|
+
REM !!!!NÃO TOQUE NESSE ARQUIVO. NÃO O APAQUE NEM O MODIFIQUE.!!!!
|
|
140
|
+
REM O serviço do windows [{config['display_name']}] que roda nesta máquina depende do conteúdo deste arquivo de lotes.
|
|
141
|
+
REM ==================================================================================================================
|
|
142
|
+
set PYTHONPATH=%~dp0
|
|
143
|
+
"%~dp0.venv\\Scripts\\python.exe" -m {modulo} %*
|
|
144
|
+
"""
|
|
145
|
+
with open(wrapper, "w", encoding="utf-8") as file:
|
|
146
|
+
file.write(wrapper_content)
|
|
147
|
+
service_cmd = f'{wrapper}'
|
|
148
|
+
|
|
149
|
+
else: ## execução direta do script (legado)
|
|
150
|
+
service_path = ConfigManager.get('service_path') if ConfigManager.get('service_path') else os.path.abspath(__file__)
|
|
151
|
+
python_path = ConfigManager.get('python_path') if ConfigManager.get('python_path') else os.path.join(os.getenv('VIRTUAL_ENV'), 'Scripts', 'python.exe') if os.getenv('VIRTUAL_ENV') else sys.executable
|
|
152
|
+
service_cmd = f'{python_path} {service_path}'
|
|
153
|
+
|
|
126
154
|
|
|
127
155
|
|
|
128
156
|
IP = socket.gethostbyname(socket.gethostname())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "lbxtoolkit"
|
|
3
|
-
version = "2.4.
|
|
3
|
+
version = "2.4.4"
|
|
4
4
|
description = "Caixa ferramentas da LBX para automações de processos (RPA), integrações, utilitários Windows e componentes reutilizáveis."
|
|
5
5
|
authors = ["Cristiano P. Ferrari <cristiano.ferrari@lbx.com.br>"]
|
|
6
6
|
readme = "README.md"
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|