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.
bcpkgfox/cli.py CHANGED
@@ -8,53 +8,114 @@ import sys
8
8
  import re
9
9
  import os
10
10
 
11
+ def main(): cli().main()
12
+
11
13
  class cli:
12
14
  def __init__(self):
13
15
  self.current_dir = os.getcwd()
16
+ self.file = None
17
+ self.args = None
14
18
 
15
19
  self.visuals = self.visual(self)
16
20
  self.exec_gen = self.exec_gen_(self)
17
21
  self.find_imports = self.find_import(self)
18
- self.venv_managment = self.venv_mangt(self)
22
+ self.venv_manager = self.venv_mangt(self)
19
23
 
20
24
  self.parser = argparse.ArgumentParser(
21
- add_help=False
25
+ add_help=False,
26
+ description=f"{self.visuals.bold}{self.visuals.DK_ORANGE} BCFOX Library \n You can use the arguments in any order you want.\n\n Most flags are independent, you can use it alone or combine them in a single command interacting with each other when applicable.{self.visuals.RESET}",
27
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter
28
+ # formatter_class=argparse.RawTextHelpFormatter # Formats the 'help' text manually
22
29
  )
23
- args = self.parser.parse_args()
24
- self.file = args.filename
30
+
25
31
  self._setup_arguments()
26
32
 
27
33
  def _setup_arguments(self):
28
34
  """Configure all CLI arguments"""
29
- venv_group = self.parser.add_argument_group('virtual environment options')
35
+ venv_group = self.parser.add_argument_group(f'{self.visuals.ORANGE}{self.visuals.bold} Virtual Environment Options{self.visuals.RESET}')
30
36
  venv_group.add_argument(
31
37
  '-v', '--venv',
32
38
  action='store_true',
33
- help="Creates a virtual environment with all dependencies installed"
39
+ help="Creates a new virtual environment with all dependencies installed\n"
34
40
  )
35
41
 
36
42
  venv_group.add_argument(
37
43
  '-vc', '--venv-clean',
38
44
  action='store_true',
39
- help="Creates a virtual environment without dependencies"
45
+ help="Creates a virtual environment without dependencies\n"
40
46
  )
41
47
 
42
48
  venv_group.add_argument(
43
49
  '-rv', '--recreate-venv',
44
50
  action='store_true',
45
- help="Recreates venv (without dependencies)"
51
+ help="Recreates venv (without dependencies)\n"
46
52
  )
47
53
 
48
54
  venv_group.add_argument(
49
55
  '-dv', '--delete-venv',
50
56
  action='store_true',
51
- help="Deletes venv"
57
+ help="Deletes venv\n"
52
58
  )
53
59
 
