lbxtoolkit 2.4.4__tar.gz → 2.4.5__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.4 → lbxtoolkit-2.4.5}/PKG-INFO +3 -3
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/api_rest.py +3 -2
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/misc.py +31 -6
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/service.py +10 -2
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/service_windows.py +34 -6
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/pyproject.toml +3 -3
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/README.md +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/__init__.py +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/auth_entra_id.py +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/backup_NewModuleMode_2.4.3.zip +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/chrome_session.py +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/config_manager.py +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/lbx_logger.py +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/locators.py +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/lbxtoolkit/postgresql.py +0 -0
- {lbxtoolkit-2.4.4 → lbxtoolkit-2.4.5}/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.5
|
|
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
|
|
@@ -14,8 +14,8 @@ Requires-Dist: numpy (>=2.0.1)
|
|
|
14
14
|
Requires-Dist: pandas (>=2.2.2)
|
|
15
15
|
Requires-Dist: psutil (>=6.0.0)
|
|
16
16
|
Requires-Dist: psycopg2 (>=2.9.9)
|
|
17
|
-
Requires-Dist: pygetwindow (>=0.0.9)
|
|
18
|
-
Requires-Dist: pywin32 (>=306)
|
|
17
|
+
Requires-Dist: pygetwindow (>=0.0.9) ; sys_platform == "win32"
|
|
18
|
+
Requires-Dist: pywin32 (>=306) ; sys_platform == "win32"
|
|
19
19
|
Requires-Dist: requests (>=2.32.3)
|
|
20
20
|
Requires-Dist: selenium (>=4.23.1)
|
|
21
21
|
Requires-Dist: validators (>=0.33.0)
|
|
@@ -265,8 +265,9 @@ Para uso em APIs com autenticação JWT (JSON Web Token), OAuth, Bearer Token Au
|
|
|
265
265
|
MsgErro = Retorno
|
|
266
266
|
except:
|
|
267
267
|
MsgErro = Retorno.replace(r'\n\t',' ')
|
|
268
|
-
finally:
|
|
269
|
-
|
|
268
|
+
# antes: "finally: return MsgErro" — mesmo efeito, sem o
|
|
269
|
+
# SyntaxWarning do Python 3.14 (PEP 765: return em finally)
|
|
270
|
+
return MsgErro
|
|
270
271
|
else:
|
|
271
272
|
return Retorno
|
|
272
273
|
#
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import ctypes
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
|
-
import tkinter as tk
|
|
5
4
|
from pathlib import Path
|
|
6
|
-
from tkinter import filedialog
|
|
7
5
|
from typing import Any, Optional
|
|
8
6
|
from unicodedata import normalize
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
# Dependências gráficas/Windows são opcionais: em Linux headless (VPS) o
|
|
9
|
+
# tkinter pode não existir e o pygetwindow lança NotImplementedError no import.
|
|
10
|
+
# Os métodos que dependem delas verificam a disponibilidade em tempo de execução.
|
|
11
|
+
try:
|
|
12
|
+
import tkinter as tk
|
|
13
|
+
from tkinter import filedialog
|
|
14
|
+
except ImportError: # pragma: no cover - depende da plataforma
|
|
15
|
+
tk = None # type: ignore[assignment]
|
|
16
|
+
filedialog = None # type: ignore[assignment]
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
import pygetwindow as gw
|
|
20
|
+
except (ImportError, NotImplementedError): # pragma: no cover - depende da plataforma
|
|
21
|
+
gw = None # type: ignore[assignment]
|
|
11
22
|
|
|
12
23
|
|
|
13
24
|
class misc:
|
|
@@ -55,6 +66,9 @@ class misc:
|
|
|
55
66
|
if TiposArquivo is None:
|
|
56
67
|
TiposArquivo = [("Todos os arquivos", "*.*")]
|
|
57
68
|
|
|
69
|
+
if tk is None or filedialog is None:
|
|
70
|
+
raise RuntimeError("seleciona_arquivo indisponível: tkinter não está instalado neste ambiente")
|
|
71
|
+
|
|
58
72
|
root = tk.Tk()
|
|
59
73
|
root.withdraw()
|
|
60
74
|
|
|
@@ -83,6 +97,9 @@ class misc:
|
|
|
83
97
|
Caminho do diretório selecionado como `Path`.
|
|
84
98
|
Se o usuário cancelar, retorna `Path('.')`.
|
|
85
99
|
"""
|
|
100
|
+
if tk is None or filedialog is None:
|
|
101
|
+
raise RuntimeError("seleciona_dir indisponível: tkinter não está instalado neste ambiente")
|
|
102
|
+
|
|
86
103
|
root = tk.Tk()
|
|
87
104
|
root.withdraw()
|
|
88
105
|
|
|
@@ -167,8 +184,12 @@ class misc:
|
|
|
167
184
|
|
|
168
185
|
Returns:
|
|
169
186
|
Objeto de janela retornado por `pygetwindow`, ou `None`
|
|
170
|
-
se nenhuma janela adequada for encontrada
|
|
187
|
+
se nenhuma janela adequada for encontrada ou se a plataforma
|
|
188
|
+
não suportar `pygetwindow` (ex.: Linux).
|
|
171
189
|
"""
|
|
190
|
+
if gw is None:
|
|
191
|
+
return None
|
|
192
|
+
|
|
172
193
|
windows = gw.getWindowsWithTitle("")
|
|
173
194
|
for window in windows:
|
|
174
195
|
if window.title and window.visible and window.topleft:
|
|
@@ -181,8 +202,12 @@ class misc:
|
|
|
181
202
|
"""
|
|
182
203
|
Maximiza a janela atual do console no Windows.
|
|
183
204
|
|
|
184
|
-
Não faz nada se o handle da janela não puder ser obtido
|
|
205
|
+
Não faz nada se o handle da janela não puder ser obtido
|
|
206
|
+
ou se a plataforma não for Windows.
|
|
185
207
|
"""
|
|
208
|
+
if os.name != "nt":
|
|
209
|
+
return
|
|
210
|
+
|
|
186
211
|
kernel32 = ctypes.WinDLL("kernel32")
|
|
187
212
|
user32 = ctypes.WinDLL("user32")
|
|
188
213
|
hWnd = kernel32.GetConsoleWindow()
|
|
@@ -487,4 +512,4 @@ class misc:
|
|
|
487
512
|
try:
|
|
488
513
|
return int(str(valor).strip())
|
|
489
514
|
except ValueError as exc:
|
|
490
|
-
raise RuntimeError(f"Variável de ambiente {nome} deve ser numérica.") from exc
|
|
515
|
+
raise RuntimeError(f"Variável de ambiente {nome} deve ser numérica.") from exc
|
|
@@ -8,8 +8,12 @@ from pathlib import Path
|
|
|
8
8
|
import platform
|
|
9
9
|
import socket
|
|
10
10
|
import argparse
|
|
11
|
-
|
|
12
|
-
import
|
|
11
|
+
try:
|
|
12
|
+
import servicemanager #type: ignore
|
|
13
|
+
import win32serviceutil #type: ignore
|
|
14
|
+
except ImportError: # pragma: no cover - fora do Windows
|
|
15
|
+
servicemanager = None # type: ignore[assignment]
|
|
16
|
+
win32serviceutil = None # type: ignore[assignment]
|
|
13
17
|
|
|
14
18
|
class Servicer(): # Cria um daemon para rodar como serviço
|
|
15
19
|
"""
|
|
@@ -216,6 +220,10 @@ class ServicerConfig(Servicer):
|
|
|
216
220
|
elif [chave for chave in config if config[chave] is None]:
|
|
217
221
|
raise ValueError(f'Argumento "config" ({config}) possui as seguintes chaves com valores inválidos [None]: {[chave for chave in config if config[chave] is None]:}')
|
|
218
222
|
|
|
223
|
+
_cmd_servico = len(sys.argv) > 1 and sys.argv[1] in ['install', 'remove', 'start', 'stop', 'restart', 'debug']
|
|
224
|
+
if (servicemanager is None or win32serviceutil is None) and (_cmd_servico or self.ambiente == 'Serviço'):
|
|
225
|
+
raise RuntimeError('Gerenciamento de serviço Windows indisponível nesta plataforma (pywin32 ausente); no Linux use systemd')
|
|
226
|
+
|
|
219
227
|
ServicoWindows._svc_name_ = config['name']
|
|
220
228
|
ServicoWindows._svc_display_name_ = config['display_name']
|
|
221
229
|
ServicoWindows._svc_description_ = config['description']
|
|
@@ -7,12 +7,38 @@ from pathlib import Path
|
|
|
7
7
|
import subprocess
|
|
8
8
|
import platform
|
|
9
9
|
import socket
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
# pywin32 só existe no Windows. Em outras plataformas o módulo continua
|
|
11
|
+
# importável (o __init__ do pacote o importa sempre), mas a classe não pode
|
|
12
|
+
# ser instanciada — no Linux o equivalente é uma unit do systemd.
|
|
13
|
+
try:
|
|
14
|
+
import servicemanager
|
|
15
|
+
import win32serviceutil
|
|
16
|
+
import win32service
|
|
17
|
+
import win32event
|
|
18
|
+
_BaseServico = win32serviceutil.ServiceFramework
|
|
19
|
+
PYWIN32_DISPONIVEL = True
|
|
20
|
+
except ImportError: # pragma: no cover - depende da plataforma
|
|
21
|
+
servicemanager = None # type: ignore[assignment]
|
|
22
|
+
win32serviceutil = None # type: ignore[assignment]
|
|
23
|
+
win32service = None # type: ignore[assignment]
|
|
24
|
+
win32event = None # type: ignore[assignment]
|
|
25
|
+
PYWIN32_DISPONIVEL = False
|
|
14
26
|
|
|
15
|
-
class
|
|
27
|
+
class _BaseServico: # type: ignore[no-redef]
|
|
28
|
+
"""
|
|
29
|
+
Base substituta usada quando o pywin32 não está disponível.
|
|
30
|
+
|
|
31
|
+
Permite importar o pacote fora do Windows; qualquer tentativa de
|
|
32
|
+
instanciar o serviço falha com mensagem explícita.
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
ServicoWindows(args) # RuntimeError fora do Windows
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
39
|
+
raise RuntimeError("ServicoWindows requer pywin32 (somente Windows); no Linux use systemd")
|
|
40
|
+
|
|
41
|
+
class ServicoWindows(_BaseServico): # type: ignore[misc, valid-type] # Gerencia a execução/instalação como serviço do windows
|
|
16
42
|
"""
|
|
17
43
|
#### Classe **ServicoWindows**
|
|
18
44
|
|
|
@@ -41,6 +67,8 @@ O objetos mandatórios a serem inicilizados pelo **ConfigManager** são:
|
|
|
41
67
|
_svc_display_name_ = None
|
|
42
68
|
_svc_description_ = None
|
|
43
69
|
def __init__(self, args):
|
|
70
|
+
if not PYWIN32_DISPONIVEL:
|
|
71
|
+
raise RuntimeError("ServicoWindows requer pywin32 (somente Windows); no Linux use systemd")
|
|
44
72
|
self.log = ConfigManager.get('log')
|
|
45
73
|
self.daemon = ConfigManager.get('daemon')
|
|
46
74
|
self.config = ConfigManager.get('config')
|
|
@@ -357,4 +385,4 @@ set PYTHONPATH=%~dp0
|
|
|
357
385
|
finally:
|
|
358
386
|
log.info('daemon encerrado!')
|
|
359
387
|
#
|
|
360
|
-
#
|
|
388
|
+
#
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "lbxtoolkit"
|
|
3
|
-
version = "2.4.
|
|
3
|
+
version = "2.4.5"
|
|
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"
|
|
@@ -16,8 +16,8 @@ requests = ">=2.32.3"
|
|
|
16
16
|
selenium = ">=4.23.1"
|
|
17
17
|
webdriver-manager = ">=4.0.2"
|
|
18
18
|
validators = ">=0.33.0"
|
|
19
|
-
pygetwindow = ">=0.0.9"
|
|
20
|
-
pywin32 = ">=306"
|
|
19
|
+
pygetwindow = { version = ">=0.0.9", markers = "sys_platform == 'win32'" }
|
|
20
|
+
pywin32 = { version = ">=306", markers = "sys_platform == 'win32'" }
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
[tool.poetry.group.docs.dependencies]
|
|
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
|