modusa 0.4.29__py3-none-any.whl → 0.4.30__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 (57) hide show
  1. modusa/__init__.py +9 -8
  2. modusa/tools/__init__.py +7 -2
  3. modusa/tools/ann_saver.py +30 -0
  4. modusa/tools/audio_recorder.py +0 -1
  5. modusa/tools/youtube_downloader.py +1 -4
  6. {modusa-0.4.29.dist-info → modusa-0.4.30.dist-info}/METADATA +2 -2
  7. modusa-0.4.30.dist-info/RECORD +21 -0
  8. pyproject.toml +2 -2
  9. modusa/config.py +0 -18
  10. modusa/decorators.py +0 -176
  11. modusa/devtools/generate_docs_source.py +0 -92
  12. modusa/devtools/generate_template.py +0 -144
  13. modusa/devtools/list_authors.py +0 -2
  14. modusa/devtools/list_plugins.py +0 -60
  15. modusa/devtools/main.py +0 -45
  16. modusa/devtools/templates/generator.py +0 -24
  17. modusa/devtools/templates/io.py +0 -24
  18. modusa/devtools/templates/model.py +0 -47
  19. modusa/devtools/templates/plugin.py +0 -41
  20. modusa/devtools/templates/test.py +0 -10
  21. modusa/devtools/templates/tool.py +0 -24
  22. modusa/generators/__init__.py +0 -13
  23. modusa/generators/audio.py +0 -188
  24. modusa/generators/audio_waveforms.py +0 -236
  25. modusa/generators/base.py +0 -29
  26. modusa/generators/ftds.py +0 -298
  27. modusa/generators/s1d.py +0 -270
  28. modusa/generators/s2d.py +0 -300
  29. modusa/generators/s_ax.py +0 -102
  30. modusa/generators/t_ax.py +0 -64
  31. modusa/generators/tds.py +0 -267
  32. modusa/models/__init__.py +0 -14
  33. modusa/models/audio.py +0 -90
  34. modusa/models/base.py +0 -70
  35. modusa/models/data.py +0 -457
  36. modusa/models/ftds.py +0 -584
  37. modusa/models/s1d.py +0 -578
  38. modusa/models/s2d.py +0 -619
  39. modusa/models/s_ax.py +0 -448
  40. modusa/models/t_ax.py +0 -335
  41. modusa/models/tds.py +0 -465
  42. modusa/plugins/__init__.py +0 -3
  43. modusa/plugins/base.py +0 -100
  44. modusa/tools/_plotter_old.py +0 -629
  45. modusa/tools/audio_saver.py +0 -30
  46. modusa/tools/base.py +0 -43
  47. modusa/tools/math_ops.py +0 -335
  48. modusa/utils/__init__.py +0 -1
  49. modusa/utils/config.py +0 -25
  50. modusa/utils/excp.py +0 -49
  51. modusa/utils/logger.py +0 -18
  52. modusa/utils/np_func_cat.py +0 -44
  53. modusa/utils/plot.py +0 -142
  54. modusa-0.4.29.dist-info/RECORD +0 -65
  55. {modusa-0.4.29.dist-info → modusa-0.4.30.dist-info}/WHEEL +0 -0
  56. {modusa-0.4.29.dist-info → modusa-0.4.30.dist-info}/entry_points.txt +0 -0
  57. {modusa-0.4.29.dist-info → modusa-0.4.30.dist-info}/licenses/LICENSE.md +0 -0