54
- self.parser.add_argument(
60
+ venv_group.add_argument(
61
+ '-r', '--requirements',
62
+ action='store_true',
63
+ # nargs='?',
64
+ # action=self.venv_manager.custom_action_requirements,
65
+ # default=False,
66
+ help="Create a requirements\n"
67
+ )
68
+
69
+ exe_group = self.parser.add_argument_group(f'{self.visuals.ORANGE}{self.visuals.bold} Exe options{self.visuals.RESET}')
70
+ exe_group.add_argument(
71
+ '-e', '--exe',
72
+ action='store_true',
73
+ help="Creates a .exe of the file\n"
74
+ )
75
+
76
+ exe_group.add_argument(
77
+ '-nc', '--no-console',
78
+ action='store_true',
79
+ help="The exe don't open the console when started\n"
80
+ )
81
+
82
+ exe_group.add_argument(
83
+ '-z', '--zip',
84
+ action='store_true',
85
+ help="Make a zip of the 'dist' and rename it to the name of the file\n"
86
+ )
87
+
88
+ exe_group.add_argument(
89
+ '-ic', '--icon',
90
+ type=str,
91
+ nargs='+',
92
+ help="Change the exe icon (put .ico path)\n"
93
+ )
94
+
95
+ exe_group.add_argument(
96
+ '-ad', '--add-data',
97
+ type=str,
98
+ nargs='+',
99
+ help="Add data(s) to .exe (similar of pyinstaller)\n"
100
+ )
101
+
102
+ file_group = self.parser.add_argument_group(f'{self.visuals.ORANGE}{self.visuals.bold} File Options{self.visuals.RESET}')
103
+ file_group.add_argument(
55
104
  '-fi', '--find-imports',
56
105
  action='store_true',
57
- help="Finds all imports necessary for the lib to work"
106
+ help="Finds all imports necessary for the lib to work\n"
107
+ )
108
+
109
+ file_group.add_argument(
110
+ '-vi', '--verify-imports',
111
+ action='store_true',
112
+ help="Shows imports that were not installed automatically\n"
113
+ )
114
+
115
+ file_group.add_argument(
116
+ '-i', '--install-imports',
117
+ action='store_true',
118
+ help="Installs all imports necessary for the lib to work\n"
58
119
  )
59
120
 
60
121
  self.parser.add_argument(
@@ -68,36 +129,77 @@ class cli:
68
129
  '-h', '--help',
69
130
  action='help',
70
131
  default=argparse.SUPPRESS,
71
- help="Salveeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
132
+ help="If you need more help contact guilherme"
72
133
  )
73
134
 
74
135
  def main(self):
75
- args = self.parser.parse_args()
136
+ self.args = self.parser.parse_args()
137
+ self.file = self.args.filename
138
+
139
+ self.data_dict = []
140
+ if self.args.exe:
141
+ if self.args.add_data:
142
+ for data in self.args.add_data:
143
+ self.data_dict.append(data)
144
+
145
+ # Icon check
146
+ if self.args.icon:
147
+ if len(self.args.icon) > 1:
148
+ raise ValueError("Put only one PATH in 'icon' argument.")
149
+
150
+ if not os.path.exists(os.path.join(self.current_dir, self.args.icon[0])):
151
+ raise ValueError(f"The path '{self.args.icon[0]}' not exists")
76
152
 
77
- if args.venv:
153
+ # Venv
154
+ if self.args.venv:
78
155
  self.venv_manager.main()
79
- elif args.venv_clean:
156
+ elif self.args.venv_clean:
80
157
  self.venv_manager.create_venv()
81
- elif args.recreate_venv:
158
+ elif self.args.recreate_venv:
82
159
  self.venv_manager.recreate_venv()
83
- elif args.delete_venv:
160
+ elif self.args.delete_venv:
84
161
  self.venv_manager.delete_venv()
85
162
 
86
- if args.find_imports:
87
- self.imports_finder.main()
88
-
89
- if args.filename:
90
- self._process_file(args.filename)
163
+ # Imports
164
+ if self.args.find_imports:
165
+ self.find_imports.main()
166
+ elif self.args.install_imports:
167
+ self.venv_manager.install_imports()
168
+
169
+ # EXEC
170
+ elif self.args.exe:
171
+ self.exec_gen.main()
172
+
173
+ if self.args.zip:
174
+ self.exec_gen.zip_file()
175
+
176
+ # LOG - Verify imports
177
+ if self.args.verify_imports:
178
+ if self.args.find_imports \
179
+ or self.args.install_imports \
180
+ or self.args.venv \
181
+ or self.args.recreate_venv \
182
+ or self.args.exe:
183
+ self.find_imports.verify_imports()
184
+ else:
185
+ print(f"{self.visuals.bold}{self.visuals.RD} > Error: You need to use one function that installs imports before verifying them{self.visuals.RESET}")
186
+ print("\033[J", end='', flush=True)
187
+
188
+ # Requirements
189
+ if self.args.requirements:
190
+ self.venv_manager.requirements()
191
+
192
+ self.clean_terminal()
91
193
 
92
194
  def clean_terminal(self):
93
195
  if self.exec_gen.error == 1 \
94
196
  or self.find_imports.error == 1 \
95
- or self.venv_managment.error == 1:
197
+ or self.venv_manager.error == 1:
96
198
  print("\033[J", end='', flush=True)
97
199
 
98
200
  if self.exec_gen.descerror: print(f"\n {self.visuals.DK_ORANGE}>{self.visuals.RESET} {self.exec_gen.descerror}")
99
201
  if self.find_imports.descerror: print(f"\n {self.visuals.DK_ORANGE}>{self.visuals.RESET} {self.find_imports.descerror}")
100
- if self.venv_managment.descerror: print(f"\n {self.visuals.DK_ORANGE}>{self.visuals.RESET} {self.venv_managment.descerror}")
202
+ if self.venv_manager.descerror: print(f"\n {self.visuals.DK_ORANGE}>{self.visuals.RESET} {self.venv_manager.descerror}")
101
203
 
102
204
  class visual:
103
205
  def __init__(self, self_cli):
@@ -105,6 +207,7 @@ class cli:
105
207
 
106
208
  self.DK_ORANGE = "\033[38;5;130m"
107
209
  self.ORANGE = "\033[38;5;214m"
210
+ self.YL = "\033[38;5;226m"
108
211
  self.RD = "\033[38;5;196m"
109
212
  self.GR = "\033[38;5;34m"
110
213
  self.RESET = "\033[0m"
@@ -136,6 +239,53 @@ class cli:
136
239
  time.sleep(delay)
137
240
  return f" \033[1m{self.rgb_text(text, r, g, b)}\033[0m"
138
241
 
242
+ class animation:
243
+ def __init__(self, self_cli):
244
+ self.cli = self_cli
245
+ self.text = None
246
+ self.braille_spinner = [
247
+ '\u280B',
248
+ '\u2809',
249
+ '\u2839',
250
+ '\u2838',
251
+ '\u283C',
252
+ '\u2834',
253
+ '\u2826',
254
+ '\u2827',
255
+ '\u2807',
256
+ '\u280F'
257
+ ]
258
+
259
+ self.retro_computer_style = [
260
+ '\u23BA', # ⎺
261
+ '\u23BB', # ⎻
262
+ '\u23BC', # ⎼
263
+ '\u23BD', # ⎽
264
+ ]
265
+
266
+ self.footer_thread = None
267
+ self.process_finished = False
268
+
269
+ def print_footer(self):
270
+ s = 0
271
+ n = 0
272
+ while not self.process_finished:
273
+ if s % 10 == 0: n += 1
274
+ if n == len(self.retro_computer_style): n = 0
275
+
276
+ 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")
277
+ sys.stdout.flush()
278
+ s += 1
279
+
280
+ def start(self, text):
281
+ self.text = text
282
+ self.footer_thread = threading.Thread(target=self.print_footer)
283
+ self.footer_thread.start()
284
+
285
+ def finish(self):
286
+ self.process_finished = True
287
+ self.footer_thread.join()
288
+
139
289
  class exec_gen_:
140
290
  def __init__(self, self_cli):
141
291
  self.cli = self_cli
@@ -144,17 +294,11 @@ class cli:
144
294
  self.error = 0
145
295
  self.descerror = ""
146
296
  self.visuals = self.cli.visuals
297
+ self.ultimate_error = None
147
298
 
148
299
  def preparations(self):
149
300
  self.current_dir = os.getcwd()
150
-
151
- parser = argparse.ArgumentParser(description="Script to generate .exe and preventing bugs")
152
- parser.add_argument("file", type=str, help="Put the name of file after the command (with the extension '.py')")
153
-
154
- # args = parser.parse_args() #TODO
155
- # self.file_name = args.file #TODO
156
- self.target_file = os.path.join(self.current_dir, self.file_name) #TODO
157
- # self.target_file = self.cli.file #FIX
301
+ self.target_file = os.path.join(self.current_dir, self.cli.file) #TODO
158
302
 
159
303
  if not os.path.exists(self.target_file):
160
304
  self.descerror = f"Error: File '{self.target_file}' does not exist."
@@ -165,23 +309,23 @@ class cli:
165
309
  global process_finished
166
310
 
167
311
  braille_spinner = [
168
- '\u280B', # ⠋
169
- '\u2809', # ⠙
170
- '\u2839', # ⠹
171
- '\u2838', # ⠸
172
- '\u283C', # ⠼
173
- '\u2834', # ⠴
174
- '\u2826', # ⠦
175
- '\u2827', # ⠧
176
- '\u2807', # ⠇
177
- '\u280F' # ⠏
312
+ '\u280B',
313
+ '\u2809',
314
+ '\u2839',
315
+ '\u2838',
316
+ '\u283C',
317
+ '\u2834',
318
+ '\u2826',
319
+ '\u2827',
320
+ '\u2807',
321
+ '\u280F'
178
322
  ]
179
323
 
180
324
  retro_computer_style = [
181
- '\u23BA', # ⎺
182
- '\u23BB', # ⎻
183
- '\u23BC', # ⎼
184
- '\u23BD', # ⎽
325
+ '\u23BA',
326
+ '\u23BB',
327
+ '\u23BC',
328
+ '\u23BD',
185
329
  ]
186
330
 
187
331
  def print_footer():
@@ -191,34 +335,123 @@ class cli:
191
335
  if s % 10 == 0: n += 1
192
336
  if n == len(braille_spinner): n = 0
193
337
 
194
- sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Gerando executável do '{self.target_file}', aguarde finalização. {braille_spinner[n]} {self.visuals.RESET}")} \n\033[F")
338
+ sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Gerando executável do '{self.cli.file}', aguarde finalização. {braille_spinner[n]} {self.visuals.RESET}")} \033[0J\n\033[F")
195
339
  sys.stdout.flush()
