FastPluggy 0.2.7__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.
- fastpluggy-0.2.7/MANIFEST.in +12 -0
- fastpluggy-0.2.7/PKG-INFO +33 -0
- fastpluggy-0.2.7/README.md +111 -0
- fastpluggy-0.2.7/pyproject.toml +10 -0
- fastpluggy-0.2.7/setup.cfg +4 -0
- fastpluggy-0.2.7/setup.py +38 -0
- fastpluggy-0.2.7/src/FastPluggy.egg-info/PKG-INFO +33 -0
- fastpluggy-0.2.7/src/FastPluggy.egg-info/SOURCES.txt +112 -0
- fastpluggy-0.2.7/src/FastPluggy.egg-info/dependency_links.txt +1 -0
- fastpluggy-0.2.7/src/FastPluggy.egg-info/requires.txt +15 -0
- fastpluggy-0.2.7/src/FastPluggy.egg-info/top_level.txt +1 -0
- fastpluggy-0.2.7/src/fastpluggy/__init__.py +4 -0
- fastpluggy-0.2.7/src/fastpluggy/core/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/core/auth/__init__.py +34 -0
- fastpluggy-0.2.7/src/fastpluggy/core/auth/auth_interface.py +78 -0
- fastpluggy-0.2.7/src/fastpluggy/core/auth/middleware.py +31 -0
- fastpluggy-0.2.7/src/fastpluggy/core/base_module.py +73 -0
- fastpluggy-0.2.7/src/fastpluggy/core/base_module_manager.py +347 -0
- fastpluggy-0.2.7/src/fastpluggy/core/config.py +38 -0
- fastpluggy-0.2.7/src/fastpluggy/core/database.py +103 -0
- fastpluggy-0.2.7/src/fastpluggy/core/dependency.py +23 -0
- fastpluggy-0.2.7/src/fastpluggy/core/error/__init__.py +8 -0
- fastpluggy-0.2.7/src/fastpluggy/core/error/degraded_mode_handler.py +55 -0
- fastpluggy-0.2.7/src/fastpluggy/core/error/exception.py +21 -0
- fastpluggy-0.2.7/src/fastpluggy/core/flash.py +51 -0
- fastpluggy-0.2.7/src/fastpluggy/core/global_registry.py +26 -0
- fastpluggy-0.2.7/src/fastpluggy/core/menu/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/core/menu/decorator.py +47 -0
- fastpluggy-0.2.7/src/fastpluggy/core/menu/menu_manager.py +171 -0
- fastpluggy-0.2.7/src/fastpluggy/core/menu/schema.py +56 -0
- fastpluggy-0.2.7/src/fastpluggy/core/models.py +26 -0
- fastpluggy-0.2.7/src/fastpluggy/core/models_tools/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/core/models_tools/base.py +16 -0
- fastpluggy-0.2.7/src/fastpluggy/core/models_tools/callable.py +60 -0
- fastpluggy-0.2.7/src/fastpluggy/core/models_tools/pydantic.py +87 -0
- fastpluggy-0.2.7/src/fastpluggy/core/models_tools/shared.py +90 -0
- fastpluggy-0.2.7/src/fastpluggy/core/models_tools/sqlalchemy.py +233 -0
- fastpluggy-0.2.7/src/fastpluggy/core/module_base.py +79 -0
- fastpluggy-0.2.7/src/fastpluggy/core/plugin/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/core/plugin/dependency_resolver.py +151 -0
- fastpluggy-0.2.7/src/fastpluggy/core/plugin/installer/__init__.py +24 -0
- fastpluggy-0.2.7/src/fastpluggy/core/plugin/installer/git_installer.py +134 -0
- fastpluggy-0.2.7/src/fastpluggy/core/plugin/installer/zip_installer.py +39 -0
- fastpluggy-0.2.7/src/fastpluggy/core/plugin/repository.py +101 -0
- fastpluggy-0.2.7/src/fastpluggy/core/plugin/service.py +59 -0
- fastpluggy-0.2.7/src/fastpluggy/core/plugin_state.py +116 -0
- fastpluggy-0.2.7/src/fastpluggy/core/repository/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/core/repository/app_settings.py +79 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/actions/__init__.py +12 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/actions/fast_pluggy.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/actions/modules.py +152 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/admin.py +200 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/app_static.py +37 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/base_module.py +190 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/execute.py +127 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/home.py +20 -0
- fastpluggy-0.2.7/src/fastpluggy/core/routers/settings.py +67 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/__init__.py +11 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/fastapi.py +105 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/fs_tools.py +53 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/git_tools.py +80 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/inspect_tools.py +262 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/install.py +19 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/serialize_tools.py +53 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/system.py +18 -0
- fastpluggy-0.2.7/src/fastpluggy/core/tools/threads_tools.py +34 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/__init__.py +87 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/__init__.py +98 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/button.py +331 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/custom.py +47 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/debug.py +31 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/form.py +115 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/list.py +38 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/model.py +114 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/pagination.py +87 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/raw.py +23 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/render_field_tools.py +59 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/tabbed.py +35 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/table.py +207 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/table_model.py +222 -0
- fastpluggy-0.2.7/src/fastpluggy/core/view_builer/form_builder.py +189 -0
- fastpluggy-0.2.7/src/fastpluggy/fastpluggy.py +239 -0
- fastpluggy-0.2.7/src/fastpluggy/static/css/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/static/css/styles.css +25 -0
- fastpluggy-0.2.7/src/fastpluggy/static/js/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/static/js/scripts.js +1 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/admin/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/admin/install_module.html.j2 +60 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/auth/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/base.html.j2 +229 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/__init__.py +0 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/button_component.html.j2 +44 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/common.html.j2 +77 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/debug/json.html.j2 +12 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/form.html.j2 +30 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/form_component.html.j2 +16 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/generic_page.html.j2 +24 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/mime.html.j2 +14 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/model_view.html.j2 +29 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/pagination_macros.html.j2 +112 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/tabbed.html.j2 +29 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/table_component.html.j2 +80 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/components/table_filter_component.html.j2 +25 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/degraded_mode.html.j2 +63 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/error.html.j2 +56 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/flash_messages.html.j2 +10 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/index.html.j2 +16 -0
- fastpluggy-0.2.7/src/fastpluggy/templates/menu.html.j2 +176 -0
- fastpluggy-0.2.7/tests/test_app.py +46 -0
- fastpluggy-0.2.7/tests/test_domain_module_manager.py +80 -0
- fastpluggy-0.2.7/tests/test_dynamic_settings.py +41 -0
- fastpluggy-0.2.7/tests/test_fast_pluggy_init.py +57 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Include all Python files
|
|
2
|
+
recursive-include src *.py
|
|
3
|
+
|
|
4
|
+
# Include all template files
|
|
5
|
+
recursive-include src/fastpluggy/templates *.html *.j2
|
|
6
|
+
|
|
7
|
+
# Include all static files (CSS, JS, etc.)
|
|
8
|
+
recursive-include src/fastpluggy/static *
|
|
9
|
+
|
|
10
|
+
# Include README and license files
|
|
11
|
+
include README.md
|
|
12
|
+
include LICENSE
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: FastPluggy
|
|
3
|
+
Version: 0.2.7
|
|
4
|
+
Summary: A FastAPI-based framework with plugin management and database handling.
|
|
5
|
+
Home-page: https://gitlab.ggcorp.fr/open/fastpluggy/fast_pluggy
|
|
6
|
+
Author: Your Name
|
|
7
|
+
Author-email: your.email@example.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.7
|
|
12
|
+
Requires-Dist: fastapi~=0.115.2
|
|
13
|
+
Requires-Dist: starlette
|
|
14
|
+
Requires-Dist: uvicorn>=0.31.1
|
|
15
|
+
Requires-Dist: python-multipart
|
|
16
|
+
Requires-Dist: pydantic
|
|
17
|
+
Requires-Dist: pydantic-settings
|
|
18
|
+
Requires-Dist: jinja2~=3.1.4
|
|
19
|
+
Requires-Dist: sqlalchemy~=2.0.35
|
|
20
|
+
Requires-Dist: loguru>=0.7.2
|
|
21
|
+
Requires-Dist: GitPython~=3.1.43
|
|
22
|
+
Requires-Dist: httpx>=0.27.2
|
|
23
|
+
Requires-Dist: itsdangerous==2.1.0
|
|
24
|
+
Requires-Dist: wtforms>=3.2.1
|
|
25
|
+
Requires-Dist: werkzeug
|
|
26
|
+
Requires-Dist: semantic-version
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: requires-python
|
|
33
|
+
Dynamic: summary
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
|
|
2
|
+
# FastPluggy
|
|
3
|
+
|
|
4
|
+
**FastPluggy** is a FastAPI-based framework that simplifies the process of building modular applications with plugin management and database handling. It allows you to easily configure plugins, static files, Jinja2 templates, and databases, making it a powerful and flexible solution for FastAPI projects.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Plugin Management**: Easily manage, enable, disable, and configure plugins.
|
|
9
|
+
- **Database Integration**: Supports SQLAlchemy for database handling.
|
|
10
|
+
- **Static Files and Templates**: Serve static files and Jinja2 templates seamlessly.
|
|
11
|
+
- **Extensibility**: Use FastPluggy as a library to extend your FastAPI applications.
|
|
12
|
+
- **Simple Setup**: Configure your project with a single class, `ProjectSetup`, for easy initialization.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
You can install **FastPluggy** using pip:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install FastPluggy
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Getting Started
|
|
23
|
+
|
|
24
|
+
### 1. Create a FastAPI App with FastPluggy
|
|
25
|
+
|
|
26
|
+
In your FastAPI project, import `ProjectSetup` from **FastPluggy** and use it to configure your app:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from fastapi import FastAPI
|
|
30
|
+
from fastpluggy.fastpluggy import FastPluggy
|
|
31
|
+
|
|
32
|
+
app = FastAPI()
|
|
33
|
+
|
|
34
|
+
# Initialize the FastPluggy class which sets up everything
|
|
35
|
+
fast_pluggy = FastPluggy(app)
|
|
36
|
+
|
|
37
|
+
# Run the application using Uvicorn or another ASGI server
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
import uvicorn
|
|
40
|
+
uvicorn.run(fast_pluggy.app, host="0.0.0.0", port=8000)
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Running the Application
|
|
45
|
+
|
|
46
|
+
Once the configuration is complete, you can run the FastAPI app using Uvicorn:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uvicorn your_project:app --reload
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. Plugin Management
|
|
53
|
+
|
|
54
|
+
With **FastPluggy**, managing plugins is straightforward. The `PluginManager` class handles loading, enabling, disabling, and configuring plugins in your application. You can define plugins and control their behavior from the admin interface or directly in code.
|
|
55
|
+
|
|
56
|
+
### Example Plugin Definition
|
|
57
|
+
|
|
58
|
+
To create a plugin, simply create a Python module with a FastAPI router and define plugin-specific functionality.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from fastapi import APIRouter
|
|
62
|
+
|
|
63
|
+
plugin_router = APIRouter()
|
|
64
|
+
|
|
65
|
+
@plugin_router.get("/hello")
|
|
66
|
+
def hello_plugin():
|
|
67
|
+
return {"message": "Hello from the plugin!"}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**FastPluggy** will automatically detect and integrate this plugin into your application.
|
|
71
|
+
|
|
72
|
+
## File Structure
|
|
73
|
+
|
|
74
|
+
After installing **FastPluggy**, your project structure might look like this:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
your_project/
|
|
78
|
+
│
|
|
79
|
+
├── src/
|
|
80
|
+
│ ├── your_project/
|
|
81
|
+
│ │ ├── __init__.py
|
|
82
|
+
│ │ ├── main.py
|
|
83
|
+
│ │ ├── core/
|
|
84
|
+
│ │ ├── templates/
|
|
85
|
+
│ │ ├── static/
|
|
86
|
+
│ └── your_project.egg-info/
|
|
87
|
+
│
|
|
88
|
+
├── tests/
|
|
89
|
+
├── README.md
|
|
90
|
+
├── setup.py
|
|
91
|
+
└── pyproject.toml
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- **main.py**: Entry point for your application.
|
|
95
|
+
- **core/**: Core logic for plugins, database handling, etc.
|
|
96
|
+
- **templates/**: Jinja2 templates for rendering HTML.
|
|
97
|
+
- **static/**: Static files like CSS and JavaScript.
|
|
98
|
+
- **tests/**: Directory for unit tests.
|
|
99
|
+
|
|
100
|
+
## Contributing
|
|
101
|
+
|
|
102
|
+
Contributions are welcome! If you'd like to contribute to **FastPluggy**, please fork the repository and submit a pull request. Be sure to follow the contribution guidelines.
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more information.
|
|
107
|
+
|
|
108
|
+
## Links
|
|
109
|
+
|
|
110
|
+
- [Homepage](https://github.com/yourusername/fastpluggy)
|
|
111
|
+
- [Documentation](https://github.com/yourusername/fastpluggy/wiki)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[tool.pytest.ini_options]
|
|
7
|
+
asyncio_mode = "auto"
|
|
8
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
9
|
+
python_files = ["test_*.py"]
|
|
10
|
+
python_functions = ["test_*"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from setuptools import setup, find_packages
|
|
4
|
+
#from fastpluggy import __version__
|
|
5
|
+
|
|
6
|
+
# Function to read the requirements from the requirements.txt file
|
|
7
|
+
def parse_requirements(filename):
|
|
8
|
+
"""Load requirements from a pip requirements file."""
|
|
9
|
+
with open(filename, 'r') as req_file:
|
|
10
|
+
return [line.strip() for line in req_file if line and not line.startswith("#")]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
requirements = []
|
|
14
|
+
if os.path.isfile("requirements.txt"):
|
|
15
|
+
requirements = parse_requirements("requirements.txt")
|
|
16
|
+
else:
|
|
17
|
+
print("requirements.txt not found")
|
|
18
|
+
|
|
19
|
+
print(f"requirements: {requirements}")
|
|
20
|
+
|
|
21
|
+
setup(
|
|
22
|
+
name='FastPluggy',
|
|
23
|
+
version="0.2.7",
|
|
24
|
+
description='A FastAPI-based framework with plugin management and database handling.',
|
|
25
|
+
author='Your Name',
|
|
26
|
+
author_email='your.email@example.com',
|
|
27
|
+
url='https://gitlab.ggcorp.fr/open/fastpluggy/fast_pluggy',
|
|
28
|
+
packages=find_packages(where='src'), # This finds all packages under src/
|
|
29
|
+
package_dir={'': 'src'}, # Tells setuptools that all packages are under the src directory
|
|
30
|
+
include_package_data=True, # This includes non-code files (static, templates)
|
|
31
|
+
install_requires=requirements,
|
|
32
|
+
classifiers=[
|
|
33
|
+
'Programming Language :: Python :: 3',
|
|
34
|
+
'License :: OSI Approved :: MIT License',
|
|
35
|
+
'Operating System :: OS Independent',
|
|
36
|
+
],
|
|
37
|
+
python_requires='>=3.7',
|
|
38
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: FastPluggy
|
|
3
|
+
Version: 0.2.7
|
|
4
|
+
Summary: A FastAPI-based framework with plugin management and database handling.
|
|
5
|
+
Home-page: https://gitlab.ggcorp.fr/open/fastpluggy/fast_pluggy
|
|
6
|
+
Author: Your Name
|
|
7
|
+
Author-email: your.email@example.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.7
|
|
12
|
+
Requires-Dist: fastapi~=0.115.2
|
|
13
|
+
Requires-Dist: starlette
|
|
14
|
+
Requires-Dist: uvicorn>=0.31.1
|
|
15
|
+
Requires-Dist: python-multipart
|
|
16
|
+
Requires-Dist: pydantic
|
|
17
|
+
Requires-Dist: pydantic-settings
|
|
18
|
+
Requires-Dist: jinja2~=3.1.4
|
|
19
|
+
Requires-Dist: sqlalchemy~=2.0.35
|
|
20
|
+
Requires-Dist: loguru>=0.7.2
|
|
21
|
+
Requires-Dist: GitPython~=3.1.43
|
|
22
|
+
Requires-Dist: httpx>=0.27.2
|
|
23
|
+
Requires-Dist: itsdangerous==2.1.0
|
|
24
|
+
Requires-Dist: wtforms>=3.2.1
|
|
25
|
+
Requires-Dist: werkzeug
|
|
26
|
+
Requires-Dist: semantic-version
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: requires-python
|
|
33
|
+
Dynamic: summary
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
src/FastPluggy.egg-info/PKG-INFO
|
|
6
|
+
src/FastPluggy.egg-info/SOURCES.txt
|
|
7
|
+
src/FastPluggy.egg-info/dependency_links.txt
|
|
8
|
+
src/FastPluggy.egg-info/requires.txt
|
|
9
|
+
src/FastPluggy.egg-info/top_level.txt
|
|
10
|
+
src/fastpluggy/__init__.py
|
|
11
|
+
src/fastpluggy/fastpluggy.py
|
|
12
|
+
src/fastpluggy/core/__init__.py
|
|
13
|
+
src/fastpluggy/core/base_module.py
|
|
14
|
+
src/fastpluggy/core/base_module_manager.py
|
|
15
|
+
src/fastpluggy/core/config.py
|
|
16
|
+
src/fastpluggy/core/database.py
|
|
17
|
+
src/fastpluggy/core/dependency.py
|
|
18
|
+
src/fastpluggy/core/flash.py
|
|
19
|
+
src/fastpluggy/core/global_registry.py
|
|
20
|
+
src/fastpluggy/core/models.py
|
|
21
|
+
src/fastpluggy/core/module_base.py
|
|
22
|
+
src/fastpluggy/core/plugin_state.py
|
|
23
|
+
src/fastpluggy/core/auth/__init__.py
|
|
24
|
+
src/fastpluggy/core/auth/auth_interface.py
|
|
25
|
+
src/fastpluggy/core/auth/middleware.py
|
|
26
|
+
src/fastpluggy/core/error/__init__.py
|
|
27
|
+
src/fastpluggy/core/error/degraded_mode_handler.py
|
|
28
|
+
src/fastpluggy/core/error/exception.py
|
|
29
|
+
src/fastpluggy/core/menu/__init__.py
|
|
30
|
+
src/fastpluggy/core/menu/decorator.py
|
|
31
|
+
src/fastpluggy/core/menu/menu_manager.py
|
|
32
|
+
src/fastpluggy/core/menu/schema.py
|
|
33
|
+
src/fastpluggy/core/models_tools/__init__.py
|
|
34
|
+
src/fastpluggy/core/models_tools/base.py
|
|
35
|
+
src/fastpluggy/core/models_tools/callable.py
|
|
36
|
+
src/fastpluggy/core/models_tools/pydantic.py
|
|
37
|
+
src/fastpluggy/core/models_tools/shared.py
|
|
38
|
+
src/fastpluggy/core/models_tools/sqlalchemy.py
|
|
39
|
+
src/fastpluggy/core/plugin/__init__.py
|
|
40
|
+
src/fastpluggy/core/plugin/dependency_resolver.py
|
|
41
|
+
src/fastpluggy/core/plugin/repository.py
|
|
42
|
+
src/fastpluggy/core/plugin/service.py
|
|
43
|
+
src/fastpluggy/core/plugin/installer/__init__.py
|
|
44
|
+
src/fastpluggy/core/plugin/installer/git_installer.py
|
|
45
|
+
src/fastpluggy/core/plugin/installer/zip_installer.py
|
|
46
|
+
src/fastpluggy/core/repository/__init__.py
|
|
47
|
+
src/fastpluggy/core/repository/app_settings.py
|
|
48
|
+
src/fastpluggy/core/routers/__init__.py
|
|
49
|
+
src/fastpluggy/core/routers/admin.py
|
|
50
|
+
src/fastpluggy/core/routers/app_static.py
|
|
51
|
+
src/fastpluggy/core/routers/base_module.py
|
|
52
|
+
src/fastpluggy/core/routers/execute.py
|
|
53
|
+
src/fastpluggy/core/routers/home.py
|
|
54
|
+
src/fastpluggy/core/routers/settings.py
|
|
55
|
+
src/fastpluggy/core/routers/actions/__init__.py
|
|
56
|
+
src/fastpluggy/core/routers/actions/fast_pluggy.py
|
|
57
|
+
src/fastpluggy/core/routers/actions/modules.py
|
|
58
|
+
src/fastpluggy/core/tools/__init__.py
|
|
59
|
+
src/fastpluggy/core/tools/fastapi.py
|
|
60
|
+
src/fastpluggy/core/tools/fs_tools.py
|
|
61
|
+
src/fastpluggy/core/tools/git_tools.py
|
|
62
|
+
src/fastpluggy/core/tools/inspect_tools.py
|
|
63
|
+
src/fastpluggy/core/tools/install.py
|
|
64
|
+
src/fastpluggy/core/tools/serialize_tools.py
|
|
65
|
+
src/fastpluggy/core/tools/system.py
|
|
66
|
+
src/fastpluggy/core/tools/threads_tools.py
|
|
67
|
+
src/fastpluggy/core/view_builer/__init__.py
|
|
68
|
+
src/fastpluggy/core/view_builer/form_builder.py
|
|
69
|
+
src/fastpluggy/core/view_builer/components/__init__.py
|
|
70
|
+
src/fastpluggy/core/view_builer/components/button.py
|
|
71
|
+
src/fastpluggy/core/view_builer/components/custom.py
|
|
72
|
+
src/fastpluggy/core/view_builer/components/debug.py
|
|
73
|
+
src/fastpluggy/core/view_builer/components/form.py
|
|
74
|
+
src/fastpluggy/core/view_builer/components/list.py
|
|
75
|
+
src/fastpluggy/core/view_builer/components/model.py
|
|
76
|
+
src/fastpluggy/core/view_builer/components/pagination.py
|
|
77
|
+
src/fastpluggy/core/view_builer/components/raw.py
|
|
78
|
+
src/fastpluggy/core/view_builer/components/render_field_tools.py
|
|
79
|
+
src/fastpluggy/core/view_builer/components/tabbed.py
|
|
80
|
+
src/fastpluggy/core/view_builer/components/table.py
|
|
81
|
+
src/fastpluggy/core/view_builer/components/table_model.py
|
|
82
|
+
src/fastpluggy/static/css/__init__.py
|
|
83
|
+
src/fastpluggy/static/css/styles.css
|
|
84
|
+
src/fastpluggy/static/js/__init__.py
|
|
85
|
+
src/fastpluggy/static/js/scripts.js
|
|
86
|
+
src/fastpluggy/templates/__init__.py
|
|
87
|
+
src/fastpluggy/templates/base.html.j2
|
|
88
|
+
src/fastpluggy/templates/degraded_mode.html.j2
|
|
89
|
+
src/fastpluggy/templates/error.html.j2
|
|
90
|
+
src/fastpluggy/templates/flash_messages.html.j2
|
|
91
|
+
src/fastpluggy/templates/index.html.j2
|
|
92
|
+
src/fastpluggy/templates/menu.html.j2
|
|
93
|
+
src/fastpluggy/templates/admin/__init__.py
|
|
94
|
+
src/fastpluggy/templates/admin/install_module.html.j2
|
|
95
|
+
src/fastpluggy/templates/auth/__init__.py
|
|
96
|
+
src/fastpluggy/templates/components/__init__.py
|
|
97
|
+
src/fastpluggy/templates/components/button_component.html.j2
|
|
98
|
+
src/fastpluggy/templates/components/common.html.j2
|
|
99
|
+
src/fastpluggy/templates/components/form.html.j2
|
|
100
|
+
src/fastpluggy/templates/components/form_component.html.j2
|
|
101
|
+
src/fastpluggy/templates/components/generic_page.html.j2
|
|
102
|
+
src/fastpluggy/templates/components/mime.html.j2
|
|
103
|
+
src/fastpluggy/templates/components/model_view.html.j2
|
|
104
|
+
src/fastpluggy/templates/components/pagination_macros.html.j2
|
|
105
|
+
src/fastpluggy/templates/components/tabbed.html.j2
|
|
106
|
+
src/fastpluggy/templates/components/table_component.html.j2
|
|
107
|
+
src/fastpluggy/templates/components/table_filter_component.html.j2
|
|
108
|
+
src/fastpluggy/templates/components/debug/json.html.j2
|
|
109
|
+
tests/test_app.py
|
|
110
|
+
tests/test_domain_module_manager.py
|
|
111
|
+
tests/test_dynamic_settings.py
|
|
112
|
+
tests/test_fast_pluggy_init.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
fastapi~=0.115.2
|
|
2
|
+
starlette
|
|
3
|
+
uvicorn>=0.31.1
|
|
4
|
+
python-multipart
|
|
5
|
+
pydantic
|
|
6
|
+
pydantic-settings
|
|
7
|
+
jinja2~=3.1.4
|
|
8
|
+
sqlalchemy~=2.0.35
|
|
9
|
+
loguru>=0.7.2
|
|
10
|
+
GitPython~=3.1.43
|
|
11
|
+
httpx>=0.27.2
|
|
12
|
+
itsdangerous==2.1.0
|
|
13
|
+
wtforms>=3.2.1
|
|
14
|
+
werkzeug
|
|
15
|
+
semantic-version
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fastpluggy
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# core/dependency.py
|
|
2
|
+
from fastapi import Request, HTTPException, Depends
|
|
3
|
+
from starlette import status
|
|
4
|
+
from starlette.authentication import UnauthenticatedUser
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def require_authentication(request: Request):
|
|
8
|
+
auth_manager = request.app.state.fastpluggy.auth_manager
|
|
9
|
+
if auth_manager:
|
|
10
|
+
if isinstance(request.user, UnauthenticatedUser):
|
|
11
|
+
# If a custom error handler is defined, call it.
|
|
12
|
+
if hasattr(auth_manager, "on_authenticate_error") and callable(auth_manager.on_authenticate_error):
|
|
13
|
+
result = await auth_manager.on_authenticate_error(request)
|
|
14
|
+
if result is not None:
|
|
15
|
+
return result
|
|
16
|
+
|
|
17
|
+
# Fallback to default behavior if no custom error handling was provided.
|
|
18
|
+
raise HTTPException(
|
|
19
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
20
|
+
detail="Not authenticated"
|
|
21
|
+
)
|
|
22
|
+
return request.user
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def require_role(role: str):
|
|
26
|
+
async def dependency(request: Request):
|
|
27
|
+
# your `require_authentication` should already have populated request.user & request.auth
|
|
28
|
+
# (e.g. via an AuthenticationMiddleware + your backend)
|
|
29
|
+
auth_manager = request.app.state.fastpluggy.auth_manager
|
|
30
|
+
if auth_manager:
|
|
31
|
+
scopes = getattr(request.auth, "scopes", [])
|
|
32
|
+
if role not in scopes:
|
|
33
|
+
raise HTTPException(status_code=403, detail=f"'{role}' role required")
|
|
34
|
+
return Depends(dependency)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Type
|
|
3
|
+
|
|
4
|
+
from fastapi import Request
|
|
5
|
+
from starlette.authentication import BaseUser, AuthenticationBackend, AuthCredentials
|
|
6
|
+
from starlette.requests import HTTPConnection
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AuthInterface(AuthenticationBackend):
|
|
10
|
+
|
|
11
|
+
async def on_authenticate_error(self, request: Request):
|
|
12
|
+
"""
|
|
13
|
+
Handle authentication errors when a user fails to authenticate.
|
|
14
|
+
|
|
15
|
+
This method is invoked when authentication fails (e.g., due to missing or invalid credentials).
|
|
16
|
+
It examines the request's 'Accept' header and, if the client expects HTML and login redirection is enabled,
|
|
17
|
+
returns a redirect response to the login page. Otherwise, it raises an HTTP 401 Unauthorized exception with
|
|
18
|
+
a WWW-Authenticate header, which can trigger the browser's Basic Authentication popup.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
request (Request): The incoming FastAPI request object containing details such as headers.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
A RedirectResponse if HTML is accepted and redirection is enabled. If not, this method raises an
|
|
25
|
+
HTTPException and does not return normally.
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
HTTPException: Raised with status code 401 if authentication fails and the client does not accept HTML,
|
|
29
|
+
prompting the Basic Auth dialog.
|
|
30
|
+
"""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def user_model(self) -> Type[BaseUser]:
|
|
36
|
+
"""
|
|
37
|
+
Returns the SQLAlchemy model class representing a user.
|
|
38
|
+
Implementations can override this property to use a different model.
|
|
39
|
+
"""
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
async def authenticate(self, conn: HTTPConnection) -> tuple[AuthCredentials, BaseUser] | None:
|
|
44
|
+
"""
|
|
45
|
+
Check if the user is authenticated.
|
|
46
|
+
Should return a User object if authenticated.
|
|
47
|
+
Otherwise, it can either raise an HTTPException or return a Response (e.g. a redirect).
|
|
48
|
+
"""
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
def get_user_menu_entries(self, request: Request) -> list:
|
|
52
|
+
"""
|
|
53
|
+
Returns menu items for the user dropdown based on whether a user is logged in.
|
|
54
|
+
If a user is logged in, the menu is obtained from the FastPluggy menu manager (using the "user" menu).
|
|
55
|
+
Otherwise, a default login entry is returned.
|
|
56
|
+
|
|
57
|
+
Each menu item should be a dictionary containing keys such as:
|
|
58
|
+
- "name": the display text
|
|
59
|
+
- "icon": (optional) an icon class
|
|
60
|
+
- "url": the destination URL
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
# Check if a user is attached to request.state (set by middleware)
|
|
65
|
+
user = getattr(request.state, "current_user", None)
|
|
66
|
+
if user:
|
|
67
|
+
from fastpluggy.fastpluggy import FastPluggy
|
|
68
|
+
|
|
69
|
+
# Retrieve the menu manager from the app state.
|
|
70
|
+
fast_pluggy: FastPluggy = request.app.state.fastpluggy
|
|
71
|
+
|
|
72
|
+
menu_manager = fast_pluggy.menu_manager
|
|
73
|
+
# Try to get the "user" menu from the manager.
|
|
74
|
+
user_menu = menu_manager.get_menu("user")
|
|
75
|
+
return user_menu
|
|
76
|
+
else:
|
|
77
|
+
# If no user is logged in, return a default login entry.
|
|
78
|
+
return [{'router': {"name": "Login", "icon": "fa-solid fa-sign-in-alt", "url": "/login"}}]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from fastapi import Request
|
|
2
|
+
from loguru import logger
|
|
3
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CurrentUserMiddleware(BaseHTTPMiddleware):
|
|
7
|
+
async def dispatch(self, request: Request, call_next):
|
|
8
|
+
# Obtain a DB session; in production you might want a better scoped session
|
|
9
|
+
|
|
10
|
+
from fastpluggy.fastpluggy import FastPluggy
|
|
11
|
+
|
|
12
|
+
# Retrieve the FastPluggy instance (assuming it's stored in app.state)
|
|
13
|
+
fast_pluggy: FastPluggy = request.app.state.fastpluggy
|
|
14
|
+
try:
|
|
15
|
+
# Use the current auth manager to authenticate the user
|
|
16
|
+
if fast_pluggy.auth_manager:
|
|
17
|
+
user = await fast_pluggy.auth_manager.authenticate(request)
|
|
18
|
+
else:
|
|
19
|
+
user = None
|
|
20
|
+
except Exception as e:
|
|
21
|
+
logger.exception(e)
|
|
22
|
+
user = None
|
|
23
|
+
# Attach the user to request.state
|
|
24
|
+
request.state.current_user = user[1] if user else None
|
|
25
|
+
request.state.roles = user[0] if user else None
|
|
26
|
+
if hasattr(fast_pluggy.auth_manager, 'get_user_menu_entries'):
|
|
27
|
+
request.state.user_menu = fast_pluggy.auth_manager.get_user_menu_entries(request)
|
|
28
|
+
else:
|
|
29
|
+
request.state.user_menu = []
|
|
30
|
+
response = await call_next(request)
|
|
31
|
+
return response
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from loguru import logger
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseModule:
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self.requirements_installed = False
|
|
10
|
+
|
|
11
|
+
# self.package_name = f"{self.module_type}s.{name}"
|
|
12
|
+
self.url = "#"
|
|
13
|
+
|
|
14
|
+
def common_module_load_param(self):
|
|
15
|
+
|
|
16
|
+
# self.files = list_modules_in_package(self.module.__path__)
|
|
17
|
+
|
|
18
|
+
# Detect models
|
|
19
|
+
self.discover_models()
|
|
20
|
+
|
|
21
|
+
def discover_models(self, base_class_name="Base"):
|
|
22
|
+
"""
|
|
23
|
+
Discover SQLAlchemy models in a plugin's models.py file using AST.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
base_class_name (str): Name of the SQLAlchemy base class (default is 'Base').
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
# Construct the path to models.py
|
|
30
|
+
models_path = os.path.join(self.path, "models.py")
|
|
31
|
+
if not os.path.exists(models_path):
|
|
32
|
+
logger.debug(f"No models.py file found in module '{self.name}'.")
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
# Parse the models.py file using AST
|
|
36
|
+
with open(models_path, "r") as file:
|
|
37
|
+
tree = ast.parse(file.read())
|
|
38
|
+
|
|
39
|
+
for node in ast.walk(tree):
|
|
40
|
+
# Look for class definitions
|
|
41
|
+
if isinstance(node, ast.ClassDef):
|
|
42
|
+
# Check if the class inherits from the specified base class
|
|
43
|
+
for base in node.bases:
|
|
44
|
+
if (
|
|
45
|
+
isinstance(base, ast.Name) and base.id == base_class_name
|
|
46
|
+
) or (
|
|
47
|
+
isinstance(base, ast.Attribute) and base.attr == base_class_name
|
|
48
|
+
):
|
|
49
|
+
# Check for __tablename__ attribute
|
|
50
|
+
tablename = None
|
|
51
|
+
for body_item in node.body:
|
|
52
|
+
if isinstance(body_item, ast.Assign):
|
|
53
|
+
for target in body_item.targets:
|
|
54
|
+
if (
|
|
55
|
+
isinstance(target, ast.Name)
|
|
56
|
+
and target.id == "__tablename__"
|
|
57
|
+
):
|
|
58
|
+
if isinstance(body_item.value, ast.Constant):
|
|
59
|
+
tablename = body_item.value.value
|
|
60
|
+
|
|
61
|
+
# Add the discovered model to the module's models
|
|
62
|
+
self.models.append(
|
|
63
|
+
{"class_name": node.name, "table_name": tablename,
|
|
64
|
+
"module_name": '.'.join([self.package_name, 'models'])}
|
|
65
|
+
)
|
|
66
|
+
logger.info(
|
|
67
|
+
f"Discovered model '{node.name}' with table '{tablename}' in module '{self.name}'"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if not self.models:
|
|
71
|
+
logger.debug(f"No SQLAlchemy models discovered in module '{self.name}'.")
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.error(f"Error discovering models in module '{self.name}': {e}")
|