table-stream 0.2.7__tar.gz → 0.2.9__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.
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: table_stream
3
- Version: 0.2.7
3
+ Version: 0.2.9
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
7
7
  Requires-Dist: openpyxl>=3.1.5
8
8
  Requires-Dist: pandas>=3.0.0
9
+ Requires-Dist: pandas-stubs~=3.0.0
9
10
 
10
11
  # table_stream
@@ -1,12 +1,13 @@
1
1
  [project]
2
2
  name = "table_stream"
3
- version = "0.2.7"
3
+ version = "0.2.9"
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"
7
7
  dependencies = [
8
8
  "openpyxl>=3.1.5",
9
9
  "pandas>=3.0.0",
10
+ "pandas-stubs~=3.0.0",
10
11
  ]
11
12
 
12
13
  [dependency-groups]
@@ -1,14 +1,14 @@
1
1
  from __future__ import annotations
2
- from collections.abc import Iterable
3
2
 
4
- from abc import abstractmethod, ABC, ABCMeta
3
+ # from collections.abc import Iterable
4
+
5
+ from abc import abstractmethod, ABC # ABCMeta
5
6
  from typing import (
6
7
  Any,
7
8
  Callable,
8
9
  Union,
9
10
  Literal,
10
11
  Optional,
11
- Type,
12
12
  TypeVar,
13
13
  NewType,
14
14
  Protocol,
@@ -27,9 +27,12 @@ from zipfile import ZipFile
27
27
 
28
28
  import json
29
29
  from pandas import DataFrame
30
- from pandas import Series
30
+
31
+ # from pandas import Series
31
32
  import pandas as pd
32
33
 
34
+ __version__ = version = "0.2.8"
35
+
33
36
  T = TypeVar("T")
34
37
  K = TypeVar("K")
35
38
  V = TypeVar("V", contravariant=True)
@@ -57,7 +60,7 @@ stateName = Literal[
57
60
  "success",
58
61
  "stopped",
59
62
  "running",
60
- "not_incialized",
63
+ "not_inicialized",
61
64
  ]
62
65
 
63
66
  MOD_ODF: bool = False
@@ -643,7 +646,9 @@ class HashMapDict[K, T](HashMap):
643
646
 
644
647
  def to_map_str(self) -> dict[str, Any]:
645
648
  final = dict()
646
- for i in self.header():
649
+ _header = self.header()
650
+
651
+ for i in _header:
647
652
  final[str(i)] = str(self.get_value(i))
648
653
  return final
649
654
 
@@ -885,9 +890,7 @@ class Listener[NOTIFIER](ABC):
885
890
 
886
891
  def __init__(self) -> None:
887
892
  super().__init__()
888
- self.func_read_notifier: Callable[[type[NOTIFIER]], NOTIFIER] = (
889
- self._read_notifier
890
- )
893
+ self.fn_read: Callable[[type[NOTIFIER]], NOTIFIER] = self._read_notifier
891
894
 
892
895
  # Notifiers já observados por este Consumer (evita registrar o
893
896
  # mesmo listener duas vezes a cada build(), e permite unwatch_all()).
@@ -895,10 +898,14 @@ class Listener[NOTIFIER](ABC):
895
898
  self.type_notifier: type[NOTIFIER] = None
896
899
 
897
900
  def _read_notifier(self, type_notifier: type[NOTIFIER]) -> NOTIFIER:
901
+ if self.type_notifier is None:
902
+ raise ValueError(
903
+ f"Nenhum notificador foi definido em ... {__class__.__name__}()"
904
+ )
898
905
  return self._watched[type_notifier]
899
906
 
900
907
  def read(self) -> NOTIFIER:
901
- return self.func_read_notifier(self.type_notifier)
908
+ return self.fn_read(self.type_notifier)
902
909
 
903
910
  def watch(self, notifier: NOTIFIER) -> NOTIFIER:
904
911
  self.type_notifier = type(notifier)
@@ -987,10 +994,10 @@ class EventState(ABC):
987
994
  estado para o ThreadStateContext (self._context._set_state(...)).
988
995
  """
989
996
 
990
- name: str = "abstract"
997
+ name: stateName = "abstract"
991
998
 
992
999
  def __init__(self) -> None:
993
- self._state_name: stateName = "not_incialized"
1000
+ self._state_name: stateName = "not_inicialized"
994
1001
 
995
1002
  def __repr__(self) -> str:
996
1003
  return f"<{self.__class__.__name__}()>"
@@ -1050,11 +1057,11 @@ class EventState(ABC):
1050
1057
  class NotInicializedState(EventState):
1051
1058
  """Estado inicial. Nenhum trabalho começou ainda."""
1052
1059
 
1053
- name = "not_started"
1060
+ name: stateName = "not_inicialized"
1054
1061
 
1055
1062
  def __init__(self) -> None:
1056
1063
  super().__init__()
1057
- self._state_name = "not_incialized"
1064
+ self._state_name: stateName = "not_inicialized"
1058
1065
 
1059
1066
  def start(self, context: StateValue) -> None:
1060
1067
  context.set_state(RunningState())
@@ -1182,11 +1189,11 @@ class StopState(EventState):
1182
1189
 
1183
1190
  class StateValue[V]:
1184
1191
 
1185
- def __init__(self, on_finish: Callable[[StateValue]] = None) -> None:
1192
+ def __init__(self, on_finish: Callable[[StateValue], None] | None = None) -> None:
1186
1193
  super().__init__()
1187
1194
 
1188
1195
  self._state: EventState = NotInicializedState()
1189
- self.on_finish: Callable[[StateValue]] = on_finish
1196
+ self.on_finish: Callable[[StateValue], None] | None = on_finish
1190
1197
 
1191
1198
  self._exception: Exception | None = None
1192
1199
  self.msg_error: str | None = None
@@ -1209,7 +1216,7 @@ class StateValue[V]:
1209
1216
  def set_state(self, new_state: EventState) -> None:
1210
1217
  self._state = new_state
1211
1218
 
1212
- def execute_command(self, cmd: Callable[[StateValue]] | None) -> None:
1219
+ def execute_command(self, cmd: Callable[[StateValue], None] | None) -> None:
1213
1220
  if cmd is not None:
1214
1221
  cmd(self)
1215
1222
 
@@ -3038,12 +3045,15 @@ def create_table_from_file(
3038
3045
  md5 = load_file_hash(file)
3039
3046
 
3040
3047
  tb: TableData[HeaderMetaData] = create_void_table_files()
3048
+ row = RowH(0)
3041
3049
 
3042
- tb.get(HeaderMetaData.FILE_NAME).add(file.name())
3043
- tb.get(HeaderMetaData.FILE_EXTENSION).add(file.extension() or ".nan")
3044
- tb.get(HeaderMetaData.FILE_PATH).add(file.absolute())
3045
- tb.get(HeaderMetaData.PARENT_DIR).add(file.parent().absolute())
3046
- tb.get(HeaderMetaData.HASH_FILE).add(md5)
3050
+ row.set(HeaderMetaData.FILE_NAME, file.name())
3051
+ row.set(HeaderMetaData.FILE_EXTENSION, file.extension() or ".nan")
3052
+ row.set(HeaderMetaData.FILE_PATH, file.absolute())
3053
+ row.set(HeaderMetaData.PARENT_DIR, file.parent().absolute())
3054
+ row.set(HeaderMetaData.HASH_FILE, md5)
3055
+
3056
+ tb.add_row(row)
3047
3057
  return tb
3048
3058
 
3049
3059
 
@@ -3211,9 +3221,16 @@ class DataStorage(Observable[pd.DataFrame]):
3211
3221
 
3212
3222
 
3213
3223
  class DataReader(object):
3224
+ """
3225
+ Faz a leitura de uma planilha e retorna um Map de DataFrame()
3214
3226
 
3215
- def __init__(self, store: DataStorage) -> None:
3227
+ """
3228
+
3229
+ def __init__(self, store: DataStorage | None = None) -> None:
3216
3230
  super().__init__()
3231
+ if store is None:
3232
+ store = DataStorage()
3233
+
3217
3234
  self._store = store
3218
3235
 
3219
3236
  def read(self, path: File) -> pd.DataFrame:
@@ -3232,9 +3249,9 @@ class DataSave(Observer[pd.DataFrame]):
3232
3249
  Salvar o DataFrame() em um arquivo sempre receber uma notificação.
3233
3250
  """
3234
3251
 
3235
- def __init__(self, path_sheet: File) -> None:
3252
+ def __init__(self, path_sheet: File | None = None) -> None:
3236
3253
  super().__init__()
3237
- self.path_sheet: File = path_sheet
3254
+ self.path_sheet: File | None = path_sheet
3238
3255
  self.csv_options: CsvOptions = CsvOptions()
3239
3256
  self.debug: bool = True
3240
3257
 
@@ -3245,6 +3262,9 @@ class DataSave(Observer[pd.DataFrame]):
3245
3262
 
3246
3263
  def update(self, value: pd.DataFrame) -> None:
3247
3264
 
3265
+ if self.path_sheet is None:
3266
+ raise ValueError(f"{__class__.__name__} o arquivo de destino é nulo.")
3267
+
3248
3268
  self._show(f"Salvando ... {self.path_sheet.absolute()}")
3249
3269
 
3250
3270
  if self.path_sheet.is_csv():
@@ -3281,6 +3301,7 @@ class SplitterData(Notifier):
3281
3301
  def split(self, df: pd.DataFrame, output: Directory) -> None:
3282
3302
  if df.empty:
3283
3303
  return None
3304
+ df = df.astype(str)
3284
3305
 
3285
3306
  self.output_dir = output
3286
3307
  values_split = Set(df[self.col_split].drop_duplicates().values.tolist())
@@ -3305,16 +3326,42 @@ class SplitterData(Notifier):
3305
3326
  return super().notify_listeners()
3306
3327
 
3307
3328
 
3308
- class DataExport(Listener):
3329
+ class ListenerSplitter(Listener[SplitterData]):
3309
3330
 
3310
3331
  def __init__(self) -> None:
3311
3332
  super().__init__()
3312
- self.saver = DataSave(None)
3333
+ self.saver = DataSave()
3334
+
3335
+ def set_csv_options(self, opt: CsvOptions):
3336
+ self.saver.csv_options = opt
3313
3337
 
3314
3338
  def receiver_notifier(self) -> None:
3315
3339
  sp = self.read()
3316
3340
  self.update(sp)
3317
3341
 
3342
+ def create_export_files(self, d: Directory, filename: str) -> Set[File]:
3343
+ dir_excel = d.concat("EXCEL", True)
3344
+ dir_csv = d.concat("CSV", True)
3345
+
3346
+ path_excel = dir_excel.join_file(f"{filename}.xlsx")
3347
+ path_csv = dir_csv.join_file(f"{filename}.csv")
3348
+ return Set([path_excel, path_csv])
3349
+
3350
+ def _run_export(self, df: pd.DataFrame, files: Set[File]) -> None:
3351
+ """
3352
+ Exporta o mesmo DataFrame() para varios caminhos/arquivos
3353
+
3354
+ util para exportar csv/excel
3355
+ """
3356
+
3357
+ if files.empty():
3358
+ return None
3359
+
3360
+ f: File
3361
+ for f in files:
3362
+ self.saver.path_sheet = f
3363
+ self.saver.update(df)
3364
+
3318
3365
  def update(self, value: SplitterData) -> None:
3319
3366
  if value.output_dir is None:
3320
3367
  return
@@ -3324,12 +3371,128 @@ class DataExport(Listener):
3324
3371
  d = value.output_dir
3325
3372
  d.mkdir()
3326
3373
 
3327
- final_name = f"{value.current_file_name}.xlsx"
3374
+ final_filename: str = str(value.current_file_name)
3328
3375
 
3329
3376
  if value.current_prefix is not None:
3330
- final_name = f"{value.current_prefix}-{final_name}"
3377
+ final_filename = f"{value.current_prefix}-{final_filename}"
3378
+
3379
+ print(f"Progresso: [{value.done}/{value.total_export}]")
3380
+
3381
+ files = self.create_export_files(d, final_filename)
3382
+ df = value.storage.get_data()
3383
+ self._run_export(df, files)
3384
+
3385
+
3386
+ class ListenerSplitterQgiz(ListenerSplitter):
3387
+
3388
+ def __init__(self) -> None:
3389
+ super().__init__()
3390
+
3391
+ def create_export_files(self, d: Directory, filename: str) -> Set[File]:
3392
+ sp = self.read()
3393
+ current_data = sp.storage.get_data()
3394
+ cols = ArrayList(current_data.columns.to_list())
3395
+
3396
+ dir_excel = d.concat("EXCEL", True)
3397
+ dir_csv = d.concat("CSV", True)
3398
+
3399
+ col_ano = "numano"
3400
+ col_mes = "nummes"
3401
+
3402
+ if cols.contains(col_ano):
3403
+ ano = str(current_data[col_ano].values.tolist()[0])
3404
+
3405
+ dir_excel = dir_excel.concat(ano, True)
3406
+ dir_csv = dir_csv.concat(ano, True)
3407
+
3408
+ if cols.contains(col_mes):
3409
+ mes = str(current_data[col_mes].values.tolist()[0])
3410
+
3411
+ dir_excel = dir_excel.concat(mes, True)
3412
+ dir_csv = dir_csv.concat(mes, True)
3413
+
3414
+ return Set.from_list(
3415
+ [
3416
+ dir_excel.join_file(f"{filename}.xlsx"),
3417
+ dir_csv.join_file(f"{filename}.csv"),
3418
+ ]
3419
+ )
3420
+
3421
+
3422
+ class ListenerStorage(Observer[pd.DataFrame]):
3423
+
3424
+ def __init__(
3425
+ self,
3426
+ output_dir: Directory,
3427
+ col_name: str,
3428
+ *,
3429
+ cols_subdirs: ArrayList[str] = None,
3430
+ ) -> None:
3431
+ super().__init__()
3432
+ if cols_subdirs is None:
3433
+ cols_subdirs = Set[str]()
3434
+ self.cols_subdirs: ArrayList[str] = cols_subdirs
3435
+ self.output_dir: Directory = output_dir
3436
+ self.col_name: str = col_name
3437
+
3438
+ def get_current_export_dir(self, df: pd.DataFrame) -> Directory:
3439
+ if self.cols_subdirs.empty():
3440
+ return self.output_dir
3441
+
3442
+ concat_dirs = ArrayList()
3443
+
3444
+ for c in self.cols_subdirs:
3445
+ first = df[c].astype(str).values.tolist()[0]
3446
+ concat_dirs.append(first)
3447
+
3448
+ final_dir = Directory(self.output_dir.absolute())
3449
+ for item in concat_dirs:
3450
+ final_dir = final_dir.concat(item)
3451
+
3452
+ final_dir.mkdir()
3453
+ return final_dir
3454
+
3455
+ def update(self, value: pd.DataFrame) -> None:
3456
+
3457
+ path_dir = self.get_current_export_dir(value)
3458
+ filename = value[self.col_name].astype(str).values.tolist()[0]
3459
+
3460
+ csv_file = path_dir.concat("CSV", True).join_file(f"{filename}.csv")
3461
+ excel_file = path_dir.concat("EXCEL", True).join_file(f"{filename}.xlsx")
3462
+
3463
+ saver = DataSave(excel_file)
3464
+ saver.update(value)
3465
+
3466
+ saver.path_sheet = csv_file
3467
+ saver.update(value)
3468
+
3469
+
3470
+ def fmt_dataframe_circuit(df: pd.DataFrame) -> pd.DataFrame:
3471
+ rmnull = ["vlr_coordenada_longitude"]
3472
+ select = [
3473
+ "numano",
3474
+ "nummes",
3475
+ "numliv",
3476
+ "codlcd",
3477
+ "numrota",
3478
+ "numcta",
3479
+ "numcdc",
3480
+ "vlr_coordenada_latitude",
3481
+ "vlr_coordenada_longitude",
3482
+ ]
3483
+
3484
+ df.dropna(subset=rmnull, inplace=True)
3485
+ df = df[select]
3486
+ return df
3487
+
3488
+
3489
+ def split_dataframe(df: pd.DataFrame, col_split: str, *, storage: DataStorage) -> None:
3490
+ df = fmt_dataframe_circuit(df)
3491
+ values_split = Set(df[col_split].drop_duplicates().values.tolist())
3492
+
3493
+ total = len(values_split)
3494
+ for num, item in enumerate(values_split):
3495
+ print(f"Progresso: {num+1}/{total}", end=" ")
3331
3496
 
3332
- path = d.join_file(final_name)
3333
- print(f"Exportando [{value.done}/{value.total_export}] ... {path}")
3334
- self.saver.path_sheet = path
3335
- self.saver.update(value.storage.get_data())
3497
+ current = df[df[col_split] == item]
3498
+ storage.set_data(current)
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: table_stream
3
- Version: 0.2.7
3
+ Version: 0.2.9
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
7
7
  Requires-Dist: openpyxl>=3.1.5
8
8
  Requires-Dist: pandas>=3.0.0
9
+ Requires-Dist: pandas-stubs~=3.0.0
9
10
 
10
11
  # table_stream
@@ -1,7 +1,6 @@
1
1
  README.md
2
2
  pyproject.toml
3
3
  table_stream/__init__.py
4
- table_stream/erros.py
5
4
  table_stream.egg-info/PKG-INFO
6
5
  table_stream.egg-info/SOURCES.txt
7
6
  table_stream.egg-info/dependency_links.txt
@@ -1,2 +1,3 @@
1
1
  openpyxl>=3.1.5
2
2
  pandas>=3.0.0
3
+ pandas-stubs~=3.0.0
@@ -1,162 +0,0 @@
1
- class CoreException(Exception):
2
-
3
- def __init__(self, message: str = f"Erro") -> None:
4
- super().__init__(message)
5
- self._message = message
6
-
7
- def get_message(self) -> str:
8
- return self._message
9
-
10
- def set_message(self, message: str) -> None:
11
- self._message = message
12
- super().__init__(f"{__class__.__name__}: {message}")
13
-
14
- def launch_exception_handler(self) -> None:
15
- raise self
16
-
17
-
18
- class ValueNotifyNullError(CoreException):
19
-
20
- def __init__(self, message: str = "Notificação nula...") -> None:
21
- super().__init__(message)
22
-
23
-
24
- class UnsuportedSheetError(CoreException):
25
-
26
- def __init__(self, message: str = "Planilha inválida...") -> None:
27
- super().__init__(message)
28
-
29
-
30
- # ============================================================#
31
- # Erros relacionados a HashMap
32
- # ============================================================#
33
-
34
-
35
- class InvalidHashMapTableError(CoreException):
36
-
37
- def __init__(self, message: str = "HashMap inválido") -> None:
38
- super().__init__(message)
39
-
40
-
41
- class InvalidBodyTableError(InvalidHashMapTableError):
42
-
43
- def __init__(self, message: str = "Erro corpo de tabela inválido") -> None:
44
- super().__init__(message)
45
-
46
-
47
- class SizeTableError(InvalidHashMapTableError):
48
-
49
- def __init__(self, message: str = "Tamanho de tabela inválido") -> None:
50
- super().__init__(message)
51
-
52
-
53
- # ============================================================#
54
- # Erros relacionados a planilhas
55
- # ============================================================#
56
- class UndefinedSheetIndex(CoreException):
57
-
58
- def __init__(self, message: str = "SheetIndexNames não foi definido") -> None:
59
- super().__init__(message)
60
-
61
-
62
- class LoadWorkbookError(CoreException):
63
-
64
- def __init__(self, message: str = "Erro ao tentar ler Workbook") -> None:
65
- super().__init__(message)
66
-
67
-
68
- # ============================================================#
69
- # Erros relacionados a arquivos/bytes de imagem (.png, .jpg, ...)
70
- # ============================================================#
71
- class InvalidSourceImageError(CoreException):
72
-
73
- def __init__(self, message: str = "Erro, use bytes de imagem") -> None:
74
- super().__init__(message)
75
-
76
-
77
- # ============================================================#
78
- # Erros relacionados a módulos
79
- # ============================================================#
80
- class NotImplementedModuleError(CoreException):
81
-
82
- def __init__(self, message: str = "Erro, módulo não implementado") -> None:
83
- super().__init__(message)
84
-
85
-
86
- class NotImplementedModuleImageError(NotImplementedModuleError):
87
-
88
- def __init__(self, message: str = "Erro, módulo IMAGEM não implementado") -> None:
89
- super().__init__(message)
90
-
91
-
92
- class NotImplementedModulePdfError(NotImplementedModuleError):
93
-
94
- def __init__(self, message: str = "Erro, módulo PDF não implementado") -> None:
95
- super().__init__(message)
96
-
97
-
98
- class NotImplementedInvertColor(NotImplementedError):
99
-
100
- def __init__(
101
- self, message: str = "Adaptador InvertColor não implementado..."
102
- ) -> None:
103
- super().__init__(message)
104
-
105
-
106
- # ============================================================#
107
- # Erros relacionados a tabelas
108
- # ============================================================#
109
-
110
-
111
- class ColumnNotFoudError(ValueError):
112
-
113
- def __init__(self, *args: object) -> None:
114
- super().__init__(*args)
115
-
116
-
117
- class ColumnExistsError(ValueError):
118
-
119
- def __init__(self, *args: object) -> None:
120
- super().__init__(*args)
121
-
122
-
123
- class ColumnNotIqualSizeError(ValueError):
124
-
125
- def __init__(self, *args: object) -> None:
126
- super().__init__(*args)
127
-
128
-
129
- class EmptyRowError(Exception):
130
-
131
- def __init__(self, *args: object) -> None:
132
- super().__init__(*args)
133
-
134
-
135
- class TableEmptyError(Exception):
136
-
137
- def __init__(self, *args: object) -> None:
138
- super().__init__(*args)
139
-
140
-
141
- class HeadersSizeNotIqualError(Exception):
142
-
143
- def __init__(self, *args: object) -> None:
144
- super().__init__(*args)
145
-
146
-
147
- class ListTablesEmptyError(ValueError):
148
-
149
- def __init__(self, *args: object) -> None:
150
- super().__init__(*args)
151
-
152
-
153
- class ColumnNotFoundError(ValueError):
154
-
155
- def __init__(self, *args: object) -> None:
156
- super().__init__(*args)
157
-
158
-
159
- class RowNotExistError(ValueError):
160
-
161
- def __init__(self, *args: object) -> None:
162
- super().__init__(*args)
File without changes
File without changes