pyflutter-app 0.3.7__tar.gz → 0.3.11__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.
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/PKG-INFO +1 -1
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/cartas/__init__.py +3 -3
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/cartas/origin.py +1 -1
- pyflutter_app-0.3.7/converter/home_page/view.py → pyflutter_app-0.3.11/converter/home_page/page_sheets.py +9 -43
- pyflutter_app-0.3.11/converter/home_page/view.py +71 -0
- pyflutter_app-0.3.11/converter/page_circuit/__init__.py +20 -0
- pyflutter_app-0.3.11/converter/page_circuit/common.py +99 -0
- pyflutter_app-0.3.11/converter/page_circuit/controller_circuit.py +359 -0
- pyflutter_app-0.3.11/converter/page_circuit/model_circuit.py +110 -0
- pyflutter_app-0.3.11/converter/page_circuit/service.py +356 -0
- pyflutter_app-0.3.11/converter/page_circuit/view_circuit.py +208 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/controller_forms.py +55 -3
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/model_forms.py +15 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/view_forms.py +11 -14
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_image/common.py +65 -6
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_image/controller_image.py +130 -4
- pyflutter_app-0.3.11/converter/page_image/model_image.py +222 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_image/renderer.py +2 -2
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_image/view_image.py +46 -0
- pyflutter_app-0.3.11/converter/page_ocr/__init__.py +4 -0
- pyflutter_app-0.3.11/converter/page_ocr/common.py +55 -0
- pyflutter_app-0.3.11/converter/page_ocr/controller_ocr.py +338 -0
- pyflutter_app-0.3.11/converter/page_ocr/model_ocr.py +191 -0
- pyflutter_app-0.3.11/converter/page_ocr/view_ocr.py +183 -0
- pyflutter_app-0.3.11/converter/page_whatsapp/PATCH_whatsapp_files.md +245 -0
- pyflutter_app-0.3.11/converter/page_whatsapp/__init__.py +4 -0
- pyflutter_app-0.3.11/converter/page_whatsapp/common.py +41 -0
- pyflutter_app-0.3.11/converter/page_whatsapp/controller_whatsapp.py +370 -0
- pyflutter_app-0.3.11/converter/page_whatsapp/model_whatsapp.py +353 -0
- pyflutter_app-0.3.11/converter/page_whatsapp/view_whatsapp.py +262 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/run_app_convert.py +6 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/table_widget.py +34 -16
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/new-export_app.sh +10 -3
- {pyflutter_app-0.3.7/ocrlib → pyflutter_app-0.3.11/ocr_stream}/__init__.py +3 -3
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyproject.toml +1 -1
- pyflutter_app-0.3.11/teste.py +9 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/uv.lock +1 -1
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/whatsapp_files/__init__.py +151 -50
- pyflutter_app-0.3.7/converter/page_image/model_image.py +0 -95
- pyflutter_app-0.3.7/converter/whatsapp/__init__.py +0 -0
- pyflutter_app-0.3.7/converter/whatsapp/model.py +0 -29
- pyflutter_app-0.3.7/test_claude.py +0 -505
- pyflutter_app-0.3.7/teste_ocr.py +0 -28
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/.gitignore +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/.idea/.gitignore +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/.idea/misc.xml +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/.idea/modules.xml +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/.idea/pyflutter_app.iml +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/.idea/vcs.xml +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/README.md +0 -0
- {pyflutter_app-0.3.7/pdflib → pyflutter_app-0.3.11/convert_stream}/__init__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/__init__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/__main__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/assets/forms_config.json +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/config_app.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/home_page/__init__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/home_page/_page_edit.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/home_page/controller.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/home_page/model.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/lib_toi.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/Diagnorstico.txt +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/__init__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/common.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/config.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/diagnose_forms.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/master_forms.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_forms/service.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_image/__init__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/page_image/widgets.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/converter/util.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/local_build/linux.sh +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/local_build/send.sh +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/main.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/mvc/controller.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/mvc/model.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/mvc/view.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/__init__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/app.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/file_picker.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/navigator.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/scheduler.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/theme.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/ui/__init__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/ui/buttons.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/ui/container.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/ui/core.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/ui/list_builder.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/ui/progress.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/ui/tables.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/pyflutter_ui/ui/widgets.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/table_stream/__init__.py +0 -0
- {pyflutter_app-0.3.7 → pyflutter_app-0.3.11}/update.sh +0 -0
|
@@ -33,7 +33,7 @@ from table_stream import (
|
|
|
33
33
|
load_file_hash,
|
|
34
34
|
)
|
|
35
35
|
|
|
36
|
-
from
|
|
36
|
+
from ocr_stream import HeaderOcr, BuilderConfigOcr, CreateRelatorioOcr
|
|
37
37
|
|
|
38
38
|
from whatsapp_files import (
|
|
39
39
|
RowWhatsApp,
|
|
@@ -51,7 +51,7 @@ __version__ = "0.2"
|
|
|
51
51
|
class ConfigTOI:
|
|
52
52
|
|
|
53
53
|
file_relatorio_toi: File
|
|
54
|
-
|
|
54
|
+
file_cartas_lancadas: File
|
|
55
55
|
file_table_toi: File
|
|
56
56
|
file_master_forms: File # NOVO
|
|
57
57
|
dir_base_toi: Directory
|
|
@@ -126,7 +126,7 @@ class BuilderConfigTOI(object):
|
|
|
126
126
|
dir_base_toi=self.dir_retorno_de_campo,
|
|
127
127
|
file_relatorio_toi=self.file_relatorio_toi,
|
|
128
128
|
file_table_toi=self.file_table_toi,
|
|
129
|
-
|
|
129
|
+
file_cartas_lancadas=self.file_relatorio_forms,
|
|
130
130
|
dir_log_excel=self.dir_log_excel,
|
|
131
131
|
dir_relatorios=self.dir_relatorios,
|
|
132
132
|
file_master_forms=self.file_master_forms,
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
from pyflutter_ui import (
|
|
2
|
-
ChangeNotifier,
|
|
3
2
|
BuildContext,
|
|
4
3
|
FlutterWidget,
|
|
5
|
-
LinearProgress,
|
|
6
4
|
StatelessWidget,
|
|
7
5
|
Consumer,
|
|
8
6
|
Column,
|
|
@@ -23,10 +21,7 @@ from pyflutter_ui import (
|
|
|
23
21
|
)
|
|
24
22
|
|
|
25
23
|
from tkinter import messagebox
|
|
26
|
-
from typing import Any
|
|
27
24
|
import pandas as pd
|
|
28
|
-
from pandas import DataFrame
|
|
29
|
-
|
|
30
25
|
|
|
31
26
|
from table_stream import (
|
|
32
27
|
ArrayList,
|
|
@@ -40,24 +35,20 @@ from table_stream import (
|
|
|
40
35
|
from converter.home_page.controller import ControllerHomePage
|
|
41
36
|
from converter.table_widget import TableOrProgress
|
|
42
37
|
from converter.home_page._page_edit import PageEditExcel
|
|
43
|
-
|
|
44
|
-
# Páginas para navegação.
|
|
45
|
-
from converter.page_forms import PageRespondsForms
|
|
46
|
-
from converter.page_forms import ControllerForms
|
|
47
|
-
from converter.config_app import MapConfig, AppConfigNotifier
|
|
48
|
-
from converter.page_image import PageImage
|
|
38
|
+
from converter.config_app import AppConfigNotifier
|
|
49
39
|
|
|
50
40
|
|
|
51
|
-
class
|
|
41
|
+
class PageSheets(StatelessWidget):
|
|
42
|
+
"""Importar/carregar planilhas. De lá se acessa a edição de dados."""
|
|
52
43
|
|
|
53
44
|
def __init__(self, key: str | None = None) -> None:
|
|
54
45
|
super().__init__(key)
|
|
55
46
|
|
|
56
47
|
def build(self, context: BuildContext) -> FlutterWidget:
|
|
57
|
-
return
|
|
48
|
+
return _PageSheetsState()
|
|
58
49
|
|
|
59
50
|
|
|
60
|
-
class
|
|
51
|
+
class _PageSheetsState(StatelessWidget):
|
|
61
52
|
|
|
62
53
|
def __init__(self, key: str | None = None) -> None:
|
|
63
54
|
super().__init__(key)
|
|
@@ -94,8 +85,7 @@ class _HomePageState(StatelessWidget):
|
|
|
94
85
|
|
|
95
86
|
@property
|
|
96
87
|
def app_config(self) -> AppConfigNotifier:
|
|
97
|
-
|
|
98
|
-
return state
|
|
88
|
+
return Provider.read(AppConfigNotifier)
|
|
99
89
|
|
|
100
90
|
@property
|
|
101
91
|
def controller(self) -> ControllerHomePage:
|
|
@@ -231,29 +221,11 @@ class _HomePageState(StatelessWidget):
|
|
|
231
221
|
df=data.head(),
|
|
232
222
|
)
|
|
233
223
|
|
|
234
|
-
def action_open_forms(self, context: BuildContext, controller: ControllerHomePage):
|
|
235
|
-
"""
|
|
236
|
-
Seta o DataFrame() da página atual como propriedade do ControllerForms()
|
|
237
|
-
antes de carregar a página.
|
|
238
|
-
"""
|
|
239
|
-
# df = controller.data_notifier.value
|
|
240
|
-
# forms_controller: ControllerForms = context.read(ControllerForms)
|
|
241
|
-
# forms_controller.set_data(df)
|
|
242
|
-
# if not forms_controller.forms_state.data_is_valid():
|
|
243
|
-
# messagebox.showerror("Erro", "Tabela TOI inválida")
|
|
244
|
-
# return
|
|
245
|
-
|
|
246
|
-
context.navigator.push(PageRespondsForms())
|
|
247
|
-
|
|
248
224
|
def _builder_body(
|
|
249
225
|
self, context: BuildContext, controller: ControllerHomePage
|
|
250
226
|
) -> FlutterWidget:
|
|
251
227
|
self.context = context
|
|
252
228
|
|
|
253
|
-
filename = controller.get_file_sheet()
|
|
254
|
-
if filename is not None:
|
|
255
|
-
filename = filename.basename()
|
|
256
|
-
|
|
257
229
|
return Column(
|
|
258
230
|
children=[
|
|
259
231
|
# -----------------------------------#
|
|
@@ -314,20 +286,14 @@ class _HomePageState(StatelessWidget):
|
|
|
314
286
|
Expanded(Consumer(ControllerHomePage, self._build_table)),
|
|
315
287
|
Row(
|
|
316
288
|
[
|
|
289
|
+
ElevatedButton(
|
|
290
|
+
"<- Voltar", lambda: context.navigator.pop()
|
|
291
|
+
),
|
|
317
292
|
Text("Ir para: "),
|
|
318
293
|
ElevatedButton(
|
|
319
294
|
"Edição de dados",
|
|
320
295
|
lambda: context.navigator.push(PageEditExcel()),
|
|
321
296
|
),
|
|
322
|
-
# ElevatedButton("Exportar dados", lambda: print()),
|
|
323
|
-
ElevatedButton(
|
|
324
|
-
"Responds Forms",
|
|
325
|
-
lambda: self.action_open_forms(context, controller),
|
|
326
|
-
),
|
|
327
|
-
ElevatedButton(
|
|
328
|
-
"Renomear imagens",
|
|
329
|
-
lambda: context.navigator.push(PageImage()),
|
|
330
|
-
),
|
|
331
297
|
],
|
|
332
298
|
main_axis_alignment=MainAxisAlignment.START,
|
|
333
299
|
),
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from pyflutter_ui import (
|
|
4
|
+
BuildContext,
|
|
5
|
+
FlutterWidget,
|
|
6
|
+
StatelessWidget,
|
|
7
|
+
Column,
|
|
8
|
+
Row,
|
|
9
|
+
ElevatedButton,
|
|
10
|
+
Divider,
|
|
11
|
+
MainAxisAlignment,
|
|
12
|
+
Scaffold,
|
|
13
|
+
Text,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Páginas para navegação.
|
|
17
|
+
from converter.home_page.page_sheets import PageSheets
|
|
18
|
+
from converter.page_forms import PageRespondsForms
|
|
19
|
+
from converter.page_image import PageImage
|
|
20
|
+
from converter.page_circuit import PageCircuit
|
|
21
|
+
from converter.page_whatsapp import PageWhatsApp
|
|
22
|
+
from converter.page_ocr import PageOcr
|
|
23
|
+
from pyflutter_ui.ui.core import GlobalKey
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class HomePage(StatelessWidget):
|
|
27
|
+
"""Home: somente botões para navegar entre as páginas."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, key: GlobalKey | None = None) -> None:
|
|
30
|
+
super().__init__(key)
|
|
31
|
+
|
|
32
|
+
def build(self, context: BuildContext) -> FlutterWidget:
|
|
33
|
+
return _HomePageState()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class _HomePageState(StatelessWidget):
|
|
37
|
+
|
|
38
|
+
# (rótulo do botão, descrição, página)
|
|
39
|
+
PAGES: list[tuple[str, str, Callable[[], FlutterWidget]]] = [
|
|
40
|
+
("Planilhas", "Importar/carregar planilhas e editar dados", PageSheets),
|
|
41
|
+
("WhatsApp", "Importar chats (.zip) para o cache do WhatsApp", PageWhatsApp),
|
|
42
|
+
("Responds Forms", "Lançar cartas TOI no Microsoft Forms", PageRespondsForms),
|
|
43
|
+
("Renomear imagens", "Identificar cartas (UC / TOI / data)", PageImage),
|
|
44
|
+
("Dividir base (QGIS)", "Dividir a base por coluna (CSV/Excel)", PageCircuit),
|
|
45
|
+
("OCR", "Aplicar OCR em PDFs e imagens de uma pasta", PageOcr),
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
def __init__(self, key: GlobalKey | None = None) -> None:
|
|
49
|
+
super().__init__(key)
|
|
50
|
+
|
|
51
|
+
def _nav_item(
|
|
52
|
+
self,
|
|
53
|
+
context: BuildContext,
|
|
54
|
+
label: str,
|
|
55
|
+
description: str,
|
|
56
|
+
page: Callable[[], FlutterWidget],
|
|
57
|
+
) -> FlutterWidget:
|
|
58
|
+
return Row(
|
|
59
|
+
[
|
|
60
|
+
ElevatedButton(label, lambda: context.navigator.push(page())),
|
|
61
|
+
Text(description),
|
|
62
|
+
],
|
|
63
|
+
main_axis_alignment=MainAxisAlignment.START,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def build(self, context: BuildContext) -> FlutterWidget:
|
|
67
|
+
items = [
|
|
68
|
+
self._nav_item(context, label, desc, page)
|
|
69
|
+
for label, desc, page in self.PAGES
|
|
70
|
+
]
|
|
71
|
+
return Scaffold(Column([Text("App Convert"), Divider(), *items]))
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from .common import (
|
|
2
|
+
ItemStatus,
|
|
3
|
+
SplitConfig,
|
|
4
|
+
SplitEvent,
|
|
5
|
+
SplitEventType,
|
|
6
|
+
SplitSummary,
|
|
7
|
+
)
|
|
8
|
+
from .service import (
|
|
9
|
+
ConsoleObserver,
|
|
10
|
+
CsvExporter,
|
|
11
|
+
DataFrameSplitService,
|
|
12
|
+
ExcelExporter,
|
|
13
|
+
ReportObserver,
|
|
14
|
+
SplitGroup,
|
|
15
|
+
SplitObserver,
|
|
16
|
+
SplitPlanner,
|
|
17
|
+
)
|
|
18
|
+
from .model_circuit import ModelCircuit
|
|
19
|
+
from .controller_circuit import ControllerCircuit
|
|
20
|
+
from .view_circuit import PageCircuit
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import re
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from enum import Enum, StrEnum
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from table_stream import CsvOptions, Directory
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# ============================================================
|
|
11
|
+
# Status / eventos (Observer)
|
|
12
|
+
# ============================================================
|
|
13
|
+
class ItemStatus(StrEnum):
|
|
14
|
+
PENDING = "pendente"
|
|
15
|
+
DONE = "exportado"
|
|
16
|
+
SKIPPED = "pulado"
|
|
17
|
+
ERROR = "erro"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SplitEventType(Enum):
|
|
21
|
+
STARTED = "started"
|
|
22
|
+
ITEM = "item" # um grupo (ex.: numliv = 5) foi processado
|
|
23
|
+
FINISHED = "finished"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True)
|
|
27
|
+
class SplitSummary:
|
|
28
|
+
total_groups: int = 0
|
|
29
|
+
exported_files: int = 0
|
|
30
|
+
skipped_files: int = 0
|
|
31
|
+
errors: int = 0
|
|
32
|
+
stopped: bool = False
|
|
33
|
+
elapsed_s: float = 0.0
|
|
34
|
+
output_dir: str = ""
|
|
35
|
+
period: tuple[str, ...] = ()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(frozen=True)
|
|
39
|
+
class SplitEvent:
|
|
40
|
+
"""Evento enviado pelo service a todos os observadores."""
|
|
41
|
+
|
|
42
|
+
type: SplitEventType
|
|
43
|
+
done: int = 0
|
|
44
|
+
total: int = 0
|
|
45
|
+
group: str = ""
|
|
46
|
+
key: str = ""
|
|
47
|
+
period: str = ""
|
|
48
|
+
rows: int = 0
|
|
49
|
+
status: ItemStatus | None = None
|
|
50
|
+
files: tuple[str, ...] = ()
|
|
51
|
+
message: str = ""
|
|
52
|
+
summary: SplitSummary | None = None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# ============================================================
|
|
56
|
+
# Configuração
|
|
57
|
+
# ============================================================
|
|
58
|
+
@dataclass
|
|
59
|
+
class SplitConfig:
|
|
60
|
+
column_split: str
|
|
61
|
+
output_dir: Directory
|
|
62
|
+
export_csv: bool = True
|
|
63
|
+
export_excel: bool = True
|
|
64
|
+
|
|
65
|
+
# Estrutura OUTPUT/<numano>/<nummes>/<CSV|EXCEL>/<grupo>.<ext>
|
|
66
|
+
use_period_dirs: bool = True
|
|
67
|
+
year_column: str = "numano"
|
|
68
|
+
month_column: str = "nummes"
|
|
69
|
+
|
|
70
|
+
replace: bool = False
|
|
71
|
+
csv_options: CsvOptions = field(default_factory=CsvOptions)
|
|
72
|
+
|
|
73
|
+
# Opcional: prefixo no nome do arquivo, vindo de outra coluna ("<prefixo>-<grupo>")
|
|
74
|
+
filename_prefix_column: str | None = None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# ============================================================
|
|
78
|
+
# Utilidades de texto
|
|
79
|
+
# ============================================================
|
|
80
|
+
_INVALID_NAME = re.compile(r'[\\/:*?"<>|\r\n\t]+')
|
|
81
|
+
_NATURAL = re.compile(r"(\d+)")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def clean_cell(value: Any) -> str:
|
|
85
|
+
"""'2025.0' -> '2025'; nan/None -> ''."""
|
|
86
|
+
s = str(value).strip()
|
|
87
|
+
if s in ("", "nan", "NaN", "None", "NaT"):
|
|
88
|
+
return ""
|
|
89
|
+
return s[:-2] if s.endswith(".0") and s[:-2].isdigit() else s
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def safe_filename(name: str) -> str:
|
|
93
|
+
cleaned = _INVALID_NAME.sub("_", name).strip(" .")
|
|
94
|
+
return cleaned or "vazio"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def natural_key(text: str) -> list[str | int]:
|
|
98
|
+
"""Ordenação natural: 2 vem antes de 10."""
|
|
99
|
+
return [int(t) if t.isdecimal() else t.lower() for t in _NATURAL.split(text)]
|