modusa/devtools/main.py DELETED
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from .generate_template import TemplateGenerator
5
- from .generate_docs_source import generate_docs_source
6
- from .list_plugins import list_plugins
7
- from . import list_authors
8
-
9
- import argparse
10
- import sys
11
-
12
- def main():
13
- try:
14
- parser = argparse.ArgumentParser(
15
- prog="modusa-dev",
16
- description="Modusa CLI Tools"
17
- )
18
- subparsers = parser.add_subparsers(dest="group", required=True)
19
-
20
- # --- CREATE group ---
21
- create_parser = subparsers.add_parser("create", help="Create new Modusa components")
22
- create_subparsers = create_parser.add_subparsers(dest="what", required=True)
23
-
24
- create_subparsers.add_parser("tool", help="Create a new tool class").set_defaults(func=lambda:TemplateGenerator.create_template("tool"))
25
- create_subparsers.add_parser("plugin", help="Create a new plugin class").set_defaults(func=lambda:TemplateGenerator.create_template("plugin"))
26
- create_subparsers.add_parser("model", help="Create a new model class").set_defaults(func=lambda:TemplateGenerator.create_template("model"))
27
- create_subparsers.add_parser("generator", help="Create a new signal generator class").set_defaults(func=lambda:TemplateGenerator.create_template("generator"))
28
- create_subparsers.add_parser("io", help="Create a new IO class").set_defaults(func=lambda:TemplateGenerator.create_template("io"))
29
- create_subparsers.add_parser("docs", help="Generate the docs").set_defaults(func=lambda:generate_docs_source())
30
-
31
- # --- LIST group ---
32
- list_parser = subparsers.add_parser("list", help="List information about Modusa components")
33
- list_subparsers = list_parser.add_subparsers(dest="what", required=True)
34
-
35
- list_subparsers.add_parser("plugins", help="List available plugins").set_defaults(func=list_plugins)
36
- list_subparsers.add_parser("authors", help="List plugin authors").set_defaults(func=list_authors)
37
-
38
- # --- Parse and execute ---
39
- args = parser.parse_args()
40
- args.func()
41
-
42
- except KeyboardInterrupt:
43
- print("\n❌ Aborted by user.")
44
- sys.exit(1)
45
-
@@ -1,24 +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
-
8
-
9
- class {class_name}(ModusaGenerator):
10
- """
11
-
12
- """
13
-
14
- #--------Meta Information----------
15
- _name = ""
16
- _description = ""
17
- _author_name = "{author_name}"
18
- _author_email = "{author_email}"
19
- _created_at = "{date_created}"
20
- #----------------------------------
21
-
22
- def __init__(self):
23
- super().__init__()
24
-
@@ -1,24 +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.io.base import ModusaIO
7
-
8
-
9
- class {class_name}(ModusaIO):
10
- """
11
-
12
- """
13
-
14
- #--------Meta Information----------
15
- _name = ""
16
- _description = ""
17
- _author_name = "{author_name}"
18
- _author_email = "{author_email}"
19
- _created_at = "{date_created}"
20
- #----------------------------------
21
-
22
-
23
-
24
-
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from modusa import excp
5
- from modusa.decorators import immutable_property, validate_args_type
6
- from modusa.signals.base import ?
7
- from typing import Self, Any
8
- import numpy as np
9
-
10
- class {class_name}():
11
- """
12
-
13
- """
14
-
15
- #--------Meta Information----------
16
- _name = ""
17
- _nickname = "" # This is to be used in repr/str methods
18
- _description = ""
19
- _author_name = "{author_name}"
20
- _author_email = "{author_email}"
21
- _created_at = "{date_created}"
22
- #----------------------------------
23
-
24
- @validate_args_type()
25
- def __init__(self):
26
- super().__init__() # Instantiating `ModusaSignal` class
27
-
28
- self.title = "" # This title will be used as plot title by default
29
-
30
- #-----------------------------------
31
- # Properties
32
- #-----------------------------------
33
-
34
-
35
- #===================================
36
-
37
-
38
-
39
-
40
-
41
-
42
- #-----------------------------------
43
- # Tools
44
- #-----------------------------------
45
-
46
-
47
- #===================================
@@ -1,41 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- from modusa import excp
5
- from modusa.decorators import immutable_property, validate_args_type, plugin_safety_check
6
- from modusa.plugins.base import ModusaPlugin
7
-
8
-
9
- class {class_name}(ModusaPlugin):
10
- """
11
-
12
- """
13
-
14
- #--------Meta Information----------
15
- _name = ""
16
- _description = ""
17
- _author_name = "{author_name}"
18
- _author_email = "{author_email}"
19
- _created_at = "{date_created}"
20
- #----------------------------------
21
-
22
- def __init__(self):
23
- super().__init__()
24
-
25
- @immutable_property(error_msg="Mutation not allowed.")
26
- def allowed_input_signal_types(self) -> tuple[type, ...]:
27
- return ()
28
-
29
-
30
- @immutable_property(error_msg="Mutation not allowed.")
31
- def allowed_output_signal_types(self) -> tuple[type, ...]:
32
- return ()
33
-
34
-
35
- @plugin_safety_check()
36
- @validate_args_type()
37
- def apply(self, signal: "") -> "":
38
-
39
- # Run the engine here
40
-
41
- return
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- from modusa import excp
4
-
5
- #--------Meta Information----------
6
- _class_name = "{class_name}"
7
- _author_name = "{author_name}"
8
- _author_email = "{author_email}"
9
- _created_at = "{date_created}"
10
- #----------------------------------
@@ -1,24 +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.tools.base import ModusaTool
7
-
8
-
9
- class {class_name}(ModusaTool):
10
- """
11
-
12
- """
13
-
14
- #--------Meta Information----------
15
- _name = ""
16
- _description = ""
17
- _author_name = "{author_name}"
18
- _author_email = "{author_email}"
19
- _created_at = "{date_created}"
20
- #----------------------------------
21
-
22
- def __init__(self):
23
- super().__init__()
24
-
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- from .base import ModusaGenerator
4
-
5
- from .s_ax import SAxGen
6
- from .t_ax import TAxGen
7
-
8
- from .s1d import S1DGen
9
- from .tds import TDSGen
10
- from .audio import AudioGen
11
-
12
- from .s2d import S2DGen
13
- from .ftds import FTDSGen
@@ -1,188 +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.t_ax import TAx
8
- from modusa.models.audio import Audio
9
- from modusa.models.data import Data
10
- import numpy as np
11
- from pathlib import Path
12
-
13
- class AudioGen(ModusaGenerator):
14
- """
15
- Provides user friendly APIs to generate instances of different
16
- `AudioSignal` instances.
17
- """
18
-
19
- #--------Meta Information----------
20
- _name = ""
21
- _description = ""
22
- _author_name = "Ankit Anand"
23
- _author_email = "ankit0.anand0@gmail.com"
24
- _created_at = "2025-07-27"
25
- #----------------------------------
26
-
27
- @staticmethod
28
- def from_array(
29
- y: np.ndarray,
30
- sr: float | int = 1.0,
31
- t0: float | int = 0.0,
32
- y_label: str = "Amplitude",
33
- t_label: str = "Time (sec)",
34
- title: str = "Audio Signal"
35
- ) -> Audio:
36
- """
37
- Create `AudioSignal` instance from basic data structures.
38
-
39
- .. code-block:: python
40
-
41
- import modusa as ms
42
- t = ms.tds.from_array([1, 2, 3])
43
- print(t)
44
- t.print_info()
45
-
46
- Parameters
47
- ----------
48
- y: np.ndarray
49
- - Audio data array.
50
- sr: float | int
51
- - Sampling rate.
52
- t0: float | int
53
- - Start timestamp.
54
- y_label: str
55
- - Y label for the signal.
56
- - Default: "Y"
57
- t_label: str
58
- - T label for the signal.
59
- - Default: "Time (sec)"
60
- title: str
61
- - Title for the signal.
62
- - Default: "1D Signal"
63
- Returns
64
- -------
65
- Audio
66
- An instance of Audio.
67
- """
68
- assert isinstance(y, np.ndarray)
69
- assert isinstance(sr, (int, float)) and isinstance(t0, (int, float))
70
- assert isinstance(y_label, str) and isinstance(t_label, str) and isinstance(title, str)
71
-
72
- assert y.ndim == 1
73
-
74
- sr = float(sr)
75
- t0 = float(t0)
76
-
77
- t = TAx(n_points=y.shape[0], sr=sr, t0=t0, label=t_label) # Creating a signal axis instance
78
- y = Data(values=y, label=y_label)
79
-
80
- return Audio(y=y, t=t, title=title)
81
-
82
- @classmethod
83
- def from_youtube(cls, url: str, sr: int | float = None):
84
- """
85
- Loads audio from youtube at a given sr.
86
- The audio is deleted from the device
87
- after loading.
88
-
89
- .. code-block:: python
90
-
91
- import modusa as ms
92
- audio = ms.audio.from_youtube(
93
- url="https://www.youtube.com/watch?v=lIpw9-Y_N0g",
94
- sr=None
95
- )
96
-
97
- PARAMETERS
98
- ----------
99
- url: str
100
- Link to the YouTube video.
101
- sr: int
102
- Sampling rate to load the audio in.
103
-
104
- Returns
105
- -------
106
- Audio:
107
- An `Audio` instance with loaded audio content from YouTube.
108
- """
109
-
110
- from modusa.tools.youtube_downloader import YoutubeDownloader
111
- from modusa import convert
112
- import soundfile as sf
113
- from scipy.signal import resample
114
- import tempfile
115
-
116
- # Download the audio in temp directory using tempfile module
117
- with tempfile.TemporaryDirectory() as tmpdir:
118
- audio_fp: Path = YoutubeDownloader.download(url=url, content_type="audio", output_dir=Path(tmpdir))
119
-
120
- # Convert the audio to ".wav" form for loading
121
- wav_audio_fp: Path = convert(inp_audio_fp=audio_fp, output_audio_fp=audio_fp.with_suffix(".wav"))
122
-
123
- # Load the audio in memory
124
- audio_data, audio_sr = sf.read(wav_audio_fp)
125
-
126
- # Convert to mono if it's multi-channel
127
- if audio_data.ndim > 1:
128
- audio_data = audio_data.mean(axis=1)
129
-
130
- # Resample if needed
131
- if sr is not None:
132
- if audio_sr != sr:
133
- n_samples = int(len(audio_data) * sr / audio_sr)
134
- audio_data = resample(audio_data, n_samples)
135
- audio_sr = sr
136
-
137
- audio = cls.from_array(y=audio_data, sr=audio_sr, title=audio_fp.stem)
138
-
139
- return audio
140
-
141
- @classmethod
142
- def from_filepath(cls, fp: str | Path, sr: int | float = None):
143
- """
144
- Loads audio from filepath at a given sr.
145
-
146
- .. code-block:: python
147
-
148
- import modusa as ms
149
- audio = ms.audio.from_filepath(
150
- fp="path/to/audio.wav",
151
- sr=None
152
- )
153
-
154
- PARAMETERS
155
- ----------
156
- fp: str | Path
157
- Audio file path.
158
- sr: int
159
- Sampling rate to load the audio in.
160
-
161
- Returns
162
- -------
163
- Audio:
164
- An `Audio` instance with loaded audio content.
165
- """
166
- import soundfile as sf
167
- from scipy.signal import resample
168
- from pathlib import Path
169
-
170
- fp = Path(fp)
171
- # Load the audio in memory
172
- audio_data, audio_sr = sf.read(fp)
173
-
174
- # Convert to mono if it's multi-channel
175
- if audio_data.ndim > 1:
176
- audio_data = audio_data.mean(axis=1)
177
-
178
- # Resample if needed
179
- if sr is not None:
180
- if audio_sr != sr:
181
- n_samples = int(len(audio_data) * sr / audio_sr)
182
- audio_data = resample(audio_data, n_samples)
183
- audio_sr = sr
184
-
185
- audio = cls.from_array(y=audio_data, sr=audio_sr, title=fp.stem)
186
-
187
- return audio
188
-
@@ -1,236 +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.audio_signal import AudioSignal
8
- import numpy as np
9
-
10
- class AudioWaveformGenerator(ModusaGenerator):
11
- """
12
- Generates different kinds of audio waveforms particulary helpful
13
- in teaching signal processing concepts and testing out newly
14
- created tools.
15
- """
16
-
17
- #--------Meta Information----------
18
- _name = "Audio Waveform Generator"
19
- _description = "Generates different kind of audio waveforms."
20
- _author_name = "Ankit Anand"
21
- _author_email = "ankit0.anand0@gmail.com"
22
- _created_at = "2025-07-07"
23
- #----------------------------------
24
-
25
- @staticmethod
26
- def generate_example() -> "AudioSignal":
27
- """
28
- Generates a simple sine wave audio signal as an example.
29
-
30
- Returns
31
- -------
32
- AudioSignal
33
- A 600 Hz sine wave lasting 2 seconds, sampled at 10,000 Hz.
34
- """
35
-
36
- sr = 10000 # Hz
37
- duration = 2 # sec
38
- freq = 600 # Hz
39
-
40
- t = np.arange(0, duration, 1 / sr)
41
- y = np.sin(2 * np.pi * freq * t)
42
-
43
- signal = AudioSignal(y=y, sr=sr, title="Example") # assuming AudioSignal accepts y and t
44
-
45
- return signal
46
-
47
-
48
- @staticmethod
49
- def generate_random(duration: float = 1.0, sr: int = 10000) -> "AudioSignal":
50
- """
51
- Generates a random audio signal of given duration and sample rate.
52
-
53
- Parameters
54
- ----------
55
- duration : float, optional
56
- Duration of the signal in seconds (default is 1.0).
57
- sr : int, optional
58
- Sampling rate in Hz (default is 10,000).
59
-
60
- Returns
61
- -------
62
- AudioSignal
63
- A randomly generated signal of the specified duration and sample rate.
64
- """
65
- num_samples = int(duration * sr)
66
- t = np.linspace(0, duration, num=num_samples, endpoint=False)
67
- y = np.random.uniform(low=-1.0, high=1.0, size=num_samples) # use uniform [-1, 1] for audio-like signal
68
-
69
- signal = AudioSignal(y=y, t=t, title="Random")
70
-
71
- return signal
72
-
73
- @staticmethod
74
- @validate_args_type()
75
- def generate_sinusoid(
76
- A: float | int = 1.0,
77
- f: float | int = 10.0,
78
- phi: float | int = 0.0,
79
- duration: float | int = 1.0,
80
- sr: int = 1000,
81
- ) -> "AudioSignal":
82
- """
83
- Generates a sinusoid audio signal with specified
84
- amplitude, frequency, phase, duration, and sample rate.
85
-
86
- Parameters
87
- ----------
88
- A : float
89
- Amplitude of the sinusoid (default: 1.0)
90
- f : float
91
- Frequency in Hz (default: 10.0)
92
- phi : float
93
- Phase in radians (default: 0.0)
94
- duration : float
95
- Duration of the signal in seconds (default: 1.0)
96
- sr : int
97
- Sampling rate in Hz (default: 1000)
98
-
99
- Returns
100
- -------
101
- AudioSignal
102
- A sinusoidal signal with the given parameters.
103
- """
104
- A, f, phi, duration, sr = float(A), float(f), float(phi), float(duration), int(sr)
105
-
106
- t = np.arange(0, duration, 1 / sr)
107
- y = A * np.sin(2 * np.pi * f * t + phi)
108
-
109
- signal = AudioSignal(y=y, sr=sr, title=f"Sinusoid ({f} Hz)")
110
-
111
- return signal
112
-
113
- @staticmethod
114
- @validate_args_type()
115
- def generate_square(
116
- A: float | int = 1.0,
117
- f: float | int = 10.0,
118
- phi: float | int = 0.0,
119
- duration: float | int = 1.0,
120
- sr: int = 1000,
121
- ) -> "AudioSignal":
122
- """
123
- Generates a square wave audio signal with specified
124
- amplitude, frequency, phase, duration, and sample rate.
125
-
126
- Parameters
127
- ----------
128
- A : float
129
- Amplitude of the square wave (default: 1.0)
130
- f : float
131
- Frequency in Hz (default: 10.0)
132
- phi : float
133
- Phase in radians (default: 0.0)
134
- duration : float
135
- Duration of the signal in seconds (default: 1.0)
136
- sr : int
137
- Sampling rate in Hz (default: 1000)
138
-
139
- Returns
140
- -------
141
- AudioSignal
142
- A square wave signal of the specified parameters.
143
- """
144
- A, f, phi, duration, sr = float(A), float(f), float(phi), float(duration), int(sr)
145
- t = np.arange(0, duration, 1 / sr)
146
-
147
- y = A * np.sign(np.sin(2 * np.pi * f * t + phi))
148
-
149
- signal = AudioSignal(y=y, sr=sr, title=f"Square ({f} Hz)")
150
-
151
- return signal
152
-
153
-
154
- @staticmethod
155
- @validate_args_type()
156
- def generate_sawtooth(
157
- A: float | int = 1.0,
158
- f: float | int = 10.0,
159
- phi: float | int = 0.0,
160
- duration: float | int = 1.0,
161
- sr: int = 1000,
162
- ) -> "AudioSignal":
163
- """
164
- Generates a sawtooth wave AudioSignal with specified amplitude, frequency, phase, duration, and sample rate.
165
-
166
- Parameters
167
- ----------
168
- A : float
169
- Amplitude of the sawtooth wave (default: 1.0)
170
- f : float
171
- Frequency in Hz (default: 10.0)
172
- phi : float
173
- Phase in radians (default: 0.0)
174
- duration : float
175
- Duration of the signal in seconds (default: 1.0)
176
- sr : int
177
- Sampling rate in Hz (default: 1000)
178
-
179
- Returns
180
- -------
181
- AudioSignal
182
- A sawtooth wave signal of the specified parameters.
183
- """
184
- A, f, phi, duration, sr = float(A), float(f), float(phi), float(duration), int(sr)
185
- t = np.arange(0, duration, 1 / sr)
186
-
187
- # Convert phase from radians to fractional cycle offset
188
- phase_offset = phi / (2 * np.pi)
189
- y = A * (2 * ((f * t + phase_offset) % 1) - 1)
190
-
191
- signal = AudioSignal(y=y, sr=sr, title=f"Sawtooth ({f} Hz)")
192
- return signal
193
-
194
-
195
- @staticmethod
196
- @validate_args_type()
197
- def generate_triangle(
198
- A: float | int = 1.0,
199
- f: float | int = 10.0,
200
- phi: float | int = 0.0,
201
- duration: float | int = 1.0,
202
- sr: int = 1000,
203
- ) -> "AudioSignal":
204
- """
205
- Generates a triangle wave AudioSignal with specified
206
- amplitude, frequency, phase, duration, and sample rate.
207
-
208
- Parameters
209
- ----------
210
- A : float
211
- Amplitude of the triangle wave (default: 1.0)
212
- f : float
213
- Frequency in Hz (default: 10.0)
214
- phi : float
215
- Phase in radians (default: 0.0)
216
- duration : float
217
- Duration of the signal in seconds (default: 1.0)
218
- sr : int
219
- Sampling rate in Hz (default: 1000)
220
-
221
- Returns
222
- -------
223
- AudioSignal
224
- A triangle wave signal of the specified parameters.
225
- """
226
- A, f, phi, duration, sr = float(A), float(f), float(phi), float(duration), int(sr)
227
- t = np.arange(0, duration, 1 / sr)
228
- phase_offset = phi / (2 * np.pi) # Convert radians to cycle offset
229
-
230
- # Triangle wave formula: 2 * abs(2 * frac(x) - 1) - 1 scaled to amplitude
231
- y = A * (2 * np.abs(2 * ((f * t + phase_offset) % 1) - 1) - 1)
232
-
233
- signal = AudioSignal(y=y, sr=sr, title=f"Triangle ({f} Hz)")
234
-
235
- return signal
236
-
modusa/generators/base.py DELETED
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- from modusa import excp
4
- from modusa.decorators import validate_args_type, immutable_property
5
- from modusa.models.base import ModusaSignal
6
- from abc import ABC, abstractmethod
7
- from typing import Any
8
-
9
- class ModusaGenerator(ABC):
10
- """
11
- Base class for any type of signal generators for modusa framework.
12
-
13
- Note
14
- ----
15
- - This class is intended to be subclassed by any Generator related tools built for the modusa framework.
16
- - In order to create a generator tool, you can use modusa-dev CLI to generate an generator template.
17
- - It is recommended to treat subclasses of ModusaGenerator as namespaces and define @staticmethods with control parameters, rather than using instance-level __init__ methods.
18
-
19
-
20
- """
21
-
22
- #--------Meta Information----------
23
- _name = ""
24
- _description = ""
25
- _author_name = "Ankit Anand"
26
- _author_email = "ankit0.anand0@gmail.com"
27
- _created_at = "2025-07-04"
28
- #----------------------------------
29
-