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.
Files changed (114) hide show
  1. fastpluggy-0.2.7/MANIFEST.in +12 -0
  2. fastpluggy-0.2.7/PKG-INFO +33 -0
  3. fastpluggy-0.2.7/README.md +111 -0
  4. fastpluggy-0.2.7/pyproject.toml +10 -0
  5. fastpluggy-0.2.7/setup.cfg +4 -0
  6. fastpluggy-0.2.7/setup.py +38 -0
  7. fastpluggy-0.2.7/src/FastPluggy.egg-info/PKG-INFO +33 -0
  8. fastpluggy-0.2.7/src/FastPluggy.egg-info/SOURCES.txt +112 -0
  9. fastpluggy-0.2.7/src/FastPluggy.egg-info/dependency_links.txt +1 -0
  10. fastpluggy-0.2.7/src/FastPluggy.egg-info/requires.txt +15 -0
  11. fastpluggy-0.2.7/src/FastPluggy.egg-info/top_level.txt +1 -0
  12. fastpluggy-0.2.7/src/fastpluggy/__init__.py +4 -0
  13. fastpluggy-0.2.7/src/fastpluggy/core/__init__.py +0 -0
  14. fastpluggy-0.2.7/src/fastpluggy/core/auth/__init__.py +34 -0
  15. fastpluggy-0.2.7/src/fastpluggy/core/auth/auth_interface.py +78 -0
  16. fastpluggy-0.2.7/src/fastpluggy/core/auth/middleware.py +31 -0
  17. fastpluggy-0.2.7/src/fastpluggy/core/base_module.py +73 -0
  18. fastpluggy-0.2.7/src/fastpluggy/core/base_module_manager.py +347 -0
  19. fastpluggy-0.2.7/src/fastpluggy/core/config.py +38 -0
  20. fastpluggy-0.2.7/src/fastpluggy/core/database.py +103 -0
  21. fastpluggy-0.2.7/src/fastpluggy/core/dependency.py +23 -0
  22. fastpluggy-0.2.7/src/fastpluggy/core/error/__init__.py +8 -0
  23. fastpluggy-0.2.7/src/fastpluggy/core/error/degraded_mode_handler.py +55 -0
  24. fastpluggy-0.2.7/src/fastpluggy/core/error/exception.py +21 -0
  25. fastpluggy-0.2.7/src/fastpluggy/core/flash.py +51 -0
  26. fastpluggy-0.2.7/src/fastpluggy/core/global_registry.py +26 -0
  27. fastpluggy-0.2.7/src/fastpluggy/core/menu/__init__.py +0 -0
  28. fastpluggy-0.2.7/src/fastpluggy/core/menu/decorator.py +47 -0
  29. fastpluggy-0.2.7/src/fastpluggy/core/menu/menu_manager.py +171 -0
  30. fastpluggy-0.2.7/src/fastpluggy/core/menu/schema.py +56 -0
  31. fastpluggy-0.2.7/src/fastpluggy/core/models.py +26 -0
  32. fastpluggy-0.2.7/src/fastpluggy/core/models_tools/__init__.py +0 -0
  33. fastpluggy-0.2.7/src/fastpluggy/core/models_tools/base.py +16 -0
  34. fastpluggy-0.2.7/src/fastpluggy/core/models_tools/callable.py +60 -0
  35. fastpluggy-0.2.7/src/fastpluggy/core/models_tools/pydantic.py +87 -0
  36. fastpluggy-0.2.7/src/fastpluggy/core/models_tools/shared.py +90 -0
  37. fastpluggy-0.2.7/src/fastpluggy/core/models_tools/sqlalchemy.py +233 -0
  38. fastpluggy-0.2.7/src/fastpluggy/core/module_base.py +79 -0
  39. fastpluggy-0.2.7/src/fastpluggy/core/plugin/__init__.py +0 -0
  40. fastpluggy-0.2.7/src/fastpluggy/core/plugin/dependency_resolver.py +151 -0
  41. fastpluggy-0.2.7/src/fastpluggy/core/plugin/installer/__init__.py +24 -0
  42. fastpluggy-0.2.7/src/fastpluggy/core/plugin/installer/git_installer.py +134 -0
  43. fastpluggy-0.2.7/src/fastpluggy/core/plugin/installer/zip_installer.py +39 -0
  44. fastpluggy-0.2.7/src/fastpluggy/core/plugin/repository.py +101 -0
  45. fastpluggy-0.2.7/src/fastpluggy/core/plugin/service.py +59 -0
  46. fastpluggy-0.2.7/src/fastpluggy/core/plugin_state.py +116 -0
  47. fastpluggy-0.2.7/src/fastpluggy/core/repository/__init__.py +0 -0
  48. fastpluggy-0.2.7/src/fastpluggy/core/repository/app_settings.py +79 -0
  49. fastpluggy-0.2.7/src/fastpluggy/core/routers/__init__.py +0 -0
  50. fastpluggy-0.2.7/src/fastpluggy/core/routers/actions/__init__.py +12 -0
  51. fastpluggy-0.2.7/src/fastpluggy/core/routers/actions/fast_pluggy.py +0 -0
  52. fastpluggy-0.2.7/src/fastpluggy/core/routers/actions/modules.py +152 -0
  53. fastpluggy-0.2.7/src/fastpluggy/core/routers/admin.py +200 -0
  54. fastpluggy-0.2.7/src/fastpluggy/core/routers/app_static.py +37 -0
  55. fastpluggy-0.2.7/src/fastpluggy/core/routers/base_module.py +190 -0
  56. fastpluggy-0.2.7/src/fastpluggy/core/routers/execute.py +127 -0
  57. fastpluggy-0.2.7/src/fastpluggy/core/routers/home.py +20 -0
  58. fastpluggy-0.2.7/src/fastpluggy/core/routers/settings.py +67 -0
  59. fastpluggy-0.2.7/src/fastpluggy/core/tools/__init__.py +11 -0
  60. fastpluggy-0.2.7/src/fastpluggy/core/tools/fastapi.py +105 -0
  61. fastpluggy-0.2.7/src/fastpluggy/core/tools/fs_tools.py +53 -0
  62. fastpluggy-0.2.7/src/fastpluggy/core/tools/git_tools.py +80 -0
  63. fastpluggy-0.2.7/src/fastpluggy/core/tools/inspect_tools.py +262 -0
  64. fastpluggy-0.2.7/src/fastpluggy/core/tools/install.py +19 -0
  65. fastpluggy-0.2.7/src/fastpluggy/core/tools/serialize_tools.py +53 -0
  66. fastpluggy-0.2.7/src/fastpluggy/core/tools/system.py +18 -0
  67. fastpluggy-0.2.7/src/fastpluggy/core/tools/threads_tools.py +34 -0
  68. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/__init__.py +87 -0
  69. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/__init__.py +98 -0
  70. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/button.py +331 -0
  71. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/custom.py +47 -0
  72. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/debug.py +31 -0
  73. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/form.py +115 -0
  74. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/list.py +38 -0
  75. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/model.py +114 -0
  76. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/pagination.py +87 -0
  77. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/raw.py +23 -0
  78. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/render_field_tools.py +59 -0
  79. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/tabbed.py +35 -0
  80. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/table.py +207 -0
  81. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/components/table_model.py +222 -0
  82. fastpluggy-0.2.7/src/fastpluggy/core/view_builer/form_builder.py +189 -0
  83. fastpluggy-0.2.7/src/fastpluggy/fastpluggy.py +239 -0
  84. fastpluggy-0.2.7/src/fastpluggy/static/css/__init__.py +0 -0
  85. fastpluggy-0.2.7/src/fastpluggy/static/css/styles.css +25 -0
  86. fastpluggy-0.2.7/src/fastpluggy/static/js/__init__.py +0 -0
  87. fastpluggy-0.2.7/src/fastpluggy/static/js/scripts.js +1 -0
  88. fastpluggy-0.2.7/src/fastpluggy/templates/__init__.py +0 -0
  89. fastpluggy-0.2.7/src/fastpluggy/templates/admin/__init__.py +0 -0
  90. fastpluggy-0.2.7/src/fastpluggy/templates/admin/install_module.html.j2 +60 -0
  91. fastpluggy-0.2.7/src/fastpluggy/templates/auth/__init__.py +0 -0
  92. fastpluggy-0.2.7/src/fastpluggy/templates/base.html.j2 +229 -0
  93. fastpluggy-0.2.7/src/fastpluggy/templates/components/__init__.py +0 -0
  94. fastpluggy-0.2.7/src/fastpluggy/templates/components/button_component.html.j2 +44 -0
  95. fastpluggy-0.2.7/src/fastpluggy/templates/components/common.html.j2 +77 -0
  96. fastpluggy-0.2.7/src/fastpluggy/templates/components/debug/json.html.j2 +12 -0
  97. fastpluggy-0.2.7/src/fastpluggy/templates/components/form.html.j2 +30 -0
  98. fastpluggy-0.2.7/src/fastpluggy/templates/components/form_component.html.j2 +16 -0
  99. fastpluggy-0.2.7/src/fastpluggy/templates/components/generic_page.html.j2 +24 -0
  100. fastpluggy-0.2.7/src/fastpluggy/templates/components/mime.html.j2 +14 -0
  101. fastpluggy-0.2.7/src/fastpluggy/templates/components/model_view.html.j2 +29 -0
  102. fastpluggy-0.2.7/src/fastpluggy/templates/components/pagination_macros.html.j2 +112 -0
  103. fastpluggy-0.2.7/src/fastpluggy/templates/components/tabbed.html.j2 +29 -0
  104. fastpluggy-0.2.7/src/fastpluggy/templates/components/table_component.html.j2 +80 -0
  105. fastpluggy-0.2.7/src/fastpluggy/templates/components/table_filter_component.html.j2 +25 -0
  106. fastpluggy-0.2.7/src/fastpluggy/templates/degraded_mode.html.j2 +63 -0
  107. fastpluggy-0.2.7/src/fastpluggy/templates/error.html.j2 +56 -0
  108. fastpluggy-0.2.7/src/fastpluggy/templates/flash_messages.html.j2 +10 -0
  109. fastpluggy-0.2.7/src/fastpluggy/templates/index.html.j2 +16 -0
  110. fastpluggy-0.2.7/src/fastpluggy/templates/menu.html.j2 +176 -0
  111. fastpluggy-0.2.7/tests/test_app.py +46 -0
  112. fastpluggy-0.2.7/tests/test_domain_module_manager.py +80 -0
  113. fastpluggy-0.2.7/tests/test_dynamic_settings.py +41 -0
  114. 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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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,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
@@ -0,0 +1,4 @@
1
+ import os
2
+
3
+ __version__ = "0.2.7" # Update this manually when needed
4
+ __SOURCE_COMMIT_CORE__ = os.getenv("SOURCE_COMMIT_CORE", "")
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}")