wavemap 2.0.0__tar.gz → 2.1.0__tar.gz

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.
wavemap-2.1.0/PKG-INFO ADDED
@@ -0,0 +1,378 @@
1
+ Metadata-Version: 2.4
2
+ Name: wavemap
3
+ Version: 2.1.0
4
+ Summary: 🌊 Memory map WAVE or raw audio files 🌊
5
+ Author: Tom Ritchford
6
+ Author-email: Tom Ritchford <tom@swirly.com>
7
+ License-Expression: MIT
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Requires-Dist: numpy>=1.24.1,<2
15
+ Requires-Dist: xmod>=1.3.2,<2
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/x-rst
18
+
19
+ 🌊 Memory map WAVE files into numpy arrays 🌊
20
+ ----------------------------------------------
21
+
22
+ .. image:: https://raw.githubusercontent.com/rec/wavemap/master/wavemap.png
23
+ :alt: WaveMap logo
24
+
25
+ Manipulate huge WAVE or RAW files as numpy matrices - even if they are too
26
+ large to fit into memory.
27
+
28
+ Memory mapping is a technique where files on disk are directly mapped to
29
+ locations in memory and use the same logic as swap space does.
30
+
31
+ Samples from a WAVE or RAW audio file are directly memory mapped to entries in
32
+ a ``numpy`` array, letting you manipulate very large audio files as if they
33
+ all fit into memory at one time, and even directly change samples on disk.
34
+
35
+ Typical usage:
36
+
37
+ .. code-block:: python
38
+
39
+ import wavemap
40
+
41
+ wm = wavemap('test.wav', 'r+') # r+ means read/write
42
+ # Now you have a numpy matrix that you can use like any other
43
+
44
+ wm /= 2
45
+ # Each sample in the file is scaled by half.
46
+
47
+ API
48
+ ===
49
+
50
+ ``wavemap()``
51
+ ~~~~~~~~~~~~~~~~~~~~~~
52
+
53
+ .. code-block:: python
54
+
55
+ wavemap(
56
+ filename: str,
57
+ mode: str='r',
58
+ order: Union[str, NoneType]=None,
59
+ always_2d: bool=False,
60
+ dtype: Union[numpy.dtype, NoneType]=None,
61
+ shape: Union[NoneType, int, tuple]=None,
62
+ sample_rate: int=0,
63
+ roffset: int=0,
64
+ warn: Union[Callable, NoneType]='<function warn: print to stderr>',
65
+ )
66
+
67
+ (`wavemap/__init__.py, 56-121 <https://github.com/rec/wavemap/blob/master/wavemap/__init__.py#L56-L121>`_)
68
+
69
+ Memory map a WAVE file to a ``numpy`` array
70
+
71
+ Return an instance of ``ReadMap`` or ``WriteMap``, depending on
72
+ ``mode``.
73
+
74
+ ARGUMENTS
75
+ filename
76
+ The name of the file being mapped
77
+
78
+ mode
79
+ The file is opened in this mode.
80
+ Must be one of ``'r'``, ``'r+'``, ``'c'``, ``'w+'``
81
+
82
+ In mode ``'r'``, the default, the file is opened read-only and
83
+ the ``numpy.darray`` is immutable.
84
+
85
+ In mode ``'r+'``, the file is opened read-write and changes to the
86
+ ``numpy.darray`` are automatically applied to the file.
87
+
88
+ In mode ``'c'``, "copy-on-write", the file is opened read-only, but
89
+ the ``numpy.darray`` is *not* immutable: changes to the array are
90
+ instead stored in memory.
91
+
92
+ In mode ``'w+'``, "write", the file is opened for write, and overwrites
93
+ whatever else is there.
94
+
95
+ order
96
+ Samples usually get laid out in into a ``numpy.darray`` with``
97
+ shape=(N, C)`` where ``N`` is the number of audio frames, and ``C`` is
98
+ the number of channels.
99
+
100
+ This is called column major order, but this can be toggled by
101
+ setting the ``order`` parameter to ``F`` for Fortan or row-major row.
102
+
103
+ See https://stackoverflow.com/questions/27266338/
104
+
105
+ always_2d
106
+ If ``False``, the default, mono WAVE files with only one channel
107
+ get special treatment and are mapped to a one-dimensional vector
108
+ with ``size=(N,)``.
109
+
110
+ If ``True``, mono WAVE files are treated the same as any other file
111
+ and are mapped to a two-dimensional matrix with ``size=(N, 1)``.
112
+
113
+ dtype
114
+ The numpy datatype of the samples in the file.
115
+
116
+ shape
117
+ The shape of the resulting numpy.darray. Can be a tuple, or a positive
118
+ integer, or ``None``.
119
+
120
+ sample_rate
121
+ The sample rate in Hz (cycles per second)
122
+
123
+ roffset
124
+ How many bytes in the file after the WAV data
125
+
126
+ warn
127
+ Programmers are sloppy so quite a lot of real-world WAVE files have
128
+ recoverable errors in their format. ``warn`` is the function used to
129
+ report those recoverable errors. By default, it's set to print to
130
+ ``sys.stderr`` but setting it to ``None`` disables errors entirely, or
131
+ you can pass your own callback in
132
+
133
+ Class ``wavemap.RawMap``
134
+ ~~~~~~~~~~~~~~~~~~~~~~~~
135
+
136
+ (`wavemap/raw.py, 14-67 <https://github.com/rec/wavemap/blob/master/wavemap/raw.py#L14-L67>`_)
137
+
138
+ "Memory map raw audio data from a disk file into a numpy matrix
139
+
140
+ ``wavemap.RawMap.__new__()``
141
+ ____________________________
142
+
143
+ .. code-block:: python
144
+
145
+ wavemap.RawMap.__new__(
146
+ cls,
147
+ filename: str,
148
+ dtype: numpy.dtype,
149
+ shape: Union[tuple, int, NoneType]=None,
150
+ mode: str='r',
151
+ offset: int=0,
152
+ roffset: int=0,
153
+ order: Union[str, NoneType]=None,
154
+ always_2d: bool=False,
155
+ warn: Union[Callable, NoneType]='<function warn: print to stderr>',
156
+ )
157
+
158
+ (`wavemap/raw.py, 17-67 <https://github.com/rec/wavemap/blob/master/wavemap/raw.py#L17-L67>`_)
159
+
160
+ Memory map raw audio data from a disk file into a numpy matrix
161
+
162
+ ARGUMENTS
163
+ cls
164
+ Think of this as ``self``. (This is because you need to implement ``__new__``
165
+ and not ``__init__`` when deriving from ``np.darray``.)
166
+
167
+ filename
168
+ The name of the file being mapped
169
+
170
+ dtype
171
+ The numpy datatype of the samples in the file.
172
+
173
+ shape
174
+ The shape of the resulting numpy.darray. Can be a tuple, or a positive
175
+ integer, or ``None``.
176
+
177
+ mode
178
+ The file is opened in this mode.
179
+ Must be one of ``'r'``, ``'r+'``, ``'c'``, ``'w+'``
180
+
181
+ In mode ``'r'``, the default, the file is opened read-only and
182
+ the ``numpy.darray`` is immutable.
183
+
184
+ In mode ``'r+'``, the file is opened read-write and changes to the
185
+ ``numpy.darray`` are automatically applied to the file.
186
+
187
+ In mode ``'c'``, "copy-on-write", the file is opened read-only, but
188
+ the ``numpy.darray`` is *not* immutable: changes to the array are
189
+ instead stored in memory.
190
+
191
+ In mode ``'w+'``, "write", the file is opened for write, and overwrites
192
+ whatever else is there.
193
+
194
+ offset
195
+ How many bytes in the file before the WAV data
196
+
197
+ roffset
198
+ How many bytes in the file after the WAV data
199
+
200
+ order
201
+ Samples usually get laid out in into a ``numpy.darray`` with``
202
+ shape=(N, C)`` where ``N`` is the number of audio frames, and ``C`` is
203
+ the number of channels.
204
+
205
+ This is called column major order, but this can be toggled by
206
+ setting the ``order`` parameter to ``F`` for Fortan or row-major row.
207
+
208
+ See https://stackoverflow.com/questions/27266338/
209
+
210
+ always_2d
211
+ If ``False``, the default, mono WAVE files with only one channel
212
+ get special treatment and are mapped to a one-dimensional vector
213
+ with ``size=(N,)``.
214
+
215
+ If ``True``, mono WAVE files are treated the same as any other file
216
+ and are mapped to a two-dimensional matrix with ``size=(N, 1)``.
217
+
218
+ warn
219
+ Programmers are sloppy so quite a lot of real-world WAVE files have
220
+ recoverable errors in their format. ``warn`` is the function used to
221
+ report those recoverable errors. By default, it's set to print to
222
+ ``sys.stderr`` but setting it to ``None`` disables errors entirely, or
223
+ you can pass your own callback in
224
+
225
+ Class ``wavemap.ReadMap``
226
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
227
+
228
+ (`wavemap/read.py, 18-84 <https://github.com/rec/wavemap/blob/master/wavemap/read.py#L18-L84>`_)
229
+
230
+ Memory-map an existing WAVE file into a numpy vector or matrix
231
+
232
+ ``wavemap.ReadMap.__new__()``
233
+ _____________________________
234
+
235
+ .. code-block:: python
236
+
237
+ wavemap.ReadMap.__new__(
238
+ cls: Type,
239
+ filename: str,
240
+ mode: str='r',
241
+ order: Union[str, NoneType]=None,
242
+ always_2d: bool=False,
243
+ warn: Union[Callable, NoneType]='<function warn: print to stderr>',
244
+ )
245
+
246
+ (`wavemap/read.py, 21-84 <https://github.com/rec/wavemap/blob/master/wavemap/read.py#L21-L84>`_)
247
+
248
+ Memory-map an existing WAVE file into a numpy matrix.
249
+
250
+ ARGUMENTS
251
+ cls
252
+ Think of this as ``self``. (This is because you need to implement ``__new__``
253
+ and not ``__init__`` when deriving from ``np.darray``.)
254
+
255
+ filename
256
+ The name of the file being mapped
257
+
258
+ mode
259
+ The file is opened in this mode.
260
+ Must be one of ``'r'``, ``'r+'`` and ``'c'``.
261
+
262
+ In mode ``'r'``, the default, the file is opened read-only and
263
+ the ``numpy.darray`` is immutable.
264
+
265
+ In mode ``'r+'``, the file is opened read-write and changes to the
266
+ ``numpy.darray`` are automatically applied to the file.
267
+
268
+ In mode ``'c'``, "copy-on-write", the file is opened read-only, but
269
+ the ``numpy.darray`` is *not* immutable: changes to the array are
270
+ instead stored in memory.
271
+
272
+ order
273
+ Samples usually get laid out in into a ``numpy.darray`` with``
274
+ shape=(N, C)`` where ``N`` is the number of audio frames, and ``C`` is
275
+ the number of channels.
276
+
277
+ This is called column major order, but this can be toggled by
278
+ setting the ``order`` parameter to ``F`` for Fortan or row-major row.
279
+
280
+ See https://stackoverflow.com/questions/27266338/
281
+
282
+ always_2d
283
+ If ``False``, the default, mono WAVE files with only one channel
284
+ get special treatment and are mapped to a one-dimensional vector
285
+ with ``size=(N,)``.
286
+
287
+ If ``True``, mono WAVE files are treated the same as any other file
288
+ and are mapped to a two-dimensional matrix with ``size=(N, 1)``.
289
+
290
+ warn
291
+ Programmers are sloppy so quite a lot of real-world WAVE files have
292
+ recoverable errors in their format. ``warn`` is the function used to
293
+ report those recoverable errors. By default, it's set to print to
294
+ ``sys.stderr`` but setting it to ``None`` disables errors entirely, or
295
+ you can pass your own callback in
296
+
297
+ Class ``wavemap.WriteMap``
298
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
299
+
300
+ (`wavemap/write.py, 12-115 <https://github.com/rec/wavemap/blob/master/wavemap/write.py#L12-L115>`_)
301
+
302
+ "Memory-map a new wave file into a new numpy vector or matrix
303
+
304
+ ``wavemap.WriteMap.__new__()``
305
+ ______________________________
306
+
307
+ .. code-block:: python
308
+
309
+ wavemap.WriteMap.__new__(
310
+ cls: Type,
311
+ filename: str,
312
+ dtype: numpy.dtype,
313
+ shape: Union[NoneType, int, tuple],
314
+ sample_rate: int,
315
+ roffset: int=0,
316
+ warn: Union[Callable, NoneType]='<function warn: print to stderr>',
317
+ )
318
+
319
+ (`wavemap/write.py, 15-85 <https://github.com/rec/wavemap/blob/master/wavemap/write.py#L15-L85>`_)
320
+
321
+ Open a memory-mapped WAVE file in write mode and overwrite any existing
322
+ file.
323
+
324
+ ARGUMENTS
325
+ cls
326
+ Think of this as ``self``. (This is because you need to implement ``__new__``
327
+ and not ``__init__`` when deriving from ``np.darray``.)
328
+
329
+ filename
330
+ The name of the file being mapped
331
+
332
+ dtype
333
+ The numpy datatype of the samples in the file.
334
+
335
+ shape
336
+ The shape of the resulting numpy.darray. Can be a tuple, or a positive
337
+ integer, or ``None``.
338
+
339
+ sample_rate
340
+ The sample rate in Hz (cycles per second)
341
+
342
+ roffset
343
+ How many bytes in the file after the WAV data
344
+
345
+ warn
346
+ Programmers are sloppy so quite a lot of real-world WAVE files have
347
+ recoverable errors in their format. ``warn`` is the function used to
348
+ report those recoverable errors. By default, it's set to print to
349
+ ``sys.stderr`` but setting it to ``None`` disables errors entirely, or
350
+ you can pass your own callback in
351
+
352
+ ``wavemap.convert()``
353
+ ~~~~~~~~~~~~~~~~~~~~~
354
+
355
+ .. code-block:: python
356
+
357
+ wavemap.convert(
358
+ arr: numpy.ndarray,
359
+ dtype: Union[numpy.dtype, NoneType],
360
+ must_copy: bool=False,
361
+ )
362
+
363
+ (`wavemap/convert.py, 6-77 <https://github.com/rec/wavemap/blob/master/wavemap/convert.py#L6-L77>`_)
364
+
365
+ Returns a copy of a numpy array or matrix that represents audio data in
366
+ another type, scaling and shifting as necessary.
367
+
368
+ ARGUMENTS
369
+ arr
370
+ A numpy darray representing an audio signal
371
+
372
+ dtype
373
+ The numpy dtype to convert to - none means "no conversion"
374
+
375
+ must_copy
376
+ If true, ``arr`` is copied even if it is already the requested type
377
+
378
+ (automatically generated by `doks <https://github.com/rec/doks/>`_ on 2021-02-23T14:37:02.652534)
@@ -0,0 +1,47 @@
1
+ [project]
2
+ name = "wavemap"
3
+ version = "2.1.0"
4
+ description = "🌊 Memory map WAVE or raw audio files 🌊"
5
+ authors = [{ name = "Tom Ritchford", email = "tom@swirly.com" }]
6
+ requires-python = ">=3.10"
7
+ readme = "README.rst"
8
+ license = "MIT"
9
+ classifiers = ["Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"]
10
+ dependencies = [
11
+ "numpy>=1.24.1,<2",
12
+ "xmod>=1.3.2,<2",
13
+ ]
14
+
15
+ [tool.doks]
16
+ auto = true
17
+ source = 'wavemap/__init__.py'
18
+
19
+ [tool.ruff]
20
+ [dependency-groups]
21
+ dev = [
22
+ "coverage>=7.1.0,<8",
23
+ "pytest>=7.2.1,<8",
24
+ "pyupgrade>=3.21.2",
25
+ "ruff>=0.14.14",
26
+ "stroll>=1.1.0,<2",
27
+ "tdir>=1.4.1,<2",
28
+ "ty>=0.0.14",
29
+ ]
30
+
31
+ [tool.uv]
32
+
33
+ [tool.uv.build-backend]
34
+ module-root = ""
35
+
36
+ [build-system]
37
+ requires = ["uv_build>=0.9.0,<0.10.0"]
38
+ build-backend = "uv_build"
39
+ [tool.coverage.run]
40
+ branch = true
41
+ source = "wavemap"
42
+
43
+ [tool.coverage.report]
44
+ fail_under = "68"
45
+ skip_covered = true
46
+ exclude_lines = ["pragma: no cover", "if False:", "if __name__ == .__main__.:", "raise NotImplementedError"]
47
+
Binary file
@@ -26,31 +26,34 @@ Typical usage:
26
26
  wm /= 2