196
340
  s += 1
341
+ print("\033[1A \r\033[K \033[1B \r\033[K") #\033[1B \r\033[K\033[1B \r\033[K\033[1B \r\033[K")
197
342
 
198
- process_finished = False
199
- command = ["pyinstaller", self.target_file]
200
- process = subprocess.Popen(
201
- command,
202
- stdout=subprocess.PIPE,
203
- stderr=subprocess.STDOUT,
204
- universal_newlines=True,
205
- bufsize=1
206
- )
207
- footer_thread = threading.Thread(target=print_footer)
208
- footer_thread.start()
343
+ try:
344
+ process_finished = False
345
+ python_executable = os.path.join(".venv", 'Scripts' if os.name == 'nt' else 'bin', 'python')
346
+ command = [python_executable, "-m", "PyInstaller", "--onefile", "--clean"]
347
+ if self.cli.data_dict:
348
+ for data in self.cli.data_dict:
349
+ if ":" in data or ";" in data: command.extend(["--add-data", data])
350
+ else: command.extend(["--add-data", f"{data}:{data}"])
351
+
352
+ if self.cli.args.no_console:
353
+ command.append("--noconsole")
354
+
355
+ if self.cli.args.icon:
356
+ command.extend(["--icon", f"{self.cli.args.icon[0]}"])
357
+
358
+ command.append(self.target_file)
359
+
360
+ process = subprocess.Popen(
361
+ command,
362
+ stdout=subprocess.PIPE,
363
+ stderr=subprocess.STDOUT,
364
+ universal_newlines=True,
365
+ bufsize=1
366
+ )
367
+ footer_thread = threading.Thread(target=print_footer)
368
+ footer_thread.start()
369
+
370
+ while True:
371
+ output = process.stdout.readline()
372
+ if output == '' and process.poll() is not None: break
373
+ if output:
374
+ sys.stdout.write(f"\033[F\r\033[K{output.strip()}\033[K\n\n")
375
+ sys.stdout.flush()
209
376
 
