singlestoredb 1.16.1__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 (183) hide show
  1. singlestoredb/__init__.py +75 -0
  2. singlestoredb/ai/__init__.py +2 -0
  3. singlestoredb/ai/chat.py +139 -0
  4. singlestoredb/ai/embeddings.py +128 -0
  5. singlestoredb/alchemy/__init__.py +90 -0
  6. singlestoredb/apps/__init__.py +3 -0
  7. singlestoredb/apps/_cloud_functions.py +90 -0
  8. singlestoredb/apps/_config.py +72 -0
  9. singlestoredb/apps/_connection_info.py +18 -0
  10. singlestoredb/apps/_dashboards.py +47 -0
  11. singlestoredb/apps/_process.py +32 -0
  12. singlestoredb/apps/_python_udfs.py +100 -0
  13. singlestoredb/apps/_stdout_supress.py +30 -0
  14. singlestoredb/apps/_uvicorn_util.py +36 -0
  15. singlestoredb/auth.py +245 -0
  16. singlestoredb/config.py +484 -0
  17. singlestoredb/connection.py +1487 -0
  18. singlestoredb/converters.py +950 -0
  19. singlestoredb/docstring/__init__.py +33 -0
  20. singlestoredb/docstring/attrdoc.py +126 -0
  21. singlestoredb/docstring/common.py +230 -0
  22. singlestoredb/docstring/epydoc.py +267 -0
  23. singlestoredb/docstring/google.py +412 -0
  24. singlestoredb/docstring/numpydoc.py +562 -0
  25. singlestoredb/docstring/parser.py +100 -0
  26. singlestoredb/docstring/py.typed +1 -0
  27. singlestoredb/docstring/rest.py +256 -0
  28. singlestoredb/docstring/tests/__init__.py +1 -0
  29. singlestoredb/docstring/tests/_pydoctor.py +21 -0
  30. singlestoredb/docstring/tests/test_epydoc.py +729 -0
  31. singlestoredb/docstring/tests/test_google.py +1007 -0
  32. singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
  33. singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
  34. singlestoredb/docstring/tests/test_parser.py +248 -0
  35. singlestoredb/docstring/tests/test_rest.py +547 -0
  36. singlestoredb/docstring/tests/test_util.py +70 -0
  37. singlestoredb/docstring/util.py +141 -0
  38. singlestoredb/exceptions.py +120 -0
  39. singlestoredb/functions/__init__.py +16 -0
  40. singlestoredb/functions/decorator.py +201 -0
  41. singlestoredb/functions/dtypes.py +1793 -0
  42. singlestoredb/functions/ext/__init__.py +1 -0
  43. singlestoredb/functions/ext/arrow.py +375 -0
  44. singlestoredb/functions/ext/asgi.py +2133 -0
  45. singlestoredb/functions/ext/json.py +420 -0
  46. singlestoredb/functions/ext/mmap.py +413 -0
  47. singlestoredb/functions/ext/rowdat_1.py +724 -0
  48. singlestoredb/functions/ext/timer.py +89 -0
  49. singlestoredb/functions/ext/utils.py +218 -0
  50. singlestoredb/functions/signature.py +1578 -0
  51. singlestoredb/functions/typing/__init__.py +41 -0
  52. singlestoredb/functions/typing/numpy.py +20 -0
  53. singlestoredb/functions/typing/pandas.py +2 -0
  54. singlestoredb/functions/typing/polars.py +2 -0
  55. singlestoredb/functions/typing/pyarrow.py +2 -0
  56. singlestoredb/functions/utils.py +421 -0
  57. singlestoredb/fusion/__init__.py +11 -0
  58. singlestoredb/fusion/graphql.py +213 -0
  59. singlestoredb/fusion/handler.py +916 -0
  60. singlestoredb/fusion/handlers/__init__.py +0 -0
  61. singlestoredb/fusion/handlers/export.py +525 -0
  62. singlestoredb/fusion/handlers/files.py +690 -0
  63. singlestoredb/fusion/handlers/job.py +660 -0
  64. singlestoredb/fusion/handlers/models.py +250 -0
  65. singlestoredb/fusion/handlers/stage.py +502 -0
  66. singlestoredb/fusion/handlers/utils.py +324 -0
  67. singlestoredb/fusion/handlers/workspace.py +956 -0
  68. singlestoredb/fusion/registry.py +249 -0
  69. singlestoredb/fusion/result.py +399 -0
  70. singlestoredb/http/__init__.py +27 -0
  71. singlestoredb/http/connection.py +1267 -0
  72. singlestoredb/magics/__init__.py +34 -0
  73. singlestoredb/magics/run_personal.py +137 -0
  74. singlestoredb/magics/run_shared.py +134 -0
  75. singlestoredb/management/__init__.py +9 -0
  76. singlestoredb/management/billing_usage.py +148 -0
  77. singlestoredb/management/cluster.py +462 -0
  78. singlestoredb/management/export.py +295 -0
  79. singlestoredb/management/files.py +1102 -0
  80. singlestoredb/management/inference_api.py +105 -0
  81. singlestoredb/management/job.py +887 -0
  82. singlestoredb/management/manager.py +373 -0
  83. singlestoredb/management/organization.py +226 -0
  84. singlestoredb/management/region.py +169 -0
  85. singlestoredb/management/utils.py +423 -0
  86. singlestoredb/management/workspace.py +1927 -0
  87. singlestoredb/mysql/__init__.py +177 -0
  88. singlestoredb/mysql/_auth.py +298 -0
  89. singlestoredb/mysql/charset.py +214 -0
  90. singlestoredb/mysql/connection.py +2032 -0
  91. singlestoredb/mysql/constants/CLIENT.py +38 -0
  92. singlestoredb/mysql/constants/COMMAND.py +32 -0
  93. singlestoredb/mysql/constants/CR.py +78 -0
  94. singlestoredb/mysql/constants/ER.py +474 -0
  95. singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
  96. singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
  97. singlestoredb/mysql/constants/FLAG.py +15 -0
  98. singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
  99. singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
  100. singlestoredb/mysql/constants/__init__.py +0 -0
  101. singlestoredb/mysql/converters.py +271 -0
  102. singlestoredb/mysql/cursors.py +896 -0
  103. singlestoredb/mysql/err.py +92 -0
  104. singlestoredb/mysql/optionfile.py +20 -0
  105. singlestoredb/mysql/protocol.py +450 -0
  106. singlestoredb/mysql/tests/__init__.py +19 -0
  107. singlestoredb/mysql/tests/base.py +126 -0
  108. singlestoredb/mysql/tests/conftest.py +37 -0
  109. singlestoredb/mysql/tests/test_DictCursor.py +132 -0
  110. singlestoredb/mysql/tests/test_SSCursor.py +141 -0
  111. singlestoredb/mysql/tests/test_basic.py +452 -0
  112. singlestoredb/mysql/tests/test_connection.py +851 -0
  113. singlestoredb/mysql/tests/test_converters.py +58 -0
  114. singlestoredb/mysql/tests/test_cursor.py +141 -0
  115. singlestoredb/mysql/tests/test_err.py +16 -0
  116. singlestoredb/mysql/tests/test_issues.py +514 -0
  117. singlestoredb/mysql/tests/test_load_local.py +75 -0
  118. singlestoredb/mysql/tests/test_nextset.py +88 -0
  119. singlestoredb/mysql/tests/test_optionfile.py +27 -0
  120. singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
  121. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  122. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
  123. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
  124. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
  125. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
  126. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
  127. singlestoredb/mysql/times.py +23 -0
  128. singlestoredb/notebook/__init__.py +16 -0
  129. singlestoredb/notebook/_objects.py +213 -0
  130. singlestoredb/notebook/_portal.py +352 -0
  131. singlestoredb/py.typed +0 -0
  132. singlestoredb/pytest.py +352 -0
  133. singlestoredb/server/__init__.py +0 -0
  134. singlestoredb/server/docker.py +452 -0
  135. singlestoredb/server/free_tier.py +267 -0
  136. singlestoredb/tests/__init__.py +0 -0
  137. singlestoredb/tests/alltypes.sql +307 -0
  138. singlestoredb/tests/alltypes_no_nulls.sql +208 -0
  139. singlestoredb/tests/empty.sql +0 -0
  140. singlestoredb/tests/ext_funcs/__init__.py +702 -0
  141. singlestoredb/tests/local_infile.csv +3 -0
  142. singlestoredb/tests/test.ipynb +18 -0
  143. singlestoredb/tests/test.sql +680 -0
  144. singlestoredb/tests/test2.ipynb +18 -0
  145. singlestoredb/tests/test2.sql +1 -0
  146. singlestoredb/tests/test_basics.py +1332 -0
  147. singlestoredb/tests/test_config.py +318 -0
  148. singlestoredb/tests/test_connection.py +3103 -0
  149. singlestoredb/tests/test_dbapi.py +27 -0
  150. singlestoredb/tests/test_exceptions.py +45 -0
  151. singlestoredb/tests/test_ext_func.py +1472 -0
  152. singlestoredb/tests/test_ext_func_data.py +1101 -0
  153. singlestoredb/tests/test_fusion.py +1527 -0
  154. singlestoredb/tests/test_http.py +288 -0
  155. singlestoredb/tests/test_management.py +1599 -0
  156. singlestoredb/tests/test_plugin.py +33 -0
  157. singlestoredb/tests/test_results.py +171 -0
  158. singlestoredb/tests/test_types.py +132 -0
  159. singlestoredb/tests/test_udf.py +737 -0
  160. singlestoredb/tests/test_udf_returns.py +459 -0
  161. singlestoredb/tests/test_vectorstore.py +51 -0
  162. singlestoredb/tests/test_xdict.py +333 -0
  163. singlestoredb/tests/utils.py +141 -0
  164. singlestoredb/types.py +373 -0
  165. singlestoredb/utils/__init__.py +0 -0
  166. singlestoredb/utils/config.py +950 -0
  167. singlestoredb/utils/convert_rows.py +69 -0
  168. singlestoredb/utils/debug.py +13 -0
  169. singlestoredb/utils/dtypes.py +205 -0
  170. singlestoredb/utils/events.py +65 -0
  171. singlestoredb/utils/mogrify.py +151 -0
  172. singlestoredb/utils/results.py +585 -0
  173. singlestoredb/utils/xdict.py +425 -0
  174. singlestoredb/vectorstore.py +192 -0
  175. singlestoredb/warnings.py +5 -0
  176. singlestoredb-1.16.1.dist-info/METADATA +165 -0
  177. singlestoredb-1.16.1.dist-info/RECORD +183 -0
  178. singlestoredb-1.16.1.dist-info/WHEEL +5 -0
  179. singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
  180. singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
  181. singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
  182. sqlx/__init__.py +4 -0
  183. sqlx/magic.py +113 -0
