audex 1.0.7a3__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.
- audex/__init__.py +9 -0
- audex/__main__.py +7 -0
- audex/cli/__init__.py +189 -0
- audex/cli/apis/__init__.py +12 -0
- audex/cli/apis/init/__init__.py +34 -0
- audex/cli/apis/init/gencfg.py +130 -0
- audex/cli/apis/init/setup.py +330 -0
- audex/cli/apis/init/vprgroup.py +125 -0
- audex/cli/apis/serve.py +141 -0
- audex/cli/args.py +356 -0
- audex/cli/exceptions.py +44 -0
- audex/cli/helper/__init__.py +0 -0
- audex/cli/helper/ansi.py +193 -0
- audex/cli/helper/display.py +288 -0
- audex/config/__init__.py +64 -0
- audex/config/core/__init__.py +30 -0
- audex/config/core/app.py +29 -0
- audex/config/core/audio.py +45 -0
- audex/config/core/logging.py +163 -0
- audex/config/core/session.py +11 -0
- audex/config/helper/__init__.py +1 -0
- audex/config/helper/client/__init__.py +1 -0
- audex/config/helper/client/http.py +28 -0
- audex/config/helper/client/websocket.py +21 -0
- audex/config/helper/provider/__init__.py +1 -0
- audex/config/helper/provider/dashscope.py +13 -0
- audex/config/helper/provider/unisound.py +18 -0
- audex/config/helper/provider/xfyun.py +23 -0
- audex/config/infrastructure/__init__.py +31 -0
- audex/config/infrastructure/cache.py +51 -0
- audex/config/infrastructure/database.py +48 -0
- audex/config/infrastructure/recorder.py +32 -0
- audex/config/infrastructure/store.py +19 -0
- audex/config/provider/__init__.py +18 -0
- audex/config/provider/transcription.py +109 -0
- audex/config/provider/vpr.py +99 -0
- audex/container.py +40 -0
- audex/entity/__init__.py +468 -0
- audex/entity/doctor.py +109 -0
- audex/entity/doctor.pyi +51 -0
- audex/entity/fields.py +401 -0
- audex/entity/segment.py +115 -0
- audex/entity/segment.pyi +38 -0
- audex/entity/session.py +133 -0
- audex/entity/session.pyi +47 -0
- audex/entity/utterance.py +142 -0
- audex/entity/utterance.pyi +48 -0
- audex/entity/vp.py +68 -0
- audex/entity/vp.pyi +35 -0
- audex/exceptions.py +157 -0
- audex/filters/__init__.py +692 -0
- audex/filters/generated/__init__.py +21 -0
- audex/filters/generated/doctor.py +987 -0
- audex/filters/generated/segment.py +723 -0
- audex/filters/generated/session.py +978 -0
- audex/filters/generated/utterance.py +939 -0
- audex/filters/generated/vp.py +815 -0
- audex/helper/__init__.py +1 -0
- audex/helper/hash.py +33 -0
- audex/helper/mixin.py +65 -0
- audex/helper/net.py +19 -0
- audex/helper/settings/__init__.py +830 -0
- audex/helper/settings/fields.py +317 -0
- audex/helper/stream.py +153 -0
- audex/injectors/__init__.py +1 -0
- audex/injectors/config.py +12 -0
- audex/injectors/lifespan.py +7 -0
- audex/lib/__init__.py +1 -0
- audex/lib/cache/__init__.py +383 -0
- audex/lib/cache/inmemory.py +513 -0
- audex/lib/database/__init__.py +83 -0
- audex/lib/database/sqlite.py +406 -0
- audex/lib/exporter.py +189 -0
- audex/lib/injectors/__init__.py +1 -0
- audex/lib/injectors/cache.py +25 -0
- audex/lib/injectors/container.py +47 -0
- audex/lib/injectors/exporter.py +26 -0
- audex/lib/injectors/recorder.py +33 -0
- audex/lib/injectors/server.py +17 -0
- audex/lib/injectors/session.py +18 -0
- audex/lib/injectors/sqlite.py +24 -0
- audex/lib/injectors/store.py +13 -0
- audex/lib/injectors/transcription.py +42 -0
- audex/lib/injectors/usb.py +12 -0
- audex/lib/injectors/vpr.py +65 -0
- audex/lib/injectors/wifi.py +7 -0
- audex/lib/recorder.py +844 -0
- audex/lib/repos/__init__.py +149 -0
- audex/lib/repos/container.py +23 -0
- audex/lib/repos/database/__init__.py +1 -0
- audex/lib/repos/database/sqlite.py +672 -0
- audex/lib/repos/decorators.py +74 -0
- audex/lib/repos/doctor.py +286 -0
- audex/lib/repos/segment.py +302 -0
- audex/lib/repos/session.py +285 -0
- audex/lib/repos/tables/__init__.py +70 -0
- audex/lib/repos/tables/doctor.py +137 -0
- audex/lib/repos/tables/segment.py +113 -0
- audex/lib/repos/tables/session.py +140 -0
- audex/lib/repos/tables/utterance.py +131 -0
- audex/lib/repos/tables/vp.py +102 -0
- audex/lib/repos/utterance.py +288 -0
- audex/lib/repos/vp.py +286 -0
- audex/lib/restful.py +251 -0
- audex/lib/server/__init__.py +97 -0
- audex/lib/server/auth.py +98 -0
- audex/lib/server/handlers.py +248 -0
- audex/lib/server/templates/index.html.j2 +226 -0
- audex/lib/server/templates/login.html.j2 +111 -0
- audex/lib/server/templates/static/script.js +68 -0
- audex/lib/server/templates/static/style.css +579 -0
- audex/lib/server/types.py +123 -0
- audex/lib/session.py +503 -0
- audex/lib/store/__init__.py +238 -0
- audex/lib/store/localfile.py +411 -0
- audex/lib/transcription/__init__.py +33 -0
- audex/lib/transcription/dashscope.py +525 -0
- audex/lib/transcription/events.py +62 -0
- audex/lib/usb.py +554 -0
- audex/lib/vpr/__init__.py +38 -0
- audex/lib/vpr/unisound/__init__.py +185 -0
- audex/lib/vpr/unisound/types.py +469 -0
- audex/lib/vpr/xfyun/__init__.py +483 -0
- audex/lib/vpr/xfyun/types.py +679 -0
- audex/lib/websocket/__init__.py +8 -0
- audex/lib/websocket/connection.py +485 -0
- audex/lib/websocket/pool.py +991 -0
- audex/lib/wifi.py +1146 -0
- audex/lifespan.py +75 -0
- audex/service/__init__.py +27 -0
- audex/service/decorators.py +73 -0
- audex/service/doctor/__init__.py +652 -0
- audex/service/doctor/const.py +36 -0
- audex/service/doctor/exceptions.py +96 -0
- audex/service/doctor/types.py +54 -0
- audex/service/export/__init__.py +236 -0
- audex/service/export/const.py +17 -0
- audex/service/export/exceptions.py +34 -0
- audex/service/export/types.py +21 -0
- audex/service/injectors/__init__.py +1 -0
- audex/service/injectors/container.py +53 -0
- audex/service/injectors/doctor.py +34 -0
- audex/service/injectors/export.py +27 -0
- audex/service/injectors/session.py +49 -0
- audex/service/session/__init__.py +754 -0
- audex/service/session/const.py +34 -0
- audex/service/session/exceptions.py +67 -0
- audex/service/session/types.py +91 -0
- audex/types.py +39 -0
- audex/utils.py +287 -0
- audex/valueobj/__init__.py +81 -0
- audex/valueobj/common/__init__.py +1 -0
- audex/valueobj/common/auth.py +84 -0
- audex/valueobj/common/email.py +16 -0
- audex/valueobj/common/ops.py +22 -0
- audex/valueobj/common/phone.py +84 -0
- audex/valueobj/common/version.py +72 -0
- audex/valueobj/session.py +19 -0
- audex/valueobj/utterance.py +15 -0
- audex/view/__init__.py +51 -0
- audex/view/container.py +17 -0
- audex/view/decorators.py +303 -0
- audex/view/pages/__init__.py +1 -0
- audex/view/pages/dashboard/__init__.py +286 -0
- audex/view/pages/dashboard/wifi.py +407 -0
- audex/view/pages/login.py +110 -0
- audex/view/pages/recording.py +348 -0
- audex/view/pages/register.py +202 -0
- audex/view/pages/sessions/__init__.py +196 -0
- audex/view/pages/sessions/details.py +224 -0
- audex/view/pages/sessions/export.py +443 -0
- audex/view/pages/settings.py +374 -0
- audex/view/pages/voiceprint/__init__.py +1 -0
- audex/view/pages/voiceprint/enroll.py +195 -0
- audex/view/pages/voiceprint/update.py +195 -0
- audex/view/static/css/dashboard.css +452 -0
- audex/view/static/css/glass.css +22 -0
- audex/view/static/css/global.css +541 -0
- audex/view/static/css/login.css +386 -0
- audex/view/static/css/recording.css +439 -0
- audex/view/static/css/register.css +293 -0
- audex/view/static/css/sessions/styles.css +501 -0
- audex/view/static/css/settings.css +186 -0
- audex/view/static/css/voiceprint/enroll.css +43 -0
- audex/view/static/css/voiceprint/styles.css +209 -0
- audex/view/static/css/voiceprint/update.css +44 -0
- audex/view/static/images/logo.svg +95 -0
- audex/view/static/js/recording.js +42 -0
- audex-1.0.7a3.dist-info/METADATA +361 -0
- audex-1.0.7a3.dist-info/RECORD +192 -0
- audex-1.0.7a3.dist-info/WHEEL +4 -0
- audex-1.0.7a3.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing as t
|
|
4
|
+
|
|
5
|
+
from pydantic.fields import FieldInfo
|
|
6
|
+
from pydantic.fields import _FieldInfoInputs
|
|
7
|
+
from pydantic_core import PydanticUndefined
|
|
8
|
+
|
|
9
|
+
from audex import __prog__
|
|
10
|
+
from audex.utils import Unset
|
|
11
|
+
|
|
12
|
+
P = t.ParamSpec("P")
|
|
13
|
+
T = t.TypeVar("T")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AudexFieldInfo(FieldInfo): # type: ignore[misc]
|
|
17
|
+
"""Extended FieldInfo with platform-specific default values.
|
|
18
|
+
|
|
19
|
+
This class extends Pydantic's FieldInfo to support platform-specific
|
|
20
|
+
default values and factories, enabling generation of OS-specific
|
|
21
|
+
configuration files.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
linux_default: Default value for Linux systems
|
|
25
|
+
linux_default_factory: Factory function for Linux default values
|
|
26
|
+
windows_default: Default value for Windows systems
|
|
27
|
+
windows_default_factory: Factory function for Windows default values
|
|
28
|
+
system_default: Default value for system configuration
|
|
29
|
+
system_default_factory: Factory function for system default
|
|
30
|
+
system_path_type: Type of system path prefix (log, data, config, etc.)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
__slots__ = (
|
|
34
|
+
*FieldInfo.__slots__,
|
|
35
|
+
"linux_default",
|
|
36
|
+
"linux_default_factory",
|
|
37
|
+
"windows_default",
|
|
38
|
+
"windows_default_factory",
|
|
39
|
+
"system_default",
|
|
40
|
+
"system_default_factory",
|
|
41
|
+
"system_path_type",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
linux_default: t.Any = PydanticUndefined,
|
|
47
|
+
linux_default_factory: t.Callable[[], t.Any] | None = None,
|
|
48
|
+
windows_default: t.Any = PydanticUndefined,
|
|
49
|
+
windows_default_factory: t.Callable[[], t.Any] | None = None,
|
|
50
|
+
system_default: t.Any = PydanticUndefined,
|
|
51
|
+
system_default_factory: t.Callable[[], t.Any] | None = None,
|
|
52
|
+
system_path_type: t.Literal["log", "data", "config", "cache", "runtime"] | None = None,
|
|
53
|
+
**kwargs: t.Unpack[_FieldInfoInputs],
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Initialize AudexFieldInfo with platform-specific defaults.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
linux_default: Default value for Linux systems
|
|
59
|
+
linux_default_factory: Factory function for Linux defaults
|
|
60
|
+
windows_default: Default value for Windows systems
|
|
61
|
+
windows_default_factory: Factory function for Windows defaults
|
|
62
|
+
system_default: Default value for system configuration
|
|
63
|
+
system_default_factory: Factory function for system default
|
|
64
|
+
system_path_type: Type of system path prefix
|
|
65
|
+
**kwargs: Keyword arguments passed to FieldInfo
|
|
66
|
+
"""
|
|
67
|
+
super().__init__(**kwargs)
|
|
68
|
+
|
|
69
|
+
self.linux_default = linux_default
|
|
70
|
+
self.linux_default_factory = linux_default_factory
|
|
71
|
+
self.windows_default = windows_default
|
|
72
|
+
self.windows_default_factory = windows_default_factory
|
|
73
|
+
self.system_default = system_default
|
|
74
|
+
self.system_default_factory = system_default_factory
|
|
75
|
+
self.system_path_type = system_path_type
|
|
76
|
+
|
|
77
|
+
def get_platform_default(self, platform: str) -> t.Any:
|
|
78
|
+
"""Get the default value for the specified platform.
|
|
79
|
+
|
|
80
|
+
Priority:
|
|
81
|
+
1. Platform-specific factory (linux_default_factory/windows_default_factory)
|
|
82
|
+
2. System path prefix + system_default (if system_path_type is set)
|
|
83
|
+
3. Standard default
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
platform: Target platform ("linux" or "windows").
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Platform-specific default value, or PydanticUndefined if not set.
|
|
90
|
+
"""
|
|
91
|
+
# Step 1: Try platform-specific factory/value
|
|
92
|
+
platform_value = self._get_platform_specific_value(platform)
|
|
93
|
+
|
|
94
|
+
# If found, join with system path if needed and return
|
|
95
|
+
if platform_value is not PydanticUndefined and not isinstance(platform_value, Unset):
|
|
96
|
+
return self._join_with_system_path(platform_value, platform)
|
|
97
|
+
if isinstance(platform_value, Unset):
|
|
98
|
+
return platform_value
|
|
99
|
+
|
|
100
|
+
# Step 2: Try system_default with system_path_type
|
|
101
|
+
if self.system_path_type is not None:
|
|
102
|
+
system_value = self._get_system_default()
|
|
103
|
+
if system_value is not PydanticUndefined:
|
|
104
|
+
return self._join_with_system_path(system_value, platform)
|
|
105
|
+
|
|
106
|
+
# Step 3: Fallback to standard default
|
|
107
|
+
if self.default_factory is not None:
|
|
108
|
+
return self.default_factory()
|
|
109
|
+
if self.default is not PydanticUndefined:
|
|
110
|
+
return self.default
|
|
111
|
+
|
|
112
|
+
return PydanticUndefined
|
|
113
|
+
|
|
114
|
+
def _get_platform_specific_value(self, platform: str) -> t.Any:
|
|
115
|
+
"""Get platform-specific value (factory or direct).
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
platform: Target platform.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Platform-specific value or PydanticUndefined.
|
|
122
|
+
"""
|
|
123
|
+
if platform == "linux":
|
|
124
|
+
if self.linux_default_factory is not None:
|
|
125
|
+
return self.linux_default_factory()
|
|
126
|
+
if self.linux_default is not PydanticUndefined:
|
|
127
|
+
return self.linux_default
|
|
128
|
+
elif platform == "windows":
|
|
129
|
+
if self.windows_default_factory is not None:
|
|
130
|
+
return self.windows_default_factory()
|
|
131
|
+
if self.windows_default is not PydanticUndefined:
|
|
132
|
+
return self.windows_default
|
|
133
|
+
|
|
134
|
+
return PydanticUndefined
|
|
135
|
+
|
|
136
|
+
def _get_system_default(self) -> t.Any:
|
|
137
|
+
"""Get system default value (factory or direct).
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
System default value or PydanticUndefined.
|
|
141
|
+
"""
|
|
142
|
+
if self.system_default_factory is not None:
|
|
143
|
+
return self.system_default_factory()
|
|
144
|
+
if self.system_default is not PydanticUndefined:
|
|
145
|
+
return self.system_default
|
|
146
|
+
|
|
147
|
+
return PydanticUndefined
|
|
148
|
+
|
|
149
|
+
def _get_system_path_prefix(self, platform: str) -> str | None:
|
|
150
|
+
"""Get the system path prefix for the specified platform.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
platform: Target platform.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
System path prefix string, or None if system_path_type not set.
|
|
157
|
+
"""
|
|
158
|
+
if self.system_path_type is None:
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
app_name = __prog__
|
|
162
|
+
|
|
163
|
+
# Linux FHS (Filesystem Hierarchy Standard) paths
|
|
164
|
+
if platform == "linux":
|
|
165
|
+
if self.system_path_type == "log":
|
|
166
|
+
return f"${{HOME}}/.local/share/{app_name}/logs"
|
|
167
|
+
if self.system_path_type == "data":
|
|
168
|
+
return f"${{HOME}}/.local/share/{app_name}"
|
|
169
|
+
if self.system_path_type == "config":
|
|
170
|
+
return f"${{HOME}}/.config/{app_name}"
|
|
171
|
+
if self.system_path_type == "cache":
|
|
172
|
+
return f"${{HOME}}/.cache/{app_name}"
|
|
173
|
+
if self.system_path_type == "runtime":
|
|
174
|
+
return f"${{HOME}}/.cache/{app_name}/runtime"
|
|
175
|
+
|
|
176
|
+
# Windows standard paths
|
|
177
|
+
elif platform == "windows":
|
|
178
|
+
if self.system_path_type == "log":
|
|
179
|
+
return f"%PROGRAMDATA%\\{app_name}\\logs"
|
|
180
|
+
if self.system_path_type == "data":
|
|
181
|
+
return f"%PROGRAMDATA%\\{app_name}\\data"
|
|
182
|
+
if self.system_path_type == "config":
|
|
183
|
+
return f"%PROGRAMDATA%\\{app_name}\\config"
|
|
184
|
+
if self.system_path_type == "cache":
|
|
185
|
+
return f"%LOCALAPPDATA%\\{app_name}\\cache"
|
|
186
|
+
if self.system_path_type == "runtime":
|
|
187
|
+
return f"%TEMP%\\{app_name}"
|
|
188
|
+
|
|
189
|
+
return None
|
|
190
|
+
|
|
191
|
+
def _join_with_system_path(self, value: t.Any, platform: str) -> t.Any:
|
|
192
|
+
"""Join value with system path prefix if applicable.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
value: Value to join.
|
|
196
|
+
platform: Target platform.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Joined path or original value.
|
|
200
|
+
"""
|
|
201
|
+
if self.system_path_type is None or value is PydanticUndefined:
|
|
202
|
+
return value
|
|
203
|
+
|
|
204
|
+
prefix = self._get_system_path_prefix(platform)
|
|
205
|
+
if prefix is None:
|
|
206
|
+
return value
|
|
207
|
+
|
|
208
|
+
# Only join string values
|
|
209
|
+
if isinstance(value, str):
|
|
210
|
+
separator = "/" if platform == "linux" else "\\"
|
|
211
|
+
# Avoid double separators
|
|
212
|
+
if not prefix.endswith(("/", "\\")):
|
|
213
|
+
prefix += separator
|
|
214
|
+
return prefix + value
|
|
215
|
+
|
|
216
|
+
return value
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def Field( # noqa
|
|
220
|
+
default: t.Any = PydanticUndefined,
|
|
221
|
+
*,
|
|
222
|
+
default_factory: t.Callable[[], t.Any] | None = None,
|
|
223
|
+
linux_default: t.Any = PydanticUndefined,
|
|
224
|
+
linux_default_factory: t.Callable[[], t.Any] | None = None,
|
|
225
|
+
windows_default: t.Any = PydanticUndefined,
|
|
226
|
+
windows_default_factory: t.Callable[[], t.Any] | None = None,
|
|
227
|
+
system_default: t.Any = PydanticUndefined,
|
|
228
|
+
system_default_factory: t.Callable[[], t.Any] | None = None,
|
|
229
|
+
system_path_type: t.Literal["log", "data", "config", "cache", "runtime"] | None = None,
|
|
230
|
+
alias: str | None = None,
|
|
231
|
+
title: str | None = None,
|
|
232
|
+
description: str | None = None,
|
|
233
|
+
**kwargs: t.Any,
|
|
234
|
+
) -> t.Any:
|
|
235
|
+
"""Create a system-aware configuration field descriptor.
|
|
236
|
+
|
|
237
|
+
This function creates a field descriptor that supports platform-specific
|
|
238
|
+
default values and automatic system path prefix joining.
|
|
239
|
+
|
|
240
|
+
Value resolution priority for system configuration:
|
|
241
|
+
1. Platform-specific factory/value (linux_default_factory/windows_default_factory)
|
|
242
|
+
2. System default + system path prefix (system_default + system_path_type)
|
|
243
|
+
3. Standard default (default/default_factory)
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
default: Default value for all platforms
|
|
247
|
+
default_factory: Factory function for default value
|
|
248
|
+
linux_default: Default value specific to Linux
|
|
249
|
+
linux_default_factory: Factory function for Linux default
|
|
250
|
+
windows_default: Default value specific to Windows
|
|
251
|
+
windows_default_factory: Factory function for Windows default
|
|
252
|
+
system_default: Default value for system configuration
|
|
253
|
+
system_default_factory: Factory function for system default
|
|
254
|
+
system_path_type: Type of system path prefix (log, data, config, cache, runtime)
|
|
255
|
+
alias: Field alias
|
|
256
|
+
title: Field title
|
|
257
|
+
description: Field description
|
|
258
|
+
**kwargs: Additional arguments passed to FieldInfo
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
AudexFieldInfo instance
|
|
262
|
+
|
|
263
|
+
Examples:
|
|
264
|
+
```python
|
|
265
|
+
from audex.helper.settings.fields import Field
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class LoggingConfig(BaseModel):
|
|
269
|
+
# Platform-specific with system path
|
|
270
|
+
# Linux: /var/log/audex/app. log
|
|
271
|
+
# Windows: %PROGRAMDATA%\\audex\\logs\\app.log
|
|
272
|
+
log_file: str = Field(
|
|
273
|
+
linux_default="app.log",
|
|
274
|
+
windows_default="app.log",
|
|
275
|
+
system_path_type="log",
|
|
276
|
+
description="Log file path",
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# System default with path prefix
|
|
280
|
+
# Linux: /var/lib/audex/audex.db
|
|
281
|
+
# Windows: %PROGRAMDATA%\\audex\\data\\audex.db
|
|
282
|
+
db_path: str = Field(
|
|
283
|
+
system_default="audex.db",
|
|
284
|
+
system_path_type="data",
|
|
285
|
+
description="Database file path",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
# Platform-specific without system path
|
|
289
|
+
native: bool = Field(
|
|
290
|
+
linux_default=True,
|
|
291
|
+
windows_default=False,
|
|
292
|
+
description="Use native mode",
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# Full control without system path
|
|
296
|
+
custom_path: str = Field(
|
|
297
|
+
linux_default="/custom/path/file.txt",
|
|
298
|
+
windows_default="C:\\custom\\path\\file.txt",
|
|
299
|
+
description="Custom path",
|
|
300
|
+
)
|
|
301
|
+
```
|
|
302
|
+
"""
|
|
303
|
+
return AudexFieldInfo(
|
|
304
|
+
default=default,
|
|
305
|
+
default_factory=default_factory,
|
|
306
|
+
linux_default=linux_default,
|
|
307
|
+
linux_default_factory=linux_default_factory,
|
|
308
|
+
windows_default=windows_default,
|
|
309
|
+
windows_default_factory=windows_default_factory,
|
|
310
|
+
system_default=system_default,
|
|
311
|
+
system_default_factory=system_default_factory,
|
|
312
|
+
system_path_type=system_path_type,
|
|
313
|
+
alias=alias,
|
|
314
|
+
title=title,
|
|
315
|
+
description=description,
|
|
316
|
+
**kwargs,
|
|
317
|
+
)
|
audex/helper/stream.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing as t
|
|
4
|
+
|
|
5
|
+
_T = t.TypeVar("_T")
|
|
6
|
+
_U = t.TypeVar("_U")
|
|
7
|
+
_V = t.TypeVar("_V")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AsyncStream(t.AsyncIterable[_T], t.Generic[_T]):
|
|
11
|
+
def __init__(self, source: t.AsyncIterable[_V], mapper: t.Callable[[_V], _T] | None = None):
|
|
12
|
+
self._source = source
|
|
13
|
+
self._mapper = mapper
|
|
14
|
+
self._is_consumed = False
|
|
15
|
+
self._items = [] # type: t.List[_T]
|
|
16
|
+
self._error = None # type: t.Optional[Exception]
|
|
17
|
+
self._completed = False
|
|
18
|
+
self._iterator = None # type: t.Optional[t.AsyncIterator[_T]]
|
|
19
|
+
|
|
20
|
+
async def __aiter__(self) -> t.AsyncIterator[_T]: # pylint: disable=invalid-overridden-method
|
|
21
|
+
if self._is_consumed:
|
|
22
|
+
# If the stream has already been consumed, return the cached items
|
|
23
|
+
for item in self._items:
|
|
24
|
+
yield item
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
self._is_consumed = True
|
|
28
|
+
try:
|
|
29
|
+
async for raw_item in self._source:
|
|
30
|
+
item = self._mapper(raw_item) if self._mapper else t.cast(_T, raw_item)
|
|
31
|
+
|
|
32
|
+
self._items.append(item)
|
|
33
|
+
yield item
|
|
34
|
+
|
|
35
|
+
except Exception as e:
|
|
36
|
+
self._error = e
|
|
37
|
+
raise
|
|
38
|
+
finally:
|
|
39
|
+
self._completed = True
|
|
40
|
+
|
|
41
|
+
async def __anext__(self) -> _T:
|
|
42
|
+
if not hasattr(self, "_iterator") or self._iterator is None:
|
|
43
|
+
self._iterator = self.__aiter__()
|
|
44
|
+
return await self._iterator.__anext__()
|
|
45
|
+
|
|
46
|
+
def filter(self, predicate: t.Callable[[_T], bool]) -> AsyncStream[_T]:
|
|
47
|
+
async def filtered_source() -> t.AsyncIterator[_T]:
|
|
48
|
+
async for item in self:
|
|
49
|
+
if predicate(item):
|
|
50
|
+
yield item
|
|
51
|
+
|
|
52
|
+
return AsyncStream(filtered_source())
|
|
53
|
+
|
|
54
|
+
def tap(self, action: t.Callable[[_T], None]) -> AsyncStream[_T]:
|
|
55
|
+
async def tap_source() -> t.AsyncIterator[_T]:
|
|
56
|
+
async for item in self:
|
|
57
|
+
action(item)
|
|
58
|
+
yield item
|
|
59
|
+
|
|
60
|
+
return AsyncStream(tap_source())
|
|
61
|
+
|
|
62
|
+
def map(self, mapper: t.Callable[[_T], _U]) -> AsyncStream[_U]:
|
|
63
|
+
async def mapped_source() -> t.AsyncIterator[_U]:
|
|
64
|
+
async for item in self:
|
|
65
|
+
yield mapper(item)
|
|
66
|
+
|
|
67
|
+
return AsyncStream(mapped_source())
|
|
68
|
+
|
|
69
|
+
def take(self, n: int, /) -> AsyncStream[_T]:
|
|
70
|
+
async def take_source() -> t.AsyncIterator[_T]:
|
|
71
|
+
count = 0
|
|
72
|
+
async for item in self:
|
|
73
|
+
if count >= n:
|
|
74
|
+
break
|
|
75
|
+
yield item
|
|
76
|
+
count += 1
|
|
77
|
+
|
|
78
|
+
return AsyncStream(take_source())
|
|
79
|
+
|
|
80
|
+
def skip(self, n: int, /) -> AsyncStream[_T]:
|
|
81
|
+
async def skip_source() -> t.AsyncIterator[_T]:
|
|
82
|
+
count = 0
|
|
83
|
+
async for item in self:
|
|
84
|
+
if count < n:
|
|
85
|
+
count += 1
|
|
86
|
+
continue
|
|
87
|
+
yield item
|
|
88
|
+
|
|
89
|
+
return AsyncStream(skip_source())
|
|
90
|
+
|
|
91
|
+
def chunk(self, size: int) -> AsyncStream[list[_T]]:
|
|
92
|
+
async def chunk_source() -> t.AsyncIterator[list[_T]]:
|
|
93
|
+
batch = []
|
|
94
|
+
async for item in self:
|
|
95
|
+
batch.append(item)
|
|
96
|
+
if len(batch) >= size:
|
|
97
|
+
yield batch
|
|
98
|
+
batch = []
|
|
99
|
+
if batch:
|
|
100
|
+
yield batch
|
|
101
|
+
|
|
102
|
+
return AsyncStream(chunk_source())
|
|
103
|
+
|
|
104
|
+
def take_while(self, predicate: t.Callable[[_T], bool]) -> AsyncStream[_T]:
|
|
105
|
+
async def take_while_source() -> t.AsyncIterator[_T]:
|
|
106
|
+
async for item in self:
|
|
107
|
+
if not predicate(item):
|
|
108
|
+
break
|
|
109
|
+
yield item
|
|
110
|
+
|
|
111
|
+
return AsyncStream(take_while_source())
|
|
112
|
+
|
|
113
|
+
def enumerate(self, start: int = 0) -> AsyncStream[tuple[int, _T]]:
|
|
114
|
+
async def enumerate_source() -> t.AsyncIterator[tuple[int, _T]]:
|
|
115
|
+
index = start
|
|
116
|
+
async for item in self:
|
|
117
|
+
yield index, item
|
|
118
|
+
index += 1
|
|
119
|
+
|
|
120
|
+
return AsyncStream(enumerate_source())
|
|
121
|
+
|
|
122
|
+
async def foreach(self, action: t.Callable[[_T], t.Awaitable[None]], /) -> None:
|
|
123
|
+
async for item in self:
|
|
124
|
+
await action(item)
|
|
125
|
+
|
|
126
|
+
async def reduce(self, func: t.Callable[[_U, _T], _U], initial: _U) -> _U:
|
|
127
|
+
result = initial
|
|
128
|
+
async for item in self:
|
|
129
|
+
result = func(result, item)
|
|
130
|
+
return result
|
|
131
|
+
|
|
132
|
+
async def all(self, predicate: t.Callable[[_T], bool] | None = None, /) -> bool:
|
|
133
|
+
if predicate is None:
|
|
134
|
+
|
|
135
|
+
def predicate(v: _T) -> bool:
|
|
136
|
+
return bool(v)
|
|
137
|
+
|
|
138
|
+
async for item in self:
|
|
139
|
+
if not predicate(item):
|
|
140
|
+
return False
|
|
141
|
+
return True
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def is_completed(self) -> bool:
|
|
145
|
+
return self._completed
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def error(self) -> Exception | None:
|
|
149
|
+
return self._error
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def items_count(self) -> int:
|
|
153
|
+
return len(self._items)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|
audex/lib/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|