210
- while True:
211
- output = process.stdout.readline()
212
- if output == '' and process.poll() is not None:
213
- break
214
- if output:
215
- sys.stdout.write(f"\033[F\r\033[K{output.strip()}\033[K\n\n")
216
- sys.stdout.flush()
377
+ process_finished = True
378
+ footer_thread.join()
217
379
 
218
- process_finished = True
219
- footer_thread.join()
380
+ except Exception as e:
381
+ process_finished = True
382
+ self.descerror = e
383
+ self.error = 1
384
+ finally: process_finished = True
385
+
386
+ rows = os.get_terminal_size().lines
387
+ print(f"\033[F\033[K\033[f\033[K\033[f\033[K{self.visuals.bold}{self.visuals.GR}\033[{rows};1H > Executável gerado com sucesso!\n{self.visuals.RESET} \033[0J")
388
+
389
+ def zip_file(self):
390
+
391
+ animation = self.visuals.animation(self.cli)
392
+ animation.start(text='Creating zip file')
393
+ zip_log = False
394
+
395
+ try:
396
+ name_dir = self.current_dir.split("\\")
397
+ print(name_dir)
398
+
399
+ name_dir = [part for part in name_dir if part]
400
+
401
+ target_name = name_dir[-1]
402
+
403
+ dist_path = os.path.join(self.current_dir, "dist")
404
+ temp_path = os.path.join(self.current_dir, f"{target_name}_temp")
405
+ inner_path = os.path.join(temp_path, target_name)
406
+
407
+ if os.path.isfile(os.path.join(self.current_dir, f"{target_name}.zip")):
408
+ os.remove(os.path.join(self.current_dir, f"{target_name}.zip"))
409
+
410
+ if os.path.exists(os.path.join(self.current_dir, f"{target_name}")):
411
+ shutil.rmtree(os.path.join(self.current_dir, f"{target_name}"))
412
+
413
+ if os.path.exists(dist_path):
414
+ if os.path.exists(temp_path):
415
+ shutil.rmtree(temp_path)
416
+ os.mkdir(temp_path)
417
+ shutil.move(dist_path, inner_path)
418
+ else:
419
+ raise FileNotFoundError(f"{self.visuals.bold}{self.visuals.RD}Error: 'dist' directory not found!{self.visuals.RESET}")
420
+
421
+ zip_path = shutil.make_archive(
422
+ os.path.join(self.current_dir, target_name),
423
+ 'zip',
424
+ root_dir=temp_path,
425
+ base_dir=target_name
426
+ )
427
+
428
+ # Espera o sistema liberar o zip
429
+ wait = 0
430
+ while True:
431
+ try:
432
+ with open(zip_path, 'rb'):
433
+ break
434
+ except (PermissionError, OSError):
435
+ time.sleep(0.1)
436
+ wait += 1
437
+ if wait >= 600:
438
+ raise TimeoutError("Timeout while waiting for zip file to be accessible.")
439
+
440
+ shutil.rmtree(temp_path)
441
+ zip_log = True
220
442
 
