table-stream 0.1.9__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.1.9 → table_stream-0.2.2}/PKG-INFO +1 -1
  2. {table_stream-0.1.9 → table_stream-0.2.2}/pyproject.toml +1 -1
  3. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/__init__.py +4 -3
  4. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/erros.py +24 -18
  5. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/sysfiles.py +0 -1
  6. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/table.py +228 -198
  7. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream.egg-info/PKG-INFO +1 -1
  8. {table_stream-0.1.9 → table_stream-0.2.2}/README.md +0 -0
  9. {table_stream-0.1.9 → table_stream-0.2.2}/setup.cfg +0 -0
  10. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/hash_map.py +0 -0
  11. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/notifier.py +0 -0
  12. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/pattner/__init__.py +0 -0
  13. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/pattner/adapter.py +0 -0
  14. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/sheet/__init__.py +0 -0
  15. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/sheet/check_mod.py +0 -0
  16. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/sheet/load.py +0 -0
  17. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/sheet/options.py +0 -0
  18. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/sheet/parse.py +0 -0
  19. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/sheet/save.py +0 -0
  20. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/state.py +0 -0
  21. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/thread.py +0 -0
  22. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream/workbook.py +0 -0
  23. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream.egg-info/SOURCES.txt +0 -0
  24. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream.egg-info/dependency_links.txt +0 -0
  25. {table_stream-0.1.9 → table_stream-0.2.2}/table_stream.egg-info/requires.txt +0 -0
  26. {table_stream-0.1.9 → 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.1.9
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.1.9"
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.1.9"
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))
@@ -6,9 +6,15 @@ from __future__ import annotations
6
6
  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
- ColumnNotFoudError, RowNotExistError, EmptyRowError,
10
- ColumnNotFoundError, HeadersSizeNotIqualError, HeaderNotFoundError,
11
- TableEmptyError, ListTablesEmptyError,
9
+ ColumnNotFoudError,
10
+ ColumnExistsError,
11
+ RowNotExistError,
12
+ EmptyRowError,
13
+ ColumnNotFoundError,
14
+ HeadersSizeNotIqualError,
15
+ ColumnNotFoudError,
16
+ TableEmptyError,
17
+ ListTablesEmptyError,
12
18
  )
13
19
  from typing import Any, TypeVar, Callable
14
20
  import pandas as pd
@@ -20,25 +26,27 @@ TP = TypeVar("TP")
20
26
 
21
27
 
22
28
  class RowH[HEAD, T]:
23
-
29
+
24
30
  def __init__(self, index: int, map: dict[HEAD, T] | None = None) -> None:
25
- if map is None:
31
+ if map is None:
26
32
  map = dict()
27
-
33
+
28
34
  self.map: dict[HEAD, T] = map
29
35
  self.index: int = index
30
36
 
31
37
  def __repr__(self) -> str:
32
- default = f"{__class__.__name__}():"
38
+ sep = "->"
39
+ default_text = f"<{__class__.__name__}()>"
40
+
33
41
  if len(self.map) == 0:
34
- return f"{default} Size: 0"
35
-
42
+ return f"{default_text} Size 0 {sep} []"
43
+
36
44
  _values = ArrayList()
37
45
  for k, v in self.map.items():
38
46
  _values.add(f"{k} -> {v}")
39
-
40
- return f"{default}\n{_values}"
41
-
47
+
48
+ return f"{default_text} Size {len(self.map)} {sep} {_values}"
49
+
42
50
  def __eq__(self, other: object) -> bool:
43
51
  if not isinstance(other, RowH):
44
52
  raise NotImplementedError()
@@ -46,30 +54,30 @@ class RowH[HEAD, T]:
46
54
 
47
55
  def __hash__(self) -> int:
48
56
  return hash(tuple(self.map.items()))
49
-
57
+
50
58
  def hash(self) -> int:
51
59
  return self.__hash__()
52
-
60
+
53
61
  def is_empty(self) -> bool:
54
62
  return self.header().empty()
55
-
63
+
56
64
  def get_first(self) -> T:
57
65
  if self.is_empty():
58
66
  raise EmptyRowError(f"Linha vazia, adicione elementos...")
59
67
  return self.get(self.header().get_first())
60
-
68
+
61
69
  def get_row_index(self) -> int:
62
70
  return self.index