27
27
  # Each sample in the file is scaled by half.
28
28
  """
29
+
30
+ from typing import Optional, Union
31
+ from collections.abc import Callable
32
+
33
+ import numpy as np
34
+ import xmod
35
+
29
36
  from . import docs
30
37
  from .convert import convert
31
38
  from .raw import RawMap, warn
32
39
  from .read import ReadMap as ReadMap
33
40
  from .write import WriteMap as WriteMap
34
- from typing import Callable, Optional, Union
35
- import numpy as np
36
- import xmod
37
41
 
38
42
  __all__ = (
39
- 'wavemap',
40
- 'RawMap',
41
- 'ReadMap',
42
- 'WriteMap',
43
- 'copy_to',
44
- 'new_like',
45
- 'convert',
43
+ "wavemap",
44
+ "RawMap",
45
+ "ReadMap",
46
+ "WriteMap",
47
+ "copy_to",
48
+ "new_like",
49
+ "convert",
46
50
  )
47
- __version__ = '2.0.0'
48
51
 
49
52
  copy_to = WriteMap.copy_to
50
53
  new_like = WriteMap.new_like
51
- _DOKS = {warn: '<function warn: print to stderr>'}
52
- _WRITE_PARAMETERS = 'dtype', 'shape', 'sample_rate'
53
- _READ_PARAMETERS = 'order', 'always_2d'
54
+ _DOKS = {warn: "<function warn: print to stderr>"}
55
+ _WRITE_PARAMETERS = "dtype", "shape", "sample_rate"
56
+ _READ_PARAMETERS = "order", "always_2d"
54
57
 
55
58
 
56
59
  @xmod(mutable=True)
@@ -60,20 +63,20 @@ def wavemap(
60
63
  #
61
64
  # Read parameters
62
65
  #
63
- mode: str = 'r',
64
- order: Optional[str] = None,
66
+ mode: str = "r",
67
+ order: str | None = None,
65
68
  always_2d: bool = False,
66
69
  #
67
70
  # Write parameters
68
71
  #
69
- dtype: Optional[np.dtype] = None,
70
- shape: Union[None, int, tuple] = None,
72
+ dtype: np.dtype | None = None,
73
+ shape: None | int | tuple = None,
71
74
  sample_rate: int = 0,
72
75
  roffset: int = 0,
73
76
  #
74
77
  # Read and write parameters
75
78
  #
76
- warn: Optional[Callable] = warn,
79
+ warn: Callable | None = warn,
77
80
  ):
78
81
  """
