modusa 0.4.29__py3-none-any.whl → 0.4.31__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.
- modusa/__init__.py +12 -8
- modusa/tools/__init__.py +11 -3
- modusa/tools/ann_saver.py +30 -0
- modusa/tools/audio_recorder.py +0 -1
- modusa/tools/audio_stft.py +72 -0
- modusa/tools/youtube_downloader.py +1 -4
- {modusa-0.4.29.dist-info → modusa-0.4.31.dist-info}/METADATA +2 -2
- modusa-0.4.31.dist-info/RECORD +22 -0
- pyproject.toml +2 -2
- modusa/config.py +0 -18
- modusa/decorators.py +0 -176
- modusa/devtools/generate_docs_source.py +0 -92
- modusa/devtools/generate_template.py +0 -144
- modusa/devtools/list_authors.py +0 -2
- modusa/devtools/list_plugins.py +0 -60
- modusa/devtools/main.py +0 -45
- modusa/devtools/templates/generator.py +0 -24
- modusa/devtools/templates/io.py +0 -24
- modusa/devtools/templates/model.py +0 -47
- modusa/devtools/templates/plugin.py +0 -41
- modusa/devtools/templates/test.py +0 -10
- modusa/devtools/templates/tool.py +0 -24
- modusa/generators/__init__.py +0 -13
- modusa/generators/audio.py +0 -188
- modusa/generators/audio_waveforms.py +0 -236
- modusa/generators/base.py +0 -29
- modusa/generators/ftds.py +0 -298
- modusa/generators/s1d.py +0 -270
- modusa/generators/s2d.py +0 -300
- modusa/generators/s_ax.py +0 -102
- modusa/generators/t_ax.py +0 -64
- modusa/generators/tds.py +0 -267
- modusa/models/__init__.py +0 -14
- modusa/models/audio.py +0 -90
- modusa/models/base.py +0 -70
- modusa/models/data.py +0 -457
- modusa/models/ftds.py +0 -584
- modusa/models/s1d.py +0 -578
- modusa/models/s2d.py +0 -619
- modusa/models/s_ax.py +0 -448
- modusa/models/t_ax.py +0 -335
- modusa/models/tds.py +0 -465
- modusa/plugins/__init__.py +0 -3
- modusa/plugins/base.py +0 -100
- modusa/tools/_plotter_old.py +0 -629
- modusa/tools/audio_saver.py +0 -30
- modusa/tools/base.py +0 -43
- modusa/tools/math_ops.py +0 -335
- modusa/utils/__init__.py +0 -1
- modusa/utils/config.py +0 -25
- modusa/utils/excp.py +0 -49
- modusa/utils/logger.py +0 -18
- modusa/utils/np_func_cat.py +0 -44
- modusa/utils/plot.py +0 -142
- modusa-0.4.29.dist-info/RECORD +0 -65
- {modusa-0.4.29.dist-info → modusa-0.4.31.dist-info}/WHEEL +0 -0
- {modusa-0.4.29.dist-info → modusa-0.4.31.dist-info}/entry_points.txt +0 -0
- {modusa-0.4.29.dist-info → modusa-0.4.31.dist-info}/licenses/LICENSE.md +0 -0
modusa/generators/t_ax.py
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
|
3
|
-
|
4
|
-
from modusa import excp
|
5
|
-
from modusa.decorators import validate_args_type
|
6
|
-
from modusa.generators.base import ModusaGenerator
|
7
|
-
from modusa.models.t_ax import TAx
|
8
|
-
import numpy as np
|
9
|
-
|
10
|
-
class TAxGen(ModusaGenerator):
|
11
|
-
"""
|
12
|
-
Provides user friendly APIs to generate time
|
13
|
-
axis for signals (instances of `TAx`).
|
14
|
-
"""
|
15
|
-
|
16
|
-
#--------Meta Information----------
|
17
|
-
_name = "TimeAxisGenerator"
|
18
|
-
_description = "APIs to generate time axis for signals."
|
19
|
-
_author_name = "Ankit Anand"
|
20
|
-
_author_email = "ankit0.anand0@gmail.com"
|
21
|
-
_created_at = "2025-07-26"
|
22
|
-
#----------------------------------
|
23
|
-
|
24
|
-
@classmethod
|
25
|
-
def linear(cls, n_points: int, sr: int | float = 1.0, t0: int | float = 0.0, label: str = "Time (sec)") -> TAx:
|
26
|
-
"""
|
27
|
-
Create a linearly spaced time axis.
|
28
|
-
|
29
|
-
.. code-block:: python
|
30
|
-
|
31
|
-
import modusa as ms
|
32
|
-
t = ms.tax.linear(n_points=100, sr=2, start=10, label="Time (sec)")
|
33
|
-
print(t)
|
34
|
-
t.print_info()
|
35
|
-
|
36
|
-
Parameters
|
37
|
-
----------
|
38
|
-
n_points: int
|
39
|
-
- Number of data points for the time axis.
|
40
|
-
sr: int | float
|
41
|
-
- Sampling rate for the time axis.
|
42
|
-
start: int | float
|
43
|
-
- Start value.
|
44
|
-
label: str
|
45
|
-
- Label for the time axis.
|
46
|
-
|
47
|
-
Returns
|
48
|
-
-------
|
49
|
-
TAx
|
50
|
-
An instance of TAx.
|
51
|
-
"""
|
52
|
-
|
53
|
-
assert isinstance(n_points, int)
|
54
|
-
assert isinstance(sr, (int, float))
|
55
|
-
assert isinstance(t0, (int, float))
|
56
|
-
assert isinstance(label, str)
|
57
|
-
|
58
|
-
sr = float(sr)
|
59
|
-
t0 = float(t0)
|
60
|
-
|
61
|
-
time_ax = TAx(n_points=n_points, sr=sr, t0=t0, label=label)
|
62
|
-
|
63
|
-
return time_ax
|
64
|
-
|
modusa/generators/tds.py
DELETED
@@ -1,267 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
|
3
|
-
|
4
|
-
from modusa import excp
|
5
|
-
from modusa.decorators import validate_args_type
|
6
|
-
from .base import ModusaGenerator
|
7
|
-
from modusa.models.tds import TDS
|
8
|
-
from modusa.models.t_ax import TAx
|
9
|
-
from modusa.models.data import Data
|
10
|
-
import numpy as np
|
11
|
-
|
12
|
-
class TDSGen(ModusaGenerator):
|
13
|
-
"""
|
14
|
-
Provides user friendly APIs to generate instances of different
|
15
|
-
`TDS` instances.
|
16
|
-
"""
|
17
|
-
|
18
|
-
#--------Meta Information----------
|
19
|
-
_name = "TDSGenerator"
|
20
|
-
_description = ""
|
21
|
-
_author_name = "Ankit Anand"
|
22
|
-
_author_email = "ankit0.anand0@gmail.com"
|
23
|
-
_created_at = "2025-07-27"
|
24
|
-
#----------------------------------
|
25
|
-
|
26
|
-
@staticmethod
|
27
|
-
def from_array(
|
28
|
-
y: np.ndarray | list | float | int | np.generic,
|
29
|
-
sr: float | int = 1.0,
|
30
|
-
t0: float | int = 0.0,
|
31
|
-
y_label: str = "Y",
|
32
|
-
t_label: str = "Time (sec)",
|
33
|
-
title: str = "Time Domain Signal"
|
34
|
-
) -> TDS:
|
35
|
-
"""
|
36
|
-
Create `TDS` instance from basic data structures.
|
37
|
-
|
38
|
-
.. code-block:: python
|
39
|
-
|
40
|
-
import modusa as ms
|
41
|
-
t = ms.tds.from_array([1, 2, 3])
|
42
|
-
print(t)
|
43
|
-
t.print_info()
|
44
|
-
|
45
|
-
Parameters
|
46
|
-
----------
|
47
|
-
y: np.ndarray | list | float | int | np.generic
|
48
|
-
- Data values.
|
49
|
-
sr: float | int
|
50
|
-
- Sampling rate.
|
51
|
-
t0: float | int
|
52
|
-
- Start timestamp.
|
53
|
-
y_label: str
|
54
|
-
- Y label for the signal.
|
55
|
-
- Default: "Y"
|
56
|
-
t_label: str
|
57
|
-
- T label for the signal.
|
58
|
-
- Default: "Time (sec)"
|
59
|
-
title: str
|
60
|
-
- Title for the signal.
|
61
|
-
- Default: "1D Signal"
|
62
|
-
Returns
|
63
|
-
-------
|
64
|
-
TDS
|
65
|
-
An instance of TDS.
|
66
|
-
"""
|
67
|
-
assert isinstance(y, (np.ndarray, list, float, int, np.generic))
|
68
|
-
assert isinstance(sr, (int, float)) and isinstance(t0, (int, float))
|
69
|
-
assert isinstance(y_label, str) and isinstance(t_label, str) and isinstance(title, str)
|
70
|
-
|
71
|
-
if isinstance(y, (float, int, np.generic)): y = [y] # Convert to list of 1 element
|
72
|
-
y = np.asarray(y)
|
73
|
-
assert y.ndim == 1
|
74
|
-
|
75
|
-
sr = float(sr)
|
76
|
-
t0 = float(t0)
|
77
|
-
|
78
|
-
y = Data(values=y, label=y_label)
|
79
|
-
t = TAx(n_points=y.shape[0], sr=sr, t0=t0, label=t_label) # Creating a signal axis instance
|
80
|
-
|
81
|
-
return TDS(y=y, t=t, title=title)
|
82
|
-
|
83
|
-
@classmethod
|
84
|
-
def zeros(cls, shape, sr=1.0, t0=0.0) -> TDS:
|
85
|
-
"""
|
86
|
-
Create `TDS` instance with all zeros.
|
87
|
-
|
88
|
-
.. code-block:: python
|
89
|
-
|
90
|
-
import modusa as ms
|
91
|
-
y = ms.tds.zeros(10, sr=10)
|
92
|
-
print(y)
|
93
|
-
y.print_info()
|
94
|
-
|
95
|
-
Parameters
|
96
|
-
----------
|
97
|
-
shape: int | tuple[int]
|
98
|
-
- Shape of the signal with zeros.
|
99
|
-
- Must be 1 dimensional
|
100
|
-
- E.g. 10 or (10, )
|
101
|
-
sr: float | int
|
102
|
-
- Sampling rate.
|
103
|
-
t0: float | int
|
104
|
-
- Start timestamp.
|
105
|
-
Returns
|
106
|
-
-------
|
107
|
-
TDS
|
108
|
-
An instance of TDS.
|
109
|
-
"""
|
110
|
-
assert isinstance(shape, (int, tuple))
|
111
|
-
y = np.zeros(shape)
|
112
|
-
|
113
|
-
return cls.from_array(y=y, sr=sr, t0=t0, title="Zeros")
|
114
|
-
|
115
|
-
@classmethod
|
116
|
-
def zeros_like(cls, signal, shape=None) -> TDS:
|
117
|
-
"""
|
118
|
-
Create `TDS` instance similar to `signal`
|
119
|
-
but with all entries being zeros.
|
120
|
-
|
121
|
-
.. code-block:: python
|
122
|
-
|
123
|
-
import modusa as ms
|
124
|
-
signal = ms.tds.from_array([1, 2, 3])
|
125
|
-
y = ms.tds.zeros_like(signal)
|
126
|
-
print(y)
|
127
|
-
x.print_info()
|
128
|
-
|
129
|
-
Parameters
|
130
|
-
----------
|
131
|
-
signal: TDS
|
132
|
-
- Reference signal to create zeros like that.
|
133
|
-
Returns
|
134
|
-
-------
|
135
|
-
TDS
|
136
|
-
An instance of TDS.
|
137
|
-
"""
|
138
|
-
|
139
|
-
assert isinstance(signal, TDS)
|
140
|
-
|
141
|
-
shape = signal.shape if shape is None else shape
|
142
|
-
|
143
|
-
return cls.from_array(y=np.zeros(shape), sr=signal.t.sr, t0=signal.t.t0, y_label=signal.y.label, t_label=signal.t.label, title=signal.title)
|
144
|
-
|
145
|
-
|
146
|
-
@classmethod
|
147
|
-
def ones(cls, shape, sr=1.0, t0=0.0) -> TDS:
|
148
|
-
"""
|
149
|
-
Create `TDS` instance with all ones.
|
150
|
-
|
151
|
-
.. code-block:: python
|
152
|
-
|
153
|
-
import modusa as ms
|
154
|
-
y = ms.tds.ones(10)
|
155
|
-
print(y)
|
156
|
-
y.print_info()
|
157
|
-
|
158
|
-
Parameters
|
159
|
-
----------
|
160
|
-
shape: int | tuple[int]
|
161
|
-
- Shape of the signal with ones.
|
162
|
-
- Must be 1 dimensional
|
163
|
-
- E.g. 10 or (10, )
|
164
|
-
sr: float | int
|
165
|
-
- Sampling rate.
|
166
|
-
t0: float | int
|
167
|
-
- Start timestamp.
|
168
|
-
Returns
|
169
|
-
-------
|
170
|
-
TDS
|
171
|
-
An instance of TDS.
|
172
|
-
"""
|
173
|
-
assert isinstance(shape, (int, tuple))
|
174
|
-
y = np.ones(shape)
|
175
|
-
|
176
|
-
return cls.from_array(y=y, sr=sr, t0=t0, title="Ones")
|
177
|
-
|
178
|
-
@classmethod
|
179
|
-
def ones_like(cls, signal, shape=None) -> TDS:
|
180
|
-
"""
|
181
|
-
Create `TDS` instance similar to `signal`
|
182
|
-
but with all entries being ones.
|
183
|
-
|
184
|
-
.. code-block:: python
|
185
|
-
|
186
|
-
import modusa as ms
|
187
|
-
signal = ms.tds.from_array([1, 2, 3])
|
188
|
-
y = ms.tds.ones_like(signal)
|
189
|
-
print(y)
|
190
|
-
y.print_info()
|
191
|
-
|
192
|
-
Parameters
|
193
|
-
----------
|
194
|
-
signal: TDS
|
195
|
-
- Reference signal to create ones like that.
|
196
|
-
Returns
|
197
|
-
-------
|
198
|
-
TDS
|
199
|
-
An instance of TDS.
|
200
|
-
"""
|
201
|
-
assert isinstance(signal, TDS)
|
202
|
-
|
203
|
-
shape = signal.shape if shape is None else shape
|
204
|
-
|
205
|
-
return cls.from_array(y=np.ones(shape), sr=signal.t.sr, t0=signal.t.t0, y_label=signal.y.label, t_label=signal.t.label, title=signal.title)
|
206
|
-
|
207
|
-
@classmethod
|
208
|
-
def random(cls, shape, sr=1.0, t0=0.0) -> TDS:
|
209
|
-
"""
|
210
|
-
Create `TDS` instance with random entries.
|
211
|
-
|
212
|
-
.. code-block:: python
|
213
|
-
|
214
|
-
import modusa as ms
|
215
|
-
x = ms.tds.random(10)
|
216
|
-
print(x)
|
217
|
-
x.print_info()
|
218
|
-
|
219
|
-
Parameters
|
220
|
-
----------
|
221
|
-
shape: int | tuple[int]
|
222
|
-
- Shape of the signal.
|
223
|
-
- Must be 1 dimensional
|
224
|
-
- E.g. 10 or (10, )
|
225
|
-
sr: float | int
|
226
|
-
- Sampling rate.
|
227
|
-
t0: float | int
|
228
|
-
- Start timestamp.
|
229
|
-
Returns
|
230
|
-
-------
|
231
|
-
TDS
|
232
|
-
An instance of TDS with random values.
|
233
|
-
"""
|
234
|
-
assert isinstance(shape, (int, tuple))
|
235
|
-
y = np.random.random(shape)
|
236
|
-
|
237
|
-
return cls.from_array(y=y, sr=sr, t0=t0, title="Random")
|
238
|
-
|
239
|
-
@classmethod
|
240
|
-
def random_like(cls, signal, shape=None) -> TDS:
|
241
|
-
"""
|
242
|
-
Create `TDS` instance similar to `signal`
|
243
|
-
but with all entries being ones.
|
244
|
-
|
245
|
-
.. code-block:: python
|
246
|
-
|
247
|
-
import modusa as ms
|
248
|
-
signal = ms.tds.from_array([1, 2, 3])
|
249
|
-
y = ms.tds.random_like(signal)
|
250
|
-
print(y)
|
251
|
-
y.print_info()
|
252
|
-
|
253
|
-
Parameters
|
254
|
-
----------
|
255
|
-
signal: TDS
|
256
|
-
- Reference signal to create one with random entries.
|
257
|
-
Returns
|
258
|
-
-------
|
259
|
-
TDS
|
260
|
-
An instance of TDS with random values.
|
261
|
-
"""
|
262
|
-
assert isinstance(signal, TDS)
|
263
|
-
|
264
|
-
shape = signal.shape if shape is None else shape
|
265
|
-
|
266
|
-
return cls.from_array(y=np.random.random(shape), sr=signal.t.sr, t0=signal.t.t0, y_label=signal.y.label, t_label=signal.t.label, title=signal.title)
|
267
|
-
|
modusa/models/__init__.py
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
|
3
|
-
from .base import ModusaSignalData, ModusaSignalAxis, ModusaSignal
|
4
|
-
|
5
|
-
from .data import Data
|
6
|
-
from .s_ax import SAx
|
7
|
-
from .t_ax import TAx
|
8
|
-
|
9
|
-
from .s1d import S1D
|
10
|
-
from .tds import TDS
|
11
|
-
from .audio import Audio
|
12
|
-
|
13
|
-
from .s2d import S2D
|
14
|
-
from .ftds import FTDS
|
modusa/models/audio.py
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
|
3
|
-
from modusa import excp
|
4
|
-
from modusa.decorators import immutable_property, validate_args_type
|
5
|
-
from .tds import TDS
|
6
|
-
from .data import Data
|
7
|
-
from .t_ax import TAx
|
8
|
-
from modusa.tools.math_ops import MathOps
|
9
|
-
from typing import Self, Any
|
10
|
-
import numpy as np
|
11
|
-
import matplotlib.pyplot as plt
|
12
|
-
from pathlib import Path
|
13
|
-
|
14
|
-
class Audio(TDS):
|
15
|
-
"""
|
16
|
-
Represents a 1D audio signal within modusa framework.
|
17
|
-
|
18
|
-
Note
|
19
|
-
----
|
20
|
-
- Use :class:`~modusa.generators.audio.AudioGen` to instantiate this class.
|
21
|
-
- Audio must be mono (1D numpy array).
|
22
|
-
|
23
|
-
Parameters
|
24
|
-
----------
|
25
|
-
y: Data
|
26
|
-
- Data object holding the main audio data.
|
27
|
-
t: TAx
|
28
|
-
- Time axis for the audio.
|
29
|
-
title: str
|
30
|
-
- Title for the signal.
|
31
|
-
- Default: None => ''
|
32
|
-
- e.g. "MySignal"
|
33
|
-
- This is used as the title while plotting.
|
34
|
-
"""
|
35
|
-
|
36
|
-
#--------Meta Information----------
|
37
|
-
_name = "Audio Signal"
|
38
|
-
_nickname = "Audio"
|
39
|
-
_description = ""
|
40
|
-
_author_name = "Ankit Anand"
|
41
|
-
_author_email = "ankit0.anand0@gmail.com"
|
42
|
-
_created_at = "2025-07-04"
|
43
|
-
#----------------------------------
|
44
|
-
|
45
|
-
@validate_args_type()
|
46
|
-
def __init__(self, y, t, title = None):
|
47
|
-
|
48
|
-
super().__init__(y=y, t=t, title=title) # Instantiating `TimeDomainSignal` class
|
49
|
-
|
50
|
-
#----------------------------------
|
51
|
-
# Utility Tools
|
52
|
-
#----------------------------------
|
53
|
-
|
54
|
-
def play(self, regions = None, title = None):
|
55
|
-
"""
|
56
|
-
Play the audio signal inside a Jupyter Notebook.
|
57
|
-
|
58
|
-
.. code-block:: python
|
59
|
-
|
60
|
-
import modusa as ms
|
61
|
-
audio = ms.audio.from_youtube("https://www.youtube.com/watch?v=lIpw9-Y_N0g")
|
62
|
-
audio.play(regions=[(10, 30, "1")])
|
63
|
-
|
64
|
-
Parameters
|
65
|
-
----------
|
66
|
-
regions : list[tuple[float, float, str], ...] | None
|
67
|
-
- [(start_time, end_time, 'tag'), ...] pairs in seconds specifying the regions to play.
|
68
|
-
- e.g. [(1, 10, "Segement 1"), (20, 25, "Segment 2")]
|
69
|
-
- Default to None for which the entire signal is played.
|
70
|
-
title : str | None
|
71
|
-
- Title for the player interface.
|
72
|
-
- Defaults to None, which means that the signal’s internal title is used.
|
73
|
-
|
74
|
-
Returns
|
75
|
-
-------
|
76
|
-
IPython.display.Audio
|
77
|
-
An interactive audio player widget for Jupyter environments.
|
78
|
-
|
79
|
-
See Also
|
80
|
-
--------
|
81
|
-
:class:`~modusa.tools.audio_player.AudioPlayer`
|
82
|
-
"""
|
83
|
-
|
84
|
-
from modusa.tools.audio_player import AudioPlayer
|
85
|
-
|
86
|
-
title = title if title is not None else self.title
|
87
|
-
|
88
|
-
audio_player = AudioPlayer.play(y=self.y.values, sr=self.t.sr, t0=self.t.t0, regions=regions, title=title)
|
89
|
-
|
90
|
-
return audio_player
|
modusa/models/base.py
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
|
3
|
-
|
4
|
-
from abc import ABC, abstractmethod
|
5
|
-
|
6
|
-
class ModusaSignal(ABC):
|
7
|
-
"""
|
8
|
-
Base class for any signal in the modusa framework.
|
9
|
-
|
10
|
-
Note
|
11
|
-
----
|
12
|
-
- Intended to be subclassed.
|
13
|
-
"""
|
14
|
-
|
15
|
-
#--------Meta Information----------
|
16
|
-
_name = "Modusa Signal"
|
17
|
-
_nickname = "MS" # This is to be used in repr/str methods
|
18
|
-
_description = "Base class for any signal types in the Modusa framework."
|
19
|
-
_author_name = "Ankit Anand"
|
20
|
-
_author_email = "ankit0.anand0@gmail.com"
|
21
|
-
_created_at = "2025-06-23"
|
22
|
-
#----------------------------------
|
23
|
-
|
24
|
-
def __init__(self):
|
25
|
-
pass
|
26
|
-
|
27
|
-
|
28
|
-
class ModusaSignalAxis(ABC):
|
29
|
-
"""
|
30
|
-
Base class for any modusa signal axis in the modusa framework.
|
31
|
-
|
32
|
-
Note
|
33
|
-
----
|
34
|
-
- Intended to be subclassed.
|
35
|
-
"""
|
36
|
-
|
37
|
-
#--------Meta Information----------
|
38
|
-
_name = "Modusa Signal Axis"
|
39
|
-
_nickname = "MSAx" # This is to be used in repr/str methods
|
40
|
-
_description = "Base class for any modusa signal axis in the modusa framework."
|
41
|
-
_author_name = "Ankit Anand"
|
42
|
-
_author_email = "ankit0.anand0@gmail.com"
|
43
|
-
_created_at = "2025-07-25"
|
44
|
-
#----------------------------------
|
45
|
-
|
46
|
-
def __init__(self):
|
47
|
-
pass
|
48
|
-
|
49
|
-
class ModusaSignalData(ABC):
|
50
|
-
"""
|
51
|
-
Base class for any modusa signal data in the modusa framework.
|
52
|
-
|
53
|
-
Note
|
54
|
-
----
|
55
|
-
- Intended to be subclassed.
|
56
|
-
"""
|
57
|
-
|
58
|
-
#--------Meta Information----------
|
59
|
-
_name = "Modusa Signal Data"
|
60
|
-
_nickname = "MSData" # This is to be used in repr/str methods
|
61
|
-
_description = "Base class for any modusa signal data in the modusa framework."
|
62
|
-
_author_name = "Ankit Anand"
|
63
|
-
_author_email = "ankit0.anand0@gmail.com"
|
64
|
-
_created_at = "2025-07-27"
|
65
|
-
#----------------------------------
|
66
|
-
|
67
|
-
def __init__(self):
|
68
|
-
pass
|
69
|
-
|
70
|
-
|