63
-
64
- def get(self, head: HEAD) -> T:
71
+
72
+ def get(self, head: HEAD) -> T:
65
73
  return self.map[head]
66
-
74
+
67
75
  def set(self, head: HEAD, v: T) -> None:
68
76
  self.map[head] = v
69
-
77
+
70
78
  def header(self) -> ArrayList[HEAD]:
71
79
  return ArrayList(list(self.map.keys()))
72
-
80
+
73
81
  def values(self) -> ArrayList[T]:
74
82
  return ArrayList(list(self.map.values()))
75
83
 
@@ -84,15 +92,15 @@ class ColumnV[HEAD, T]:
84
92
  self.head: HEAD = head
85
93
 
86
94
  def __repr__(self) -> str:
87
-
88
- return f"{__class__.__name__}(): Head {self.head}; Size {self.size()}; Type {self.get_type()};\n{self._elements}"
89
-
90
- #---------------------------------------------------#
95
+ txt = f"Head {self.head}; Size {self.size()}; Type {self.get_type()} -> {self._elements}"
96
+ return f"{__class__.__name__}(): {txt}"
97
+
98
+ # ---------------------------------------------------#
91
99
  # Leitura de Dados.
92
- #---------------------------------------------------#
100
+ # ---------------------------------------------------#
93
101
  def get_type(self) -> type[T] | None:
94
102
  return None if self.is_empty() else type(self.get_first())
95
-
103
+
96
104
  def get_elements(self) -> ArrayList[T]:
97
105
  return self._elements
98
106
 
@@ -101,60 +109,62 @@ class ColumnV[HEAD, T]:
101
109
  Retorna um elemento da coluna apartir de seu índice, se o
102
110
  índice do elemento não existir, lança a exceção RowNotExistError()