221
- print(f"\r \033[F\r\033[K\033[f\r\033[K\033[2E{self.visuals.bold}{self.visuals.DK_ORANGE}>{self.visuals.RESET}{self.visuals.bold} Executável gerado com sucesso!\n{self.visuals.RESET}\033[3E")
443
+ except Exception as e:
444
+ self.ultimate_error = e
445
+
446
+ finally:
447
+ animation.finish()
448
+
449
+ if zip_log:
450
+ print(f"{self.visuals.bold}{self.visuals.GR} > Zip file created successfully {self.visuals.RESET}\033[J\n\033[J")
451
+ else:
452
+ print(f"{self.visuals.bold}{self.visuals.RD} > Error creating zip file:\033[J")
453
+ print(f"{self.ultimate_error}{self.visuals.RESET}")
454
+ sys.exit(1)
222
455
 
223
456
  def main(self):
224
457
  script = self.cli.exec_gen
@@ -234,6 +467,7 @@ class cli:
234
467
  self.descerror = ""
235
468
 
236
469
  self.imports = None
470
+ self.error_libs = []
237
471
 
238
472
  def hsl_to_rgb(self, h, s, l):
239
473
  h = h % 360
@@ -269,19 +503,22 @@ class cli:
269
503
  hue = (hue + 1) % 360
270
504
  time.sleep(delay)
271
505
 
506
+ def verify_imports(self):
507
+ if self.error_libs:
508
+ print(f"{self.visuals.bold}{self.visuals.YL} WARNING: \n The libraries below can't be installed. This is not necessarily an error, just an alert.{self.visuals.RESET}")
509
+ for lib in self.error_libs:
510
+ print(f" {self.visuals.bold}{self.visuals.YL} - {lib} {self.visuals.RESET}")
511
+
272
512
  def main(self, return_=False):
273
- parser = argparse.ArgumentParser(description="A CLI tool to find imports.")
274
- parser.add_argument("file", type=str, help="The target .py file to process")
513
+ self.target_file = self.cli.file
275
514
 
276
- # args = parser.parse_args() #TODO
277
- # self.file_name = args.file #TODO
278
- # self.target_file = os.path.join(self.current_dir, self.file_name) #TODO
279
- self.target_file = self.cli.file #FIX
515
+ if not self.target_file:
516
+ print(f"{self.visuals.bold}{self.visuals.RD} > Error: Please pass your 'target_file' to detect the libraries.{self.visuals.RESET}")
517
+ sys.exit(1)
280
518
 
281
519
  if not os.path.exists(self.target_file):
282
- self.descerror = f"Error: File '{self.target_file}' does not exist."
283
- self.error = 1
284
- return
520
+ print(f"{self.visuals.bold}{self.visuals.RD} > Error: Your 'target_file' does not exist or can't be accessed.{self.visuals.RESET}")
521
+ sys.exit(1)
285
522
 
286
523
  try:
287
524
  with open(self.target_file, "r", encoding="utf-8", errors="replace") as file:
@@ -294,25 +531,38 @@ class cli:
294
531
  print(f"Erro: Não foi possível ler o arquivo '{self.target_file}' com nenhuma codificação testada.")
295
532
  return
296
533
 