79
82
  Memory map a WAVE file to a `numpy` array
@@ -81,18 +84,18 @@ def wavemap(
81
84
  Return an instance of `ReadMap` or `WriteMap`, depending on
82
85
  `mode`.
83
86
  """
84
- if mode.startswith('w'):
87
+ if mode.startswith("w"):
85
88
  if not dtype:
86
- raise ValueError('dtype must be set for write')
89
+ raise ValueError("dtype must be set for write")
87
90
  if not shape:
88
- raise ValueError('shape must be set for write')
91
+ raise ValueError("shape must be set for write")
89
92
  if not sample_rate:
90
- raise ValueError('sample_rate must be set for write')
93
+ raise ValueError("sample_rate must be set for write")
91
94
 
92
95
  if order:
93
- raise ValueError('order cannot be set for write')
96
+ raise ValueError("order cannot be set for write")
94
97
  if always_2d:
95
- raise ValueError('always_2d cannot be set for write')
98
+ raise ValueError("always_2d cannot be set for write")
96
99
 
97
100
  return WriteMap(
98
101
  filename=filename,
@@ -104,9 +107,9 @@ def wavemap(
104
107
  )
105
108
  else:
106
109
  if shape:
107
- raise ValueError('shape cannot be set for write')
110
+ raise ValueError("shape cannot be set for write")
108
111
  if sample_rate:
109
- raise ValueError('sample_rate cannot be set for write')
112
+ raise ValueError("sample_rate cannot be set for write")
110
113
 
111
114
  result = ReadMap(
112
115
  filename=filename,
@@ -1,11 +1,10 @@
1
- from numpy.lib.stride_tricks import as_strided
2
1
  from typing import Optional
2
+
3
3
  import numpy as np
4
+ from numpy.lib.stride_tricks import as_strided
4
5
 
5
6
 
6
- def convert(
7
- arr: np.ndarray, dtype: Optional[np.dtype], must_copy: bool = False
8
- ):
7
+ def convert(arr: np.ndarray, dtype: np.dtype | None, must_copy: bool = False):
9
8
  """
10
9
  Returns a copy of a numpy array or matrix that represents audio data in
11
10
  another type, scaling and shifting as necessary.
@@ -27,8 +26,8 @@ def convert(
27
26
  arr = np.copy(arr)
28
27
  return arr
29
28
 
30
- old_int = 'int' in str(old_t)
31
- new_int = 'int' in str(new_t)
29
+ old_int = "int" in str(old_t)
30
+ new_int = "int" in str(new_t)
32
31
 
33
32
  if not (new_int or old_int):
34
33
  # Convert between floats
@@ -96,8 +95,15 @@ def _twenty_four_bit(shape, new, raw, itemsize):
96
95
  assert not (frames % 4)
97
96
 
98
97
  # https://stackoverflow.com/a/34128171/4383
99
- raw = new(shape=(itemsize * frames // 4,), dtype='int32')
100
- strided = as_strided(raw, strides=(12, 3,), shape=(frames, 4))
98
+ raw = new(shape=(itemsize * frames // 4,), dtype="int32")
99
+ strided = as_strided(
100
+ raw,
101
+ strides=(
102
+ 12,
103
+ 3,
104
+ ),
105
+ shape=(frames, 4),
106
+ )
101
107
  reshaped = np.reshape(strided, shape=shape)
102
108
 
103
109
  result = reshaped & 0x00FFFFFF
@@ -15,9 +15,9 @@ Think of this as `self`. (This is because you need to implement `__new__`
15
15
  and not `__init__` when deriving from `np.darray`.)
16
16
  """
17
17
 
18
- DTYPE = 'The numpy datatype of the samples in the file.'
18
+ DTYPE = "The numpy datatype of the samples in the file."
19
19
 
20
- FILENAME = 'The name of the file being mapped'
20
+ FILENAME = "The name of the file being mapped"
21
21
 
22
22
  ORDER = """
23
23
  Samples usually get laid out in into a `numpy.darray` with`
@@ -63,9 +63,9 @@ In mode `'w+'`, "write", the file is opened for write, and overwrites
63
63
  whatever else is there.
64
64
  """
65
65
 
66
- OFFSET = 'How many bytes in the file before the WAV data'
67
- ROFFSET = 'How many bytes in the file after the WAV data'
68
- SAMPLE_RATE = 'The sample rate in Hz (cycles per second)'
66
+ OFFSET = "How many bytes in the file before the WAV data"
67
+ ROFFSET = "How many bytes in the file after the WAV data"
68
+ SAMPLE_RATE = "The sample rate in Hz (cycles per second)"
69
69
 
70
70
  SHAPE = """
71
71
  The shape of the resulting numpy.darray. Can be a tuple, or a positive
@@ -87,19 +87,19 @@ def arguments(*names, subs=None):
87
87
  names = [(i, subs.get(i, i).upper()) for i in names]
88
88
  missing = [n for (n, a) in names if a not in globals()]
89
89
  if missing:
90
- raise ValueError(f'Cannot document arguments {missing}')
90
+ raise ValueError(f"Cannot document arguments {missing}")
91
91
 
92
- yield 'ARGUMENTS'
92
+ yield "ARGUMENTS"
93
93
  for name, attr in names:
94
- yield f' {name}'
94
+ yield f" {name}"
95
95
  for line in globals()[attr].strip().splitlines():
96
- yield line and f' {line}'
97
- yield ''
96
+ yield line and f" {line}"
97
+ yield ""
98
98
 
99
99
 
100
100
  def add_arguments(func, names, subs=None):
101
101
  params = arguments(*names, subs=subs)
102
- func.__doc__ = func.__doc__.rstrip() + '\n\n' + '\n'.join(params)
102
+ func.__doc__ = func.__doc__.rstrip() + "\n\n" + "\n".join(params)
103
103
  return func
104
104
 
105
105