103
111
  """
104
-
112
+
105
113
  if idx >= self.size():
106
- raise RowNotExistError(f"{__class__.__name__} Linha não encontrada ... {idx}")
114
+ raise RowNotExistError(
115
+ f"{__class__.__name__} Linha não encontrada ... {idx}"
116
+ )
107
117
  return self._elements.get_element_at(idx)
108
-
118
+
109
119
  def get_first(self) -> T:
110
120
  total = self.size()
111
-
121
+
112
122
  if total == 0:
113
123
  raise ValueError(f"A coluna {self.head} está vazia")
114
124
  return self._elements[0]
115
-
125
+
116
126
  def add(self, item: T) -> None:
117
- self._elements.append(item)
118
-
127
+ self._elements.append(item)
128
+
119
129
  def add_all(self, items: ArrayList[T]) -> None:
120
130
  items.for_each(self.add)
121
-
122
- #---------------------------------------------------#
131
+
132
+ # ---------------------------------------------------#
123
133
  # Inserção/Edição de dados.
124
- #---------------------------------------------------#
134
+ # ---------------------------------------------------#
125
135
  def set(self, idx: int, value: T) -> None:
126
136
  self._elements[idx] = value
127
-
137
+
128
138
  def set_elements(self, e: ArrayList[T]) -> None:
129
- self._elements = e
139
+ self._elements = e
130
140
 
131
141
  def astype[TP](self, new_type: type[TP]) -> ArrayList[TP]:
132
- new = ArrayList[TP]()
142
+ new = ArrayList[TP]()
133
143
  for e in self._elements:
134
144
  new.append(new_type(e))
135
145
  return new
136
-
146
+
137
147
  def replace_value(self, old: T, new: T) -> None:
138
- """
139
- Substitui old por new em todas as ocorrências.
140
- """
141
- list_index = self.find_all(old)
142
-
143
- if list_index.empty():
144
- return
145
-
146
- for num in list_index:
147
- self._elements.replace(num, new)
148
-
148
+ """
149
+ Substitui old por new em todas as ocorrências.
150
+ """
151
+ list_index = self.find_all(old)
152
+
153
+ if list_index.empty():
154
+ return
155
+
156
+ for num in list_index:
157
+ self._elements.replace(num, new)
158
+
149
159
  def replace_at(self, idx: int, new: T) -> None:
150
160
  self._elements.replace(idx, new)
151
-
161
+
152
162
  def merge(self, col: ColumnV) -> None:
153
163
  self.add_all(col.get_elements())
154
164
 
155
- #---------------------------------------------------#
165
+ # ---------------------------------------------------#
156
166
  # Verificação/Validação de dados.
157
- #---------------------------------------------------#
167
+ # ---------------------------------------------------#
158
168
  def is_empty(self) -> bool:
159
169
  return self._elements.empty()
160
170
 
@@ -164,37 +174,39 @@ class ColumnV[HEAD, T]:
164
174
  def contains(self, element: T) -> bool:
165
175
  return self._elements.contains(element)
166
176
 
167
- #---------------------------------------------------#
177
+ # ---------------------------------------------------#
168
178
  # Exclusão de dados.
169
- #---------------------------------------------------#
179
+ # ---------------------------------------------------#
170
180
  def remove(self, v: T) -> None:
171
181
  self._elements.remove(v)
172
-
173
- def remove_all(self, values: ArrayList[T], *, inplace: bool = False) -> ColumnV[HEAD, T]:
174
-
182
+
183
+ def remove_all(
184
+ self, values: ArrayList[T], *, inplace: bool = False
185
+ ) -> ColumnV[HEAD, T]:
186
+
175
187
  new_elements = ArrayList[T]()
176
-
188
+
177
189
  for e in self._elements:
178
190
  if not values.contains(e):
179
191
  new_elements.add(e)
180
-
192
+
181
193
  if inplace:
182
194
  self.set_elements(new_elements)
183
-
195
+
184
196
  return ColumnV(self.head, new_elements)
185
-
186
- #---------------------------------------------------#
197
+
198
+ # ---------------------------------------------------#
187
199
  # Comandos
188
- #---------------------------------------------------#
200
+ # ---------------------------------------------------#
189
201
  def for_each(self, fn: Callable[[T], None]) -> None:
190
202
  self._elements.for_each(fn)
191
203
 
192
- def apply_command(self, fn: Callable[[T], None]) -> ColumnV[HEAD, Any]:
204
+ def apply_command(self, fn: Callable[[T], None]) -> ColumnV[HEAD, Any]:
193
205
  return ColumnV(self.head, self._elements.apply_command(fn))
194
-
195
- #---------------------------------------------------#
206
+
207
+ # ---------------------------------------------------#
196
208
  # Pesquisar/Buscar informações.
197
- #---------------------------------------------------#
209
+ # ---------------------------------------------------#
198
210
  def select(self, list_index: ArrayList[int]) -> ColumnV[HEAD, T]:
199
211
  new_col = ColumnV[HEAD, T](self.head)
200
212
  list_index.for_each(lambda num: new_col.add(self.get(num)))
@@ -220,7 +232,7 @@ class ColumnV[HEAD, T]:
220
232
  return final
221
233
 
222
234
  def filter_value(self, value: T, iqual: bool = False) -> ColumnV[HEAD, T]:
223
- list_index: ArrayList[int]
235
+ list_index: ArrayList[int]
224
236
 
225
237
  if iqual:
226
238
  list_index = self.find_all(value)
@@ -239,27 +251,25 @@ class ColumnV[HEAD, T]:
239
251
  for idx in list_index:
240
252
  final_elements.append(self._elements[idx])
241
253
  return ColumnV(self.head, final_elements)
242
-
254
+
243
255
  def filter_all(self, values: ArrayList[T]) -> ColumnV[HEAD, T]:
244
256
  final = ColumnV[HEAD, T](self.head)
245
-
246
- values.for_each(
247
- lambda item: final.merge(self.filter_value(item))
248
- )
257
+
258
+ values.for_each(lambda item: final.merge(self.filter_value(item)))
249
259
  return final
250
260
 
251
261
  def drop_duplicates(self) -> ColumnV[HEAD, T]:
252
262
  final_list = ArrayList()
253
-
263
+
254
264
  for e in self._elements:
255
265
  if not final_list.contains(e):
256
266
  final_list.append(e)
257
267
  return ColumnV(self.head, final_list)
258
-
268
+
259
269
  @classmethod
260
270
  def create_from_list(cls, h: HEAD, values: list[T]) -> ColumnV:
261
271
  return cls(h, ArrayList(values))
262
-
272
+
263
273
  @classmethod
264
274
  def create_from_series(cls, h: HEAD, s: pd.Series) -> ColumnV:
265
275
  return cls(h, ArrayList(s.values.tolist()))
@@ -281,7 +291,7 @@ class Table[HEAD](ABC):
281
291
  Adiciona uma nova coluna com texto padrão NULL_TEXT.
282
292
  """
