bcpkgfox 0.15.30__py3-none-any.whl → 0.17.7__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.
Potentially problematic release.
This version of bcpkgfox might be problematic. Click here for more details.
- bcpkgfox/__init__.py +79 -26
- bcpkgfox/clean.py +257 -0
- bcpkgfox/cli.py +465 -138
- bcpkgfox/find_elements.py +33 -8
- bcpkgfox/get_driver.py +33 -14
- bcpkgfox/invoke_api.py +386 -88
- bcpkgfox/system.py +42 -9
- {bcpkgfox-0.15.30.dist-info → bcpkgfox-0.17.7.dist-info}/METADATA +20 -4
- bcpkgfox-0.17.7.dist-info/RECORD +12 -0
- {bcpkgfox-0.15.30.dist-info → bcpkgfox-0.17.7.dist-info}/WHEEL +1 -1
- bcpkgfox-0.17.7.dist-info/entry_points.txt +22 -0
- bcpkgfox/cli 2.py +0 -536
- bcpkgfox/cli copy 2.py +0 -237
- bcpkgfox/cli copy.py +0 -306
- bcpkgfox/cli2.py +0 -303
- bcpkgfox/dasdad.py +0 -68
- bcpkgfox/exec_file copy 2.py +0 -100
- bcpkgfox/exec_file copy.py +0 -99
- bcpkgfox/exec_file.py +0 -100
- bcpkgfox-0.15.30.dist-info/RECORD +0 -19
- bcpkgfox-0.15.30.dist-info/entry_points.txt +0 -2
- {bcpkgfox-0.15.30.dist-info → bcpkgfox-0.17.7.dist-info}/top_level.txt +0 -0
bcpkgfox/__init__.py
CHANGED
|
@@ -96,6 +96,20 @@ def create_dirs(specifics_dirs: Optional[list] = None, disable_print_response: b
|
|
|
96
96
|
else:
|
|
97
97
|
print(f" {DK_ORANGE}>{RESET} Todos os diretórios padrões presentes")
|
|
98
98
|
|
|
99
|
+
def resource_path(relative_path):
|
|
100
|
+
"""
|
|
101
|
+
Returns the absolute path of a resource, whether running normally or in a PyInstaller executable.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
relative_path (str): Relative path of the resource.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
str: Absolute path of the resource.
|
|
108
|
+
"""
|
|
109
|
+
try: base_path = sys._MEIPASS
|
|
110
|
+
except AttributeError: base_path = os.path.abspath(".")
|
|
111
|
+
return os.path.join(base_path, relative_path)
|
|
112
|
+
|
|
99
113
|
def initialize_driver(extension_path: Optional[str] = None, captcha_name: Optional[str] = None, captcha_api_key: Optional[str] = None) -> WebElement:
|
|
100
114
|
|
|
101
115
|
""" Passe somente o nome da pasta, no mesmo diretório da main """
|
|
@@ -211,7 +225,7 @@ def wait_for_element_disappear(object, type, timeout=10):
|
|
|
211
225
|
|
|
212
226
|
return find_elements.backcode__dont_use__wait_for_d(driver, object, type, timeout=tempo)
|
|
213
227
|
|
|
214
|
-
def selectfox(elemento, method, key):
|
|
228
|
+
def selectfox(elemento, method, key, relative = None):
|
|
215
229
|
"""
|
|
216
230
|
Seleciona uma opção em um elemento <select>.
|
|
217
231
|
|
|
@@ -219,6 +233,7 @@ def selectfox(elemento, method, key):
|
|
|
219
233
|
- elemento: Elemento <select> encontrado pelo Selenium.
|
|
220
234
|
- method: Método de seleção ('index', 'text' ou 'value').
|
|
221
235
|
- key: Valor usado na seleção (índice, texto visível ou valor do atributo 'value').
|
|
236
|
+
- relative: Ao invés de selecionar um elemento identico, seleciona um elemento que apenas contém a 'key'
|
|
222
237
|
|
|
223
238
|
- Exemplo:
|
|
224
239
|
elemento_select = bc.find_element_with_wait("xpath", '//select[@value="VALUE_DO_PRIMEIRO_SELECT"]')
|
|
@@ -248,11 +263,17 @@ def selectfox(elemento, method, key):
|
|
|
248
263
|
select.select_by_value(key)
|
|
249
264
|
|
|
250
265
|
if method == "text":
|
|
251
|
-
elements =
|
|
266
|
+
elements = select.options
|
|
252
267
|
for elm in elements:
|
|
253
|
-
if
|
|
254
|
-
|
|
255
|
-
|
|
268
|
+
if relative:
|
|
269
|
+
if key.lower().strip() in elm.text.lower().strip():
|
|
270
|
+
select.select_by_visible_text(elm.text)
|
|
271
|
+
return
|
|
272
|
+
else:
|
|
273
|
+
if key == elm.text:
|
|
274
|
+
select.select_by_visible_text(elm.text)
|
|
275
|
+
return
|
|
276
|
+
|
|
256
277
|
raise ModuleNotFoundError(f"Option {key} não encontrada")
|
|
257
278
|
|
|
258
279
|
if method == "index":
|
|
@@ -322,7 +343,6 @@ def cpf_or_cnpj(numero: str) -> str:
|
|
|
322
343
|
janela = None
|
|
323
344
|
@staticmethod
|
|
324
345
|
def mostrar_mensagem(mensagem, tamanho_fonte=12, negrito=False, button: Optional[bool] = True):
|
|
325
|
-
|
|
326
346
|
global janela
|
|
327
347
|
|
|
328
348
|
try: fechar_janela(janela)
|
|
@@ -335,28 +355,61 @@ def mostrar_mensagem(mensagem, tamanho_fonte=12, negrito=False, button: Optional
|
|
|
335
355
|
janela.title("Atenção!")
|
|
336
356
|
janela.configure(bg="white")
|
|
337
357
|
|
|
338
|
-
largura, altura = 400, 200
|
|
339
|
-
pos_x = (janela.winfo_screenwidth() - largura) // 2
|
|
340
|
-
pos_y = (janela.winfo_screenheight() - altura) // 2
|
|
341
|
-
janela.geometry(f"{largura}x{altura}+{pos_x}+{pos_y}")
|
|
342
|
-
janela.resizable(False, False)
|
|
343
|
-
janela.attributes("-topmost", True)
|
|
344
|
-
|
|
345
358
|
estilo_fonte = ("Helvetica", tamanho_fonte, "bold" if negrito else "normal")
|
|
346
359
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
360
|
+
# container para label + botões
|
|
361
|
+
container = tk.Frame(janela, bg="white")
|
|
362
|
+
container.pack(padx=20, pady=20)
|
|
363
|
+
|
|
364
|
+
label = tk.Label(container, text=mensagem, bg="white", fg="black",
|
|
365
|
+
font=estilo_fonte, wraplength=360, justify="center")
|
|
366
|
+
label.pack(fill="both", expand=True)
|
|
367
|
+
|
|
368
|
+
if isinstance(button, dict):
|
|
369
|
+
resultado = tk.IntVar()
|
|
370
|
+
|
|
371
|
+
def make_cmd(value):
|
|
372
|
+
return lambda: resultado.set(value)
|
|
373
|
+
|
|
374
|
+
frame_botoes = tk.Frame(container, bg="white")
|
|
375
|
+
frame_botoes.pack(pady=10)
|
|
376
|
+
for i, texto in enumerate(button.keys(), start=1):
|
|
377
|
+
tk.Button(frame_botoes, text=texto, command=make_cmd(i), width=10,
|
|
378
|
+
font=("Helvetica", 10)).pack(side="left", padx=5)
|
|
379
|
+
|
|
380
|
+
janela.grab_set()
|
|
381
|
+
janela.focus_set()
|
|
382
|
+
janela.update_idletasks()
|
|
383
|
+
# ajusta ao tamanho real
|
|
384
|
+
w = janela.winfo_reqwidth()
|
|
385
|
+
h = janela.winfo_reqheight()
|
|
386
|
+
x = (janela.winfo_screenwidth() - w) // 2
|
|
387
|
+
y = (janela.winfo_screenheight() - h) // 2
|
|
388
|
+
janela.geometry(f"{w}x{h}+{x}+{y}")
|
|
389
|
+
janela.wait_variable(resultado)
|
|
390
|
+
root.destroy()
|
|
391
|
+
return resultado.get()
|
|
350
392
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
393
|
+
else:
|
|
394
|
+
if button:
|
|
395
|
+
tk.Button(container, text="OK",
|
|
396
|
+
command=lambda: (janela.destroy(), root.destroy()),
|
|
397
|
+
width=10, font=("Helvetica", 10)).pack(pady=10)
|
|
398
|
+
|
|
399
|
+
janela.grab_set()
|
|
400
|
+
janela.focus_set()
|
|
401
|
+
janela.update_idletasks()
|
|
402
|
+
w = janela.winfo_reqwidth()
|
|
403
|
+
h = janela.winfo_reqheight()
|
|
404
|
+
x = (janela.winfo_screenwidth() - w) // 2
|
|
405
|
+
y = (janela.winfo_screenheight() - h) // 2
|
|
406
|
+
janela.geometry(f"{w}x{h}+{x}+{y}")
|
|
407
|
+
|
|
408
|
+
if button:
|
|
409
|
+
janela.wait_window()
|
|
410
|
+
else:
|
|
411
|
+
root.mainloop()
|
|
412
|
+
return janela
|
|
360
413
|
|
|
361
414
|
def fechar_janela(janela_=None):
|
|
362
415
|
global janela
|
|
@@ -404,6 +457,6 @@ def move_mouse_smoothly(element, click=False):
|
|
|
404
457
|
RESET, GR, ORANGE, DK_ORANGE = "\033[0m", "\033[38;5;34m", "\033[38;5;214m", "\033[38;5;130m"
|
|
405
458
|
result = subprocess.run(['pip', 'show', "bcpkgfox"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
406
459
|
version_line = next((line for line in result.stdout.decode().splitlines() if line.startswith('Version:')), None)
|
|
407
|
-
try: print(f"\n\n{ORANGE}Biblioteca BCFOX importada - {re.sub(r
|
|
460
|
+
try: print(f"\n\n{ORANGE}Biblioteca BCFOX importada - {re.sub(r'[^0-9.b]', '', version_line)}{RESET}")
|
|
408
461
|
except: pass
|
|
409
462
|
create_dirs()
|
bcpkgfox/clean.py
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import threading
|
|
3
|
+
import argparse
|
|
4
|
+
import time
|
|
5
|
+
import sys
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class clean_main:
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.current_dir = os.getcwd()
|
|
13
|
+
self.args = None
|
|
14
|
+
self.file = None
|
|
15
|
+
|
|
16
|
+
def main(self):
|
|
17
|
+
|
|
18
|
+
# Detect the user input
|
|
19
|
+
self.args = self.parser.parse_args()
|
|
20
|
+
self.file = self.args.filename
|
|
21
|
+
|
|
22
|
+
self.data_dict = []
|
|
23
|
+
if self.args.exe:
|
|
24
|
+
if self.args.add_data:
|
|
25
|
+
for data in self.args.add_data:
|
|
26
|
+
self.data_dict.append(data)
|
|
27
|
+
|
|
28
|
+
# Icon check
|
|
29
|
+
if self.args.icon:
|
|
30
|
+
if len(self.args.icon) > 1:
|
|
31
|
+
raise ValueError("Put only one PATH in 'icon' argument.")
|
|
32
|
+
|
|
33
|
+
if not os.path.exists(os.path.join(self.current_dir, self.args.icon[0])):
|
|
34
|
+
raise ValueError(f"The path '{self.args.icon[0]}' not exists")
|
|
35
|
+
|
|
36
|
+
# Venv
|
|
37
|
+
if self.args.venv:
|
|
38
|
+
self.venv_manager.main()
|
|
39
|
+
elif self.args.venv_clean:
|
|
40
|
+
self.venv_manager.create_venv()
|
|
41
|
+
elif self.args.recreate_venv:
|
|
42
|
+
self.venv_manager.recreate_venv()
|
|
43
|
+
elif self.args.delete_venv:
|
|
44
|
+
self.venv_manager.delete_venv()
|
|
45
|
+
|
|
46
|
+
# Imports
|
|
47
|
+
if self.args.find_imports:
|
|
48
|
+
self.find_imports.main()
|
|
49
|
+
elif self.args.install_imports:
|
|
50
|
+
self.venv_manager.install_imports()
|
|
51
|
+
|
|
52
|
+
# EXEC
|
|
53
|
+
elif self.args.exe:
|
|
54
|
+
self.exec_gen.main()
|
|
55
|
+
|
|
56
|
+
if self.args.zip:
|
|
57
|
+
self.exec_gen.zip_file()
|
|
58
|
+
|
|
59
|
+
# LOG - Verify imports
|
|
60
|
+
if self.args.verify_imports:
|
|
61
|
+
if self.args.find_imports \
|
|
62
|
+
or self.args.install_imports \
|
|
63
|
+
or self.args.venv \
|
|
64
|
+
or self.args.recreate_venv \
|
|
65
|
+
or self.args.exe:
|
|
66
|
+
self.find_imports.verify_imports()
|
|
67
|
+
else:
|
|
68
|
+
print(f"{self.visuals.bold}{self.visuals.RD} > Error: You need to use one function that installs imports before verifying them.{self.visuals.RESET}")
|
|
69
|
+
print("\033[J", end='', flush=True)
|
|
70
|
+
|
|
71
|
+
self.clean_terminal()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class Visual():
|
|
76
|
+
def __init__(self):
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# Colors
|
|
80
|
+
self.DK_ORANGE = "\033[38;5;130m"
|
|
81
|
+
self.ORANGE = "\033[38;5;214m"
|
|
82
|
+
self.YL = "\033[38;5;226m"
|
|
83
|
+
self.RD = "\033[38;5;196m"
|
|
84
|
+
self.GR = "\033[38;5;34m"
|
|
85
|
+
self.RESET = "\033[0m"
|
|
86
|
+
self.bold = "\033[1m"
|
|
87
|
+
|
|
88
|
+
class Visual(clean_main):
|
|
89
|
+
def __init__(self):
|
|
90
|
+
super().__init__()
|
|
91
|
+
|
|
92
|
+
self.hue = 0
|
|
93
|
+
|
|
94
|
+
def hsl_to_rgb(self, h, s, l):
|
|
95
|
+
h = h % 360
|
|
96
|
+
c = (1 - abs(2 * l - 1)) * s
|
|
97
|
+
x = c * (1 - abs((h / 60) % 2 - 1))
|
|
98
|
+
m = l - c / 2
|
|
99
|
+
|
|
100
|
+
if 0 <= h < 60: r, g, b = c, x, 0
|
|
101
|
+
elif 60 <= h < 120: r, g, b = x, c, 0
|
|
102
|
+
elif 120 <= h < 180: r, g, b = 0, c, x
|
|
103
|
+
elif 180 <= h < 240: r, g, b = 0, x, c
|
|
104
|
+
elif 240 <= h < 300: r, g, b = x, 0, c
|
|
105
|
+
elif 300 <= h < 360: r, g, b = c, 0, x
|
|
106
|
+
|
|
107
|
+
r = int((r + m) * 255) ; g = int((g + m) * 255) ; b = int((b + m) * 255)
|
|
108
|
+
return r, g, b
|
|
109
|
+
|
|
110
|
+
def rgb_text(self, text, r, g, b): return f"\033[38;2;{r};{g};{b}m{text}\033[0m"
|
|
111
|
+
|
|
112
|
+
def animate_rgb_text(self, text, delay=0.01):
|
|
113
|
+
r, g, b = self.hsl_to_rgb(self.hue, s=1.0, l=0.5)
|
|
114
|
+
self.hue = (self.hue + 1) % 360
|
|
115
|
+
time.sleep(delay)
|
|
116
|
+
return f" \033[1m{self.rgb_text(text, r, g, b)}\033[0m"
|
|
117
|
+
|
|
118
|
+
class animation:
|
|
119
|
+
def __init__(self, self_cli):
|
|
120
|
+
self.cli = self_cli
|
|
121
|
+
self.text = None
|
|
122
|
+
self.braille_spinner = [
|
|
123
|
+
'\u280B',
|
|
124
|
+
'\u2809',
|
|
125
|
+
'\u2839',
|
|
126
|
+
'\u2838',
|
|
127
|
+
'\u283C',
|
|
128
|
+
'\u2834',
|
|
129
|
+
'\u2826',
|
|
130
|
+
'\u2827',
|
|
131
|
+
'\u2807',
|
|
132
|
+
'\u280F'
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
self.retro_computer_style = [
|
|
136
|
+
'\u23BA', # ⎺
|
|
137
|
+
'\u23BB', # ⎻
|
|
138
|
+
'\u23BC', # ⎼
|
|
139
|
+
'\u23BD', # ⎽
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
self.footer_thread = None
|
|
143
|
+
self.process_finished = False
|
|
144
|
+
|
|
145
|
+
def print_footer(self):
|
|
146
|
+
s = 0
|
|
147
|
+
n = 0
|
|
148
|
+
while not self.process_finished:
|
|
149
|
+
if s % 10 == 0: n += 1
|
|
150
|
+
if n == len(self.retro_computer_style): n = 0
|
|
151
|
+
|
|
152
|
+
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.cli.visuals.animate_rgb_text(f" {self.cli.visuals.bold} {self.retro_computer_style[n]} {self.text} {self.retro_computer_style[n]} {self.cli.visuals.RESET}")} \033[0J\n\033[F")
|
|
153
|
+
sys.stdout.flush()
|
|
154
|
+
s += 1
|
|
155
|
+
|
|
156
|
+
def start(self, text):
|
|
157
|
+
self.text = text
|
|
158
|
+
self.footer_thread = threading.Thread(target=self.print_footer)
|
|
159
|
+
self.footer_thread.start()
|
|
160
|
+
|
|
161
|
+
def finish(self):
|
|
162
|
+
self.process_finished = True
|
|
163
|
+
self.footer_thread.join()
|
|
164
|
+
|
|
165
|
+
def main():
|
|
166
|
+
|
|
167
|
+
class visual():
|
|
168
|
+
def __init__(self):
|
|
169
|
+
self.RESET = "\033[0m"
|
|
170
|
+
self.DK_ORANGE = "\033[38;5;130m"
|
|
171
|
+
self.Neg = "\033[1m"
|
|
172
|
+
self.hue = 0
|
|
173
|
+
|
|
174
|
+
def hsl_to_rgb(self, h, s, l):
|
|
175
|
+
h = h % 360
|
|
176
|
+
c = (1 - abs(2 * l - 1)) * s
|
|
177
|
+
x = c * (1 - abs((h / 60) % 2 - 1))
|
|
178
|
+
m = l - c / 2
|
|
179
|
+
|
|
180
|
+
if 0 <= h < 60: r, g, b = c, x, 0
|
|
181
|
+
elif 60 <= h < 120: r, g, b = x, c, 0
|
|
182
|
+
elif 120 <= h < 180: r, g, b = 0, c, x
|
|
183
|
+
elif 180 <= h < 240: r, g, b = 0, x, c
|
|
184
|
+
elif 240 <= h < 300: r, g, b = x, 0, c
|
|
185
|
+
elif 300 <= h < 360: r, g, b = c, 0, x
|
|
186
|
+
|
|
187
|
+
r = int((r + m) * 255) ; g = int((g + m) * 255) ; b = int((b + m) * 255)
|
|
188
|
+
return r, g, b
|
|
189
|
+
|
|
190
|
+
def rgb_text(self, text, r, g, b): return f"\033[38;2;{r};{g};{b}m{text}\033[0m"
|
|
191
|
+
|
|
192
|
+
def animate_rgb_text(self, text, delay=0.01):
|
|
193
|
+
r, g, b = self.hsl_to_rgb(self.hue, s=1.0, l=0.5)
|
|
194
|
+
self.hue = (self.hue + 1) % 360
|
|
195
|
+
time.sleep(delay)
|
|
196
|
+
return f" \033[1m{self.rgb_text(text, r, g, b)}\033[0m"
|
|
197
|
+
|
|
198
|
+
class exec_gen():
|
|
199
|
+
def __init__(self):
|
|
200
|
+
self.current_dir = None
|
|
201
|
+
self.target_file = None
|
|
202
|
+
self.file_name = None
|
|
203
|
+
|
|
204
|
+
def preparations(self):
|
|
205
|
+
self.current_dir = os.getcwd()
|
|
206
|
+
|
|
207
|
+
parser = argparse.ArgumentParser(description="Script to generate .exe and preventing bugs")
|
|
208
|
+
parser.add_argument("file", type=str, help="Put the name of file after the command (with the extension '.py')")
|
|
209
|
+
|
|
210
|
+
args = parser.parse_args()
|
|
211
|
+
self.file_name = args.file
|
|
212
|
+
self.target_file = os.path.join(self.current_dir, self.file_name)
|
|
213
|
+
|
|
214
|
+
if not os.path.exists(self.target_file):
|
|
215
|
+
print(f"Error: File '{self.target_file}' does not exist.")
|
|
216
|
+
return
|
|
217
|
+
|
|
218
|
+
def run_pyinstaller(self):
|
|
219
|
+
global process_finished
|
|
220
|
+
|
|
221
|
+
def print_footer():
|
|
222
|
+
"""Função que mantém a mensagem 'Aguarde download' na última linha."""
|
|
223
|
+
while not process_finished:
|
|
224
|
+
sys.stdout.write(f"\r \033[F\r\033[K\033[E {visuals.animate_rgb_text(f" {visuals.Neg}| Gerando executável do '{self.file_name}', aguarde finalização. |{visuals.RESET}")}\n\033[F")
|
|
225
|
+
sys.stdout.flush()
|
|
226
|
+
|
|
227
|
+
process_finished = False
|
|
228
|
+
|
|
229
|
+
command = ["pyinstaller", self.target_file]
|
|
230
|
+
process = subprocess.Popen(
|
|
231
|
+
command,
|
|
232
|
+
stdout=subprocess.PIPE,
|
|
233
|
+
stderr=subprocess.STDOUT,
|
|
234
|
+
universal_newlines=True,
|
|
235
|
+
bufsize=1
|
|
236
|
+
)
|
|
237
|
+
footer_thread = threading.Thread(target=print_footer)
|
|
238
|
+
footer_thread.start()
|
|
239
|
+
|
|
240
|
+
# Lê a saída do PyInstaller em tempo real
|
|
241
|
+
while True:
|
|
242
|
+
output = process.stdout.readline()
|
|
243
|
+
if output == '' and process.poll() is not None:
|
|
244
|
+
break
|
|
245
|
+
if output:
|
|
246
|
+
sys.stdout.write(f"\033[F\r\033[K{output.strip()}\033[K\n\n")
|
|
247
|
+
sys.stdout.flush()
|
|
248
|
+
|
|
249
|
+
process_finished = True
|
|
250
|
+
footer_thread.join()
|
|
251
|
+
|
|
252
|
+
print(f"\r \033[F\r\033[K\033[f\r\033[K\033[2E{visuals.Neg}{visuals.DK_ORANGE}>{visuals.RESET}{visuals.Neg} Executável gerado com sucesso!\n{visuals.RESET}\033[3E")
|
|
253
|
+
|
|
254
|
+
script = exec_gen()
|
|
255
|
+
visuals = visual()
|
|
256
|
+
script.preparations()
|
|
257
|
+
script.run_pyinstaller()
|