297
- self.imports = []
534
+ self.imports = ["bcpkgfox"]
298
535
  import_data = {
299
536
  "extract_pdf": "PyMuPDF",
300
537
  "import requests": "requests",
301
538
  "import pyautogui": "pyautogui",
302
539
  "import cv2": "opencv-python",
540
+ "fitz": "PyMuPDF",
303
541
  "from PIL": "Pillow",
304
542
  "from reportlab.lib import utils": "reportlab",
305
543
  "from PyPDF2 import PdfMerger": "PyPDF2",
544
+ "PdfWriter": "pypdf",
306
545
  "import PyPDF2": "PyPDF2",
307
546
  "invoke_api_": "requests",
547
+ "login_2fac": "pyautogui",
308
548
  "wait_for": "pygetwindow",
309
549
  "from selenium_stealth import stealth": "selenium-stealth",
550
+ "capmonstercloudclient": "bcpkgfox[capmonstercloudclient]",
551
+ "capmonstercloud_client": "bcpkgfox[capmonstercloudclient]",
310
552
  "import undetected_chromedriver": "undetected-chromedriver",
311
- "from webdriver_manager.chrome import ChromeDriverManager": "webdriver-manager",
553
+ "webdriver_manager": "webdriver-manager",
312
554
  "move_to_image": ["pyscreeze", "pyautogui", "Pillow", "opencv-python"],
313
555
  "move_mouse_smoothly": ["pyscreeze", "pyautogui", "Pillow"],
314
556
  "initialize_driver": ["webdriver-manager", "undetected-chromedriver", "pyautogui", "psutil"],
315
- "stealth max": ["webdriver-manager", "undetected-chromedriver", "fake-useragent"]
557
+ "stealth max": ["webdriver-manager", "undetected-chromedriver"],
558
+ "bs4": "beautifulsoup4", "beautifulsoup":"beautifulsoup4",
559
+ "psutil": "bcpkgfox[psutil]",
560
+ "screeninfo": "bcpkgfox[screeninfo]", "get_monitors": "bcpkgfox[screeninfo]",
561
+ "pynput": "bcpkgfox[pynput]", "pynput.mouse": "bcpkgfox[pynput]",
562
+ "pynput.keyboard": "bcpkgfox[pynput]",
563
+ "pywinauto": "bcpkgfox[pywinauto]",
564
+ "pdfplumber": "pdfplumber",
565
+ "twocaptcha": "bcpkgfox[twocaptcha]", "TwoCaptcha": "bcpkgfox[twocaptcha]",
316
566
  }
317
567
 
318
568
  for name, import_name in import_data.items():
@@ -321,6 +571,14 @@ class cli:
321
571
  self.imports.extend(import_name)
322
572
  else: self.imports.append(import_name)
323
573
 
574
+ IMPORT_PATTERN = re.compile(r'^(?:from|import)\s+([A-Za-z0-9_\.]+)', re.MULTILINE)
575
+
576
+ # Encontra outras libs por regex
577
+ for match in IMPORT_PATTERN.finditer(file_content):
578
+ módulo = match.group(1).split('.')[0] # pega o pacote raiz
579
+ if módulo not in self.imports:
580
+ self.imports.append(módulo)
581
+
324
582
  self.imports = list(set(self.imports))
325
583
  import pyperclip
326
584
 
@@ -339,8 +597,6 @@ class cli:
339
597
  else: return self.imports
340
598
  else: print("No libraries from the list were found in the script.")
341
599
 
342
-
343
-
344
600
  class venv_mangt:
345
601
  def __init__(self, self_cli):
346
602
  self.cli = self_cli
@@ -380,24 +636,31 @@ class cli:
380
636
  if s % 10 == 0: n += 1
381
637
  if n == len(braille_spinner): n = 0
382
638
 
383
- sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Deleting virtual environment {braille_spinner[n]} {self.visuals.RESET}")} \n\033[F")
639
+ sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Deleting virtual environment {braille_spinner[n]} {self.visuals.RESET}")} \033[0J\n\033[F")
384
640
  sys.stdout.flush()
385
641
  s += 1
386
642
 