283
293
 
284
- if self.empty():
294
+ if self.is_empty():
285
295
  self.add(ColumnV(h))
286
296
  return
287
297
 
@@ -289,29 +299,14 @@ class Table[HEAD](ABC):
289
299
  values = [Table.NULL_STRING] * total
290
300
  self.add(ColumnV(h, ArrayList(values)))
291
301
 
302
+ @abstractmethod
292
303
  def merge(self, tb: Table) -> None:
293
- if tb.empty():
294
- raise TableEmptyError(f"Não é possível unir uma tabela vazia!")
295
-
296
- if self.header().size() != tb.header().size():
297
- raise HeadersSizeNotIqualError(
298
- "Não é possível juntar tabelas com cabeçalhos diferentes!"
299
- )
300
-
301
- header = self.header()
302
- # print(f"[UNINDO TABELAS] Atual: {self} Incrementando: {tb}")
303
-
304
- for h in header:
305
- if not tb.contains_header(h):
306
- raise ColumnNotFoundError(f"Coluna inexistente ... {h}")
307
-
308
- current_col: ColumnV = tb.get(h)
309
- self.get(h).add_all(current_col._elements)
304
+ pass
310
305
 
311
306
  @abstractmethod
312
307
  def set(self, col: ColumnV[HEAD, ArrayList[T]]):
313
308
  pass
314
-
309
+
315
310
  @abstractmethod
316
311
  def set_data(self, df: pd.DataFrame) -> None:
317
312
  pass
@@ -319,53 +314,31 @@ class Table[HEAD](ABC):
319
314
  @abstractmethod
320
315
  def add(self, col: ColumnV) -> None:
321
316
  """
322
- 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()
323
319
  """
324
320
  pass
325
321
 
322
+ @abstractmethod
326
323
  def add_row(self, row: RowH[HEAD, Any]):
327
324
  """
328
325
  Adiciona uma linha a tabela se a linha não estiver vazia.
329
326
  """
330
- if row.is_empty():
331
- return None
332
-
333
- if self.empty():
334
- for row_header in row.header():
335
- self.add(ColumnV(row_header))
336
-
337
- header: ArrayList[HEAD] = self.header()
338
-
339
- if row.header().size() < header.size():
340
- raise HeadersSizeNotIqualError(
341
- "A linha que você está tentando adicionar tem cabeçalho menor que o da tabela!!!"
342
- )
343
-
344
- for h in header:
345
- if not row.header().contains(h):
346
- msg = f"Você está tentando adicionar uma linha que não possui o cabeçalho >> [{h}] <<"
347
-
348
- raise HeaderNotFoundError(
349
- f"{msg} \nCabeçalhos existentes na linha => {row.header()}\n\nCabeçalhos da tabela => {header}"
350
- )
351
-
352
- # self.tb_map[h].add(row.get(h))
353
- self.get(h).add(row.get(h))
354
- return None
327
+ pass
355
328
 
356
- #---------------------------------------------------#
329
+ # ---------------------------------------------------#
357
330
  # Leitura de dados - READ
358
- #---------------------------------------------------#
331
+ # ---------------------------------------------------#
359
332
  @abstractmethod
360
333
  def get_data(self) -> pd.DataFrame:
361
334
  pass
362
-
335
+
363
336
  @abstractmethod
364
337
  def get(self, h: HEAD) -> ColumnV[HEAD, Any]:
365
338
  pass
366
339
 
367
340
  def get_row_at(self, idx: int) -> RowH[HEAD, Any]:
368
- if self.empty():
341
+ if self.is_empty():
369
342
  raise TableEmptyError("A tabela está vazia")
370
343
 
371
344
  total = self.get_first().size()
@@ -390,7 +363,7 @@ class Table[HEAD](ABC):
390
363
  def rows(self) -> ArrayList[RowH[HEAD, Any]]:
391
364
  final = ArrayList[RowH]()
392
365
 
393
- if self.empty():
366
+ if self.is_empty():
394
367
  return final
395
368
 
396
369
  total = self.get(self.header().get_first()).size()
@@ -405,7 +378,7 @@ class Table[HEAD](ABC):
405
378
 
