table-stream 0.2.0__tar.gz → 0.2.2__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 (26) hide show
  1. {table_stream-0.2.0 → table_stream-0.2.2}/PKG-INFO +1 -1
  2. {table_stream-0.2.0 → table_stream-0.2.2}/pyproject.toml +1 -1
  3. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/__init__.py +4 -3
  4. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/erros.py +24 -18
  5. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/sysfiles.py +0 -1
  6. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/table.py +129 -110
  7. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream.egg-info/PKG-INFO +1 -1
  8. {table_stream-0.2.0 → table_stream-0.2.2}/README.md +0 -0
  9. {table_stream-0.2.0 → table_stream-0.2.2}/setup.cfg +0 -0
  10. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/hash_map.py +0 -0
  11. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/notifier.py +0 -0
  12. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/pattner/__init__.py +0 -0
  13. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/pattner/adapter.py +0 -0
  14. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/sheet/__init__.py +0 -0
  15. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/sheet/check_mod.py +0 -0
  16. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/sheet/load.py +0 -0
  17. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/sheet/options.py +0 -0
  18. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/sheet/parse.py +0 -0
  19. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/sheet/save.py +0 -0
  20. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/state.py +0 -0
  21. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/thread.py +0 -0
  22. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream/workbook.py +0 -0
  23. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream.egg-info/SOURCES.txt +0 -0
  24. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream.egg-info/dependency_links.txt +0 -0
  25. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream.egg-info/requires.txt +0 -0
  26. {table_stream-0.2.0 → table_stream-0.2.2}/table_stream.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: table_stream
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Tipos de dados e implementações para o uso em tabelas.
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "table_stream"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "Tipos de dados e implementações para o uso em tabelas."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -66,11 +66,12 @@ from .table import (
66
66
  TableEmptyError,
67
67
  EmptyRowError,
68
68
  ColumnNotFoundError,
69
- HeaderNotFoundError,
69
+ ColumnNotFoudError,
70
70
  HeadersSizeNotIqualError,
71
71
  concat_tables,
72
72
  RowNotExistError,
73
73
  TableData,
74
+ Table,
74
75
  ListTablesEmptyError,
75
76
  )
76
77
 
@@ -84,8 +85,8 @@ from .erros import (
84
85
  ListTablesEmptyError,
85
86
  LoadWorkbookError,
86
87
  NotImplementedModuleError,
87
- HeaderNotFoundError,
88
+ ColumnNotFoudError,
88
89
  HeadersSizeNotIqualError,
89
90
  )
90
91
 
91
- __version__ = "0.2.0"
92
+ __version__ = "0.2.2"
@@ -1,6 +1,6 @@
1
1
  class CoreException(Exception):
2
2
 
3
- def __init__(self, message: str = f'Erro') -> None:
3
+ def __init__(self, message: str = f"Erro") -> None:
4
4
  super().__init__(message)
5
5
  self._message = message
6
6
 
@@ -17,13 +17,13 @@ class CoreException(Exception):
17
17
 
18
18
  class ValueNotifyNullError(CoreException):
19
19
 
20
- def __init__(self, message: str = 'Notificação nula...') -> None:
20
+ def __init__(self, message: str = "Notificação nula...") -> None:
21
21
  super().__init__(message)
22
22
 
23
23
 
24
24
  class UnsuportedSheetError(CoreException):
25
25
 
26
- def __init__(self, message: str = 'Planilha inválida...') -> None:
26
+ def __init__(self, message: str = "Planilha inválida...") -> None:
27
27
  super().__init__(message)
28
28
 
29
29
 
@@ -31,21 +31,22 @@ class UnsuportedSheetError(CoreException):
31
31
  # Erros relacionados a HashMap
32
32
  # ============================================================#
33
33
 
34
+
34
35
  class InvalidHashMapTableError(CoreException):
35
36
 
36
- def __init__(self, message: str = 'HashMap inválido') -> None:
37
+ def __init__(self, message: str = "HashMap inválido") -> None:
37
38
  super().__init__(message)
38
39
 
39
40
 