387
- footer_thread = threading.Thread(target=print_footer)
388
- footer_thread.start()
389
-
390
- if os.path.exists(os.path.join(self.current_dir, ".venv")):
391
- try:
392
- shutil.rmtree(".venv")
393
- except Exception as e:
394
- print(f"{self.visuals.RD} > Failed to remove venv: {e} {self.visuals.RESET}")
395
- return False
396
- process_finished = True
397
- footer_thread.join()
398
-
399
- print(f"{self.visuals.bold}{self.visuals.GR} > Oldest virtual environment deleted with sucessfuly {self.visuals.RESET}\n")
643
+ try:
644
+ footer_thread = threading.Thread(target=print_footer)
645
+ footer_thread.start()
646
+
647
+ if os.path.exists(os.path.join(self.current_dir, ".venv")):
648
+ try:
649
+ shutil.rmtree(".venv")
650
+ except Exception as e:
651
+ print(f"{self.visuals.RD} > Failed to remove venv: {e} {self.visuals.RESET}")
652
+ return False
653
+ process_finished = True
654
+ footer_thread.join()
400
655
 
656
+ print(f"{self.visuals.bold}{self.visuals.GR} > Oldest virtual environment deleted with sucessfuly {self.visuals.RESET}\n")
657
+ except Exception as e:
658
+ process_finished = True
659
+ self.descerror = e
660
+ self.error = 1
661
+ sys.exit()
662
+ raise SystemExit()
663
+ finally: process_finished = True
401
664
 
402
665
  def create_venv(self):
403
666
 
@@ -429,34 +692,40 @@ class cli:
429
692
  if s % 10 == 0: n += 1
430
693
  if n == len(braille_spinner): n = 0
431
694
 
432
- sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Generating virtual environment {braille_spinner[n]} {self.visuals.RESET}")} \n\033[F")
695
+ sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Generating virtual environment {braille_spinner[n]} {self.visuals.RESET}")} \033[0J\n\033[F")
433
696
  sys.stdout.flush()
434
697
  s += 1
435
698
 
436
- process_finished = False
437
- command = [sys.executable, '-m', 'venv', ".venv"]
438
- process = subprocess.Popen(
439
- command,
440
- stdout=subprocess.PIPE,
441
- stderr=subprocess.STDOUT,
442
- universal_newlines=True,
443
- bufsize=1
444
- )
445
- footer_thread = threading.Thread(target=print_footer)
446
- footer_thread.start()
447
-
448
- while True:
449
- output = process.stdout.readline()
450
- if output == '' and process.poll() is not None:
451
- break
452
- if output:
453
- sys.stdout.write(f"\033[F\r\033[K{output.strip()}\033[K\n\n")
454
- sys.stdout.flush()
699
+ try:
700
+ process_finished = False
701
+ command = [sys.executable, '-m', 'venv', ".venv"]
702
+ process = subprocess.Popen(
703
+ command,
704
+ stdout=subprocess.PIPE,
705
+ stderr=subprocess.STDOUT,
706
+ universal_newlines=True,
707
+ bufsize=1
708
+ )
709
+ footer_thread = threading.Thread(target=print_footer)
710
+ footer_thread.start()
711
+
712
+ while True:
713
+ output = process.stdout.readline()
714
+ if output == '' and process.poll() is not None:
715
+ break
716
+ if output:
717
+ sys.stdout.write(f"\033[F\r\033[K{output.strip()}\033[K\n\n")
718
+ sys.stdout.flush()
455
719
 
456
- process_finished = True
457
- footer_thread.join()
720
+ process_finished = True
721
+ footer_thread.join()
458
722
 
459
- print(f"{self.visuals.bold}{self.visuals.GR} > Virtual environment created successfully {self.visuals.RESET}", end="\r")
723
+ print(f"{self.visuals.bold}{self.visuals.GR} > Virtual environment created successfully {self.visuals.RESET}\n")
724
+ except Exception as e:
725
+ process_finished = True
726
+ self.descerror = e
727
+ self.error = 1
728
+ finally: process_finished = True
460
729
 
461
730
  def install_imports(self):
462
731
  pip_path = os.path.join(".venv", 'Scripts' if os.name == 'nt' else 'bin', 'pip')
@@ -490,47 +759,105 @@ class cli:
490
759
  if s % 10 == 0: n += 1
491
760
  if n == len(braille_spinner): n = 0
492
761
 
493
- sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Installing all dependencies {braille_spinner[n]} {self.visuals.RESET}")} \n\033[F")
762
+ sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Installing all dependencies {braille_spinner[n]} {self.visuals.RESET}")} \033[0J\n\033[F")
494
763
  sys.stdout.flush()
495
764
  s += 1
496
765
 
