botflow-gui 0.0.1__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.
- botflow_gui-0.0.1/LICENSE +21 -0
- botflow_gui-0.0.1/PKG-INFO +100 -0
- botflow_gui-0.0.1/README.md +87 -0
- botflow_gui-0.0.1/botflow/__init__.py +53 -0
- botflow_gui-0.0.1/botflow/__pycache__/__init__.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/exceptions.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/i18n.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/logger.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/manager.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/pages.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/qss.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/resolver.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/runtime.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/threads.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/types.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/widgets.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pycache__/workers.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pyinstaller/__init__.py +0 -0
- botflow_gui-0.0.1/botflow/__pyinstaller/__pycache__/hook-botflow.cpython-312.pyc +0 -0
- botflow_gui-0.0.1/botflow/__pyinstaller/hook-botflow.py +10 -0
- botflow_gui-0.0.1/botflow/exceptions.py +4 -0
- botflow_gui-0.0.1/botflow/i18n.py +57 -0
- botflow_gui-0.0.1/botflow/logger.py +45 -0
- botflow_gui-0.0.1/botflow/manager.py +318 -0
- botflow_gui-0.0.1/botflow/pages.py +117 -0
- botflow_gui-0.0.1/botflow/qss.py +21 -0
- botflow_gui-0.0.1/botflow/resolver.py +94 -0
- botflow_gui-0.0.1/botflow/resources/assets/loading.gif +0 -0
- botflow_gui-0.0.1/botflow/resources/locales/en_US/common.json +8 -0
- botflow_gui-0.0.1/botflow/resources/locales/en_US/dialogs.json +15 -0
- botflow_gui-0.0.1/botflow/resources/locales/en_US/initial_page.json +3 -0
- botflow_gui-0.0.1/botflow/resources/locales/en_US/loading.json +3 -0
- botflow_gui-0.0.1/botflow/resources/locales/en_US/messages.json +5 -0
- botflow_gui-0.0.1/botflow/resources/locales/pt_BR/common.json +8 -0
- botflow_gui-0.0.1/botflow/resources/locales/pt_BR/dialogs.json +15 -0
- botflow_gui-0.0.1/botflow/resources/locales/pt_BR/initial_page.json +3 -0
- botflow_gui-0.0.1/botflow/resources/locales/pt_BR/loading.json +3 -0
- botflow_gui-0.0.1/botflow/resources/locales/pt_BR/messages.json +5 -0
- botflow_gui-0.0.1/botflow/resources/styles/file_widget.qss +62 -0
- botflow_gui-0.0.1/botflow/resources/styles/flow_choice_widget.qss +0 -0
- botflow_gui-0.0.1/botflow/resources/styles/flow_manager.qss +51 -0
- botflow_gui-0.0.1/botflow/resources/styles/form_widget.qss +40 -0
- botflow_gui-0.0.1/botflow/resources/styles/initial_page.qss +30 -0
- botflow_gui-0.0.1/botflow/resources/styles/loading_page.qss +37 -0
- botflow_gui-0.0.1/botflow/resources/styles/text_widget.qss +33 -0
- botflow_gui-0.0.1/botflow/runtime.py +42 -0
- botflow_gui-0.0.1/botflow/types.py +87 -0
- botflow_gui-0.0.1/botflow/widgets.py +244 -0
- botflow_gui-0.0.1/botflow/workers.py +130 -0
- botflow_gui-0.0.1/botflow_gui.egg-info/PKG-INFO +100 -0
- botflow_gui-0.0.1/botflow_gui.egg-info/SOURCES.txt +55 -0
- botflow_gui-0.0.1/botflow_gui.egg-info/dependency_links.txt +1 -0
- botflow_gui-0.0.1/botflow_gui.egg-info/entry_points.txt +2 -0
- botflow_gui-0.0.1/botflow_gui.egg-info/requires.txt +6 -0
- botflow_gui-0.0.1/botflow_gui.egg-info/top_level.txt +1 -0
- botflow_gui-0.0.1/pyproject.toml +32 -0
- botflow_gui-0.0.1/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fernando Luiz Fontes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: botflow-gui
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Requires-Python: >=3.12
|
|
5
|
+
Description-Content-Type: text/markdown
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: pyside6>=6.9.1
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: ruff==0.6; extra == "dev"
|
|
10
|
+
Requires-Dist: pytest==9.0.2; extra == "dev"
|
|
11
|
+
Requires-Dist: pyinstaller==6.17.0; extra == "dev"
|
|
12
|
+
Dynamic: license-file
|
|
13
|
+
|
|
14
|
+
# Botflow
|
|
15
|
+
|
|
16
|
+
Botflow is a lightweight Python framework for building automation workflows and bots with a focus on simplicity, modularity, and ease of integration.
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- **Workflow Management**: Define complex bot workflows with simple, declarative syntax
|
|
21
|
+
- **Multi-language Support**: Built-in i18n support with locale management
|
|
22
|
+
- **Resource Management**: Centralized handling of themes, assets, and locales
|
|
23
|
+
- **Bundle Support**: PyInstaller integration for creating standalone executables
|
|
24
|
+
- **Qt Integration**: PySide6 support for GUI-based automation
|
|
25
|
+
- **Configuration**: Flexible runtime configuration with environment variables
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
1. Install Botflow via pip:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install botflow
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
2. Create a simple bot workflow:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from botflow import run_application, run_flow_manager, FlowManager, TextStepSpec, FlowSpec
|
|
39
|
+
|
|
40
|
+
RESOURCES_DIR = 'resources'
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def greet_user(ctx):
|
|
44
|
+
name = ctx.data.get('greet_step')
|
|
45
|
+
ctx.logger.info(f'Hello, {name}!')
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
flow = FlowSpec(
|
|
49
|
+
name='simple_flow',
|
|
50
|
+
steps=[
|
|
51
|
+
TextStepSpec(
|
|
52
|
+
key='greet_step',
|
|
53
|
+
title='Greet User',
|
|
54
|
+
placeholder='Enter your name',
|
|
55
|
+
),
|
|
56
|
+
],
|
|
57
|
+
on_finish=[greet_user]
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if __name__ == '__main__':
|
|
62
|
+
run_application()
|
|
63
|
+
flow_manager = FlowManager(flow)
|
|
64
|
+
run_flow_manager(flow_manager, window_title='Simple Flow Manager')
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
3. Run your bot:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python your_bot_script.py
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## How to create a bundle
|
|
74
|
+
|
|
75
|
+
To create a standalone executable bundle of your Botflow application, you can use PyInstaller. Follow these steps:
|
|
76
|
+
|
|
77
|
+
1. Install PyInstaller:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pip install pyinstaller
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
2. Create a spec file for your application. You can generate a default spec file using:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pyinstaller your_bot_script.py
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
3. If you are using your own resources (like themes, locales, etc.), make sure to include them in the spec file. You can modify the `datas` section of the spec file to include your resources directory:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pyinstaller your_bot_script.py --add-data "path/to/your/resources:resources"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
4. If you want to specify a custom resources directory for your bundle, you can set the `BUNDLE_RESOURCES_DIR` variable in your main script:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
BUNDLE_RESOURCES_DIR = 'path/to/your/bundle/resources'
|
|
99
|
+
```
|
|
100
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Botflow
|
|
2
|
+
|
|
3
|
+
Botflow is a lightweight Python framework for building automation workflows and bots with a focus on simplicity, modularity, and ease of integration.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Workflow Management**: Define complex bot workflows with simple, declarative syntax
|
|
8
|
+
- **Multi-language Support**: Built-in i18n support with locale management
|
|
9
|
+
- **Resource Management**: Centralized handling of themes, assets, and locales
|
|
10
|
+
- **Bundle Support**: PyInstaller integration for creating standalone executables
|
|
11
|
+
- **Qt Integration**: PySide6 support for GUI-based automation
|
|
12
|
+
- **Configuration**: Flexible runtime configuration with environment variables
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
1. Install Botflow via pip:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install botflow
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
2. Create a simple bot workflow:
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from botflow import run_application, run_flow_manager, FlowManager, TextStepSpec, FlowSpec
|
|
26
|
+
|
|
27
|
+
RESOURCES_DIR = 'resources'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def greet_user(ctx):
|
|
31
|
+
name = ctx.data.get('greet_step')
|
|
32
|
+
ctx.logger.info(f'Hello, {name}!')
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
flow = FlowSpec(
|
|
36
|
+
name='simple_flow',
|
|
37
|
+
steps=[
|
|
38
|
+
TextStepSpec(
|
|
39
|
+
key='greet_step',
|
|
40
|
+
title='Greet User',
|
|
41
|
+
placeholder='Enter your name',
|
|
42
|
+
),
|
|
43
|
+
],
|
|
44
|
+
on_finish=[greet_user]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == '__main__':
|
|
49
|
+
run_application()
|
|
50
|
+
flow_manager = FlowManager(flow)
|
|
51
|
+
run_flow_manager(flow_manager, window_title='Simple Flow Manager')
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. Run your bot:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python your_bot_script.py
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## How to create a bundle
|
|
61
|
+
|
|
62
|
+
To create a standalone executable bundle of your Botflow application, you can use PyInstaller. Follow these steps:
|
|
63
|
+
|
|
64
|
+
1. Install PyInstaller:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install pyinstaller
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
2. Create a spec file for your application. You can generate a default spec file using:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pyinstaller your_bot_script.py
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
3. If you are using your own resources (like themes, locales, etc.), make sure to include them in the spec file. You can modify the `datas` section of the spec file to include your resources directory:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pyinstaller your_bot_script.py --add-data "path/to/your/resources:resources"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
4. If you want to specify a custom resources directory for your bundle, you can set the `BUNDLE_RESOURCES_DIR` variable in your main script:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
BUNDLE_RESOURCES_DIR = 'path/to/your/bundle/resources'
|
|
86
|
+
```
|
|
87
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from botflow.manager import FlowManager
|
|
2
|
+
from botflow.types import FlowSpec
|
|
3
|
+
from botflow.widgets import (
|
|
4
|
+
FileStepSpec,
|
|
5
|
+
FileWidget,
|
|
6
|
+
FormInput,
|
|
7
|
+
FormStepSpec,
|
|
8
|
+
FormWidget,
|
|
9
|
+
TextStepSpec,
|
|
10
|
+
TextWidget,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'FlowManager',
|
|
15
|
+
'FileStepSpec',
|
|
16
|
+
'FileWidget',
|
|
17
|
+
'FormInput',
|
|
18
|
+
'FormStepSpec',
|
|
19
|
+
'FormWidget',
|
|
20
|
+
'TextStepSpec',
|
|
21
|
+
'TextWidget',
|
|
22
|
+
'FlowSpec',
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
import sys
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
from PySide6.QtWidgets import QApplication
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_hook_dirs():
|
|
32
|
+
return [str(Path(__file__).resolve().with_name('__pyinstaller'))]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def run_application():
|
|
36
|
+
app = QApplication.instance()
|
|
37
|
+
if not app:
|
|
38
|
+
app = QApplication(sys.argv)
|
|
39
|
+
return app
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def run_flow_manager(
|
|
43
|
+
flow_manager: FlowManager,
|
|
44
|
+
*,
|
|
45
|
+
width: int = 720,
|
|
46
|
+
height: int = 300,
|
|
47
|
+
window_title: str = 'Flow Manager',
|
|
48
|
+
):
|
|
49
|
+
app = run_application()
|
|
50
|
+
flow_manager.resize(width, height)
|
|
51
|
+
flow_manager.setWindowTitle(window_title)
|
|
52
|
+
flow_manager.show()
|
|
53
|
+
sys.exit(app.exec())
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from PyInstaller.utils.hooks import get_module_file_attribute
|
|
4
|
+
|
|
5
|
+
module_path = get_module_file_attribute('botflow')
|
|
6
|
+
if module_path:
|
|
7
|
+
botflow_dir = Path(module_path).parent
|
|
8
|
+
datas = [(str(botflow_dir / 'resources'), 'lib_resources')]
|
|
9
|
+
else:
|
|
10
|
+
datas = []
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from botflow.resolver import find_all_locales_dirs
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class I18n:
|
|
9
|
+
def __init__(self, catalog: dict[str, Any], lang: str, fallback_lang: str = 'en_US'):
|
|
10
|
+
self.catalog = catalog
|
|
11
|
+
self.lang = lang
|
|
12
|
+
self.fallback_lang = fallback_lang
|
|
13
|
+
|
|
14
|
+
def t(self, key: str, **params: Any) -> str:
|
|
15
|
+
loc = self.lang or self.fallback_lang
|
|
16
|
+
|
|
17
|
+
bucket = self.catalog.get(loc, {})
|
|
18
|
+
v = bucket.get(key)
|
|
19
|
+
|
|
20
|
+
if v is None and self.fallback_lang and self.fallback_lang != loc:
|
|
21
|
+
v = self.catalog.get(self.fallback_lang, {}).get(key)
|
|
22
|
+
|
|
23
|
+
if v is None:
|
|
24
|
+
raise KeyError(f'Missing translation key: {key} (lang={self.lang})')
|
|
25
|
+
|
|
26
|
+
if not isinstance(v, str):
|
|
27
|
+
return str(v)
|
|
28
|
+
|
|
29
|
+
return v.format(**params) if params else v
|
|
30
|
+
|
|
31
|
+
def set_lang(self, lang: str) -> None:
|
|
32
|
+
self.lang = lang
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def from_locales_dirs(lang: str):
|
|
36
|
+
locales_dirs = find_all_locales_dirs()
|
|
37
|
+
catalog: dict[str, dict[str, Any]] = {}
|
|
38
|
+
|
|
39
|
+
for locales_dir in locales_dirs if isinstance(locales_dirs, list) else [locales_dirs]:
|
|
40
|
+
for json_file in Path(locales_dir).glob('**/*.json'):
|
|
41
|
+
locale_name = json_file.parent.name
|
|
42
|
+
|
|
43
|
+
with open(json_file, 'r', encoding='utf-8') as f:
|
|
44
|
+
data = json.load(f)
|
|
45
|
+
|
|
46
|
+
catalog.setdefault(locale_name, {})
|
|
47
|
+
|
|
48
|
+
if isinstance(data, dict):
|
|
49
|
+
for v in data.values():
|
|
50
|
+
if isinstance(v, dict):
|
|
51
|
+
catalog[locale_name].update(v)
|
|
52
|
+
|
|
53
|
+
for k, v in data.items():
|
|
54
|
+
if isinstance(v, str):
|
|
55
|
+
catalog[locale_name][k] = v
|
|
56
|
+
|
|
57
|
+
return I18n(catalog, lang)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from datetime import datetime as dt
|
|
3
|
+
from logging.handlers import TimedRotatingFileHandler
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def configure_logger(
|
|
8
|
+
name: str = 'big_views',
|
|
9
|
+
log_dir: str | Path = './logs',
|
|
10
|
+
level: int = logging.INFO,
|
|
11
|
+
console: bool = True,
|
|
12
|
+
rotating_file: bool = True,
|
|
13
|
+
) -> logging.Logger:
|
|
14
|
+
logger = logging.getLogger(name)
|
|
15
|
+
logger.setLevel(level)
|
|
16
|
+
logger.propagate = False
|
|
17
|
+
|
|
18
|
+
log_dir = Path(log_dir)
|
|
19
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
20
|
+
|
|
21
|
+
fmt = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s')
|
|
22
|
+
|
|
23
|
+
if rotating_file:
|
|
24
|
+
log_name = dt.now().strftime('%d-%m-%Y_%Hh-%Mm-%Ss')
|
|
25
|
+
log_path = log_dir / f'{log_name}.log'
|
|
26
|
+
|
|
27
|
+
file_handler = TimedRotatingFileHandler(
|
|
28
|
+
filename=str(log_path),
|
|
29
|
+
when='midnight',
|
|
30
|
+
interval=1,
|
|
31
|
+
backupCount=7,
|
|
32
|
+
encoding='utf-8',
|
|
33
|
+
)
|
|
34
|
+
file_handler.suffix = '%Y%m%d'
|
|
35
|
+
file_handler.setLevel(level)
|
|
36
|
+
file_handler.setFormatter(fmt)
|
|
37
|
+
logger.addHandler(file_handler)
|
|
38
|
+
|
|
39
|
+
if console:
|
|
40
|
+
console_handler = logging.StreamHandler()
|
|
41
|
+
console_handler.setLevel(level)
|
|
42
|
+
console_handler.setFormatter(fmt)
|
|
43
|
+
logger.addHandler(console_handler)
|
|
44
|
+
|
|
45
|
+
return logger
|