@@ -0,0 +1,729 @@
1
+ """Tests for epydoc-style docstring routines."""
2
+ import typing as T
3
+
4
+ import pytest
5
+
6
+ from singlestoredb.docstring.common import ParseError
7
+ from singlestoredb.docstring.common import RenderingStyle
8
+ from singlestoredb.docstring.epydoc import compose
9
+ from singlestoredb.docstring.epydoc import parse
10
+
11
+
12
+ @pytest.mark.parametrize(
13
+ 'source, expected',
14
+ [
15
+ pytest.param(None, None, id='No __doc__'),
16
+ ('', None),
17
+ ('\n', None),
18
+ ('Short description', 'Short description'),
19
+ ('\nShort description\n', 'Short description'),
20
+ ('\n Short description\n', 'Short description'),
21
+ ],
22
+ )
23
+ def test_short_description(
24
+ source: T.Optional[str], expected: T.Optional[str],
25
+ ) -> None:
26
+ """Test parsing short description."""
27
+ docstring = parse(source)
28
+ assert docstring.short_description == expected
29
+ assert docstring.long_description is None
30
+ assert not docstring.meta
31
+
32
+
33
+ @pytest.mark.parametrize(
34
+ 'source, expected_short_desc, expected_long_desc, expected_blank',
35
+ [
36
+ (
37
+ 'Short description\n\nLong description',
38
+ 'Short description',
39
+ 'Long description',
40
+ True,
41
+ ),
42
+ (
43
+ """
44
+ Short description
45
+
46
+ Long description
47
+ """,
48
+ 'Short description',
49
+ 'Long description',
50
+ True,
51
+ ),
52
+ (
53
+ """
54
+ Short description
55
+
56
+ Long description
57
+ Second line
58
+ """,
59
+ 'Short description',
60
+ 'Long description\nSecond line',
61
+ True,
62
+ ),
63
+ (
64
+ 'Short description\nLong description',
65
+ 'Short description',
66
+ 'Long description',
67
+ False,
68
+ ),
69
+ (
70
+ """
71
+ Short description
72
+ Long description
73
+ """,
74
+ 'Short description',
75
+ 'Long description',
76
+ False,
77
+ ),
78
+ (
79
+ '\nShort description\nLong description\n',
80
+ 'Short description',
81
+ 'Long description',
82
+ False,
83
+ ),
84
+ (
85
+ """
86
+ Short description
87
+ Long description
88
+ Second line
89
+ """,
90
+ 'Short description',
91
+ 'Long description\nSecond line',
92
+ False,
93
+ ),
94
+ ],
95
+ )
96
+ def test_long_description(
97
+ source: str,
98
+ expected_short_desc: str,
99
+ expected_long_desc: str,
100
+ expected_blank: bool,
101
+ ) -> None:
102
+ """Test parsing long description."""
103
+ docstring = parse(source)
104
+ assert docstring.short_description == expected_short_desc
105
+ assert docstring.long_description == expected_long_desc
106
+ assert docstring.blank_after_short_description == expected_blank
107
+ assert not docstring.meta
108
+
109
+
110
+ @pytest.mark.parametrize(
111
+ 'source, expected_short_desc, expected_long_desc, '
112
+ 'expected_blank_short_desc, expected_blank_long_desc',
113
+ [
114
+ (
115
+ """
116
+ Short description
117
+ @meta: asd
118
+ """,
119
+ 'Short description',
120
+ None,
121
+ False,
122
+ False,
123
+ ),
124
+ (
125
+ """
126
+ Short description
127
+ Long description
128
+ @meta: asd
129
+ """,
130
+ 'Short description',
131
+ 'Long description',
132
+ False,
133
+ False,
134
+ ),
135
+ (
136
+ """
137
+ Short description
138
+ First line
139
+ Second line
140
+ @meta: asd
141
+ """,
142
+ 'Short description',
143
+ 'First line\n Second line',
144
+ False,
145
+ False,
146
+ ),
147
+ (
148
+ """
149
+ Short description
150
+
151
+ First line
152
+ Second line
153
+ @meta: asd
154
+ """,
155
+ 'Short description',
156
+ 'First line\n Second line',
157
+ True,
158
+ False,
159
+ ),
160
+ (
161
+ """
162
+ Short description
163
+
164
+ First line
165
+ Second line
166
+
167
+ @meta: asd
168
+ """,
169
+ 'Short description',
170
+ 'First line\n Second line',
171
+ True,
172
+ True,
173
+ ),
174
+ (
175
+ """
176
+ @meta: asd
177
+ """,
178
+ None,
179
+ None,
180
+ False,
181
+ False,
182
+ ),
183
+ ],
184
+ )
185
+ def test_meta_newlines(
186
+ source: str,
187
+ expected_short_desc: T.Optional[str],
188
+ expected_long_desc: T.Optional[str],
189
+ expected_blank_short_desc: bool,
190
+ expected_blank_long_desc: bool,
191
+ ) -> None:
192
+ """Test parsing newlines around description sections."""
193
+ docstring = parse(source)
194
+ assert docstring.short_description == expected_short_desc
195
+ assert docstring.long_description == expected_long_desc
196
+ assert docstring.blank_after_short_description == expected_blank_short_desc
197
+ assert docstring.blank_after_long_description == expected_blank_long_desc
198
+ assert len(docstring.meta) == 1
199
+
200
+
201
+ def test_meta_with_multiline_description() -> None:
202
+ """Test parsing multiline meta documentation."""
203
+ docstring = parse(
204
+ """
205
+ Short description
206
+
207
+ @meta: asd
208
+ 1
209
+ 2
210
+ 3
211
+ """,
212
+ )
213
+ assert docstring.short_description == 'Short description'
214
+ assert len(docstring.meta) == 1
215
+ assert docstring.meta[0].args == ['meta']
216
+ assert docstring.meta[0].description == 'asd\n1\n 2\n3'
217
+
218
+
219
+ def test_multiple_meta() -> None:
220
+ """Test parsing multiple meta."""
221
+ docstring = parse(
222
+ """
223
+ Short description
224
+
225
+ @meta1: asd
226
+ 1
227
+ 2
228
+ 3
229
+ @meta2: herp
230
+ @meta3: derp
231
+ """,
232
+ )
233
+ assert docstring.short_description == 'Short description'
234
+ assert len(docstring.meta) == 3
235
+ assert docstring.meta[0].args == ['meta1']
236
+ assert docstring.meta[0].description == 'asd\n1\n 2\n3'
237
+ assert docstring.meta[1].args == ['meta2']
238
+ assert docstring.meta[1].description == 'herp'
239
+ assert docstring.meta[2].args == ['meta3']
240
+ assert docstring.meta[2].description == 'derp'
241
+
242
+
243
+ def test_meta_with_args() -> None:
244
+ """Test parsing meta with additional arguments."""
245
+ docstring = parse(
246
+ """
247
+ Short description
248
+
249
+ @meta ene due rabe: asd
250
+ """,
251
+ )
252
+ assert docstring.short_description == 'Short description'
253
+ assert len(docstring.meta) == 1
254
+ assert docstring.meta[0].args == ['meta', 'ene', 'due', 'rabe']
255
+ assert docstring.meta[0].description == 'asd'
256
+
257
+
258
+ def test_params() -> None:
259
+ """Test parsing params."""
260
+ docstring = parse('Short description')
261
+ assert len(docstring.params) == 0
262
+
263
+ docstring = parse(
264
+ """
265
+ Short description
266
+
267
+ @param name: description 1
268
+ @param priority: description 2
269
+ @type priority: int
270
+ @param sender: description 3
271
+ @type sender: str?
272
+ @param message: description 4, defaults to 'hello'
273
+ @type message: str?
274
+ @param multiline: long description 5,
275
+ defaults to 'bye'
276
+ @type multiline: str?
277
+ """,
278
+ )
279
+ assert len(docstring.params) == 5
280
+ assert docstring.params[0].arg_name == 'name'
281
+ assert docstring.params[0].type_name is None
282
+ assert docstring.params[0].description == 'description 1'
283
+ assert docstring.params[0].default is None
284
+ assert not docstring.params[0].is_optional
285
+ assert docstring.params[1].arg_name == 'priority'
286
+ assert docstring.params[1].type_name == 'int'
287
+ assert docstring.params[1].description == 'description 2'
288
+ assert not docstring.params[1].is_optional
289
+ assert docstring.params[1].default is None
290
+ assert docstring.params[2].arg_name == 'sender'
291
+ assert docstring.params[2].type_name == 'str'
292
+ assert docstring.params[2].description == 'description 3'
293
+ assert docstring.params[2].is_optional
294
+ assert docstring.params[2].default is None
295
+ assert docstring.params[3].arg_name == 'message'
296
+ assert docstring.params[3].type_name == 'str'
297
+ assert (
298
+ docstring.params[3].description == "description 4, defaults to 'hello'"
299
+ )
300
+ assert docstring.params[3].is_optional
301
+ assert docstring.params[3].default == "'hello'"
302
+ assert docstring.params[4].arg_name == 'multiline'
303
+ assert docstring.params[4].type_name == 'str'
304
+ assert (
305
+ docstring.params[4].description
306
+ == "long description 5,\ndefaults to 'bye'"
307
+ )
308
+ assert docstring.params[4].is_optional
309
+ assert docstring.params[4].default == "'bye'"
310
+
311
+
312
+ def test_returns() -> None:
313
+ """Test parsing returns."""
314
+ docstring = parse(
315
+ """
316
+ Short description
317
+ """,
318
+ )
319
+ assert docstring.returns is None
320
+
321
+ docstring = parse(
322
+ """
323
+ Short description
324
+ @return: description
325
+ """,
326
+ )
327
+ assert docstring.returns is not None
328
+ assert docstring.returns.type_name is None
329
+ assert docstring.returns.description == 'description'
330
+ assert not docstring.returns.is_generator
331
+
332
+ docstring = parse(
333
+ """
334
+ Short description
335
+ @return: description
336
+ @rtype: int
337
+ """,
338
+ )
339
+ assert docstring.returns is not None
340
+ assert docstring.returns.type_name == 'int'
341
+ assert docstring.returns.description == 'description'
342
+ assert not docstring.returns.is_generator
343
+
344
+
345
+ def test_yields() -> None:
346
+ """Test parsing yields."""
347
+ docstring = parse(
348
+ """
349
+ Short description
350
+ """,
351
+ )
352
+ assert docstring.returns is None
353
+
354
+ docstring = parse(
355
+ """
356
+ Short description
357
+ @yield: description
358
+ """,
359
+ )
360
+ assert docstring.returns is not None
361
+ assert docstring.returns.type_name is None
362
+ assert docstring.returns.description == 'description'
363
+ assert docstring.returns.is_generator
364
+
365
+ docstring = parse(
366
+ """
367
+ Short description
368
+ @yield: description
369
+ @ytype: int
370
+ """,
371
+ )
372
+ assert docstring.returns is not None
373
+ assert docstring.returns.type_name == 'int'
374
+ assert docstring.returns.description == 'description'
375
+ assert docstring.returns.is_generator
376
+
377
+
378
+ def test_raises() -> None:
379
+ """Test parsing raises."""
380
+ docstring = parse(
381
+ """
382
+ Short description
383
+ """,
384
+ )
385
+ assert len(docstring.raises) == 0
386
+
387
+ docstring = parse(
388
+ """
389
+ Short description
390
+ @raise: description
391
+ """,
392
+ )
393
+ assert len(docstring.raises) == 1
394
+ assert docstring.raises[0].type_name is None
395
+ assert docstring.raises[0].description == 'description'
396
+
397
+ docstring = parse(
398
+ """
399
+ Short description
400
+ @raise ValueError: description
401
+ """,
402
+ )
403
+ assert len(docstring.raises) == 1
404
+ assert docstring.raises[0].type_name == 'ValueError'
405
+ assert docstring.raises[0].description == 'description'
406
+
407
+
408
+ def test_broken_meta() -> None:
409
+ """Test parsing broken meta."""
410
+ with pytest.raises(ParseError):
411
+ parse('@')
412
+
413
+ with pytest.raises(ParseError):
414
+ parse('@param herp derp')
415
+
416
+ with pytest.raises(ParseError):
417
+ parse('@param: invalid')
418
+
419
+ with pytest.raises(ParseError):
420
+ parse('@param with too many args: desc')
421
+
422
+ # these should not raise any errors
423
+ parse('@sthstrange: desc')
424
+
425
+
426
+ @pytest.mark.parametrize(
427
+ 'source, expected',
428
+ [
429
+ ('', ''),
430
+ ('\n', ''),
431
+ ('Short description', 'Short description'),
432
+ ('\nShort description\n', 'Short description'),
433
+ ('\n Short description\n', 'Short description'),
434
+ (
435
+ 'Short description\n\nLong description',
436
+ 'Short description\n\nLong description',
437
+ ),
438
+ (
439
+ """
440
+ Short description
441
+
442
+ Long description
443
+ """,
444
+ 'Short description\n\nLong description',
445
+ ),
446
+ (
447
+ """
448
+ Short description
449
+
450
+ Long description
451
+ Second line
452
+ """,
453
+ 'Short description\n\nLong description\nSecond line',
454
+ ),
455
+ (
456
+ 'Short description\nLong description',
457
+ 'Short description\nLong description',
458
+ ),
459
+ (
460
+ """
461
+ Short description
462
+ Long description
463
+ """,
464
+ 'Short description\nLong description',
465
+ ),
466
+ (
467
+ '\nShort description\nLong description\n',
468
+ 'Short description\nLong description',
469
+ ),
470
+ (
471
+ """
472
+ Short description
473
+ Long description
474
+ Second line
475
+ """,
476
+ 'Short description\nLong description\nSecond line',
477
+ ),
478
+ (
479
+ """
480
+ Short description
481
+ @meta: asd
482
+ """,
483
+ 'Short description\n@meta: asd',
484
+ ),
485
+ (
486
+ """
487
+ Short description
488
+ Long description
489
+ @meta: asd
490
+ """,
491
+ 'Short description\nLong description\n@meta: asd',
492
+ ),
493
+ (
494
+ """
495
+ Short description
496
+ First line
497
+ Second line
498
+ @meta: asd
499
+ """,
500
+ 'Short description\nFirst line\n Second line\n@meta: asd',
501
+ ),
502
+ (
503
+ """
504
+ Short description
505
+
506
+ First line
507
+ Second line
508
+ @meta: asd
509
+ """,
510
+ 'Short description\n'
511
+ '\n'
512
+ 'First line\n'
513
+ ' Second line\n'
514
+ '@meta: asd',
515
+ ),
516
+ (
517
+ """
518
+ Short description
519
+
520
+ First line
521
+ Second line
522
+
523
+ @meta: asd
524
+ """,
525
+ 'Short description\n'
526
+ '\n'
527
+ 'First line\n'
528
+ ' Second line\n'
529
+ '\n'
530
+ '@meta: asd',
531
+ ),
532
+ (
533
+ """
534
+ @meta: asd
535
+ """,
536
+ '@meta: asd',
537
+ ),
538
+ (
539
+ """
540
+ Short description
541
+
542
+ @meta: asd
543
+ 1
544
+ 2
545
+ 3
546
+ """,
547
+ 'Short description\n'
548
+ '\n'
549
+ '@meta: asd\n'
550
+ ' 1\n'
551
+ ' 2\n'
552
+ ' 3',
553
+ ),
554
+ (
555
+ """
556
+ Short description
557
+
558
+ @meta1: asd
559
+ 1
560
+ 2
561
+ 3
562
+ @meta2: herp
563
+ @meta3: derp
564
+ """,
565
+ 'Short description\n'
566
+ '\n@meta1: asd\n'
567
+ ' 1\n'
568
+ ' 2\n'
569
+ ' 3\n@meta2: herp\n'
570
+ '@meta3: derp',
571
+ ),
572
+ (
573
+ """
574
+ Short description
575
+
576
+ @meta ene due rabe: asd
577
+ """,
578
+ 'Short description\n\n@meta ene due rabe: asd',
579
+ ),
580
+ (
581
+ """
582
+ Short description
583
+
584
+ @param name: description 1
585
+ @param priority: description 2
586
+ @type priority: int
587
+ @param sender: description 3
588
+ @type sender: str?
589
+ @type message: str?
590
+ @param message: description 4, defaults to 'hello'
591
+ @type multiline: str?
592
+ @param multiline: long description 5,
593
+ defaults to 'bye'
594
+ """,
595
+ 'Short description\n'
596
+ '\n'
597
+ '@param name: description 1\n'
598
+ '@type priority: int\n'
599
+ '@param priority: description 2\n'
600
+ '@type sender: str?\n'
601
+ '@param sender: description 3\n'
602
+ '@type message: str?\n'
603
+ "@param message: description 4, defaults to 'hello'\n"
604
+ '@type multiline: str?\n'
605
+ '@param multiline: long description 5,\n'
606
+ " defaults to 'bye'",
607
+ ),
608
+ (
609
+ """
610
+ Short description
611
+ @raise: description
612
+ """,
613
+ 'Short description\n@raise: description',
614
+ ),
615
+ (
616
+ """
617
+ Short description
618
+ @raise ValueError: description
619
+ """,
620
+ 'Short description\n@raise ValueError: description',
621
+ ),
622
+ ],
623
+ )
624
+ def test_compose(source: str, expected: str) -> None:
625
+ """Test compose in default mode."""
626
+ assert compose(parse(source)) == expected
627
+
628
+
629
+ @pytest.mark.parametrize(
630
+ 'source, expected',
631
+ [
632
+ (
633
+ """
634
+ Short description
635
+
636
+ @param name: description 1
637
+ @param priority: description 2
638
+ @type priority: int
639
+ @param sender: description 3
640
+ @type sender: str?
641
+ @type message: str?
642
+ @param message: description 4, defaults to 'hello'
643
+ @type multiline: str?
644
+ @param multiline: long description 5,
645
+ defaults to 'bye'
646
+ """,
647
+ 'Short description\n'
648
+ '\n'
649
+ '@param name:\n'
650
+ ' description 1\n'
651
+ '@type priority: int\n'
652
+ '@param priority:\n'
653
+ ' description 2\n'
654
+ '@type sender: str?\n'
655
+ '@param sender:\n'
656
+ ' description 3\n'
657
+ '@type message: str?\n'
658
+ '@param message:\n'
659
+ " description 4, defaults to 'hello'\n"
660
+ '@type multiline: str?\n'
661
+ '@param multiline:\n'
662
+ ' long description 5,\n'
663
+ " defaults to 'bye'",
664
+ ),
665
+ ],
666
+ )
667
+ def test_compose_clean(source: str, expected: str) -> None:
668
+ """Test compose in clean mode."""
669
+ assert (
670
+ compose(parse(source), rendering_style=RenderingStyle.CLEAN)
671
+ == expected
672
+ )
673
+
674
+
675
+ @pytest.mark.parametrize(
676
+ 'source, expected',
677
+ [
678
+ (
679
+ """
680
+ Short description
681
+
682
+ @param name: description 1
683
+ @param priority: description 2
684
+ @type priority: int
685
+ @param sender: description 3
686
+ @type sender: str?
687
+ @type message: str?
688
+ @param message: description 4, defaults to 'hello'
689
+ @type multiline: str?
690
+ @param multiline: long description 5,
691
+ defaults to 'bye'
692
+ """,
693
+ 'Short description\n'
694
+ '\n'
695
+ '@param name:\n'
696
+ ' description 1\n'
697
+ '@type priority:\n'
698
+ ' int\n'
699
+ '@param priority:\n'
700
+ ' description 2\n'
701
+ '@type sender:\n'
702
+ ' str?\n'
703
+ '@param sender:\n'
704
+ ' description 3\n'
705
+ '@type message:\n'
706
+ ' str?\n'
707
+ '@param message:\n'
708
+ " description 4, defaults to 'hello'\n"
709
+ '@type multiline:\n'
710
+ ' str?\n'
711
+ '@param multiline:\n'
712
+ ' long description 5,\n'
713
+ " defaults to 'bye'",
714
+ ),
715
+ ],
716
+ )
717
+ def test_compose_expanded(source: str, expected: str) -> None:
718
+ """Test compose in expanded mode."""
719
+ assert (
720
+ compose(parse(source), rendering_style=RenderingStyle.EXPANDED)
721
+ == expected
722
+ )
723
+
724
+
725
+ def test_short_rtype() -> None:
726
+ """Test abbreviated docstring with only return type information."""
727
+ string = 'Short description.\n\n@rtype: float'
728
+ docstring = parse(string)
729
+ assert compose(docstring) == string