convert-stream 2.3.3__tar.gz → 2.3.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.
Files changed (36) hide show
  1. {convert_stream-2.3.3 → convert_stream-2.3.5}/PKG-INFO +5 -3
  2. {convert_stream-2.3.3 → convert_stream-2.3.5}/README.md +4 -2
  3. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/__init__.py +14 -3
  4. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/doc_stream.py +1 -1
  5. convert_stream-2.3.5/convert_stream/image/__init__.py +7 -0
  6. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/image/img_object.py +87 -22
  7. convert_stream-2.3.5/convert_stream/mod_types/__init__.py +100 -0
  8. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/mod_types/table_types.py +95 -100
  9. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/pdf/pdf_document.py +113 -118
  10. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/pdf/pdf_page.py +2 -2
  11. convert_stream-2.3.5/convert_stream/table_files.py +153 -0
  12. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/text/find_text.py +1 -1
  13. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream.egg-info/PKG-INFO +5 -3
  14. {convert_stream-2.3.3 → convert_stream-2.3.5}/pyproject.toml +1 -1
  15. convert_stream-2.3.3/convert_stream/image/__init__.py +0 -7
  16. convert_stream-2.3.3/convert_stream/mod_types/__init__.py +0 -42
  17. convert_stream-2.3.3/convert_stream/table_files.py +0 -138
  18. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/__main__.py +0 -0
  19. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/_version.py +0 -0
  20. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/mod_types/enums.py +0 -0
  21. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/mod_types/modules.py +0 -0
  22. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/pdf/__init__.py +0 -0
  23. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/pdf/image_to_pdf.py +0 -0
  24. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/pdf/pdf_to_image.py +0 -0
  25. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/sheets/__init__.py +0 -0
  26. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/sheets/load.py +0 -0
  27. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/sheets/parse.py +0 -0
  28. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/sheets/save.py +0 -0
  29. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/text/__init__.py +0 -0
  30. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/text/date.py +0 -0
  31. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream/text/terminal.py +0 -0
  32. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream.egg-info/SOURCES.txt +0 -0
  33. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream.egg-info/dependency_links.txt +0 -0
  34. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream.egg-info/requires.txt +0 -0
  35. {convert_stream-2.3.3 → convert_stream-2.3.5}/convert_stream.egg-info/top_level.txt +0 -0
  36. {convert_stream-2.3.3 → convert_stream-2.3.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: convert_stream
3
- Version: 2.3.3
3
+ Version: 2.3.5
4
4
  Summary: Manipulação de documentos PDF e Imagens. Converter, Ler, rotacionar exportar etc.
5
5
  Author: Bruno Chaves
6
6
  Requires-Python: >=3.11
@@ -21,8 +21,9 @@ pip3 install -r requirements.txt
21
21
 
22
22
 
23
23
  # Uso dividir páginas de um arquivo PDF:
24
- >>> from file import File, Directory
24
+ >>> from soup_files import File, Directory
25
25
  >>> from pdflib import PdfStream
26
+
26
27
  # instâncie o caminho do arquivo PDF e o diretório para exportar os dados.
27
28
  file_pdf = File('path/to/file.pdf')
28
29
  output_dir = Directory('path/to/save')
@@ -32,8 +33,9 @@ pip3 install -r requirements.txt
32
33
  pdf_stream.to_files_pdf(output_dir) # isso irá converter cada página em um arquivo PDF
33
34
 
34
35
  # Uso para unir vários arquivos PDF.
35
- >>> from file import File, Directory
36
+ >>> from soup_files import File, Directory
36
37
  >>> from pdflib import PdfStream
38
+
37
39
  # instâncie o caminho dos arquivos PDF que deseja unir.
38
40
  f = File('path/to/file.pdf')
39
41
  f2 = File('path/to/file2.pdf)
@@ -3,8 +3,9 @@ pip3 install -r requirements.txt
3
3
 
4
4
 
5
5
  # Uso dividir páginas de um arquivo PDF:
6
- >>> from file import File, Directory
6
+ >>> from soup_files import File, Directory
7
7
  >>> from pdflib import PdfStream
8
+
8
9
  # instâncie o caminho do arquivo PDF e o diretório para exportar os dados.
9
10
  file_pdf = File('path/to/file.pdf')
10
11
  output_dir = Directory('path/to/save')
@@ -14,8 +15,9 @@ pip3 install -r requirements.txt
14
15
  pdf_stream.to_files_pdf(output_dir) # isso irá converter cada página em um arquivo PDF
15
16
 
16
17
  # Uso para unir vários arquivos PDF.
17
- >>> from file import File, Directory
18
+ >>> from soup_files import File, Directory
18
19
  >>> from pdflib import PdfStream
20
+
19
21
  # instâncie o caminho dos arquivos PDF que deseja unir.
20
22
  f = File('path/to/file.pdf')
21
23
  f2 = File('path/to/file2.pdf)
@@ -2,14 +2,21 @@
2
2
  from __future__ import annotations
3
3
  from io import BytesIO
4
4
  from typing import Union
5
- from soup_files import File
5
+ from soup_files import File, Directory, LibraryDocs, InputFiles
6
6
 
7
7
  from ._version import (
8
8
  __module_name__, __author__, __license__, __modify_date__, __version__
9
9
  )
10
+ from .mod_types import (
11
+ MetaDataFile, MetaDataItem, create_metadata, ColumnsTable, ListString, ArrayString,
12
+ HeadCell, HeadValues, ColumnBody, TextTable, LibDate, LibPDF, LibImage, LibPdfToImage,
13
+ LibImageToPdf, create_dict_map_from_file, create_void_dict_map, RotationAngle
14
+ )
10
15
  from .image import ImageObject, CollectionImages
11
16
  from .pdf import DocumentPdf, PageDocumentPdf, CollectionPagePdf
12
- from .doc_stream import PdfStream
17
+ from .pdf.pdf_document import SearchableTextPdf
18
+ from .doc_stream import PdfStream, SplitPdf
19
+ from .table_files import PdfFinder
13
20
 
14
21
 
15
22
  def __create_stream() -> PdfStream:
@@ -68,6 +75,10 @@ def read_image(img: Union[str, File, bytes, BytesIO]) -> PdfStream:
68
75
  __all__ = [
69
76
  '__modify_date__', '__author__', '__license__', '__module_name__', '__version__',
70
77
  'PdfStream', 'DocumentPdf', 'PageDocumentPdf', 'CollectionPagePdf', 'CollectionImages',
71
- 'read_pdf', 'read_files_pdf', 'read_image',
78
+ 'ImageObject', 'File', 'Directory', 'LibraryDocs', 'InputFiles', 'SearchableTextPdf',
79
+ 'PdfFinder', 'SplitPdf', 'read_pdf', 'read_files_pdf', 'read_image',
80
+ 'MetaDataFile', 'MetaDataItem', 'create_metadata', 'ColumnsTable', 'ListString', 'ArrayString',
81
+ 'HeadCell', 'HeadValues', 'ColumnBody', 'TextTable', 'LibDate', 'LibPDF', 'LibImage', 'LibPdfToImage',
82
+ 'LibImageToPdf', 'create_dict_map_from_file', 'create_void_dict_map', 'RotationAngle'
72
83
  ]
73
84
 
@@ -183,7 +183,7 @@ class PdfStream(object):
183
183
 
184
184
  class SplitPdf(object):
185
185
 
186
- def __init__(self, pages: list[PageDocumentPdf] = [], pbar: ProgressBarAdapter = ProgressBarAdapter()):
186
+ def __init__(self, pages: list[PageDocumentPdf], pbar: ProgressBarAdapter = ProgressBarAdapter()):
187
187
  self.pbar: ProgressBarAdapter = pbar
188
188
  self.__collection_pages: CollectionPagePdf = CollectionPagePdf(pages)
189
189
  self.__collection_pages.set_pbar(self.pbar)
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from .img_object import ImageObject, CollectionImages, ProcessImageScanner
4
+ __all__ = ['ImageObject', 'CollectionImages', 'ProcessImageScanner']
5
+
6
+
7
+
@@ -10,12 +10,12 @@ from soup_files import File, Directory, InputFiles, LibraryDocs, ProgressBarAdap
10
10
  from io import BytesIO
11
11
  import numpy as np
12
12
  from scipy.ndimage import uniform_filter
13
- from convert_stream.mod_types import get_void_metadata, get_hash_from_bytes
13
+ from convert_stream.mod_types import get_hash_from_bytes, MetaDataFile, MetaDataItem, create_metadata
14
14
  from convert_stream.mod_types.enums import LibImage, RotationAngle
15
15
  from convert_stream.mod_types.table_types import ListItems
16
16
  from convert_stream.mod_types.modules import (
17
17
  MOD_IMG_PIL, ModuleImage, DEFAULT_LIB_IMAGE,
18
- cv2, MatLike, Image, ImageFilter
18
+ cv2, MatLike, Image, ImageFilter, LibImage
19
19
  )
20
20
 
21
21
 
@@ -26,11 +26,11 @@ class ABCImageObject(ABC):
26
26
  self.max_size: tuple[int, int] = (1980, 720)
27
27
  self.module_image: ModuleImage = module_image
28
28
  self.lib_image: LibImage = LibImage.OPENCV
29
- self.metadata: dict[str, str | None] = get_void_metadata()
29
+ self.metadata: MetaDataFile = MetaDataFile()
30
30
 
31
31
  @property
32
32
  def name(self) -> str | None:
33
- return self.metadata['name']
33
+ return self.metadata.name if not self.metadata.name.is_empty else None
34
34
 
35
35
  @abstractmethod
36
36
  def get_dimensions(self) -> tuple[int, int]:
@@ -205,11 +205,7 @@ class ImplementOpenCv(ABCImageObject):
205
205
  if img is None:
206
206
  raise ValueError(f"Não foi possível abrir a imagem: {f.absolute()}")
207
207
  im_obj = cls(img)
208
- im_obj.metadata['file_path'] = f.absolute()
209
- im_obj.metadata['md5'] = f.md5()
210
- im_obj.metadata['name'] = f.absolute()
211
- im_obj.metadata['size'] = f.size()
212
- im_obj.metadata['extension'] = f.extension()
208
+ im_obj.metadata = create_metadata(f)
213
209
  return im_obj
214
210
 
215
211
  @classmethod
@@ -221,10 +217,10 @@ class ImplementOpenCv(ABCImageObject):
221
217
  bytes_io = BytesIO(bt)
222
218
  name: str = get_hash_from_bytes(bytes_io)
223
219
  bytes_io.close()
224
- _obj = cls(img)
225
- _obj.metadata['md5'] = name
226
- _obj.metadata['name'] = name
227
- return _obj
220
+ im_obj = cls(img)
221
+ im_obj.metadata.name = MetaDataItem(name)
222
+ im_obj.metadata.md5 = MetaDataItem(name)
223
+ return im_obj
228
224
 
229
225
 
230
226
  class ImplementPIL(ABCImageObject):
@@ -352,13 +348,9 @@ class ImplementPIL(ABCImageObject):
352
348
 
353
349
  @classmethod
354
350
  def create_from_file(cls, f: File) -> ABCImageObject:
355
- img = Image.open(f.path)
351
+ img = Image.open(f.absolute())
356
352
  im_obj = cls(img)
357
- im_obj.metadata['file_path'] = f.absolute()
358
- im_obj.metadata['md5'] = f.md5()
359
- im_obj.metadata['name'] = f.absolute()
360
- im_obj.metadata['size'] = f.size()
361
- im_obj.metadata['extension'] = f.extension()
353
+ im_obj.metadata = create_metadata(f)
362
354
  return im_obj
363
355
 
364
356
  @classmethod
@@ -368,8 +360,8 @@ class ImplementPIL(ABCImageObject):
368
360
  name = get_hash_from_bytes(bytes_io)
369
361
  bytes_io.close()
370
362
  _obj = cls(img)
371
- _obj.metadata['md5'] = name
372
- _obj.metadata['name'] = name
363
+ _obj.metadata.name = MetaDataItem(name)
364
+ _obj.metadata.md5 = MetaDataItem(name)
373
365
  return _obj
374
366
 
375
367
 
@@ -419,9 +411,13 @@ class ImageObject(object):
419
411
  return self.img_adapter.name
420
412
 
421
413
  @property
422
- def metadata(self) -> dict[str, str | None]:
414
+ def metadata(self) -> MetaDataFile:
423
415
  return self.img_adapter.metadata
424
416
 
417
+ @metadata.setter
418
+ def metadata(self, metadata: MetaDataFile) -> None:
419
+ self.img_adapter.metadata = metadata
420
+
425
421
  def to_pil(self) -> Image.Image:
426
422
  """
427
423
  Converte o ImageObject para um objeto PIL.Image.
@@ -600,3 +596,72 @@ class CollectionImages(ListItems):
600
596
  def set_pbar(self, p: ProgressBarAdapter) -> None:
601
597
  self.pbar = p
602
598
 
599
+
600
+ class ProcessImageScanner(object):
601
+
602
+ def __init__(self, image: ImageObject):
603
+ self.image: ImageObject = image
604
+
605
+ def select_doc(self) -> ImageObject | None:
606
+ """
607
+ Detecta e recorta automaticamente a área do documento principal
608
+ (texto ou folha digitalizada) em uma imagem.
609
+ Retorna um novo ImageObject contendo apenas o recorte detectado.
610
+ """
611
+ # Converte para matriz OpenCV
612
+ img_cv: np.ndarray = cv2.imdecode(self.image.to_numpy(), cv2.IMREAD_COLOR)
613
+ if img_cv is None:
614
+ print(f'[NDARRAY] Falha na imagem: {self.image.metadata.name}')
615
+ return None
616
+
617
+ # Etapa 1: converter para tons de cinza
618
+ gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
619
+
620
+ # Etapa 2: aplicar blur para suavizar ruídos
621
+ gray_blur = cv2.GaussianBlur(gray, (5, 5), 0)
622
+
623
+ # Etapa 3: detecção de bordas
624
+ edges = cv2.Canny(gray_blur, 50, 150)
625
+
626
+ # Etapa 4: encontrar contornos
627
+ contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
628
+ if not contours:
629
+ print(f'[CONTOURS] Falha na imagem: {self.image.metadata.name}')
630
+ return None
631
+
632
+ # Etapa 5: selecionar o maior contorno plausível (maior área retangular)
633
+ contours = sorted(contours, key=cv2.contourArea, reverse=True)
634
+ doc_contour = None
635
+
636
+ for c in contours:
637
+ perimeter = cv2.arcLength(c, True)
638
+ approx = cv2.approxPolyDP(c, 0.02 * perimeter, True)
639
+ if len(approx) == 4:
640
+ doc_contour = approx
641
+ break
642
+
643
+ if doc_contour is None:
644
+ # Caso não encontre um quadrilátero, usa o maior contorno
645
+ doc_contour = contours[0]
646
+
647
+ # Etapa 6: criar bounding box e recortar
648
+ x, y, w, h = cv2.boundingRect(doc_contour)
649
+ cropped = img_cv[y:y + h, x:x + w]
650
+
651
+ # Evitar recortes muito pequenos (ruído)
652
+ if w < 50 or h < 50:
653
+ return None
654
+
655
+ # Etapa 7: converter o recorte em ImageObject
656
+ success, buffer = cv2.imencode(".png", cropped)
657
+ if not success:
658
+ print(f'Falha na imagem: {self.image.metadata.name}')
659
+ return None
660
+
661
+ bytes_io = BytesIO(buffer.tobytes())
662
+ new_image = ImageObject(bytes_io, lib_image=LibImage.OPENCV)
663
+ # Herdar metadados originais
664
+ new_image.metadata = self.image.metadata
665
+ new_image.metadata.name = MetaDataItem(f"{self.image.metadata.name}_crop")
666
+ return new_image
667
+
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ from __future__ import annotations
4
+ from hashlib import md5 as md5_hash
5
+ from io import BytesIO
6
+ from soup_files import File
7
+ from .enums import (
8
+ RotationAngle, ColumnsTable, LibImage, LibPdfToImage, LibPDF, LibImageToPdf, LibDate
9
+ )
10
+
11
+ from .table_types import (
12
+ TextTable, ListString, ArrayString, HeadCell, HeadValues,
13
+ ColumnBody, create_void_dict_map, create_dict_map_values, create_void_df_map,
14
+ create_dict_map_from_file, concat_maps, contains, get_text_from_file
15
+ )
16
+
17
+
18
+ def get_hash_from_bytes(bt: BytesIO | bytes) -> str:
19
+ if isinstance(bt, BytesIO):
20
+ return md5_hash(bt.getvalue()).hexdigest().upper()
21
+ elif isinstance(bt, bytes):
22
+ return md5_hash(bt).hexdigest().upper()
23
+ else:
24
+ raise TypeError(f"Unsupported type {type(bt)}")
25
+
26
+
27
+ class MetaDataItem(str):
28
+
29
+ def __init__(self, text: str = 'nan'):
30
+ super().__init__()
31
+ self.text: str = text
32
+
33
+ @property
34
+ def is_empty(self) -> bool:
35
+ return self.text == 'nan'
36
+
37
+
38
+ class MetaDataFile(object):
39
+
40
+ def __init__(
41
+ self, *,
42
+ file_path: MetaDataItem = MetaDataItem(),
43
+ dir_path: MetaDataItem = MetaDataItem(),
44
+ name: MetaDataItem = MetaDataItem(),
45
+ md5: MetaDataItem = MetaDataItem(),
46
+ size: MetaDataItem = MetaDataItem(),
47
+ extension: MetaDataItem = MetaDataItem(),
48
+ origin_src: MetaDataItem = MetaDataItem(),
49
+ ):
50
+ self.file_path: MetaDataItem = file_path
51
+ self.dir_path: MetaDataItem = dir_path
52
+ self.name: MetaDataItem = name
53
+ self.md5: MetaDataItem = md5
54
+ self.size: MetaDataItem = size
55
+ self.extension: MetaDataItem = extension
56
+ self.origin_src: MetaDataItem = origin_src
57
+
58
+ def to_dict(self) -> dict[str, str | None]:
59
+ return {
60
+ 'file_path': self.file_path if not self.file_path.is_empty else None,
61
+ 'dir_path': self.dir_path if not self.dir_path.is_empty else None,
62
+ 'name': self.name if not self.name.is_empty else None,
63
+ 'md5': self.md5 if not self.md5.is_empty else None,
64
+ 'size': self.size if not self.size.is_empty else None,
65
+ 'extension': self.extension if not self.extension.is_empty else None,
66
+ 'origin_src': self.origin_src if not self.origin_src.is_empty else None,
67
+ }
68
+
69
+
70
+ def get_void_metadata() -> dict[str, str | None]:
71
+ """
72
+ Salvar os metadados básico de documentos/imagens lidas em disco.
73
+ """
74
+ return MetaDataFile().to_dict()
75
+
76
+
77
+ def create_metadata(file: str | File) -> MetaDataFile:
78
+ if isinstance(file, str):
79
+ file = File(file)
80
+ mt = MetaDataFile(
81
+ file_path=MetaDataItem(file.absolute()),
82
+ dir_path=MetaDataItem(file.dirname()),
83
+ extension=MetaDataItem(file.extension()),
84
+ origin_src=MetaDataItem('file'),
85
+ name=MetaDataItem(file.name()),
86
+ )
87
+ if file.exists():
88
+ mt.size = MetaDataItem(file.size())
89
+ mt.md5 = MetaDataItem(file.md5())
90
+ return mt
91
+
92
+
93
+ __all__ = [
94
+ 'get_hash_from_bytes', 'get_void_metadata', 'get_void_metadata', 'contains',
95
+ 'concat_maps', 'create_dict_map_from_file', 'create_dict_map_values',
96
+ 'create_void_df_map', 'create_void_dict_map', 'ColumnBody', 'ColumnsTable',
97
+ 'ListString', 'HeadCell', 'HeadValues', 'TextTable', 'RotationAngle', 'LibPDF',
98
+ 'LibImageToPdf', 'LibPdfToImage', 'LibImage', 'LibDate', 'ArrayString',
99
+ 'MetaDataFile', 'MetaDataItem', 'create_metadata',
100
+ ]
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env python3
2
- #
2
+
3
3
  from __future__ import annotations
4
4
  from convert_stream.mod_types.enums import ColumnsTable
5
5
  import os.path
6
6
  import pandas as pd
7
- from soup_files import File, ProgressBarAdapter, CreatePbar
7
+ from soup_files import File
8
8
 
9
9
 
10
10
  def contains(text: str, values: list[str], *, case: bool = True, iqual: bool = False) -> bool:
@@ -32,6 +32,61 @@ def contains(text: str, values: list[str], *, case: bool = True, iqual: bool = F
32
32
  return False
33
33
 
34
34
 
35
+ def find_index(text: str, values: list[str], *, case: bool = True, iqual: bool = False) -> int | None:
36
+ """
37
+ Verificar se um texto existe em lista de ‘strings’ se existir, retorna o índice da posição
38
+ do texto na lista.
39
+ """
40
+ _idx: int | None = None
41
+ if case:
42
+ if iqual:
43
+ for num, x in enumerate(values):
44
+ if text == x:
45
+ _idx = num
46
+ break
47
+ else:
48
+ for num, x in enumerate(values):
49
+ if text in x:
50
+ _idx = num
51
+ break
52
+ else:
53
+ if iqual:
54
+ for num, x in enumerate(values):
55
+ if text.upper() == x.upper():
56
+ _idx = num
57
+ break
58
+ else:
59
+ for num, x in enumerate(values):
60
+ if text.upper() in x.upper():
61
+ _idx = num
62
+ break
63
+ return _idx
64
+
65
+
66
+ def find_all_index(text: str, values: list[str], *, case: bool = True, iqual: bool = False) -> list[int]:
67
+ """
68
+
69
+ """
70
+ items: list[int] = ListItems([])
71
+ if iqual:
72
+ for num, i in enumerate(values):
73
+ if case:
74
+ if i == text:
75
+ items.append(num)
76
+ else:
77
+ if text.lower() == i.lower():
78
+ items.append(num)
79
+ else:
80
+ for num, i in enumerate(values):
81
+ if case:
82
+ if text in i:
83
+ items.append(num)
84
+ else:
85
+ if text.lower() in i.lower():
86
+ items.append(num)
87
+ return items
88
+
89
+
35
90
  class ListItems(list):
36
91
 
37
92
  def __init__(self, items: list):
@@ -57,6 +112,9 @@ class ListString(ListItems):
57
112
  def contains(self, item: str, *, case: bool = True, iqual: bool = False) -> bool:
58
113
  return contains(item, self, case=case, iqual=iqual)
59
114
 
115
+ def find_index(self, item: str, *, case: bool = True, iqual: bool = False) -> int | None:
116
+ return find_index(item, self, case=case, iqual=iqual)
117
+
60
118
  def get(self, idx: int) -> str:
61
119
  return self[idx]
62
120
 
@@ -77,35 +135,23 @@ class ArrayString(ListString):
77
135
  def __init__(self, items: list[str]):
78
136
  super().__init__(items)
79
137
 
80
- def get_next(self, text: str, *, iqual: bool = False, case: bool = False) -> str | None:
138
+ def get_next_string(self, text: str, *, iqual: bool = False, case: bool = False) -> str | None:
81
139
  """
82
140
  Ao encontrar o texto 'text' na lista retorna a próxima string se existir, se não retorna None.
83
141
  """
84
- _idx: int | None = self.get_back_index(text, iqual=iqual, case=case)
85
- if _idx is None:
86
- return None
87
- if _idx < 0:
88
- return None
89
- if _idx >= self.length - 1:
90
- return None
91
- return self[_idx+1]
142
+ next_idx: int | None = self.get_next_index(text, iqual=iqual, case=case)
143
+ return None if next_idx is None else self[next_idx]
92
144
 
93
145
  def get_next_all(self, text: str, iqual: bool = False, case: bool = False) -> ListString:
94
- _idx: int | None = self.get_back_index(text, iqual=iqual, case=case)
95
- if _idx is None:
96
- return ListString([])
97
- if _idx < 0:
98
- return ListString([])
99
- if _idx >= self.length - 1:
100
- return ListString([])
101
- return ListString(self[(_idx + 1):])
146
+ next_idx: int | None = self.get_next_index(text, iqual=iqual, case=case)
147
+ return ListString([]) if next_idx is None else ListString(self[next_idx:])
102
148
 
103
149
  def get_next_index(self, text: str, *, iqual: bool = False, case: bool = False) -> int | None:
104
150
  """
105
151
  Ao encontrar o texto 'text' na lista retorna o índice da string anterior
106
152
  se existir, se não retorna None.
107
153
  """
108
- _idx: int | None = self.get_back_index(text, iqual=iqual, case=case)
154
+ _idx: int | None = self.find_index(text, iqual=iqual, case=case)
109
155
  if _idx is None:
110
156
  return None
111
157
  if _idx < 0:
@@ -126,7 +172,7 @@ class ArrayString(ListString):
126
172
  return None
127
173
  return _final_idx - 1
128
174
 
129
- def get_back(self, text: str, iqual: bool = False, case: bool = False) -> str | None:
175
+ def get_back_string(self, text: str, iqual: bool = False, case: bool = False) -> str | None:
130
176
  """
131
177
  Ao encontrar o texto 'text' na lista retorna a string anterior se existir, se não retorna None.
132
178
  """
@@ -137,79 +183,24 @@ class ArrayString(ListString):
137
183
  _idx = self.get_back_index(text, iqual=iqual, case=case)
138
184
  return ListString([]) if _idx is None else ListString(self[:_idx])
139
185
 
140
- def find_index(self, text: str, *, iqual: bool = False, case: bool = True) -> int | None:
141
- num_idx = None
142
- if iqual:
143
- for idx, i in enumerate(self):
144
- if case:
145
- if i == text:
146
- num_idx = idx
147
- break
148
- else:
149
- if text.lower() == i.lower():
150
- num_idx = idx
151
- break
152
- else:
153
- for idx, i in enumerate(self):
154
- if case:
155
- if text in i:
156
- num_idx = idx
157
- break
158
- else:
159
- if text.lower() in i.lower():
160
- num_idx = idx
161
- break
162
- return num_idx
163
-
164
186
  def get(self, idx: int) -> str:
165
187
  return self[idx]
166
188
 
167
- def find(self, text: str, *, iqual: bool = False, case: bool = False) -> str | None:
168
- if text is None:
189
+ def find_text(self, text: str, *, iqual: bool = False, case: bool = False) -> str | None:
190
+ if (text is None) or (text == ""):
169
191
  raise ValueError(f'{__class__.__name__}: text is None')
192
+ idx_item = self.find_index(text, iqual=iqual, case=case)
193
+ return None if idx_item is None else self[idx_item]
170
194
 
171
- element = None
172
- if iqual:
173
- for i in self:
174
- if case:
175
- if text == i:
176
- element = i
177
- break
178
- else:
179
- if text.lower() == i.lower():
180
- element = i
181
- break
182
- else:
183
- for i in self:
184
- if case:
185
- if text in i:
186
- element = i
187
- break
188
- else:
189
- if text.lower() in i.lower():
190
- element = i
191
- break
192
- return element
195
+ def find_all(self, text: str, *, iqual: bool = False, case: bool = True) -> ListString:
196
+ list_idx: list[int] = find_all_index(text, self, case=case, iqual=iqual)
197
+ if len(list_idx) == 0:
198
+ return ListString([])
193
199
 
194
- def find_all(self, text: str, *, iqual: bool = False, case: bool = True) -> list[str]:
195
- items = []
196
- if iqual:
197
- for i in self:
198
- if case:
199
- if i == text:
200
- items.append(i)
201
- else:
202
- if text.lower() == i.lower():
203
- items.append(i)
204
- else:
205
- for i in self:
206
- if case:
207
- if text in i:
208
- items.append(i)
209
- else:
210
- if text.lower() in i.lower():
211
- items.append(i)
212
- return items
200
+ new_values = ListString([])
201
+ for idx in list_idx:
202
+ new_values.append(self[idx])
203
+ return new_values
213
204
 
214
205
  def count(self, text: str, *, iqual: bool = False, case: bool = True) -> int:
215
206
  count: int = 0
@@ -257,7 +248,7 @@ class HeadValues(ListString):
257
248
  self.append(i)
258
249
 
259
250
 
260
- class ColumnBody(ListString):
251
+ class ColumnBody(ArrayString):
261
252
  """
262
253
  Lista de strings nomeada para representar os dados da coluna de uma tabela.
263
254
  """
@@ -301,7 +292,7 @@ class TextTable(dict):
301
292
  self[col.col_name] = col
302
293
 
303
294
 
304
- def create_void_map() -> dict[str, ColumnBody]:
295
+ def create_void_dict_map() -> dict[str, ColumnBody]:
305
296
 
306
297
  return {
307
298
  ColumnsTable.KEY.value: ColumnBody(ColumnsTable.KEY.value, ListString([])),
@@ -315,16 +306,16 @@ def create_void_map() -> dict[str, ColumnBody]:
315
306
  }
316
307
 
317
308
 
318
- def create_void_table() -> pd.DataFrame:
309
+ def create_void_df_map() -> pd.DataFrame:
319
310
  """
320
311
  Retorna um DataFrame() vazio, apenas com as colunas formatadas
321
312
  para tabela de arquivos.
322
313
  @rtype: pd.DataFrame
323
314
  """
324
- return pd.DataFrame.from_dict(create_void_map())
315
+ return pd.DataFrame.from_dict(create_void_dict_map())
325
316
 
326
317
 
327
- def create_map_from_values(
318
+ def create_dict_map_values(
328
319
  values: list[str], *,
329
320
  page_num: str = 'nan',
330
321
  file_path: str = 'nan',
@@ -343,9 +334,9 @@ def create_map_from_values(
343
334
  """
344
335
  max_num = len(values)
345
336
  if max_num < 1:
346
- return create_void_map()
337
+ return create_void_dict_map()
347
338
 
348
- _map: dict[str, ColumnBody] = create_void_map()
339
+ _map: dict[str, ColumnBody] = create_void_dict_map()
349
340
  _map[ColumnsTable.KEY.value].extend([f'{x}' for x in range(0, max_num)])
350
341
  _map[ColumnsTable.NUM_PAGE.value].extend([page_num] * max_num)
351
342
  _map[ColumnsTable.NUM_LINE.value].extend([f'{x+1}' for x in range(0, max_num)])
@@ -357,8 +348,9 @@ def create_map_from_values(
357
348
  return _map
358
349
 
359
350
 
360
- def create_map_from_file_values(
361
- file: File, values: list[str], *,
351
+ def create_dict_map_from_file(
352
+ file: File,
353
+ values: list[str], *,
362
354
  page_num: str = 'nan'
363
355
  ) -> dict[str, ColumnBody]:
364
356
  """
@@ -370,16 +362,19 @@ def create_map_from_file_values(
370
362
  """
371
363
  max_num = len(values)
372
364
  if max_num < 1:
373
- return create_void_map()
374
- return create_map_from_values(
365
+ return create_void_dict_map()
366
+ return create_dict_map_values(
375
367
  values, page_num=page_num, file_path=file.absolute(), dir_path=file.dirname(), file_type=file.extension()
376
368
  )
377
369
 
378
370
 
379
- def get_text_from_file(file: str) -> ListString:
371
+ def get_text_from_file(file: str | File) -> ListString:
380
372
  """
381
373
  Retorna o texto de um arquivo .txt em formato de lista
382
374
  """
375
+ if isinstance(file, File):
376
+ file = file.absolute()
377
+
383
378
  try:
384
379
  with open(file, 'rt') as f:
385
380
  lines = ListString(f.readlines())