40
41
  class InvalidBodyTableError(InvalidHashMapTableError):
41
42
 
42
- def __init__(self, message: str = 'Erro corpo de tabela inválido') -> None:
43
+ def __init__(self, message: str = "Erro corpo de tabela inválido") -> None:
43
44
  super().__init__(message)
44
45
 
45
46
 
46
47
  class SizeTableError(InvalidHashMapTableError):
47
48
 
48
- def __init__(self, message: str = 'Tamanho de tabela inválido') -> None:
49
+ def __init__(self, message: str = "Tamanho de tabela inválido") -> None:
49
50
  super().__init__(message)
50
51
 
51
52
 
@@ -54,21 +55,22 @@ class SizeTableError(InvalidHashMapTableError):
54
55
  # ============================================================#
55
56
  class UndefinedSheetIndex(CoreException):
56
57
 
57
- def __init__(self, message: str = 'SheetIndexNames não foi definido') -> None:
58
+ def __init__(self, message: str = "SheetIndexNames não foi definido") -> None:
58
59
  super().__init__(message)
59
60
 
60
61
 
61
62
  class LoadWorkbookError(CoreException):
62
63
 
63
- def __init__(self, message: str = 'Erro ao tentar ler Workbook') -> None:
64
+ def __init__(self, message: str = "Erro ao tentar ler Workbook") -> None:
64
65
  super().__init__(message)
65
66
 
67
+
66
68
  # ============================================================#
67
69
  # Erros relacionados a arquivos/bytes de imagem (.png, .jpg, ...)
68
70
  # ============================================================#
69
71
  class InvalidSourceImageError(CoreException):
70
72
 
71
- def __init__(self, message: str = 'Erro, use bytes de imagem') -> None:
73
+ def __init__(self, message: str = "Erro, use bytes de imagem") -> None:
72
74
  super().__init__(message)
73
75
 
74
76
 
@@ -77,56 +79,60 @@ class InvalidSourceImageError(CoreException):
77
79
  # ============================================================#
78
80
  class NotImplementedModuleError(CoreException):
79
81
 
80
- def __init__(self, message: str = 'Erro, módulo não implementado') -> None:
82
+ def __init__(self, message: str = "Erro, módulo não implementado") -> None:
81
83
  super().__init__(message)
82
84
 
83
85
 
84
86
  class NotImplementedModuleImageError(NotImplementedModuleError):
85
87
 
86
- def __init__(self, message: str = 'Erro, módulo IMAGEM não implementado') -> None:
88
+ def __init__(self, message: str = "Erro, módulo IMAGEM não implementado") -> None:
87
89
  super().__init__(message)
88
90
 
89
91
 
90
92
  class NotImplementedModulePdfError(NotImplementedModuleError):
91
93
 
92
- def __init__(self, message: str = 'Erro, módulo PDF não implementado') -> None:
94
+ def __init__(self, message: str = "Erro, módulo PDF não implementado") -> None:
93
95
  super().__init__(message)
94
96
 
95
97
 
96
98
  class NotImplementedInvertColor(NotImplementedError):
97
99
 
98
- def __init__(self, message: str = 'Adaptador InvertColor não implementado...') -> None:
100
+ def __init__(
101
+ self, message: str = "Adaptador InvertColor não implementado..."
102
+ ) -> None:
99
103
  super().__init__(message)
100
104
 
105
+
101
106
  # ============================================================#
102
107
  # Erros relacionados a tabelas
103
108
  # ============================================================#
104
109
 
105
110
 
106
111
  class ColumnNotFoudError(ValueError):
107
-
112
+
108
113
  def __init__(self, *args: object) -> None:
109
114
  super().__init__(*args)
110
115
 
111
- class ColumnNotIqualSizeError(ValueError):
116
+
117
+ class ColumnExistsError(ValueError):
112
118
 
113
119
  def __init__(self, *args: object) -> None:
114
120
  super().__init__(*args)
115
121
 
116
122
 
117
- class EmptyRowError(Exception):
123
+ class ColumnNotIqualSizeError(ValueError):
118
124
 