497
- log_animation = threading.Thread(target=print_footer)
498
- log_animation.start()
499
-
500
- process_finished = False
501
766
  try:
767
+ log_animation = threading.Thread(target=print_footer)
768
+ log_animation.start()
769
+
770
+ process_finished = False
502
771
  for lib in librarys:
503
772
  result = subprocess.run(
504
773
  [pip_path, 'install', lib],
505
- check=True,
774
+ # check=True,
506
775
  stdout=subprocess.PIPE,
507
776
  stderr=subprocess.PIPE,
508
777
  text=True
509
778
  )
510
779
 
780
+ if result.returncode != 0:
781
+ if isinstance(lib, list):
782
+ self.cli.find_imports.error_libs.extend(lib)
783
+ else: self.cli.find_imports.error_libs.append(lib)
784
+ continue
785
+
511
786
 
512
- if result.stdout:
787
+ elif result.stdout:
513
788
  print(f"\033[0J{result.stdout.strip()}\033[0J")
514
789
 
515
- except subprocess.CalledProcessError as e:
516
- print(f"{self.visuals.bold}{self.visuals.RD} Failed to install {lib}: {e.stderr.strip()}{self.visuals.RESET}", end="\r")
517
- return False
518
- finally:
519
790
  process_finished = True
520
791
  log_animation.join()
521
- print(f" {self.visuals.bold}{self.visuals.GR} > All packges installed with sucessfully {self.visuals.RESET}", end="\r")
792
+ print(f" {self.visuals.bold}{self.visuals.GR} > All packages installed successfully {self.visuals.RESET}\n\n")
793
+
794
+ except Exception as e:
795
+ process_finished = True
796
+ self.descerror = e
797
+ self.error = 1
798
+ print(e)
799
+ sys.exit()
522
800
 
523
801
  def recreate_venv(self):
524
802
  self.delete_venv()
525
803
  self.create_venv()
526
804
 
805
+ class custom_action_requirements(argparse.Action):
806
+ ''' This is necessary to define a new action and the parser identifies it as valid '''
807
+
808
+ def __call__(self, parser, namespace, values, option_string=None):
809
+ if values is None:
810
+ setattr(namespace, self.dest, 'requirements.txt')
811
+ else:
812
+ setattr(namespace, self.dest, values)
813
+
814
+ def requirements(self):
815
+
816
+ # # Identifies endwish
817
+ # if '.' in self.cli.args.requirements:
818
+ # name = self.cli.args.requirements
819
+ # else:
820
+ # name = self.cli.args.requirements + '.txt'
821
+
822
+ # FIX: name is always 'requirements.txt'
823
+ name = 'requirements.txt'
824
+
825
+ # Attempt of recreate
826
+ try:
827
+ os.remove(os.path.join(self.current_dir, name))
828
+ except:
829
+ pass
830
+
831
+ # Creates a new one
832
+ subprocess.run(f"pip freeze > {name}", shell=True)
833
+
834
+ # Read
835
+ with open(f'{name}', 'r') as f:
836
+ lines = f.readlines()
837
+
838
+ # Re-write
839
+ add_list = []
840
+ imports = self.cli.find_imports.main(return_=True)
841
+ imports_lower = {imp.lower() for imp in imports}
842
+ with open(f'{name}', 'w') as f:
843
+
844
+ for line in lines:
845
+
846
+ # Formats
847
+ if '\n' in line:
848
+ line_for_print = line.replace('\n', '').strip()
849
+
850
+ # Compares
851
+ pkg = line.split('==')[0].strip().lower()
852
+ if pkg in imports_lower:
853
+ f.write(line)
854
+ add_list.append(line_for_print)
855
+
856
+ print(f"\n{self.visuals.bold}{self.visuals.GR} > Requirements created with sucessfuly {self.visuals.RESET}\n")
857
+ print(f"{self.visuals.bold}{self.visuals.YL} Libraries installed: {self.visuals.RESET}{self.visuals.YL}" + "".join(f"\n {lib}" for lib in add_list) + f"{self.visuals.RESET}")
527
858
 
528
859
  def main(self):
529
- self.delete_venv()
860
+ try: self.delete_venv()
861
+ except: pass
530
862
  self.create_venv()
531
- self.install_imports()
532
-
533
- code = cli("bcpkgfox//cli.py")
534
- code.exec_gen.main()
535
- code.clean_terminal()
536
- print()
863
+ self.install_imports()