winipedia-utils 0.1.63__py3-none-any.whl → 0.2.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.
Potentially problematic release.
This version of winipedia-utils might be problematic. Click here for more details.
- winipedia_utils/concurrent/concurrent.py +245 -242
- winipedia_utils/concurrent/multiprocessing.py +130 -115
- winipedia_utils/concurrent/multithreading.py +93 -93
- winipedia_utils/consts.py +23 -23
- winipedia_utils/data/__init__.py +1 -1
- winipedia_utils/data/dataframe/__init__.py +1 -0
- winipedia_utils/data/dataframe/cleaning.py +378 -0
- winipedia_utils/data/structures/__init__.py +1 -0
- winipedia_utils/data/structures/dicts.py +16 -0
- winipedia_utils/django/__init__.py +24 -24
- winipedia_utils/django/bulk.py +538 -538
- winipedia_utils/django/command.py +334 -334
- winipedia_utils/django/database.py +289 -289
- winipedia_utils/git/__init__.py +1 -1
- winipedia_utils/git/gitignore/__init__.py +1 -1
- winipedia_utils/git/gitignore/gitignore.py +136 -136
- winipedia_utils/git/pre_commit/__init__.py +1 -1
- winipedia_utils/git/pre_commit/config.py +70 -70
- winipedia_utils/git/pre_commit/hooks.py +109 -109
- winipedia_utils/git/pre_commit/run_hooks.py +49 -49
- winipedia_utils/iterating/__init__.py +1 -1
- winipedia_utils/iterating/iterate.py +29 -29
- winipedia_utils/logging/ansi.py +6 -6
- winipedia_utils/logging/config.py +64 -64
- winipedia_utils/logging/logger.py +26 -26
- winipedia_utils/modules/class_.py +119 -119
- winipedia_utils/modules/function.py +101 -103
- winipedia_utils/modules/module.py +379 -379
- winipedia_utils/modules/package.py +390 -390
- winipedia_utils/oop/mixins/meta.py +333 -331
- winipedia_utils/oop/mixins/mixin.py +37 -37
- winipedia_utils/os/__init__.py +1 -1
- winipedia_utils/os/os.py +63 -63
- winipedia_utils/projects/__init__.py +1 -1
- winipedia_utils/projects/poetry/__init__.py +1 -1
- winipedia_utils/projects/poetry/config.py +91 -91
- winipedia_utils/projects/poetry/poetry.py +31 -31
- winipedia_utils/projects/project.py +48 -48
- winipedia_utils/pyside/__init__.py +1 -1
- winipedia_utils/pyside/core/__init__.py +1 -1
- winipedia_utils/pyside/core/py_qiodevice.py +476 -476
- winipedia_utils/pyside/ui/__init__.py +1 -1
- winipedia_utils/pyside/ui/base/__init__.py +1 -1
- winipedia_utils/pyside/ui/base/base.py +180 -180
- winipedia_utils/pyside/ui/pages/__init__.py +1 -1
- winipedia_utils/pyside/ui/pages/base/__init__.py +1 -1
- winipedia_utils/pyside/ui/pages/base/base.py +92 -92
- winipedia_utils/pyside/ui/pages/browser.py +26 -26
- winipedia_utils/pyside/ui/pages/player.py +85 -85
- winipedia_utils/pyside/ui/widgets/__init__.py +1 -1
- winipedia_utils/pyside/ui/widgets/browser.py +243 -243
- winipedia_utils/pyside/ui/widgets/clickable_widget.py +57 -57
- winipedia_utils/pyside/ui/widgets/media_player.py +430 -430
- winipedia_utils/pyside/ui/widgets/notification.py +78 -78
- winipedia_utils/pyside/ui/windows/__init__.py +1 -1
- winipedia_utils/pyside/ui/windows/base/__init__.py +1 -1
- winipedia_utils/pyside/ui/windows/base/base.py +49 -49
- winipedia_utils/resources/__init__.py +1 -1
- winipedia_utils/resources/svgs/__init__.py +1 -1
- winipedia_utils/resources/svgs/download_arrow.svg +2 -2
- winipedia_utils/resources/svgs/exit_fullscreen_icon.svg +5 -5
- winipedia_utils/resources/svgs/fullscreen_icon.svg +2 -2
- winipedia_utils/resources/svgs/menu_icon.svg +3 -3
- winipedia_utils/resources/svgs/pause_icon.svg +3 -3
- winipedia_utils/resources/svgs/play_icon.svg +16 -16
- winipedia_utils/resources/svgs/plus_icon.svg +23 -23
- winipedia_utils/resources/svgs/svg.py +15 -15
- winipedia_utils/security/__init__.py +1 -1
- winipedia_utils/security/cryptography.py +29 -29
- winipedia_utils/security/keyring.py +70 -70
- winipedia_utils/setup.py +47 -47
- winipedia_utils/testing/assertions.py +23 -23
- winipedia_utils/testing/convention.py +177 -177
- winipedia_utils/testing/create_tests.py +291 -291
- winipedia_utils/testing/fixtures.py +28 -28
- winipedia_utils/testing/tests/base/fixtures/__init__.py +1 -1
- winipedia_utils/testing/tests/base/fixtures/fixture.py +6 -6
- winipedia_utils/testing/tests/base/fixtures/scopes/class_.py +33 -33
- winipedia_utils/testing/tests/base/fixtures/scopes/function.py +7 -7
- winipedia_utils/testing/tests/base/fixtures/scopes/module.py +31 -31
- winipedia_utils/testing/tests/base/fixtures/scopes/package.py +7 -7
- winipedia_utils/testing/tests/base/fixtures/scopes/session.py +312 -312
- winipedia_utils/testing/tests/base/utils/utils.py +82 -82
- winipedia_utils/testing/tests/conftest.py +32 -32
- winipedia_utils/text/string.py +126 -126
- {winipedia_utils-0.1.63.dist-info → winipedia_utils-0.2.0.dist-info}/METADATA +5 -4
- winipedia_utils-0.2.0.dist-info/RECORD +103 -0
- {winipedia_utils-0.1.63.dist-info → winipedia_utils-0.2.0.dist-info}/WHEEL +1 -1
- {winipedia_utils-0.1.63.dist-info → winipedia_utils-0.2.0.dist-info/licenses}/LICENSE +21 -21
- winipedia_utils/data/dataframe.py +0 -7
- winipedia_utils-0.1.63.dist-info/RECORD +0 -100
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
"""Notification module.
|
|
2
|
-
|
|
3
|
-
This module contains functions to show notifications.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from pyqttoast import Toast, ToastIcon, ToastPosition # type: ignore[import-untyped]
|
|
7
|
-
from PySide6.QtWidgets import QApplication
|
|
8
|
-
|
|
9
|
-
from winipedia_utils.text.string import value_to_truncated_string
|
|
10
|
-
|
|
11
|
-
Toast.setPosition(ToastPosition.TOP_MIDDLE)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class Notification(Toast): # type: ignore[misc]
|
|
15
|
-
"""Notification class."""
|
|
16
|
-
|
|
17
|
-
def __init__(
|
|
18
|
-
self,
|
|
19
|
-
title: str,
|
|
20
|
-
text: str,
|
|
21
|
-
icon: ToastIcon = ToastIcon.INFORMATION,
|
|
22
|
-
duration: int = 10000,
|
|
23
|
-
) -> None:
|
|
24
|
-
"""Initialize the notification.
|
|
25
|
-
|
|
26
|
-
The notification is shown in the top middle of the screen.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
title: The title of the notification.
|
|
30
|
-
text: The text of the notification.
|
|
31
|
-
icon: The icon of the notification. Defaults to INFORMATION.
|
|
32
|
-
duration: The duration of the notification in milliseconds.
|
|
33
|
-
Defaults to 10000.
|
|
34
|
-
"""
|
|
35
|
-
super().__init__(QApplication.activeWindow())
|
|
36
|
-
self.setDuration(duration)
|
|
37
|
-
self.setIcon(icon)
|
|
38
|
-
self.set_title(title)
|
|
39
|
-
self.set_text(text)
|
|
40
|
-
|
|
41
|
-
def set_title(self, title: str) -> None:
|
|
42
|
-
"""Set the title of the notification.
|
|
43
|
-
|
|
44
|
-
Truncates the title to fit within half the window width before setting it.
|
|
45
|
-
|
|
46
|
-
Args:
|
|
47
|
-
title: The title text to set.
|
|
48
|
-
"""
|
|
49
|
-
title = self.str_to_half_window_width(title)
|
|
50
|
-
self.setTitle(title)
|
|
51
|
-
|
|
52
|
-
def set_text(self, text: str) -> None:
|
|
53
|
-
"""Set the text of the notification.
|
|
54
|
-
|
|
55
|
-
Truncates the text to fit within half the window width before setting it.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
text: The notification text to set.
|
|
59
|
-
"""
|
|
60
|
-
text = self.str_to_half_window_width(text)
|
|
61
|
-
self.setText(text)
|
|
62
|
-
|
|
63
|
-
def str_to_half_window_width(self, string: str) -> str:
|
|
64
|
-
"""Truncate the string to the width of the active window.
|
|
65
|
-
|
|
66
|
-
Calculates half the width of the active window and truncates the string
|
|
67
|
-
to fit within that width. Falls back to 500 pixels if no active window.
|
|
68
|
-
|
|
69
|
-
Args:
|
|
70
|
-
string: The string to truncate.
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
The truncated string that fits within half the window width.
|
|
74
|
-
"""
|
|
75
|
-
main_window = QApplication.activeWindow()
|
|
76
|
-
width = main_window.width() / 2 if main_window is not None else 500
|
|
77
|
-
width = int(width)
|
|
78
|
-
return value_to_truncated_string(string, width)
|
|
1
|
+
"""Notification module.
|
|
2
|
+
|
|
3
|
+
This module contains functions to show notifications.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pyqttoast import Toast, ToastIcon, ToastPosition # type: ignore[import-untyped]
|
|
7
|
+
from PySide6.QtWidgets import QApplication
|
|
8
|
+
|
|
9
|
+
from winipedia_utils.text.string import value_to_truncated_string
|
|
10
|
+
|
|
11
|
+
Toast.setPosition(ToastPosition.TOP_MIDDLE)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Notification(Toast): # type: ignore[misc]
|
|
15
|
+
"""Notification class."""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
title: str,
|
|
20
|
+
text: str,
|
|
21
|
+
icon: ToastIcon = ToastIcon.INFORMATION,
|
|
22
|
+
duration: int = 10000,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Initialize the notification.
|
|
25
|
+
|
|
26
|
+
The notification is shown in the top middle of the screen.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
title: The title of the notification.
|
|
30
|
+
text: The text of the notification.
|
|
31
|
+
icon: The icon of the notification. Defaults to INFORMATION.
|
|
32
|
+
duration: The duration of the notification in milliseconds.
|
|
33
|
+
Defaults to 10000.
|
|
34
|
+
"""
|
|
35
|
+
super().__init__(QApplication.activeWindow())
|
|
36
|
+
self.setDuration(duration)
|
|
37
|
+
self.setIcon(icon)
|
|
38
|
+
self.set_title(title)
|
|
39
|
+
self.set_text(text)
|
|
40
|
+
|
|
41
|
+
def set_title(self, title: str) -> None:
|
|
42
|
+
"""Set the title of the notification.
|
|
43
|
+
|
|
44
|
+
Truncates the title to fit within half the window width before setting it.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
title: The title text to set.
|
|
48
|
+
"""
|
|
49
|
+
title = self.str_to_half_window_width(title)
|
|
50
|
+
self.setTitle(title)
|
|
51
|
+
|
|
52
|
+
def set_text(self, text: str) -> None:
|
|
53
|
+
"""Set the text of the notification.
|
|
54
|
+
|
|
55
|
+
Truncates the text to fit within half the window width before setting it.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
text: The notification text to set.
|
|
59
|
+
"""
|
|
60
|
+
text = self.str_to_half_window_width(text)
|
|
61
|
+
self.setText(text)
|
|
62
|
+
|
|
63
|
+
def str_to_half_window_width(self, string: str) -> str:
|
|
64
|
+
"""Truncate the string to the width of the active window.
|
|
65
|
+
|
|
66
|
+
Calculates half the width of the active window and truncates the string
|
|
67
|
+
to fit within that width. Falls back to 500 pixels if no active window.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
string: The string to truncate.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
The truncated string that fits within half the window width.
|
|
74
|
+
"""
|
|
75
|
+
main_window = QApplication.activeWindow()
|
|
76
|
+
width = main_window.width() / 2 if main_window is not None else 500
|
|
77
|
+
width = int(width)
|
|
78
|
+
return value_to_truncated_string(string, width)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""__init__ module."""
|
|
1
|
+
"""__init__ module."""
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""__init__ module."""
|
|
1
|
+
"""__init__ module."""
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
"""Base window module.
|
|
2
|
-
|
|
3
|
-
This module contains the base window class for the VideoVault application.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from abc import abstractmethod
|
|
7
|
-
|
|
8
|
-
from PySide6.QtWidgets import QMainWindow, QStackedWidget
|
|
9
|
-
|
|
10
|
-
from winipedia_utils.pyside.ui.base.base import Base as BaseUI
|
|
11
|
-
from winipedia_utils.pyside.ui.pages.base.base import Base as BasePage
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class Base(BaseUI, QMainWindow):
|
|
15
|
-
"""Base window class for the VideoVault application."""
|
|
16
|
-
|
|
17
|
-
@classmethod
|
|
18
|
-
@abstractmethod
|
|
19
|
-
def get_all_page_classes(cls) -> list[type[BasePage]]:
|
|
20
|
-
"""Get all page classes."""
|
|
21
|
-
|
|
22
|
-
@classmethod
|
|
23
|
-
@abstractmethod
|
|
24
|
-
def get_start_page_cls(cls) -> type[BasePage]:
|
|
25
|
-
"""Get the start page class."""
|
|
26
|
-
|
|
27
|
-
def base_setup(self) -> None:
|
|
28
|
-
"""Get the Qt object of the UI."""
|
|
29
|
-
self.setWindowTitle(self.get_display_name())
|
|
30
|
-
|
|
31
|
-
self.stack = QStackedWidget()
|
|
32
|
-
self.setCentralWidget(self.stack)
|
|
33
|
-
|
|
34
|
-
self.make_pages()
|
|
35
|
-
|
|
36
|
-
self.set_start_page()
|
|
37
|
-
|
|
38
|
-
def make_pages(self) -> None:
|
|
39
|
-
"""Get the pages to add to the window."""
|
|
40
|
-
for page_cls in self.get_all_page_classes():
|
|
41
|
-
page_cls(base_window=self)
|
|
42
|
-
|
|
43
|
-
def set_start_page(self) -> None:
|
|
44
|
-
"""Set the start page."""
|
|
45
|
-
self.set_current_page(self.get_start_page_cls())
|
|
46
|
-
|
|
47
|
-
def add_page(self, page: BasePage) -> None:
|
|
48
|
-
"""Add the pages to the window."""
|
|
49
|
-
self.stack.addWidget(page)
|
|
1
|
+
"""Base window module.
|
|
2
|
+
|
|
3
|
+
This module contains the base window class for the VideoVault application.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from abc import abstractmethod
|
|
7
|
+
|
|
8
|
+
from PySide6.QtWidgets import QMainWindow, QStackedWidget
|
|
9
|
+
|
|
10
|
+
from winipedia_utils.pyside.ui.base.base import Base as BaseUI
|
|
11
|
+
from winipedia_utils.pyside.ui.pages.base.base import Base as BasePage
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Base(BaseUI, QMainWindow):
|
|
15
|
+
"""Base window class for the VideoVault application."""
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def get_all_page_classes(cls) -> list[type[BasePage]]:
|
|
20
|
+
"""Get all page classes."""
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def get_start_page_cls(cls) -> type[BasePage]:
|
|
25
|
+
"""Get the start page class."""
|
|
26
|
+
|
|
27
|
+
def base_setup(self) -> None:
|
|
28
|
+
"""Get the Qt object of the UI."""
|
|
29
|
+
self.setWindowTitle(self.get_display_name())
|
|
30
|
+
|
|
31
|
+
self.stack = QStackedWidget()
|
|
32
|
+
self.setCentralWidget(self.stack)
|
|
33
|
+
|
|
34
|
+
self.make_pages()
|
|
35
|
+
|
|
36
|
+
self.set_start_page()
|
|
37
|
+
|
|
38
|
+
def make_pages(self) -> None:
|
|
39
|
+
"""Get the pages to add to the window."""
|
|
40
|
+
for page_cls in self.get_all_page_classes():
|
|
41
|
+
page_cls(base_window=self)
|
|
42
|
+
|
|
43
|
+
def set_start_page(self) -> None:
|
|
44
|
+
"""Set the start page."""
|
|
45
|
+
self.set_current_page(self.get_start_page_cls())
|
|
46
|
+
|
|
47
|
+
def add_page(self, page: BasePage) -> None:
|
|
48
|
+
"""Add the pages to the window."""
|
|
49
|
+
self.stack.addWidget(page)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""__init__ module."""
|
|
1
|
+
"""__init__ module."""
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""__init__ module."""
|
|
1
|
+
"""__init__ module."""
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="24" height="24">
|
|
2
|
-
<path d="M12 3v12m0 0l-5-5m5 5l5-5M5 21h14" stroke="black" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="24" height="24">
|
|
2
|
+
<path d="M12 3v12m0 0l-5-5m5 5l5-5M5 21h14" stroke="black" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
3
|
</svg>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
2
|
-
<svg width="800px" height="800px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
-
<path d="M1 6L6 6L6 1L4.2 1L4.2 4.2L1 4.2L1 6Z" fill="#000000"/>
|
|
4
|
-
<path d="M15 10L10 10L10 15L11.8 15L11.8 11.8L15 11.8L15 10Z" fill="#000000"/>
|
|
5
|
-
<path d="M6 15L6 10L1 10L1 11.8L4.2 11.8L4.2 15L6 15Z" fill="#000000"/>
|
|
6
|
-
<path d="M10 1L10 6L15 6L15 4.2L11.8 4.2L11.8 1L10 1Z" fill="#000000"/>
|
|
2
|
+
<svg width="800px" height="800px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path d="M1 6L6 6L6 1L4.2 1L4.2 4.2L1 4.2L1 6Z" fill="#000000"/>
|
|
4
|
+
<path d="M15 10L10 10L10 15L11.8 15L11.8 11.8L15 11.8L15 10Z" fill="#000000"/>
|
|
5
|
+
<path d="M6 15L6 10L1 10L1 11.8L4.2 11.8L4.2 15L6 15Z" fill="#000000"/>
|
|
6
|
+
<path d="M10 1L10 6L15 6L15 4.2L11.8 4.2L11.8 1L10 1Z" fill="#000000"/>
|
|
7
7
|
</svg>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
2
|
-
<svg width="800px" height="800px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 15H15V10H13.2V13.2H10V15ZM6 15V13.2H2.8V10H1V15H6ZM10 2.8H12.375H13.2V6H15V1H10V2.8ZM6 1V2.8H2.8V6H1V1H6Z" fill="#000000"/>
|
|
2
|
+
<svg width="800px" height="800px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 15H15V10H13.2V13.2H10V15ZM6 15V13.2H2.8V10H1V15H6ZM10 2.8H12.375H13.2V6H15V1H10V2.8ZM6 1V2.8H2.8V6H1V1H6Z" fill="#000000"/>
|
|
4
4
|
</svg>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
2
|
-
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
-
<path d="M4 6H20M4 12H20M4 18H20" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
2
|
+
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path d="M4 6H20M4 12H20M4 18H20" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
4
|
</svg>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
|
2
|
-
<rect x="4" y="4" width="6" height="16"/>
|
|
3
|
-
<rect x="14" y="4" width="6" height="16"/>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
|
2
|
+
<rect x="4" y="4" width="6" height="16"/>
|
|
3
|
+
<rect x="14" y="4" width="6" height="16"/>
|
|
4
4
|
</svg>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
-
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
3
|
-
<svg width="800px" height="800px" viewBox="-3 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
|
4
|
-
|
|
5
|
-
<title>play</title>
|
|
6
|
-
<desc>Created with Sketch Beta.</desc>
|
|
7
|
-
<defs>
|
|
8
|
-
|
|
9
|
-
</defs>
|
|
10
|
-
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
|
11
|
-
<g id="Icon-Set-Filled" sketch:type="MSLayerGroup" transform="translate(-419.000000, -571.000000)" fill="#000000">
|
|
12
|
-
<path d="M440.415,583.554 L421.418,571.311 C420.291,570.704 419,570.767 419,572.946 L419,597.054 C419,599.046 420.385,599.36 421.418,598.689 L440.415,586.446 C441.197,585.647 441.197,584.353 440.415,583.554" id="play" sketch:type="MSShapeGroup">
|
|
13
|
-
|
|
14
|
-
</path>
|
|
15
|
-
</g>
|
|
16
|
-
</g>
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
3
|
+
<svg width="800px" height="800px" viewBox="-3 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
|
4
|
+
|
|
5
|
+
<title>play</title>
|
|
6
|
+
<desc>Created with Sketch Beta.</desc>
|
|
7
|
+
<defs>
|
|
8
|
+
|
|
9
|
+
</defs>
|
|
10
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
|
11
|
+
<g id="Icon-Set-Filled" sketch:type="MSLayerGroup" transform="translate(-419.000000, -571.000000)" fill="#000000">
|
|
12
|
+
<path d="M440.415,583.554 L421.418,571.311 C420.291,570.704 419,570.767 419,572.946 L419,597.054 C419,599.046 420.385,599.36 421.418,598.689 L440.415,586.446 C441.197,585.647 441.197,584.353 440.415,583.554" id="play" sketch:type="MSShapeGroup">
|
|
13
|
+
|
|
14
|
+
</path>
|
|
15
|
+
</g>
|
|
16
|
+
</g>
|
|
17
17
|
</svg>
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
<?xml version="1.0" ?>
|
|
2
|
-
|
|
3
|
-
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
4
|
-
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
5
|
-
|
|
6
|
-
<title/>
|
|
7
|
-
|
|
8
|
-
<g id="Complete">
|
|
9
|
-
|
|
10
|
-
<g data-name="add" id="add-2">
|
|
11
|
-
|
|
12
|
-
<g>
|
|
13
|
-
|
|
14
|
-
<line fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="12" x2="12" y1="19" y2="5"/>
|
|
15
|
-
|
|
16
|
-
<line fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="5" x2="19" y1="12" y2="12"/>
|
|
17
|
-
|
|
18
|
-
</g>
|
|
19
|
-
|
|
20
|
-
</g>
|
|
21
|
-
|
|
22
|
-
</g>
|
|
23
|
-
|
|
1
|
+
<?xml version="1.0" ?>
|
|
2
|
+
|
|
3
|
+
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
4
|
+
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
5
|
+
|
|
6
|
+
<title/>
|
|
7
|
+
|
|
8
|
+
<g id="Complete">
|
|
9
|
+
|
|
10
|
+
<g data-name="add" id="add-2">
|
|
11
|
+
|
|
12
|
+
<g>
|
|
13
|
+
|
|
14
|
+
<line fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="12" x2="12" y1="19" y2="5"/>
|
|
15
|
+
|
|
16
|
+
<line fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="5" x2="19" y1="12" y2="12"/>
|
|
17
|
+
|
|
18
|
+
</g>
|
|
19
|
+
|
|
20
|
+
</g>
|
|
21
|
+
|
|
22
|
+
</g>
|
|
23
|
+
|
|
24
24
|
</svg>
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
"""utils for svgs."""
|
|
2
|
-
|
|
3
|
-
from importlib.resources import as_file, files
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from types import ModuleType
|
|
6
|
-
|
|
7
|
-
from winipedia_utils.resources import svgs
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def get_svg_path(svg_name: str, package: ModuleType | None = None) -> Path:
|
|
11
|
-
"""Get the path to a svg."""
|
|
12
|
-
package = package or svgs
|
|
13
|
-
svg_path = files(package) / f"{svg_name}.svg"
|
|
14
|
-
with as_file(svg_path) as path:
|
|
15
|
-
return path
|
|
1
|
+
"""utils for svgs."""
|
|
2
|
+
|
|
3
|
+
from importlib.resources import as_file, files
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from types import ModuleType
|
|
6
|
+
|
|
7
|
+
from winipedia_utils.resources import svgs
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_svg_path(svg_name: str, package: ModuleType | None = None) -> Path:
|
|
11
|
+
"""Get the path to a svg."""
|
|
12
|
+
package = package or svgs
|
|
13
|
+
svg_path = files(package) / f"{svg_name}.svg"
|
|
14
|
+
with as_file(svg_path) as path:
|
|
15
|
+
return path
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""__init__ module for winipedia_utils.security."""
|
|
1
|
+
"""__init__ module for winipedia_utils.security."""
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
"""Cryptography utilities for secure data handling.
|
|
2
|
-
|
|
3
|
-
This module provides utility functions for working with cryptography,
|
|
4
|
-
including encryption and decryption using Fernet and AESGCM.
|
|
5
|
-
These utilities help with secure data handling.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import os
|
|
9
|
-
|
|
10
|
-
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
11
|
-
|
|
12
|
-
IV_LEN = 12
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def encrypt_with_aes_gcm(
|
|
16
|
-
aes_gcm: AESGCM, data: bytes, aad: bytes | None = None
|
|
17
|
-
) -> bytes:
|
|
18
|
-
"""Encrypt data using AESGCM."""
|
|
19
|
-
iv = os.urandom(IV_LEN)
|
|
20
|
-
encrypted = aes_gcm.encrypt(iv, data, aad)
|
|
21
|
-
return iv + encrypted
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def decrypt_with_aes_gcm(
|
|
25
|
-
aes_gcm: AESGCM, data: bytes, aad: bytes | None = None
|
|
26
|
-
) -> bytes:
|
|
27
|
-
"""Decrypt data using AESGCM."""
|
|
28
|
-
iv, encrypted = data[:IV_LEN], data[IV_LEN:]
|
|
29
|
-
return aes_gcm.decrypt(iv, encrypted, aad)
|
|
1
|
+
"""Cryptography utilities for secure data handling.
|
|
2
|
+
|
|
3
|
+
This module provides utility functions for working with cryptography,
|
|
4
|
+
including encryption and decryption using Fernet and AESGCM.
|
|
5
|
+
These utilities help with secure data handling.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
11
|
+
|
|
12
|
+
IV_LEN = 12
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def encrypt_with_aes_gcm(
|
|
16
|
+
aes_gcm: AESGCM, data: bytes, aad: bytes | None = None
|
|
17
|
+
) -> bytes:
|
|
18
|
+
"""Encrypt data using AESGCM."""
|
|
19
|
+
iv = os.urandom(IV_LEN)
|
|
20
|
+
encrypted = aes_gcm.encrypt(iv, data, aad)
|
|
21
|
+
return iv + encrypted
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def decrypt_with_aes_gcm(
|
|
25
|
+
aes_gcm: AESGCM, data: bytes, aad: bytes | None = None
|
|
26
|
+
) -> bytes:
|
|
27
|
+
"""Decrypt data using AESGCM."""
|
|
28
|
+
iv, encrypted = data[:IV_LEN], data[IV_LEN:]
|
|
29
|
+
return aes_gcm.decrypt(iv, encrypted, aad)
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
"""Keyring utilities for secure storage and retrieval of secrets.
|
|
2
|
-
|
|
3
|
-
This module provides utility functions for working with keyring,
|
|
4
|
-
including getting and creating secrets and fernets.
|
|
5
|
-
These utilities help with secure storage and retrieval of secrets.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from base64 import b64decode, b64encode
|
|
9
|
-
from collections.abc import Callable
|
|
10
|
-
|
|
11
|
-
import keyring
|
|
12
|
-
from cryptography.fernet import Fernet
|
|
13
|
-
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def get_or_create_fernet(service_name: str, username: str) -> tuple[Fernet, bytes]:
|
|
17
|
-
"""Get the app secret using keyring.
|
|
18
|
-
|
|
19
|
-
If it does not exist, create it with a Fernet.
|
|
20
|
-
"""
|
|
21
|
-
return get_or_create_key(
|
|
22
|
-
service_name, username, Fernet, lambda: Fernet.generate_key()
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def get_or_create_aes_gcm(service_name: str, username: str) -> tuple[AESGCM, bytes]:
|
|
27
|
-
"""Get the app secret using keyring.
|
|
28
|
-
|
|
29
|
-
If it does not exist, create it with a AESGCM.
|
|
30
|
-
"""
|
|
31
|
-
return get_or_create_key(
|
|
32
|
-
service_name, username, AESGCM, lambda: AESGCM.generate_key(bit_length=256)
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def get_or_create_key[T](
|
|
37
|
-
service_name: str,
|
|
38
|
-
username: str,
|
|
39
|
-
key_class: Callable[[bytes], T],
|
|
40
|
-
generate_key_func: Callable[..., bytes],
|
|
41
|
-
) -> tuple[T, bytes]:
|
|
42
|
-
"""Get the app secret using keyring.
|
|
43
|
-
|
|
44
|
-
If it does not exist, create it with the generate_func.
|
|
45
|
-
"""
|
|
46
|
-
key = get_key_as_str(service_name, username, key_class)
|
|
47
|
-
if key is None:
|
|
48
|
-
binary_key = generate_key_func()
|
|
49
|
-
key = b64encode(binary_key).decode("ascii")
|
|
50
|
-
modified_service_name = make_service_name(service_name, key_class)
|
|
51
|
-
keyring.set_password(modified_service_name, username, key)
|
|
52
|
-
|
|
53
|
-
binary_key = b64decode(key)
|
|
54
|
-
return key_class(binary_key), binary_key
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def get_key_as_str[T](
|
|
58
|
-
service_name: str, username: str, key_class: Callable[[bytes], T]
|
|
59
|
-
) -> str | None:
|
|
60
|
-
"""Get the app secret using keyring.
|
|
61
|
-
|
|
62
|
-
If it does not exist, create it with the generate_func.
|
|
63
|
-
"""
|
|
64
|
-
service_name = make_service_name(service_name, key_class)
|
|
65
|
-
return keyring.get_password(service_name, username)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def make_service_name[T](service_name: str, key_class: Callable[[bytes], T]) -> str:
|
|
69
|
-
"""Make a service name from a service name and a key class."""
|
|
70
|
-
return f"{service_name}_{key_class.__name__}"
|
|
1
|
+
"""Keyring utilities for secure storage and retrieval of secrets.
|
|
2
|
+
|
|
3
|
+
This module provides utility functions for working with keyring,
|
|
4
|
+
including getting and creating secrets and fernets.
|
|
5
|
+
These utilities help with secure storage and retrieval of secrets.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from base64 import b64decode, b64encode
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
|
|
11
|
+
import keyring
|
|
12
|
+
from cryptography.fernet import Fernet
|
|
13
|
+
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_or_create_fernet(service_name: str, username: str) -> tuple[Fernet, bytes]:
|
|
17
|
+
"""Get the app secret using keyring.
|
|
18
|
+
|
|
19
|
+
If it does not exist, create it with a Fernet.
|
|
20
|
+
"""
|
|
21
|
+
return get_or_create_key(
|
|
22
|
+
service_name, username, Fernet, lambda: Fernet.generate_key()
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_or_create_aes_gcm(service_name: str, username: str) -> tuple[AESGCM, bytes]:
|
|
27
|
+
"""Get the app secret using keyring.
|
|
28
|
+
|
|
29
|
+
If it does not exist, create it with a AESGCM.
|
|
30
|
+
"""
|
|
31
|
+
return get_or_create_key(
|
|
32
|
+
service_name, username, AESGCM, lambda: AESGCM.generate_key(bit_length=256)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_or_create_key[T](
|
|
37
|
+
service_name: str,
|
|
38
|
+
username: str,
|
|
39
|
+
key_class: Callable[[bytes], T],
|
|
40
|
+
generate_key_func: Callable[..., bytes],
|
|
41
|
+
) -> tuple[T, bytes]:
|
|
42
|
+
"""Get the app secret using keyring.
|
|
43
|
+
|
|
44
|
+
If it does not exist, create it with the generate_func.
|
|
45
|
+
"""
|
|
46
|
+
key = get_key_as_str(service_name, username, key_class)
|
|
47
|
+
if key is None:
|
|
48
|
+
binary_key = generate_key_func()
|
|
49
|
+
key = b64encode(binary_key).decode("ascii")
|
|
50
|
+
modified_service_name = make_service_name(service_name, key_class)
|
|
51
|
+
keyring.set_password(modified_service_name, username, key)
|
|
52
|
+
|
|
53
|
+
binary_key = b64decode(key)
|
|
54
|
+
return key_class(binary_key), binary_key
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_key_as_str[T](
|
|
58
|
+
service_name: str, username: str, key_class: Callable[[bytes], T]
|
|
59
|
+
) -> str | None:
|
|
60
|
+
"""Get the app secret using keyring.
|
|
61
|
+
|
|
62
|
+
If it does not exist, create it with the generate_func.
|
|
63
|
+
"""
|
|
64
|
+
service_name = make_service_name(service_name, key_class)
|
|
65
|
+
return keyring.get_password(service_name, username)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def make_service_name[T](service_name: str, key_class: Callable[[bytes], T]) -> str:
|
|
69
|
+
"""Make a service name from a service name and a key class."""
|
|
70
|
+
return f"{service_name}_{key_class.__name__}"
|