119
125
  def __init__(self, *args: object) -> None:
120
126
  super().__init__(*args)
121
127
 
122
128
 
123
- class TableEmptyError(Exception):
129
+ class EmptyRowError(Exception):
124
130
 
125
131
  def __init__(self, *args: object) -> None:
126
132
  super().__init__(*args)
127
133
 
128
134
 
129
- class HeaderNotFoundError(Exception):
135
+ class TableEmptyError(Exception):
130
136
 
131
137
  def __init__(self, *args: object) -> None:
132
138
  super().__init__(*args)
@@ -687,7 +687,6 @@ def create_void_table_files() -> TableData[HeaderMetaData]:
687
687
  """
688
688
 
689
689
  tb = TableData()
690
-
691
690
  tb.add(ColumnV(HeaderMetaData.HASH_FILE))
692
691
  tb.add(ColumnV(HeaderMetaData.FILE_NAME))
693
692
  tb.add(ColumnV(HeaderMetaData.FILE_EXTENSION))
@@ -7,11 +7,12 @@ from abc import abstractmethod, ABC
7
7
  from table_stream.hash_map import ArrayList, HashMapDict, HashMap, HashMapDataFrame
8
8
  from table_stream.erros import (
9
9
  ColumnNotFoudError,
10
+ ColumnExistsError,
10
11
  RowNotExistError,
11
12
  EmptyRowError,
12
13
  ColumnNotFoundError,
13
14
  HeadersSizeNotIqualError,
14
- HeaderNotFoundError,
15
+ ColumnNotFoudError,
15
16
  TableEmptyError,
16
17
  ListTablesEmptyError,
17
18
  )
@@ -34,15 +35,17 @@ class RowH[HEAD, T]:
34
35
  self.index: int = index
35
36
 
36
37
  def __repr__(self) -> str:
37
- default = f"{__class__.__name__}():"
38
+ sep = "->"
39
+ default_text = f"<{__class__.__name__}()>"
40
+
38
41
  if len(self.map) == 0:
39
- return f"{default} Size: 0"
42
+ return f"{default_text} Size 0 {sep} []"
40
43
 
41
44
  _values = ArrayList()
42
45
  for k, v in self.map.items():
43
46
  _values.add(f"{k} -> {v}")
44
47
 
45
- return f"{default}\n{_values}"
48
+ return f"{default_text} Size {len(self.map)} {sep} {_values}"
46
49
 
47
50
  def __eq__(self, other: object) -> bool:
48
51
  if not isinstance(other, RowH):
@@ -89,8 +92,8 @@ class ColumnV[HEAD, T]:
89
92
  self.head: HEAD = head
90
93
 
91
94
  def __repr__(self) -> str:
92
-
93
- return f"{__class__.__name__}(): Head {self.head}; Size {self.size()}; Type {self.get_type()};\n{self._elements}"
95
+ txt = f"Head {self.head}; Size {self.size()}; Type {self.get_type()} -> {self._elements}"
96
+ return f"{__class__.__name__}(): {txt}"
94
97
 
95
98
  # ---------------------------------------------------#
96
99
  # Leitura de Dados.
@@ -288,7 +291,7 @@ class Table[HEAD](ABC):
288
291
  Adiciona uma nova coluna com texto padrão NULL_TEXT.
289
292
  """
290
293
 
291
- if self.empty():
294
+ if self.is_empty():
292
295
  self.add(ColumnV(h))
293
296
  return
294
297
 
@@ -296,24 +299,9 @@ class Table[HEAD](ABC):
296
299
  values = [Table.NULL_STRING] * total
297
300
  self.add(ColumnV(h, ArrayList(values)))
298
301
 
302
+ @abstractmethod
299
303
  def merge(self, tb: Table) -> None:
300
- if tb.empty():
301
- raise TableEmptyError(f"Não é possível unir uma tabela vazia!")
302
-
303
- if self.header().size() != tb.header().size():
304
- raise HeadersSizeNotIqualError(
305
- "Não é possível juntar tabelas com cabeçalhos diferentes!"
306
- )
307
-
308
- header = self.header()
309
- # print(f"[UNINDO TABELAS] Atual: {self} Incrementando: {tb}")
310
-
311
- for h in header:
312
- if not tb.contains_header(h):
313
- raise ColumnNotFoundError(f"Coluna inexistente ... {h}")
314
-
315
- current_col: ColumnV = tb.get(h)
316
- self.get(h).add_all(current_col._elements)
304
+ pass
317
305
 
318
306
  @abstractmethod
319
307
  def set(self, col: ColumnV[HEAD, ArrayList[T]]):
@@ -326,39 +314,17 @@ class Table[HEAD](ABC):
326
314
  @abstractmethod
327
315
  def add(self, col: ColumnV) -> None:
328
316
  """
329
- Adiciona uma coluna na tabela.
317
+ Adiciona uma coluna na tabela, se já existir uma coluna com o mesmo nome lança uma
318
+ exceção ColumnExistsError()
330
319
  """
331
320
  pass
332
321
 
322
+ @abstractmethod
333
323
  def add_row(self, row: RowH[HEAD, Any]):
334
324
  """
335
325
  Adiciona uma linha a tabela se a linha não estiver vazia.
336
326
  """
337
- if row.is_empty():
338
- return None
339
-
340
- if self.empty():
341
- for row_header in row.header():
342
- self.add(ColumnV(row_header))
343
-
344
- header: ArrayList[HEAD] = self.header()
345
-
346
- if row.header().size() < header.size():
347
- raise HeadersSizeNotIqualError(
348
- "A linha que você está tentando adicionar tem cabeçalho menor que o da tabela!!!"
349
- )
350
-
351
- for h in header:
352
- if not row.header().contains(h):
353
- msg = f"Você está tentando adicionar uma linha que não possui o cabeçalho >> [{h}] <<"
354
-
355
- raise HeaderNotFoundError(
356
- f"{msg} \nCabeçalhos existentes na linha => {row.header()}\n\nCabeçalhos da tabela => {header}"
357
- )
358
-
359
- # self.tb_map[h].add(row.get(h))
360
- self.get(h).add(row.get(h))
361
- return None
327
+ pass
362
328
 
363
329
  # ---------------------------------------------------#
364
330
  # Leitura de dados - READ
@@ -372,7 +338,7 @@ class Table[HEAD](ABC):
372
338
  pass
373
339
 
374
340
  def get_row_at(self, idx: int) -> RowH[HEAD, Any]:
375
- if self.empty():
341
+ if self.is_empty():
376
342
  raise TableEmptyError("A tabela está vazia")
377
343
 
378
344
  total = self.get_first().size()
@@ -397,7 +363,7 @@ class Table[HEAD](ABC):
397
363
  def rows(self) -> ArrayList[RowH[HEAD, Any]]:
398
364
  final = ArrayList[RowH]()
399
365
 
400
- if self.empty():
366
+ if self.is_empty():
401
367
  return final
402
368
 
403
369
  total = self.get(self.header().get_first()).size()
@@ -425,7 +391,7 @@ class Table[HEAD](ABC):
425
391
  header = self.header()
426
392
  h: HEAD
427
393
 
428
- if self.empty():
394
+ if self.is_empty():
429
395
  if header.empty():
430
396
  print(f"{self}")
431
397
  else:
@@ -457,14 +423,21 @@ class Table[HEAD](ABC):
457
423
  def search(self, h: HEAD, value: Any) -> Table[HEAD]:
458
424
  pass
459
425
 
426
+ @abstractmethod
427
+ def search_all(self, h: HEAD, values: list[T]) -> Table[HEAD] | None:
428
+ pass
429
+
460
430
  # ---------------------------------------------------#
461
431
  # Verificação/validação de dados
462
432
  # ---------------------------------------------------#
463
433
  def size(self) -> int:
464
- if self.empty():
434
+ if self.is_empty():
465
435
  return 0
466
436
  return self.get_first().size()
467
437
 
438
+ def size_header(self) -> int:
439
+ return self.header().size()
440
+
468
441
  def contains_header(self, h: HEAD) -> bool:
