wiederverwendbar 0.8.6__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.
Files changed (62) hide show
  1. wiederverwendbar/__init__.py +8 -6
  2. wiederverwendbar/branding/__init__.py +1 -0
  3. wiederverwendbar/branding/settings.py +85 -0
  4. wiederverwendbar/console/__init__.py +3 -0
  5. wiederverwendbar/console/console.py +199 -0
  6. wiederverwendbar/console/out_files.py +19 -0
  7. wiederverwendbar/console/settings.py +9 -0
  8. wiederverwendbar/default.py +4 -1
  9. wiederverwendbar/fastapi/__init__.py +3 -0
  10. wiederverwendbar/fastapi/app.py +385 -0
  11. wiederverwendbar/fastapi/dependencies.py +11 -0
  12. wiederverwendbar/fastapi/settings.py +39 -0
  13. wiederverwendbar/functions/is_coroutine_function.py +19 -0
  14. wiederverwendbar/inspect.py +26 -0
  15. wiederverwendbar/logger/__init__.py +0 -1
  16. wiederverwendbar/logger/handlers/rich_console_handler.py +15 -6
  17. wiederverwendbar/logger/handlers/stream_console_handler.py +3 -16
  18. wiederverwendbar/logger/log_levels.py +2 -3
  19. wiederverwendbar/logger/settings.py +15 -20
  20. wiederverwendbar/rich/__init__.py +2 -0
  21. wiederverwendbar/rich/console.py +215 -0
  22. wiederverwendbar/rich/settings.py +26 -0
  23. wiederverwendbar/typer/__init__.py +3 -1
  24. wiederverwendbar/typer/app.py +172 -0
  25. wiederverwendbar/typer/settings.py +14 -0
  26. {wiederverwendbar-0.8.6.dist-info → wiederverwendbar-0.9.0.dist-info}/METADATA +9 -6
  27. {wiederverwendbar-0.8.6.dist-info → wiederverwendbar-0.9.0.dist-info}/RECORD +29 -45
  28. wiederverwendbar/examples/__init__.py +0 -0
  29. wiederverwendbar/examples/before_after_wrap.py +0 -74
  30. wiederverwendbar/examples/colors.py +0 -16
  31. wiederverwendbar/examples/extended_thread.py +0 -28
  32. wiederverwendbar/examples/file_config.py +0 -11
  33. wiederverwendbar/examples/indexable_model.py +0 -19
  34. wiederverwendbar/examples/logger.py +0 -31
  35. wiederverwendbar/examples/logger_context/__init__.py +0 -0
  36. wiederverwendbar/examples/logger_context/example.py +0 -58
  37. wiederverwendbar/examples/logger_context/example_module.py +0 -13
  38. wiederverwendbar/examples/mongoengine/__init__.py +0 -0
  39. wiederverwendbar/examples/mongoengine/automatic_reference.py +0 -25
  40. wiederverwendbar/examples/mongoengine/db.py +0 -7
  41. wiederverwendbar/examples/mongoengine/log_streamer.py +0 -9
  42. wiederverwendbar/examples/mongoengine/logger.py +0 -25
  43. wiederverwendbar/examples/post_init.py +0 -29
  44. wiederverwendbar/examples/route.py +0 -12
  45. wiederverwendbar/examples/singletons.py +0 -59
  46. wiederverwendbar/examples/sqlalchemy/__init__.py +0 -0
  47. wiederverwendbar/examples/sqlalchemy/db.py +0 -89
  48. wiederverwendbar/examples/starlette_admin/__init__.py +0 -0
  49. wiederverwendbar/examples/starlette_admin/action_log.py +0 -126
  50. wiederverwendbar/examples/starlette_admin/action_log_file_download.py +0 -99
  51. wiederverwendbar/examples/starlette_admin/action_log_form.py +0 -149
  52. wiederverwendbar/examples/starlette_admin/action_log_thread.py +0 -192
  53. wiederverwendbar/examples/starlette_admin/automatic_reference_admin.py +0 -47
  54. wiederverwendbar/examples/starlette_admin/generic_embedded_document_field.py +0 -74
  55. wiederverwendbar/examples/starlette_admin/multi_path_admin.py +0 -18
  56. wiederverwendbar/examples/task_manager.py +0 -55
  57. wiederverwendbar/examples/test_file.py +0 -14
  58. wiederverwendbar/examples/typer_resolve_defaults.py +0 -15
  59. wiederverwendbar/examples/uvicorn_server.py +0 -32
  60. wiederverwendbar/logger/terminal_out_files.py +0 -10
  61. {wiederverwendbar-0.8.6.dist-info → wiederverwendbar-0.9.0.dist-info}/WHEEL +0 -0
  62. {wiederverwendbar-0.8.6.dist-info → wiederverwendbar-0.9.0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,8 @@
1
- __version__ = "0.8.6"
2
- TITLE = "wiederverwendbar"
3
- VERSION = __version__
4
- AUTHOR = "Julius Koenig"
5
- AUTHOR_EMAIL = "info@bastelquartier.de"
6
- LICENSE = "GPL-3.0"
1
+ __title__ = "wiederverwendbar"
2
+ __description__ = "A collection of scripts, classes and tools they are \\\"wiederverwendbar\\\"."
3
+ __version__ = "0.9.0"
4
+ __author__ = "Julius Koenig"
5
+ __author_email__ = "info@bastelquartier.de"
6
+ __license__ = "GPL-3.0"
7
+ __license_url__ = "https://www.gnu.org/licenses/gpl-3.0.md"
8
+ __terms_of_service__ = "https://bastelquartier.de/terms-of-service"
@@ -0,0 +1 @@
1
+ from wiederverwendbar.branding.settings import (BrandingSettings)
@@ -0,0 +1,85 @@
1
+ import importlib.util
2
+ import sys
3
+ from pathlib import Path
4
+ from typing import Optional, Any, Union
5
+ from pydantic import BaseModel, Field, computed_field
6
+
7
+ from wiederverwendbar.default import Default
8
+
9
+
10
+ class BrandingSettings(BaseModel):
11
+ branding_title: Union[None, Default, str] = Field(default=Default(), title="Branding Title", description="Branding title.")
12
+ branding_description: Union[None, Default, str] = Field(default=Default(), title="Branding Description", description="Branding description.")
13
+ branding_version: Union[None, Default, str] = Field(default=Default(), title="Branding Version", description="Branding version.")
14
+ branding_author: Union[None, Default, str] = Field(default=Default(), title="Branding Author", description="Branding author.")
15
+ branding_author_email: Union[None, Default, str] = Field(default=Default(), title="Branding Author Email", description="Branding author email.")
16
+ branding_license: Union[None, Default, str] = Field(default=Default(), title="Branding License Name", description="Branding license name.")
17
+ branding_license_url: Union[None, Default, str] = Field(default=Default(), title="Branding License URL", description="Branding license URL.")
18
+ branding_terms_of_service: Union[None, Default, str] = Field(default=Default(), title="Branding Terms of Service", description="Branding terms of service.")
19
+
20
+ def model_post_init(self, context: Any, /):
21
+ # get attributes from __main__ module
22
+ main_module = sys.modules["__main__"]
23
+ module_data = self.get_attributes(main_module.__dict__)
24
+ if module_data is None:
25
+ init_file = Path(main_module.__file__).parent / "__init__.py"
26
+ if init_file.is_file():
27
+ init_file_module_spec = importlib.util.spec_from_file_location("__main__.__init__", init_file)
28
+ init_file_module = importlib.util.module_from_spec(init_file_module_spec)
29
+ sys.modules["__main__.__init__"] = init_file_module
30
+ init_file_module_spec.loader.exec_module(init_file_module)
31
+ module_data = self.get_attributes(init_file_module.__dict__)
32
+ if module_data is None:
33
+ module_data = {}
34
+
35
+ for key in ["branding_title",
36
+ "branding_description",
37
+ "branding_version",
38
+ "branding_author",
39
+ "branding_author_email",
40
+ "branding_license",
41
+ "branding_license_url",
42
+ "branding_terms_of_service"]:
43
+ value = module_data.get(key, None)
44
+ if type(getattr(self, key)) is Default:
45
+ setattr(self, key, value)
46
+
47
+ super().model_post_init(context)
48
+
49
+ @classmethod
50
+ def get_attributes(cls, ns: dict[str, Any]) -> Optional[dict[str, str]]:
51
+ found_something = False
52
+ attributes = {}
53
+ for key, module_key in {"branding_title": "__title__",
54
+ "branding_description": "__description__",
55
+ "branding_version": "__version__",
56
+ "branding_author": "__author__",
57
+ "branding_author_email": "__author_email__",
58
+ "branding_license": "__license__",
59
+ "branding_license_url": "__license_url__",
60
+ "branding_terms_of_service": "__terms_of_service__"}.items():
61
+ if module_key in ns:
62
+ found_something = True
63
+ attributes[key] = ns[module_key]
64
+ return attributes if found_something else None
65
+
66
+ @computed_field(title="Branding Version Major", description="Branding version major.")
67
+ @property
68
+ def branding_version_major(self) -> Optional[int]:
69
+ if self.branding_version is None:
70
+ return None
71
+ return int(self.branding_version.split(".")[0])
72
+
73
+ @computed_field(title="Branding Version Minor", description="Branding version minor.")
74
+ @property
75
+ def branding_version_minor(self) -> Optional[int]:
76
+ if self.branding_version is None:
77
+ return None
78
+ return int(self.branding_version.split(".")[1])
79
+
80
+ @computed_field(title="Branding Version Patch", description="Branding version patch.")
81
+ @property
82
+ def branding_version_patch(self) -> Optional[int]:
83
+ if self.branding_version is None:
84
+ return None
85
+ return int(self.branding_version.split(".")[2])
@@ -0,0 +1,3 @@
1
+ from wiederverwendbar.console.console import (Console)
2
+ from wiederverwendbar.console.out_files import (OutFiles)
3
+ from wiederverwendbar.console.settings import (ConsoleSettings)
@@ -0,0 +1,199 @@
1
+ from typing import Optional, Any, Literal, Union
2
+
3
+ from wiederverwendbar.console.out_files import OutFiles
4
+ from wiederverwendbar.console.settings import ConsoleSettings
5
+
6
+
7
+ class Console:
8
+ print_function = print
9
+ print_function_blacklist_kwargs = ["file"]
10
+ console_border_styles = {
11
+ "single_line": ["─", "│", "┌", "┐", "└", "┘", "├", "┤"],
12
+ "double_line": ["═", "║", "╔", "╗", "╚", "╝", "╠", "╣"]
13
+ }
14
+
15
+ def __init__(self,
16
+ *,
17
+ console_file: Optional[OutFiles] = None,
18
+ console_seperator: Optional[str] = None,
19
+ console_end: Optional[str] = None,
20
+ settings: Optional[ConsoleSettings] = None):
21
+ """
22
+ Create a new console.
23
+
24
+ :param console_file: Console file. Default is STDOUT.
25
+ :param console_seperator: Console seperator. Default is a space.
26
+ :param console_end: Console end. Default is a newline.
27
+ :param settings: A settings object to use. If None, defaults to ConsoleSettings().
28
+ """
29
+
30
+ if settings is None:
31
+ settings = ConsoleSettings()
32
+
33
+ if console_file is None:
34
+ console_file = settings.console_file
35
+ self._console_file = console_file
36
+
37
+ if console_seperator is None:
38
+ console_seperator = settings.console_seperator
39
+ self._console_seperator = console_seperator
40
+
41
+ if console_end is None:
42
+ console_end = settings.console_end
43
+ self._console_end = console_end
44
+
45
+ def _print_method_kwargs_filter(self, **kwargs) -> dict[str, Any]:
46
+ for key in kwargs.copy():
47
+ if key not in self.print_function_blacklist_kwargs:
48
+ continue
49
+ del kwargs[key]
50
+ return kwargs
51
+
52
+ def print(self,
53
+ *args: Any,
54
+ sep: Optional[str] = None,
55
+ end: Optional[str] = None,
56
+ **kwargs) -> None:
57
+ """
58
+ Prints the values.
59
+
60
+ :param args: values to be printed.
61
+ :param sep: string inserted between values, default a space.
62
+ :param end: string appended after the last value, default a newline.
63
+ :param kwargs: Additional parameters.
64
+ """
65
+
66
+ if sep is None:
67
+ sep = self._console_seperator
68
+ if end is None:
69
+ end = self._console_end
70
+ self.print_function(*args, **self._print_method_kwargs_filter(sep=sep, end=end, file=OutFiles.STDOUT.get_file(), **kwargs))
71
+
72
+ def _card_kwargs(self, mode: Literal["text", "header", "border", "print"], **kwargs) -> dict[str, Any]:
73
+ return {}
74
+
75
+ def _card_get_text(self, text: str, **kwargs) -> str:
76
+ return text
77
+
78
+ def _card_get_header_text(self, text: str, **kwargs) -> str:
79
+ return text
80
+
81
+ def _card_get_border(self,
82
+ border_style: Literal["single_line", "double_line"],
83
+ border_part: Literal["horizontal", "vertical", "top_left", "top_right", "bottom_left", "bottom_right", "vertical_left", "vertical_right"],
84
+ **kwargs):
85
+ border_style = self.console_border_styles[border_style]
86
+ if border_part == "horizontal":
87
+ return border_style[0]
88
+ elif border_part == "vertical":
89
+ return border_style[1]
90
+ elif border_part == "top_left":
91
+ return border_style[2]
92
+ elif border_part == "top_right":
93
+ return border_style[3]
94
+ elif border_part == "bottom_left":
95
+ return border_style[4]
96
+ elif border_part == "bottom_right":
97
+ return border_style[5]
98
+ elif border_part == "vertical_left":
99
+ return border_style[6]
100
+ elif border_part == "vertical_right":
101
+ return border_style[7]
102
+ else:
103
+ raise ValueError(f"Unknown border part '{border_part}'.")
104
+
105
+ def card(self,
106
+ *sections: Union[str, tuple[str, str]],
107
+ min_width: Optional[int] = None,
108
+ max_width: Optional[int] = None,
109
+ border_style: Literal["single_line", "double_line"] = "single_line",
110
+ topic_offest: int = 1,
111
+ padding_left: int = 0,
112
+ padding_right: int = 0,
113
+ **kwargs) -> None:
114
+ if min_width and max_width and min_width > max_width:
115
+ raise ValueError(f"min_width '{min_width}' is greater than max_width '{max_width}'.")
116
+ if min_width is not None:
117
+ min_width -= 2
118
+ if max_width is not None:
119
+ if max_width < 10:
120
+ raise ValueError(f"max_width '{max_width}' is smaller than 10.")
121
+ max_width -= 2
122
+
123
+ # get real width
124
+ real_width = 0
125
+ if min_width is not None:
126
+ real_width = min_width
127
+ for section in sections:
128
+ section_topic = ""
129
+ if isinstance(section, tuple):
130
+ section_topic = section[0]
131
+ section = section[1]
132
+
133
+ # update real with
134
+ if len(section_topic) + topic_offest > real_width:
135
+ real_width = len(section_topic) + topic_offest
136
+
137
+ for line in section.splitlines():
138
+ line = " " * padding_left + line + " " * padding_right # add padding
139
+ # update real with
140
+ if len(line) > real_width:
141
+ real_width = len(line)
142
+ if max_width is not None:
143
+ if real_width > max_width:
144
+ real_width = max_width
145
+
146
+ # format sections
147
+ section_topics: list[str] = []
148
+ formatted_sections: list[list[str]] = []
149
+ for section in sections:
150
+ section_topic = ""
151
+ if isinstance(section, tuple):
152
+ section_topic = section[0]
153
+ section = section[1]
154
+ if section_topic != "":
155
+ section_topic = " " + section_topic + " "
156
+
157
+ # topic max width
158
+ if len(section_topic) + topic_offest > real_width:
159
+ section_topic = section_topic[:real_width - topic_offest - 3] + "..."
160
+
161
+ section_topics.append(section_topic)
162
+ formatted_lines: list[str] = []
163
+ lines = section.splitlines()
164
+ while len(lines) > 0:
165
+ line = lines.pop(0)
166
+
167
+ # add topic
168
+ line = " " * padding_left + line # add padding
169
+
170
+ # max width
171
+ if len(line) + padding_right > real_width:
172
+ lines.insert(0, line[real_width - padding_right:])
173
+ line = line[:real_width - padding_right] + " " * padding_right
174
+ else:
175
+ line = line.ljust(real_width - padding_right) + " " * padding_right
176
+
177
+ formatted_lines.append(line)
178
+ formatted_sections.append(formatted_lines)
179
+ card = (f"{self._card_get_border(border_style, 'top_left', **kwargs)}"
180
+ f"{self._card_get_border(border_style, 'horizontal', **kwargs) * topic_offest}"
181
+ f"{self._card_get_header_text(section_topics[0], **kwargs)}"
182
+ f"{self._card_get_border(border_style, 'horizontal', **kwargs) * (real_width - len(section_topics.pop(0)) - topic_offest)}"
183
+ f"{self._card_get_border(border_style, 'top_right', **kwargs)}\n")
184
+ while len(formatted_sections) > 0:
185
+ for line in formatted_sections.pop(0):
186
+ card += (f"{self._card_get_border(border_style, 'vertical', **kwargs)}"
187
+ f"{self._card_get_text(line, **kwargs)}"
188
+ f"{self._card_get_border(border_style, 'vertical', **kwargs)}\n")
189
+ if len(formatted_sections) > 0:
190
+ card += (f"{self._card_get_border(border_style, 'vertical_left', **kwargs)}"
191
+ f"{self._card_get_border(border_style, 'horizontal', **kwargs) * topic_offest}"
192
+ f"{self._card_get_header_text(section_topics[0], **kwargs)}"
193
+ f"{self._card_get_border(border_style, 'horizontal', **kwargs) * (real_width - len(section_topics.pop(0)) - topic_offest)}"
194
+ f"{self._card_get_border(border_style, 'vertical_right', **kwargs)}\n")
195
+ else:
196
+ card += (f"{self._card_get_border(border_style, 'bottom_left', **kwargs)}"
197
+ f"{self._card_get_border(border_style, 'horizontal', **kwargs) * real_width}"
198
+ f"{self._card_get_border(border_style, 'bottom_right', **kwargs)}")
199
+ return self.print(card, **kwargs)
@@ -0,0 +1,19 @@
1
+ import sys
2
+ from enum import Enum
3
+ from typing import IO, Any, Union
4
+
5
+
6
+ class OutFiles(str, Enum):
7
+ """
8
+ Output files
9
+ """
10
+
11
+ STDOUT = "stdout"
12
+ STDERR = "stderr"
13
+
14
+ def get_file(self) -> Union[IO[str], Any]:
15
+ if self == OutFiles.STDOUT:
16
+ return sys.stdout
17
+ elif self == OutFiles.STDERR:
18
+ return sys.stderr
19
+ raise ValueError(f"Unknown outfile '{self}'.")
@@ -0,0 +1,9 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ from wiederverwendbar.console.out_files import OutFiles
4
+
5
+
6
+ class ConsoleSettings(BaseModel):
7
+ console_file: OutFiles = Field(default=OutFiles.STDOUT, title="Console File", description="The file to write the console output to.")
8
+ console_seperator: str = Field(default=" ", title="Console Separator", description="The separator to be used between values.")
9
+ console_end: str = Field(default="\n", title="Console End", description="The end to be used after the last value.")
@@ -1,4 +1,7 @@
1
- class Default:
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class Default(BaseModel):
2
5
  """
3
6
  Default value
4
7
  """
@@ -0,0 +1,3 @@
1
+ from wiederverwendbar.fastapi.app import (FastAPI)
2
+ from wiederverwendbar.fastapi.dependencies import (get_app)
3
+ from wiederverwendbar.fastapi.settings import (FastAPISettings)