wiederverwendbar 0.8.5__py3-none-any.whl → 0.9.0__py3-none-any.whl
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.
- wiederverwendbar/__init__.py +8 -6
- wiederverwendbar/branding/__init__.py +1 -0
- wiederverwendbar/branding/settings.py +85 -0
- wiederverwendbar/console/__init__.py +3 -0
- wiederverwendbar/console/console.py +199 -0
- wiederverwendbar/console/out_files.py +19 -0
- wiederverwendbar/console/settings.py +9 -0
- wiederverwendbar/default.py +4 -1
- wiederverwendbar/fastapi/__init__.py +3 -0
- wiederverwendbar/fastapi/app.py +385 -0
- wiederverwendbar/fastapi/dependencies.py +11 -0
- wiederverwendbar/fastapi/settings.py +39 -0
- wiederverwendbar/functions/is_coroutine_function.py +19 -0
- wiederverwendbar/inspect.py +26 -0
- wiederverwendbar/logger/__init__.py +0 -1
- wiederverwendbar/logger/handlers/rich_console_handler.py +15 -6
- wiederverwendbar/logger/handlers/stream_console_handler.py +3 -16
- wiederverwendbar/logger/log_levels.py +4 -0
- wiederverwendbar/logger/settings.py +15 -20
- wiederverwendbar/pydantic/file_config.py +20 -4
- wiederverwendbar/rich/__init__.py +2 -0
- wiederverwendbar/rich/console.py +215 -0
- wiederverwendbar/rich/settings.py +26 -0
- wiederverwendbar/sqlalchemy/base.py +4 -4
- wiederverwendbar/task_manger/task.py +1 -4
- wiederverwendbar/task_manger/task_manager.py +14 -19
- wiederverwendbar/typer/__init__.py +3 -1
- wiederverwendbar/typer/app.py +172 -0
- wiederverwendbar/typer/settings.py +14 -0
- wiederverwendbar/warnings.py +6 -0
- {wiederverwendbar-0.8.5.dist-info → wiederverwendbar-0.9.0.dist-info}/METADATA +9 -6
- {wiederverwendbar-0.8.5.dist-info → wiederverwendbar-0.9.0.dist-info}/RECORD +34 -49
- wiederverwendbar/examples/__init__.py +0 -0
- wiederverwendbar/examples/before_after_wrap.py +0 -74
- wiederverwendbar/examples/colors.py +0 -16
- wiederverwendbar/examples/extended_thread.py +0 -28
- wiederverwendbar/examples/file_config.py +0 -11
- wiederverwendbar/examples/indexable_model.py +0 -19
- wiederverwendbar/examples/logger.py +0 -31
- wiederverwendbar/examples/logger_context/__init__.py +0 -0
- wiederverwendbar/examples/logger_context/example.py +0 -58
- wiederverwendbar/examples/logger_context/example_module.py +0 -13
- wiederverwendbar/examples/mongoengine/__init__.py +0 -0
- wiederverwendbar/examples/mongoengine/automatic_reference.py +0 -25
- wiederverwendbar/examples/mongoengine/db.py +0 -7
- wiederverwendbar/examples/mongoengine/log_streamer.py +0 -9
- wiederverwendbar/examples/mongoengine/logger.py +0 -25
- wiederverwendbar/examples/post_init.py +0 -29
- wiederverwendbar/examples/route.py +0 -12
- wiederverwendbar/examples/singletons.py +0 -59
- wiederverwendbar/examples/sqlalchemy/__init__.py +0 -0
- wiederverwendbar/examples/sqlalchemy/db.py +0 -89
- wiederverwendbar/examples/starlette_admin/__init__.py +0 -0
- wiederverwendbar/examples/starlette_admin/action_log.py +0 -126
- wiederverwendbar/examples/starlette_admin/action_log_file_download.py +0 -99
- wiederverwendbar/examples/starlette_admin/action_log_form.py +0 -149
- wiederverwendbar/examples/starlette_admin/action_log_thread.py +0 -192
- wiederverwendbar/examples/starlette_admin/automatic_reference_admin.py +0 -47
- wiederverwendbar/examples/starlette_admin/generic_embedded_document_field.py +0 -74
- wiederverwendbar/examples/starlette_admin/multi_path_admin.py +0 -18
- wiederverwendbar/examples/task_manager.py +0 -55
- wiederverwendbar/examples/test_file.py +0 -14
- wiederverwendbar/examples/typer_resolve_defaults.py +0 -15
- wiederverwendbar/examples/uvicorn_server.py +0 -32
- wiederverwendbar/logger/terminal_out_files.py +0 -10
- {wiederverwendbar-0.8.5.dist-info → wiederverwendbar-0.9.0.dist-info}/WHEEL +0 -0
- {wiederverwendbar-0.8.5.dist-info → wiederverwendbar-0.9.0.dist-info}/entry_points.txt +0 -0
@@ -1,89 +0,0 @@
|
|
1
|
-
from pathlib import Path
|
2
|
-
from typing import Optional
|
3
|
-
|
4
|
-
from sqlalchemy import Column, ForeignKey, Integer, Text
|
5
|
-
|
6
|
-
from sqlalchemy.orm import relationship
|
7
|
-
|
8
|
-
from wiederverwendbar.logger import LoggerSingleton, LoggerSettings, LogLevels
|
9
|
-
from wiederverwendbar.sqlalchemy import Base, SqlalchemySettings, SqlalchemyDbSingleton
|
10
|
-
|
11
|
-
LoggerSingleton(name="test", settings=LoggerSettings(log_level=LogLevels.DEBUG), init=True)
|
12
|
-
SqlalchemyDbSingleton(settings=SqlalchemySettings(db_file=Path("test.db")), init=True)
|
13
|
-
|
14
|
-
|
15
|
-
class MyBase(Base, SqlalchemyDbSingleton().Base):
|
16
|
-
__abstract__ = True
|
17
|
-
|
18
|
-
|
19
|
-
class Parent(MyBase):
|
20
|
-
__tablename__ = "parent"
|
21
|
-
__str_columns__: list[str] = ["id", "name"]
|
22
|
-
|
23
|
-
id: int = Column(Integer(), primary_key=True, autoincrement=True, name="parent_id")
|
24
|
-
name: str = Column(Text(50), nullable=False, unique=True)
|
25
|
-
children: list["Child"] = relationship("Child",
|
26
|
-
foreign_keys="Child.parent_id",
|
27
|
-
primaryjoin="Parent.id == Child.parent_id",
|
28
|
-
viewonly=True)
|
29
|
-
|
30
|
-
|
31
|
-
class Child(MyBase):
|
32
|
-
__tablename__ = "child"
|
33
|
-
__str_columns__: list[str] = ["id", "name"]
|
34
|
-
|
35
|
-
id: int = Column(Integer(), primary_key=True, autoincrement=True, name="parent_id")
|
36
|
-
name: str = Column(Text(50), nullable=False, unique=True)
|
37
|
-
parent_id: int = Column(Integer(), ForeignKey("parent.parent_id"), nullable=False, name="child_parent_id")
|
38
|
-
parent: Optional[Parent] = relationship("Parent",
|
39
|
-
foreign_keys="Parent.id",
|
40
|
-
primaryjoin="Child.parent_id == Parent.id")
|
41
|
-
|
42
|
-
|
43
|
-
if __name__ == '__main__':
|
44
|
-
SqlalchemyDbSingleton().create_all()
|
45
|
-
|
46
|
-
parent1 = Parent.get(name="parent1")
|
47
|
-
if parent1 is None:
|
48
|
-
parent1 = Parent(name="parent1")
|
49
|
-
parent1.save()
|
50
|
-
|
51
|
-
child1 = Child.get(name="child1")
|
52
|
-
if child1 is None:
|
53
|
-
child1 = Child(name="child1", parent_id=parent1.id)
|
54
|
-
child1.save()
|
55
|
-
|
56
|
-
child2 = Child.get(name="child2")
|
57
|
-
if child2 is None:
|
58
|
-
child2 = Child(name="child2", parent_id=parent1.id)
|
59
|
-
child2.save()
|
60
|
-
|
61
|
-
child3 = Child.get(name="child3")
|
62
|
-
if child3 is None:
|
63
|
-
child3 = Child(name="child3", parent_id=parent1.id)
|
64
|
-
child3.save()
|
65
|
-
|
66
|
-
parent2 = Parent.get(name="parent2")
|
67
|
-
if parent2 is None:
|
68
|
-
parent2 = Parent(name="parent2")
|
69
|
-
parent2.save()
|
70
|
-
|
71
|
-
child4 = Child.get(name="child4")
|
72
|
-
if child4 is None:
|
73
|
-
child4 = Child(name="child4", parent_id=parent2.id)
|
74
|
-
child4.save()
|
75
|
-
|
76
|
-
child5 = Child.get(name="child5")
|
77
|
-
if child5 is None:
|
78
|
-
child5 = Child(name="child5", parent_id=parent2.id)
|
79
|
-
child5.save()
|
80
|
-
|
81
|
-
child6 = Child.get(name="child6")
|
82
|
-
if child6 is None:
|
83
|
-
child6 = Child(name="child6", parent_id=parent2.id)
|
84
|
-
child6.save()
|
85
|
-
|
86
|
-
Parent.delete_all() # Should raise an IntegrityError --> FOREIGN KEY constraint failed
|
87
|
-
parent2.delete() # Should raise an IntegrityError --> FOREIGN KEY constraint failed
|
88
|
-
|
89
|
-
print()
|
File without changes
|
@@ -1,126 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import asyncio
|
3
|
-
|
4
|
-
import uvicorn
|
5
|
-
from starlette.applications import Starlette
|
6
|
-
from starlette.responses import HTMLResponse
|
7
|
-
from starlette.routing import Route
|
8
|
-
from starlette.requests import Request
|
9
|
-
from starlette_admin.contrib.mongoengine import Admin, ModelView
|
10
|
-
from starlette_admin.actions import action
|
11
|
-
from mongoengine import Document, StringField
|
12
|
-
from kombu import Connection
|
13
|
-
|
14
|
-
from wiederverwendbar.mongoengine import MongoengineDbSingleton
|
15
|
-
from wiederverwendbar.starlette_admin import ActionLogAdmin, ActionLogger
|
16
|
-
|
17
|
-
logger = logging.getLogger(__name__)
|
18
|
-
ch = logging.StreamHandler()
|
19
|
-
ch.setLevel(logging.DEBUG)
|
20
|
-
logger.addHandler(ch)
|
21
|
-
logger.setLevel(logging.DEBUG)
|
22
|
-
|
23
|
-
# connect to database
|
24
|
-
MongoengineDbSingleton(init=True)
|
25
|
-
|
26
|
-
# create kombu connection
|
27
|
-
kombu_connection = Connection(MongoengineDbSingleton().connection_string)
|
28
|
-
|
29
|
-
|
30
|
-
# Create starlette app
|
31
|
-
app = Starlette(
|
32
|
-
routes=[
|
33
|
-
Route(
|
34
|
-
"/",
|
35
|
-
lambda r: HTMLResponse("<a href=/admin/>Click me to get to Admin!</a>"),
|
36
|
-
),
|
37
|
-
],
|
38
|
-
)
|
39
|
-
|
40
|
-
|
41
|
-
class MyAdmin(Admin, ActionLogAdmin):
|
42
|
-
...
|
43
|
-
|
44
|
-
|
45
|
-
# Create admin
|
46
|
-
admin = MyAdmin(title="Test Admin", kombu_connection=kombu_connection)
|
47
|
-
|
48
|
-
|
49
|
-
class Test(Document):
|
50
|
-
meta = {"collection": "test"}
|
51
|
-
|
52
|
-
test_str = StringField()
|
53
|
-
|
54
|
-
|
55
|
-
class TestView(ModelView):
|
56
|
-
def __init__(self):
|
57
|
-
super().__init__(document=Test, icon="fa fa-server", name="Test", label="Test")
|
58
|
-
|
59
|
-
actions = ["delete", "test_action_normal", "test_action_action_log"]
|
60
|
-
|
61
|
-
@action(name="test_action_normal",
|
62
|
-
text="Test Action - Normal")
|
63
|
-
# confirmation="Möchtest du die Test Aktion durchführen?",
|
64
|
-
# icon_class="fa-regular fa-network-wired",
|
65
|
-
# submit_btn_text="Ja, fortsetzen",
|
66
|
-
# submit_btn_class="btn-success")
|
67
|
-
async def test_action_normal(self, request: Request, pk: list[str]) -> str:
|
68
|
-
await asyncio.sleep(2)
|
69
|
-
|
70
|
-
return "Test Aktion erfolgreich."
|
71
|
-
|
72
|
-
@action(name="test_action_action_log",
|
73
|
-
text="Test Action - Action Log")
|
74
|
-
# confirmation="Möchtest du die Test Aktion durchführen?",
|
75
|
-
# icon_class="fa-regular fa-network-wired",
|
76
|
-
# submit_btn_text="Ja, fortsetzen",
|
77
|
-
# submit_btn_class="btn-success")
|
78
|
-
async def test_action_action_log(self, request: Request, pk: list[str]) -> str:
|
79
|
-
with ActionLogger(request, parent=logger) as action_logger:
|
80
|
-
# use context manager to ensure that the logger is finalized
|
81
|
-
with action_logger.sub_logger("sub_action_1", "Sub Action 1", steps=3, ignore_loggers_like=["pymongo"]) as sub_logger:
|
82
|
-
sub_logger.info("Test Aktion startet ...")
|
83
|
-
sub_logger.debug("Debug")
|
84
|
-
sub_logger.info("Test Aktion step 1")
|
85
|
-
await asyncio.sleep(2)
|
86
|
-
sub_logger.next_step()
|
87
|
-
sub_logger.info("Test Aktion step 2")
|
88
|
-
_ = 1 / 0 # raise exception
|
89
|
-
# raise ActionFailed("Test Aktion fehlgeschlagen.")
|
90
|
-
await asyncio.sleep(2)
|
91
|
-
sub_logger.next_step()
|
92
|
-
sub_logger.steps += 100
|
93
|
-
for i in range(1, 100):
|
94
|
-
sub_logger.info(f"Test Aktion step 2 - {i}")
|
95
|
-
sub_logger.next_step()
|
96
|
-
await asyncio.sleep(0.1)
|
97
|
-
sub_logger.info("Test Aktion step 3")
|
98
|
-
await asyncio.sleep(2)
|
99
|
-
|
100
|
-
sub_action_2_logger = action_logger.new_sub_logger("sub_action_2", "Sub Action 2")
|
101
|
-
sub_action_2_logger.start(steps=3)
|
102
|
-
sub_action_3_logger = action_logger.new_sub_logger("sub_action_3", "Sub Action 3")
|
103
|
-
sub_action_3_logger.start()
|
104
|
-
sub_action_3_logger.steps = 3
|
105
|
-
sub_action_2_logger.info("Test Aktion startet ...")
|
106
|
-
sub_action_3_logger.info("Test Aktion startet ...")
|
107
|
-
await asyncio.sleep(2)
|
108
|
-
sub_action_2_logger.next_step()
|
109
|
-
sub_action_3_logger.next_step()
|
110
|
-
await asyncio.sleep(2)
|
111
|
-
sub_action_2_logger.next_step()
|
112
|
-
sub_action_3_logger.next_step()
|
113
|
-
sub_action_2_logger.finalize(success=False, on_error_msg="Test Aktion fehlgeschlagen.")
|
114
|
-
sub_action_3_logger.finalize(success=True, on_success_msg="Test Aktion erfolgreich.")
|
115
|
-
|
116
|
-
return "Test Aktion erfolgreich."
|
117
|
-
|
118
|
-
|
119
|
-
# Add views to admin#
|
120
|
-
admin.add_view(TestView())
|
121
|
-
|
122
|
-
# Mount admin to app
|
123
|
-
admin.mount_to(app)
|
124
|
-
|
125
|
-
if __name__ == "__main__":
|
126
|
-
uvicorn.run(app, host="0.0.0.0", port=8000)
|
@@ -1,99 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import asyncio
|
3
|
-
|
4
|
-
import uvicorn
|
5
|
-
from starlette.applications import Starlette
|
6
|
-
from starlette.responses import HTMLResponse
|
7
|
-
from starlette.routing import Route
|
8
|
-
from starlette.requests import Request
|
9
|
-
from starlette_admin.contrib.mongoengine import Admin, ModelView
|
10
|
-
from starlette_admin.actions import action
|
11
|
-
from mongoengine import Document, StringField
|
12
|
-
from kombu import Connection
|
13
|
-
|
14
|
-
from wiederverwendbar.functions.test_file import test_file
|
15
|
-
from wiederverwendbar.mongoengine import MongoengineDbSingleton
|
16
|
-
from wiederverwendbar.starlette_admin import ActionLogAdmin, ActionLogger, FormCommand, MultiPathAdmin, DownloadCommand
|
17
|
-
|
18
|
-
logger = logging.getLogger(__name__)
|
19
|
-
ch = logging.StreamHandler()
|
20
|
-
ch.setLevel(logging.DEBUG)
|
21
|
-
logger.addHandler(ch)
|
22
|
-
logger.setLevel(logging.DEBUG)
|
23
|
-
|
24
|
-
# connect to database
|
25
|
-
MongoengineDbSingleton(init=True)
|
26
|
-
|
27
|
-
# create kombu connection
|
28
|
-
kombu_connection = Connection(MongoengineDbSingleton().connection_string)
|
29
|
-
|
30
|
-
|
31
|
-
# Create starlette app
|
32
|
-
app = Starlette(
|
33
|
-
routes=[
|
34
|
-
Route(
|
35
|
-
"/",
|
36
|
-
lambda r: HTMLResponse("<a href=/admin/>Click me to get to Admin!</a>"),
|
37
|
-
),
|
38
|
-
],
|
39
|
-
)
|
40
|
-
|
41
|
-
|
42
|
-
class MyAdmin(Admin, ActionLogAdmin, MultiPathAdmin):
|
43
|
-
...
|
44
|
-
|
45
|
-
|
46
|
-
# Create admin
|
47
|
-
admin = MyAdmin(title="Test Admin", kombu_connection=kombu_connection)
|
48
|
-
|
49
|
-
|
50
|
-
class Test(Document):
|
51
|
-
meta = {"collection": "test"}
|
52
|
-
|
53
|
-
test_str = StringField()
|
54
|
-
|
55
|
-
|
56
|
-
class TestView(ModelView):
|
57
|
-
def __init__(self):
|
58
|
-
super().__init__(document=Test, icon="fa fa-server", name="Test", label="Test")
|
59
|
-
|
60
|
-
actions = ["delete", "test_action_normal", "test_action_action_log"]
|
61
|
-
|
62
|
-
@action(name="test_action_normal",
|
63
|
-
text="Test Action - Normal")
|
64
|
-
# confirmation="Möchtest du die Test Aktion durchführen?",
|
65
|
-
# icon_class="fa-regular fa-network-wired",
|
66
|
-
# submit_btn_text="Ja, fortsetzen",
|
67
|
-
# submit_btn_class="btn-success")
|
68
|
-
async def test_action_normal(self, request: Request, pk: list[str]) -> str:
|
69
|
-
await asyncio.sleep(2)
|
70
|
-
|
71
|
-
return "Test Aktion erfolgreich."
|
72
|
-
|
73
|
-
@action(name="test_action_action_log",
|
74
|
-
text="Test Action - Action Log")
|
75
|
-
# confirmation="Möchtest du die Test Aktion durchführen?",
|
76
|
-
# icon_class="fa-regular fa-network-wired",
|
77
|
-
# submit_btn_text="Ja, fortsetzen",
|
78
|
-
# submit_btn_class="btn-success")
|
79
|
-
async def test_action_action_log(self, request: Request, pk: list[str]) -> str:
|
80
|
-
with await ActionLogger(request, parent=logger) as action_logger:
|
81
|
-
# use context manager to ensure that the logger is finalized
|
82
|
-
with action_logger.sub_logger("sub_action_1", "Sub Action 1", steps=3, ignore_loggers_like=["pymongo"]) as sub_logger:
|
83
|
-
sub_logger_yes_no = sub_logger.yes_no("Möchtest du eine Testdatei generieren?")()
|
84
|
-
if not sub_logger_yes_no:
|
85
|
-
sub_logger.finalize(success=False, on_error_msg="Test Aktion abgebrochen.")
|
86
|
-
generated_file = test_file(1, 'MB')
|
87
|
-
DownloadCommand(sub_logger, text="Testdatei", file_path=generated_file)()
|
88
|
-
|
89
|
-
return "Test Aktion erfolgreich."
|
90
|
-
|
91
|
-
|
92
|
-
# Add views to admin#
|
93
|
-
admin.add_view(TestView())
|
94
|
-
|
95
|
-
# Mount admin to app
|
96
|
-
admin.mount_to(app)
|
97
|
-
|
98
|
-
if __name__ == "__main__":
|
99
|
-
uvicorn.run(app, host="0.0.0.0", port=8000)
|
@@ -1,149 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import asyncio
|
3
|
-
|
4
|
-
import uvicorn
|
5
|
-
from starlette.applications import Starlette
|
6
|
-
from starlette.responses import HTMLResponse
|
7
|
-
from starlette.routing import Route
|
8
|
-
from starlette.requests import Request
|
9
|
-
from starlette_admin.contrib.mongoengine import Admin, ModelView
|
10
|
-
from starlette_admin.actions import action
|
11
|
-
from starlette_admin.exceptions import ActionFailed
|
12
|
-
from mongoengine import Document, StringField
|
13
|
-
from kombu import Connection
|
14
|
-
|
15
|
-
from wiederverwendbar.mongoengine import MongoengineDbSingleton
|
16
|
-
from wiederverwendbar.starlette_admin import ActionLogAdmin, ActionLogger, FormCommand
|
17
|
-
|
18
|
-
logger = logging.getLogger(__name__)
|
19
|
-
ch = logging.StreamHandler()
|
20
|
-
ch.setLevel(logging.DEBUG)
|
21
|
-
logger.addHandler(ch)
|
22
|
-
logger.setLevel(logging.DEBUG)
|
23
|
-
|
24
|
-
# connect to database
|
25
|
-
MongoengineDbSingleton(init=True)
|
26
|
-
|
27
|
-
# create kombu connection
|
28
|
-
kombu_connection = Connection(MongoengineDbSingleton().connection_string)
|
29
|
-
|
30
|
-
|
31
|
-
# Create starlette app
|
32
|
-
app = Starlette(
|
33
|
-
routes=[
|
34
|
-
Route(
|
35
|
-
"/",
|
36
|
-
lambda r: HTMLResponse("<a href=/admin/>Click me to get to Admin!</a>"),
|
37
|
-
),
|
38
|
-
],
|
39
|
-
)
|
40
|
-
|
41
|
-
|
42
|
-
class MyAdmin(Admin, ActionLogAdmin):
|
43
|
-
...
|
44
|
-
|
45
|
-
|
46
|
-
# Create admin
|
47
|
-
admin = MyAdmin(title="Test Admin", kombu_connection=kombu_connection)
|
48
|
-
|
49
|
-
|
50
|
-
class Test(Document):
|
51
|
-
meta = {"collection": "test"}
|
52
|
-
|
53
|
-
test_str = StringField()
|
54
|
-
|
55
|
-
|
56
|
-
class TestView(ModelView):
|
57
|
-
def __init__(self):
|
58
|
-
super().__init__(document=Test, icon="fa fa-server", name="Test", label="Test")
|
59
|
-
|
60
|
-
actions = ["delete", "test_action_normal", "test_action_action_log"]
|
61
|
-
|
62
|
-
@action(name="test_action_normal",
|
63
|
-
text="Test Action - Normal")
|
64
|
-
# confirmation="Möchtest du die Test Aktion durchführen?",
|
65
|
-
# icon_class="fa-regular fa-network-wired",
|
66
|
-
# submit_btn_text="Ja, fortsetzen",
|
67
|
-
# submit_btn_class="btn-success")
|
68
|
-
async def test_action_normal(self, request: Request, pk: list[str]) -> str:
|
69
|
-
await asyncio.sleep(2)
|
70
|
-
|
71
|
-
return "Test Aktion erfolgreich."
|
72
|
-
|
73
|
-
@action(name="test_action_action_log",
|
74
|
-
text="Test Action - Action Log")
|
75
|
-
# confirmation="Möchtest du die Test Aktion durchführen?",
|
76
|
-
# icon_class="fa-regular fa-network-wired",
|
77
|
-
# submit_btn_text="Ja, fortsetzen",
|
78
|
-
# submit_btn_class="btn-success")
|
79
|
-
async def test_action_action_log(self, request: Request, pk: list[str]) -> str:
|
80
|
-
with await ActionLogger(request, parent=logger) as action_logger:
|
81
|
-
# send form
|
82
|
-
action_logger_form_data = FormCommand(action_logger,
|
83
|
-
"""<form>
|
84
|
-
<div class="mt-3">
|
85
|
-
<input type="hidden" name="hidden">
|
86
|
-
<div>
|
87
|
-
<label class="form-check">
|
88
|
-
<input type="radio" class="form-check-input" name="action" value="choice1" checked>
|
89
|
-
<span class="form-check-label">Choice 1</span>
|
90
|
-
</label>
|
91
|
-
<label class="form-check">
|
92
|
-
<input type="radio" class="form-check-input" name="action" value="choice2">
|
93
|
-
<span class="form-check-label">Choice 2</span>
|
94
|
-
</label>
|
95
|
-
<label class="form-check">
|
96
|
-
<input type="radio" class="form-check-input" name="action" value="choice3">
|
97
|
-
<span class="form-check-label">Choice 3</span>
|
98
|
-
</label>
|
99
|
-
</div>
|
100
|
-
</div>
|
101
|
-
</form>""",
|
102
|
-
"Weiter",
|
103
|
-
"Abbrechen")()
|
104
|
-
if not action_logger_form_data:
|
105
|
-
raise ActionFailed("Test Aktion abgebrochen.")
|
106
|
-
|
107
|
-
action_logger_yes_no = action_logger.yes_no("Möchtest du fortfahren?")()
|
108
|
-
if not action_logger_yes_no:
|
109
|
-
raise ActionFailed("Test Aktion abgebrochen.")
|
110
|
-
|
111
|
-
# use context manager to ensure that the logger is finalized
|
112
|
-
with action_logger.sub_logger("sub_action_1", "Sub Action 1", steps=3, ignore_loggers_like=["pymongo"]) as sub_logger:
|
113
|
-
sub_logger.info("Test Aktion startet ...")
|
114
|
-
sub_logger.debug("Debug")
|
115
|
-
sub_logger.info("Test Aktion step 1")
|
116
|
-
await asyncio.sleep(2)
|
117
|
-
sub_logger.next_step()
|
118
|
-
sub_logger.info("Test Aktion step 2")
|
119
|
-
|
120
|
-
# send form with positive/negative buttons
|
121
|
-
sub_logger_confirm = sub_logger.confirm("Information")()
|
122
|
-
sub_logger.info(f"Confirm: {sub_logger_confirm}")
|
123
|
-
|
124
|
-
|
125
|
-
sub_logger_yes_no = sub_logger.yes_no("Möchtest du fortfahren?")()
|
126
|
-
if not sub_logger_yes_no:
|
127
|
-
sub_logger.finalize(success=False, on_error_msg="Test Aktion abgebrochen.")
|
128
|
-
|
129
|
-
await asyncio.sleep(2)
|
130
|
-
sub_logger.next_step()
|
131
|
-
sub_logger.steps += 100
|
132
|
-
for i in range(1, 100):
|
133
|
-
sub_logger.info(f"Test Aktion step 2 - {i}")
|
134
|
-
sub_logger.next_step()
|
135
|
-
await asyncio.sleep(0.01)
|
136
|
-
sub_logger.info("Test Aktion step 3")
|
137
|
-
await asyncio.sleep(2)
|
138
|
-
|
139
|
-
return "Test Aktion erfolgreich."
|
140
|
-
|
141
|
-
|
142
|
-
# Add views to admin#
|
143
|
-
admin.add_view(TestView())
|
144
|
-
|
145
|
-
# Mount admin to app
|
146
|
-
admin.mount_to(app)
|
147
|
-
|
148
|
-
if __name__ == "__main__":
|
149
|
-
uvicorn.run(app, host="0.0.0.0", port=8000)
|
@@ -1,192 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import asyncio
|
3
|
-
import threading
|
4
|
-
import time
|
5
|
-
from typing import Optional
|
6
|
-
|
7
|
-
import uvicorn
|
8
|
-
from starlette.applications import Starlette
|
9
|
-
from starlette.responses import HTMLResponse
|
10
|
-
from starlette.routing import Route
|
11
|
-
from starlette.requests import Request
|
12
|
-
from starlette_admin.contrib.mongoengine import Admin, ModelView
|
13
|
-
from starlette_admin.actions import action
|
14
|
-
from mongoengine import Document, StringField
|
15
|
-
from kombu import Connection
|
16
|
-
|
17
|
-
from wiederverwendbar.mongoengine import MongoengineDbSingleton
|
18
|
-
from wiederverwendbar.starlette_admin import ActionLogAdmin, ActionLogger
|
19
|
-
|
20
|
-
logger = logging.getLogger(__name__)
|
21
|
-
ch = logging.StreamHandler()
|
22
|
-
ch.setLevel(logging.DEBUG)
|
23
|
-
logger.addHandler(ch)
|
24
|
-
logger.setLevel(logging.DEBUG)
|
25
|
-
|
26
|
-
# connect to database
|
27
|
-
MongoengineDbSingleton(init=True)
|
28
|
-
|
29
|
-
# create kombu connection
|
30
|
-
kombu_connection = Connection(MongoengineDbSingleton().connection_string)
|
31
|
-
|
32
|
-
# Create starlette app
|
33
|
-
app = Starlette(
|
34
|
-
routes=[
|
35
|
-
Route(
|
36
|
-
"/",
|
37
|
-
lambda r: HTMLResponse("<a href=/admin/>Click me to get to Admin!</a>"),
|
38
|
-
),
|
39
|
-
],
|
40
|
-
)
|
41
|
-
|
42
|
-
|
43
|
-
class MyAdmin(Admin, ActionLogAdmin):
|
44
|
-
...
|
45
|
-
|
46
|
-
|
47
|
-
# Create admin
|
48
|
-
admin = MyAdmin(title="Test Admin", kombu_connection=kombu_connection)
|
49
|
-
|
50
|
-
|
51
|
-
class Test(Document):
|
52
|
-
meta = {"collection": "test"}
|
53
|
-
|
54
|
-
test_str = StringField()
|
55
|
-
|
56
|
-
|
57
|
-
class TestView(ModelView):
|
58
|
-
def __init__(self):
|
59
|
-
super().__init__(document=Test, icon="fa fa-server", name="Test", label="Test")
|
60
|
-
|
61
|
-
actions = ["delete", "test_action_normal", "test_action_action_log"]
|
62
|
-
|
63
|
-
@action(name="test_action_normal",
|
64
|
-
text="Test Action - Normal")
|
65
|
-
# confirmation="Möchtest du die Test Aktion durchführen?",
|
66
|
-
# icon_class="fa-regular fa-network-wired",
|
67
|
-
# submit_btn_text="Ja, fortsetzen",
|
68
|
-
# submit_btn_class="btn-success")
|
69
|
-
async def test_action_normal(self, request: Request, pk: list[str]) -> str:
|
70
|
-
await asyncio.sleep(2)
|
71
|
-
|
72
|
-
return "Test Aktion erfolgreich."
|
73
|
-
|
74
|
-
@action(name="test_action_action_log",
|
75
|
-
text="Test Action - Action Log")
|
76
|
-
# confirmation="Möchtest du die Test Aktion durchführen?",
|
77
|
-
# icon_class="fa-regular fa-network-wired",
|
78
|
-
# submit_btn_text="Ja, fortsetzen",
|
79
|
-
# submit_btn_class="btn-success")
|
80
|
-
async def test_action_action_log(self, request: Request, pk: list[str]) -> str:
|
81
|
-
with ActionLogger(request, parent=logger) as action_logger:
|
82
|
-
action_thread = ActionThread(action_logger=action_logger, payload=payload, name="action_thrad_1", title="Action Thread 1")
|
83
|
-
action_thread.start()
|
84
|
-
await action_thread.wait(timeout=5)
|
85
|
-
|
86
|
-
return "Test Aktion erfolgreich."
|
87
|
-
|
88
|
-
|
89
|
-
class ActionThread(threading.Thread):
|
90
|
-
def __init__(self,
|
91
|
-
action_logger: ActionLogger,
|
92
|
-
name: str,
|
93
|
-
payload: Optional[callable] = None,
|
94
|
-
payload_args: Optional[list] = None,
|
95
|
-
payload_kwargs: Optional[dict] = None,
|
96
|
-
title: Optional[str] = None,
|
97
|
-
log_level: int = logging.NOTSET,
|
98
|
-
parent: Optional[logging.Logger] = None,
|
99
|
-
formatter: Optional[logging.Formatter] = None,
|
100
|
-
steps: Optional[int] = None,
|
101
|
-
on_success_msg: Optional[str] = None,
|
102
|
-
on_error_msg: Optional[str] = "Something went wrong.",
|
103
|
-
show_errors: Optional[bool] = None,
|
104
|
-
halt_on_error: Optional[bool] = None,
|
105
|
-
use_context_logger_level: bool = True,
|
106
|
-
use_context_logger_level_on_not_set: Optional[bool] = None,
|
107
|
-
ignore_loggers_equal: Optional[list[str]] = None,
|
108
|
-
ignore_loggers_like: Optional[list[str]] = None,
|
109
|
-
handle_origin_logger: bool = True,
|
110
|
-
*args,
|
111
|
-
**kwargs):
|
112
|
-
super().__init__(*args, **kwargs)
|
113
|
-
|
114
|
-
self.lock = threading.Lock()
|
115
|
-
self._payload = payload
|
116
|
-
self._payload_args = payload_args if payload_args is not None else []
|
117
|
-
self._payload_kwargs = payload_kwargs if payload_kwargs is not None else {}
|
118
|
-
|
119
|
-
self._action_logger = action_logger
|
120
|
-
self._sub_logger = None
|
121
|
-
|
122
|
-
self._name = name
|
123
|
-
self._title = title
|
124
|
-
self._log_level = log_level
|
125
|
-
self._parent = parent
|
126
|
-
self._formatter = formatter
|
127
|
-
self._steps = steps
|
128
|
-
self._on_success_msg = on_success_msg
|
129
|
-
self._on_error_msg = on_error_msg
|
130
|
-
self._show_errors = show_errors
|
131
|
-
self._halt_on_error = halt_on_error
|
132
|
-
self._use_context_logger_level = use_context_logger_level
|
133
|
-
self._use_context_logger_level_on_not_set = use_context_logger_level_on_not_set
|
134
|
-
self._ignore_loggers_equal = ignore_loggers_equal
|
135
|
-
self._ignore_loggers_like = ignore_loggers_like
|
136
|
-
self._handle_origin_logger = handle_origin_logger
|
137
|
-
|
138
|
-
def run(self):
|
139
|
-
with self._action_logger.sub_logger(name=self._name,
|
140
|
-
title=self._title,
|
141
|
-
log_level=self._log_level,
|
142
|
-
parent=self._parent,
|
143
|
-
formatter=self._formatter,
|
144
|
-
steps=self._steps,
|
145
|
-
on_success_msg=self._on_success_msg,
|
146
|
-
on_error_msg=self._on_error_msg,
|
147
|
-
show_errors=self._show_errors,
|
148
|
-
halt_on_error=self._halt_on_error,
|
149
|
-
use_context_logger_level=self._use_context_logger_level,
|
150
|
-
use_context_logger_level_on_not_set=self._use_context_logger_level_on_not_set,
|
151
|
-
ignore_loggers_equal=self._ignore_loggers_equal,
|
152
|
-
ignore_loggers_like=self._ignore_loggers_like,
|
153
|
-
handle_origin_logger=self._handle_origin_logger) as sub_logger:
|
154
|
-
self._sub_logger = sub_logger
|
155
|
-
try:
|
156
|
-
self.payload()
|
157
|
-
except Exception as e:
|
158
|
-
with self.lock:
|
159
|
-
self._sub_logger.finalize(success=False, on_error_msg=str(e))
|
160
|
-
self._sub_logger.finalize(success=True)
|
161
|
-
|
162
|
-
async def wait(self, timeout: int = -1):
|
163
|
-
start_wait = time.perf_counter()
|
164
|
-
while self.is_alive():
|
165
|
-
if timeout != -1:
|
166
|
-
if time.perf_counter() - start_wait > timeout:
|
167
|
-
with self.lock:
|
168
|
-
self._sub_logger.finalize(success=False, on_error_msg="Thread timed out.")
|
169
|
-
await asyncio.sleep(0.1)
|
170
|
-
|
171
|
-
def payload(self):
|
172
|
-
if self._payload is None:
|
173
|
-
raise NotImplementedError("Payload not implemented.")
|
174
|
-
self._payload(*self._payload_args, **self._payload_kwargs)
|
175
|
-
|
176
|
-
|
177
|
-
def payload():
|
178
|
-
while True:
|
179
|
-
t_logger = logging.getLogger("test_foo")
|
180
|
-
t_logger.debug("foo")
|
181
|
-
print("foo")
|
182
|
-
time.sleep(1)
|
183
|
-
|
184
|
-
|
185
|
-
# Add views to admin#
|
186
|
-
admin.add_view(TestView())
|
187
|
-
|
188
|
-
# Mount admin to app
|
189
|
-
admin.mount_to(app)
|
190
|
-
|
191
|
-
if __name__ == "__main__":
|
192
|
-
uvicorn.run(app, host="0.0.0.0", port=8000)
|