406
379
  def get_last(self) -> ColumnV:
407
380
  return self.get(self.header().get_last())
408
-
381
+
409
382
  @abstractmethod
410
383
  def select_columns(self, header: list[HEAD]) -> Table:
411
384
  pass
@@ -418,7 +391,7 @@ class Table[HEAD](ABC):
418
391
  header = self.header()
419
392
  h: HEAD
420
393
 
421
- if self.empty():
394
+ if self.is_empty():
422
395
  if header.empty():
423
396
  print(f"{self}")
424
397
  else:
@@ -450,14 +423,21 @@ class Table[HEAD](ABC):
450
423
  def search(self, h: HEAD, value: Any) -> Table[HEAD]:
451
424
  pass
452
425
 
453
- #---------------------------------------------------#
426
+ @abstractmethod
427
+ def search_all(self, h: HEAD, values: list[T]) -> Table[HEAD] | None:
428
+ pass
429
+
430
+ # ---------------------------------------------------#
454
431
  # Verificação/validação de dados
455
- #---------------------------------------------------#
432
+ # ---------------------------------------------------#
456
433
  def size(self) -> int:
457
- if self.empty():
434
+ if self.is_empty():
458
435
  return 0
459
436
  return self.get_first().size()
460
437
 
438
+ def size_header(self) -> int:
439
+ return self.header().size()
440
+
461
441
  def contains_header(self, h: HEAD) -> bool:
462
442
  return self.header().contains(h)
463
443
 
@@ -468,23 +448,33 @@ class Table[HEAD](ABC):
468
448
  return self.get(h).contains(value)
469
449
 
470
450
  @abstractmethod
471
- 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
+ """
472
455
  pass
473
456
 
474
- #---------------------------------------------------#
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
+
464
+ # ---------------------------------------------------#
475
465
  # Exclusão de dados - DELETE
476
- #---------------------------------------------------#
466
+ # ---------------------------------------------------#
477
467
  @abstractmethod
478
468
  def clear(self) -> None:
479
469
  pass
480
-
470
+
481
471
  @abstractmethod
482
472
  def remove_null(self, header: HEAD) -> Table:
483
473
  pass
484
474
 
485
- #---------------------------------------------------#
475
+ # ---------------------------------------------------#
486
476
  # Conversão de dados
487
- #---------------------------------------------------#
477
+ # ---------------------------------------------------#
488
478
  def to_string(self, h: HEAD) -> str:
489
479
  return " ".join(self.get(h).astype(str))
490
480
 
@@ -533,13 +523,27 @@ class TableData[HEAD](Table):
533
523
  self._table_data: pd.DataFrame = data
534
524
 
535
525
  def __repr__(self) -> str:
536
- 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}"
537
533
 
538
534
  # ---------------------------------------------------------- #
539
535
  # Verificação/Validação de dados.
540
536
  # ---------------------------------------------------------- #
541
- def empty(self) -> bool:
542
- 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()
543
547
 
544
548
  def size(self) -> int:
545
549
  return len(self._table_data)
@@ -547,25 +551,25 @@ class TableData[HEAD](Table):
547
551
  # ---------------------------------------------------------- #
548
552
  # Leitura de dados - READ
549
553
  # ---------------------------------------------------------- #
550
-
554
+
551
555
  def get_data(self) -> pd.DataFrame:
552
556
  return self._table_data
553
-
554
- def get_row_at(self, idx: int) -> RowH[HEAD, Any]:
555
- if self.empty():
556
- raise TableEmptyError("A tabela está vazia")
557
557
 
558
- if idx < 0 or idx >= len(self._table_data):
559
- raise RowNotExistError(f"A linha ... {idx} não existe na tabela {self}")
558
+ def get_row_at(self, idx: int) -> RowH[HEAD, Any]:
559
+ total = self.size()
560
+ if idx >= total:
561
+ raise RowNotExistError(f"A linha {idx} não existe ... Total {total}")
560
562
 
561
- values = self._table_data.iloc[idx].tolist()
562
- 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
563
567
 
564
568
  def get_data_columns(self) -> pd.Index:
565
569
  return TableData._object_index(self._table_data.columns)
566
570
 
567
571
  def header(self) -> ArrayList[HEAD]:
568
- return ArrayList(self._table_data.columns.tolist()) # type: ignore > não falha apartir do pandas 3.x
572
+ return ArrayList(self._table_data.columns.tolist()) # type: ignore > não falha apartir do pandas 3.x
569
573
 
570
574
  def select_columns(self, header: list[HEAD]) -> TableData:
571
575
  current = self.header()
@@ -573,9 +577,7 @@ class TableData[HEAD](Table):
573
577
  if not current.contains(h):
574
578
  raise ColumnNotFoundError(f"Coluna não encontrada: {h}")
575
579
 
576
- return TableData(
577
- self._table_data[list(header)].copy()
578
- )
580
+ return TableData(self._table_data[list(header)].copy())
579
581
 
580
582
  def get(self, h: HEAD) -> ColumnV[HEAD, Any]:
581
583
  """