469
442
  return self.header().contains(h)
470
443
 
@@ -475,9 +448,19 @@ class Table[HEAD](ABC):
475
448
  return self.get(h).contains(value)
476
449
 
477
450
  @abstractmethod
478
- def empty(self) -> bool:
451
+ def is_empty(self) -> bool:
452
+ """
453
+ Retorna True se a tabela não tiver linhas, mesmo que o cabeçalho exista.
454
+ """
479
455
  pass
480
456
 
457
+ @abstractmethod
458
+ def is_void(self) -> bool:
459
+ """
460
+ Retorna True se o cabeçalho estiver vazio. False se a tabela tiver pelo menos uma coluna
461
+ mesmo que esteja vazia.
462
+ """
463
+
481
464
  # ---------------------------------------------------#
482
465
  # Exclusão de dados - DELETE
483
466
  # ---------------------------------------------------#
@@ -540,13 +523,27 @@ class TableData[HEAD](Table):
540
523
  self._table_data: pd.DataFrame = data
541
524
 
542
525
  def __repr__(self) -> str:
543
- return f"{__class__.__name__}(): Size {self.size()}; Columns {self.header().size()}"
526
+ msg = f"{__class__.__name__}(): Size {self.size()}; Columns {self.header().size()};"
527
+
528
+ if self.size() > 0:
529
+ row = self.get_row_at(0)
530
+ msg = f"{msg}\n{row}"
531
+
532
+ return f"{msg}"
544
533
 
545
534
  # ---------------------------------------------------------- #
546
535
  # Verificação/Validação de dados.
547
536
  # ---------------------------------------------------------- #
548
- def empty(self) -> bool:
549
- return self._table_data.empty
537
+ def is_empty(self) -> bool:
538
+ if self.size_header() == 0:
539
+ return True
540
+ return len(self._table_data[self.header().get_first()]) == 0
541
+
542
+ def is_void(self) -> bool:
543
+ return self.size_header() == 0
544
+
545
+ def size_header(self) -> int:
546
+ return self.header().size()
550
547
 
551
548
  def size(self) -> int:
552
549
  return len(self._table_data)
@@ -559,14 +556,14 @@ class TableData[HEAD](Table):
559
556
  return self._table_data
560
557
 
561
558
  def get_row_at(self, idx: int) -> RowH[HEAD, Any]:
562
- if self.empty():
563
- raise TableEmptyError("A tabela está vazia")
564
-
565
- if idx < 0 or idx >= len(self._table_data):
566
- raise RowNotExistError(f"A linha ... {idx} não existe na tabela {self}")
559
+ total = self.size()
560
+ if idx >= total:
561
+ raise RowNotExistError(f"A linha {idx} não existe ... Total {total}")
567
562
 
568
- values = self._table_data.iloc[idx].tolist()
569
- return RowH(idx, dict(zip(self.header(), values)))
563
+ row = RowH(idx)
564
+ header = self.header()
565
+ header.for_each(lambda h: row.set(h, self.get(h).get(idx)))
566
+ return row
570
567
 
571
568
  def get_data_columns(self) -> pd.Index:
572
569
  return TableData._object_index(self._table_data.columns)
@@ -602,8 +599,10 @@ class TableData[HEAD](Table):
602
599
  if row.is_empty():
603
600
  return None
604
601
 
605
- if self.header().empty():
602
+ # Tabela completamente vazia, criar o cabeçalho com base na linha recebida.
603
+ if self.is_void():
606
604
  self._table_data = pd.DataFrame(columns=row.header())
605
+ row.index = 0
607
606
 
608
607
  header: ArrayList[HEAD] = self.header()
609
608
 
@@ -616,7 +615,7 @@ class TableData[HEAD](Table):
616
615
  if not row.header().contains(h):
617
616
  msg = f"Você está tentando adicionar uma linha que não possui o cabeçalho >> [{h}] <<"
618
617
 