@@ -592,13 +594,15 @@ class TableData[HEAD](Table):
592
594
  # ---------------------------------------------------------- #
593
595
  def add_row(self, row: RowH[HEAD, Any]) -> None:
594
596
  """
595
- Adiciona uma linha a tabela se a linha não estiver vazia.
597
+ Adiciona uma linha a tabela se a linha não estiver vazia.
596
598
  """
597
599
  if row.is_empty():
598
600
  return None
599
601
 
600
- if self.header().empty():
602
+ # Tabela completamente vazia, criar o cabeçalho com base na linha recebida.
603
+ if self.is_void():
601
604
  self._table_data = pd.DataFrame(columns=row.header())
605
+ row.index = 0
602
606
 
603
607
  header: ArrayList[HEAD] = self.header()
604
608
 
@@ -611,7 +615,7 @@ class TableData[HEAD](Table):
611
615
  if not row.header().contains(h):
612
616
  msg = f"Você está tentando adicionar uma linha que não possui o cabeçalho >> [{h}] <<"
613
617
 
614
- raise HeaderNotFoundError(
618
+ raise ColumnNotFoudError(
615
619
  f"{msg} \nCabeçalhos existentes na linha => {row.header()}\nCabeçalhos da tabela => {header}"
616
620
  )
617
621
 
@@ -627,19 +631,28 @@ class TableData[HEAD](Table):
627
631
  return None
628
632
 
629
633
  def merge(self, tb: Table) -> None:
630
- if tb.empty():
634
+ if tb.is_empty():
631
635
  raise TableEmptyError("Não é possível unir uma tabela vazia!")
632
636
 
633
- if self.header().size() != tb.header().size():
634
- 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()}"
635
647
  raise HeadersSizeNotIqualError(
636
648
  f"Não é possível juntar tabelas com cabeçalhos diferentes.\n{msg}"
637
649
  )
638
650
 
639
- header = self.header()
640
651
  for h in header:
641
652
  if not tb.contains_header(h):
642
- raise ColumnNotFoundError(f"Coluna inexistente ... {h}")
653
+ raise ColumnNotFoundError(
654
+ f"Coluna inexistente ... {h} ... Colunas disponíveis ... {self.header()}"
655
+ )
643
656
 
644
657
  other = tb.to_dataframe()[list(header)]
645
658
 
@@ -649,36 +662,48 @@ class TableData[HEAD](Table):
649
662
  self._table_data = pd.concat([self._table_data, other], ignore_index=True)
650
663
 
651
664
  def add(self, col: ColumnV) -> None:
652
- """
653
- Faz o mesmo que .set()
654
- """
655
- 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())
656
681
 
657
682
  def set(self, col: ColumnV[HEAD, ArrayList[T]]) -> None:
683
+
658
684
  values: ArrayList = col.get_elements()
659
685
 
660
- if self.size() == 0:
686
+ if self.header().empty():
661
687
  # Tabela sem colunas: cria o DataFrame a partir da primeira coluna.
662
688
  self._table_data = pd.DataFrame({col.head: values})
689
+ self._table_data.columns = self.get_data_columns()
663
690
  return
664
691
 
665
692
  total = self.size()
666
693
  total_values = values.size()
667
694
 
668
695
  if total == 0 and total_values > 0:
669
- # Tabela só com cabeçalho (0 linhas): estende o índice.
670
696
  self._table_data = self._table_data.reindex(range(total_values))
671
697
  total = total_values
672
698
 
673
699
  if total_values != total:
674
-
675
700
  raise HeadersSizeNotIqualError(
676
701
  f"{__class__.__name__}() Não é possível adicionar uma coluna com tamanho "
677
- f"diferente da tabela. Tabela {total} | Coluna {len(values)} {col.head}"
702
+ f"diferente da tabela. Tabela {total} | Coluna {total_values} {col.head}"
678
703
  )
679
704
  self._table_data[col.head] = values
680
705
  self._table_data.columns = self.get_data_columns()
681
-
706
+
682
707
  def set_data(self, df: pd.DataFrame) -> None:
683
708
  self._table_data = df
684
709
 
@@ -704,7 +729,6 @@ class TableData[HEAD](Table):
704
729
  # Pesquisar/Buscar dados - SEARCH
705
730
  # ---------------------------------------------------------- #
706
731
  def search(self, h: HEAD, value: Any) -> TableData[HEAD]:
707
-
708
732
  """
709
733
  Retorna uma nova tabela apenas com as linhas onde a coluna `h` == value.
710
734
  Se nada for encontrado, retorna uma tabela com o mesmo cabeçalho e 0 linhas.
@@ -715,6 +739,22 @@ class TableData[HEAD](Table):
715
739
  df = self._table_data[self._table_data[h] == value].reset_index(drop=True)
716
740
  return TableData(df)
717
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
+
718
758
  # ---------------------------------------------------------- #
719
759
  # Exclusão de dados - DELETE
720
760
  # ---------------------------------------------------------- #
@@ -722,7 +762,7 @@ class TableData[HEAD](Table):
722
762
  self._table_data = pd.DataFrame()
723
763
 
724
764
  def drop_duplicates(self) -> TableData:
725
- if self.empty():
765
+ if self.is_empty():
726
766
  raise TableEmptyError()
727
767
 
728
768
  df = self._table_data.drop_duplicates().reset_index(drop=True)
@@ -730,9 +770,9 @@ class TableData[HEAD](Table):
730
770
 
731
771
  def remove_null(self, header: HEAD) -> TableData[HEAD]:
732
772
  """
733
- Remove as linhas em que a coluna `header` seja NaN, "", "nan" ou "NaN".
773
+ Remove as linhas em que a coluna `header` seja NaN, "", "nan" ou "NaN".
734
774
  """
735
- if self.empty():
775
+ if self.is_empty():
736
776
  raise TableEmptyError(f"A tabela está vazia e não possui a coluna {header}")
737
777
 
738
778
  if not self.contains_header(header):
@@ -771,7 +811,13 @@ class TableData[HEAD](Table):
771
811
  def create_from_map(cls, hash_map: HashMap[HEAD, list[Any]]) -> TableData:
772
812
  return cls(hash_map.to_data_frame())
773
813
 
774
- def concat_tables(values: list[Table], *, rt_type: type[TableData | TableMap] = TableData) -> TableData | TableMap:
814
+
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:
775
821
  """
776
822
  Concatenar uma lista de tabelas, se receber uma lista vazia gera a exceção ListTablesEmptyError().
777
823
  """
@@ -779,27 +825,11 @@ def concat_tables(values: list[Table], *, rt_type: type[TableData | TableMap] =
779
825
  if len(values) == 0:
780
826
  raise ListTablesEmptyError("Não é possível concatenar uma lista vazia")
781
827
 
782
- final: TableData | TableMap = rt_type()
783
-
784
- first = values[0]
785
- header = first.header()
786
-
787
- for h in header:
788
- final.add(ColumnV(h))
828
+ header = values[0].header()
829
+ final: Table = rt_type()
830
+ header.for_each(lambda h: final.add(ColumnV(h)))
789
831
 
790
832
  current_table: Table
791
-
792
833
  for current_table in values:
793
- if current_table.empty():
794
- raise TableEmptyError(f"Não é possível concatenar uma tabela vazia!")
795
-
796
- if current_table.header().size() != header.size():
797
- raise HeadersSizeNotIqualError("As tabelas precisam ter colunas de tamanhos iguais para concatenar!")
798
-
799
- for h in header:
800
- if not current_table.header().contains(h):
801
- raise ColumnNotFoundError(f'Coluna não encontrada: {h}')
802
-
803
- final.get(h).add_all(current_table.get(h).get_elements())
804
-
834
+ final.merge(current_table)
805
835
  return final
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: table_stream
3
- Version: 0.1.9
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