619
- raise HeaderNotFoundError(
618
+ raise ColumnNotFoudError(
620
619
  f"{msg} \nCabeçalhos existentes na linha => {row.header()}\nCabeçalhos da tabela => {header}"
621
620
  )
622
621
 
@@ -632,19 +631,28 @@ class TableData[HEAD](Table):
632
631
  return None
633
632
 
634
633
  def merge(self, tb: Table) -> None:
635
- if tb.empty():
634
+ if tb.is_empty():
636
635
  raise TableEmptyError("Não é possível unir uma tabela vazia!")
637
636
 
638
- if self.header().size() != tb.header().size():
639
- msg = f"Cabeçalho da tabela -> {self.header().size()} | Cabeçalho da tabela externa -> {tb.header().size()}"
637
+ header = self.header()
638
+ size_header_table = self.size_header()
639
+ size_header_other = header.size()
640
+
641
+ if size_header_table == 0:
642
+ cols = tb.header()
643
+ cols.for_each(lambda c: self.add(ColumnV(c)))
644
+
645
+ if size_header_table != size_header_other:
646
+ msg = f"Cabeçalho da tabela -> {self.header().size()} | Cabeçalho externo -> {tb.header().size()}"
640
647
  raise HeadersSizeNotIqualError(
641
648
  f"Não é possível juntar tabelas com cabeçalhos diferentes.\n{msg}"
642
649
  )
643
650
 
644
- header = self.header()
645
651
  for h in header:
646
652
  if not tb.contains_header(h):
647
- raise ColumnNotFoundError(f"Coluna inexistente ... {h}")
653
+ raise ColumnNotFoundError(
654
+ f"Coluna inexistente ... {h} ... Colunas disponíveis ... {self.header()}"
655
+ )
648
656
 
649
657
  other = tb.to_dataframe()[list(header)]
650
658
 
@@ -654,32 +662,44 @@ class TableData[HEAD](Table):
654
662
  self._table_data = pd.concat([self._table_data, other], ignore_index=True)
655
663
 
656
664
  def add(self, col: ColumnV) -> None:
657
- """
658
- Faz o mesmo que .set()
659
- """
660
- self.set(col)
665
+ if self.header().contains(col.head):
666
+ raise ColumnExistsError(f"Já existe uma coluna com o nome: {col.head}")
667
+
668
+ if self.is_void():
669
+ self._table_data = pd.DataFrame({col.head: col.get_elements()})
670
+ return
671
+
672
+ current_size = col.size()
673
+ cols_size = self.get_first().size()
674
+
675
+ if cols_size != current_size:
676
+ raise HeadersSizeNotIqualError(
677
+ f"Não é possível adicionar uma coluna com tamanho {current_size} ... Tamanho da tabela ... {cols_size}!"
678
+ )
679
+
680
+ self._table_data[col.head] = pd.Series(col.get_elements())
661
681
 
662
682
  def set(self, col: ColumnV[HEAD, ArrayList[T]]) -> None:
683
+
663
684
  values: ArrayList = col.get_elements()
664
685
 
665
- if self.size() == 0:
686
+ if self.header().empty():
666
687
  # Tabela sem colunas: cria o DataFrame a partir da primeira coluna.
667
688
  self._table_data = pd.DataFrame({col.head: values})
689
+ self._table_data.columns = self.get_data_columns()
668
690
  return
669
691
 
670
692
  total = self.size()
671
693
  total_values = values.size()
672
694
 
673
695
  if total == 0 and total_values > 0:
674
- # Tabela só com cabeçalho (0 linhas): estende o índice.
675
696
  self._table_data = self._table_data.reindex(range(total_values))
676
697
  total = total_values
677
698
 
678
699
  if total_values != total:
679
-
680
700
  raise HeadersSizeNotIqualError(
681
701
  f"{__class__.__name__}() Não é possível adicionar uma coluna com tamanho "
682
- f"diferente da tabela. Tabela {total} | Coluna {len(values)} {col.head}"
702
+ f"diferente da tabela. Tabela {total} | Coluna {total_values} {col.head}"
683
703
  )
684
704
  self._table_data[col.head] = values
685
705
  self._table_data.columns = self.get_data_columns()
@@ -714,13 +734,27 @@ class TableData[HEAD](Table):
714
734
  Se nada for encontrado, retorna uma tabela com o mesmo cabeçalho e 0 linhas.
715
735
  """
716
736
  if not self.contains_header(h):
717
- raise ColumnNotFoundError(
718
- f"Coluna não encontrada: {h}\nColunas disponiveis -> {self.header()}"
719
- )
737
+ raise ColumnNotFoundError(f"Coluna não encontrada: {h}")
720
738
 
721
739
  df = self._table_data[self._table_data[h] == value].reset_index(drop=True)
722
740
  return TableData(df)
723
741
 
742
+ def search_all(self, h: Any, values: list[T]) -> Table | None:
743
+ if len(values) == 0:
744
+ return None
745
+
746
+ content = ArrayList[Table]()
747
+
748
+ for v in values:
749
+ found = self.search(h, v)
750
+
751
+ if not found.is_empty():
752
+ content.add(found)
753
+
754
+ if content.empty():
755
+ return None
756
+ return concat_tables(content)
757
+
724
758
  # ---------------------------------------------------------- #
725
759
  # Exclusão de dados - DELETE
726
760
  # ---------------------------------------------------------- #
@@ -728,7 +762,7 @@ class TableData[HEAD](Table):
728
762
  self._table_data = pd.DataFrame()
729
763
 
730
764
  def drop_duplicates(self) -> TableData:
731
- if self.empty():
765
+ if self.is_empty():
732
766
  raise TableEmptyError()
733
767
 
734
768
  df = self._table_data.drop_duplicates().reset_index(drop=True)
@@ -738,7 +772,7 @@ class TableData[HEAD](Table):
738
772
  """
739
773
  Remove as linhas em que a coluna `header` seja NaN, "", "nan" ou "NaN".
740
774
  """
741
- if self.empty():
775
+ if self.is_empty():
742
776
  raise TableEmptyError(f"A tabela está vazia e não possui a coluna {header}")
743
777
 
744
778
  if not self.contains_header(header):
@@ -778,9 +812,12 @@ class TableData[HEAD](Table):
778
812
  return cls(hash_map.to_data_frame())
779
813
 
780
814
 
781
- def concat_tables(
782
- values: list[Table], *, rt_type: type[TableData | TableMap] = TableData
783
- ) -> TableData | TableMap:
815
+ TB_TYPE = TypeVar("TB_TYPE", bound="Table")
816
+
817
+
818
+ def concat_tables[TB_TYPE](
819
+ values: list[Table], *, rt_type: type[Table | TB_TYPE] = TableData
820
+ ) -> TableData | Table | TB_TYPE:
784
821
  """
785
822
  Concatenar uma lista de tabelas, se receber uma lista vazia gera a exceção ListTablesEmptyError().
786
823
  """
@@ -788,29 +825,11 @@ def concat_tables(
788
825
  if len(values) == 0:
789
826
  raise ListTablesEmptyError("Não é possível concatenar uma lista vazia")
790
827
 
791
- final: TableData | TableMap = rt_type()
792
-
793
- first = values[0]
794
- header = first.header()
795
-
796
- for h in header:
797
- final.add(ColumnV(h))
828
+ header = values[0].header()
829
+ final: Table = rt_type()
830
+ header.for_each(lambda h: final.add(ColumnV(h)))
798
831
 
799
832
  current_table: Table
800
-
801
833
  for current_table in values:
802
- if current_table.empty():
803
- raise TableEmptyError(f"Não é possível concatenar uma tabela vazia!")
804
-
805
- if current_table.header().size() != header.size():
806
- raise HeadersSizeNotIqualError(
807
- "As tabelas precisam ter colunas de tamanhos iguais para concatenar!"
808
- )
809
-
810
- for h in header:
811
- if not current_table.header().contains(h):
812
- raise ColumnNotFoundError(f"Coluna não encontrada: {h}")
813
-
814
- final.get(h).add_all(current_table.get(h).get_elements())
815
-
834
+ final.merge(current_table)
816
835
  return final
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: table_stream
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Tipos de dados e implementações para o uso em tabelas.
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
File without changes
File without changes