rencode 1.0.7__tar.gz → 1.0.9__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.
@@ -0,0 +1,5 @@
1
+ include COPYING
2
+ include README.md
3
+ include SPEC.md
4
+ include tests/*.py
5
+ include rencode/_rencode.pyx
rencode-1.0.9/PKG-INFO ADDED
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: rencode
3
+ Version: 1.0.9
4
+ Summary: rencode is an object serialization library similar to bencode from the Bittorrent project.
5
+ Author-email: Andrew Resch <andrewresch@gmail.com>
6
+ License-Expression: GPL-3.0-only
7
+ Project-URL: Homepage, https://github.com/aresch/rencode
8
+ Project-URL: Repository, https://github.com/aresch/rencode
9
+ Project-URL: Issues, https://github.com/aresch/rencode/issues
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Cython
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: COPYING
26
+ Provides-Extra: dev
27
+ Requires-Dist: cython>=3.0.0; extra == "dev"
28
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
29
+ Requires-Dist: black>=24.0.0; extra == "dev"
30
+ Requires-Dist: line-profiler>=4.2.0; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # rencode
34
+
35
+ The rencode module is similar to bencode from the BitTorrent project. For complex, heterogeneous data structures with many small elements, r-encodings take up significantly less space than b-encodings:
36
+
37
+ ```
38
+ >>> len(rencode.dumps({'a':0, 'b':[1,2], 'c':99}))
39
+ 13
40
+
41
+ >>> len(bencode.bencode({'a':0, 'b':[1,2], 'c':99}))
42
+ 26
43
+ ```
44
+
45
+ This version of rencode is a complete rewrite in Cython to attempt to increase the performance over the pure Python module written by Petru Paler, Connelly Barnes et al.
46
+
47
+ ## Data Format
48
+ See [SPEC](SPEC.md)
49
+
50
+ ## Performance Comparison
51
+ The test program used for these results is included in the repository:
52
+ https://github.com/aresch/rencode/blob/master/tests/timetest.py
53
+
54
+ ### Encode functions
55
+ ```
56
+ test_encode_fixed_pos_int:
57
+ rencode.pyx: 0.003s (+0.013s) 589.17%
58
+ rencode.py: 0.016s
59
+
60
+ test_encode_int_int_size:
61
+ rencode.pyx: 0.006s (+0.032s) 625.99%
62
+ rencode.py: 0.038s
63
+
64
+ test_encode_int_long_long_size:
65
+ rencode.pyx: 0.014s (+0.026s) 279.96%
66
+ rencode.py: 0.040s
67
+
68
+ test_encode_int_short_size:
69
+ rencode.pyx: 0.006s (+0.030s) 629.80%
70
+ rencode.py: 0.036s
71
+
72
+ test_encode_str:
73
+ rencode.pyx: 0.006s (+0.010s) 263.96%
74
+ rencode.py: 0.017s
75
+
76
+ test_encode_dict:
77
+ rencode.pyx: 0.135s (+0.302s) 324.68%
78
+ rencode.py: 0.437s
79
+
80
+ test_encode_fixed_list:
81
+ rencode.pyx: 0.012s (+0.025s) 307.78%
82
+ rencode.py: 0.037s
83
+
84
+ test_encode_fixed_neg_int:
85
+ rencode.pyx: 0.003s (+0.012s) 536.97%
86
+ rencode.py: 0.015s
87
+
88
+ test_encode_fixed_dict:
89
+ rencode.pyx: 0.046s (+0.105s) 331.07%
90
+ rencode.py: 0.151s
91
+
92
+ test_encode_int_char_size:
93
+ rencode.pyx: 0.005s (+0.029s) 687.64%
94
+ rencode.py: 0.034s
95
+
96
+ test_encode_fixed_str:
97
+ rencode.pyx: 0.003s (+0.011s) 438.07%
98
+ rencode.py: 0.015s
99
+
100
+ test_encode_list:
101
+ rencode.pyx: 0.148s (+0.228s) 253.68%
102
+ rencode.py: 0.376s
103
+
104
+ test_encode_none:
105
+ rencode.pyx: 0.004s (+0.011s) 386.06%
106
+ rencode.py: 0.014s
107
+
108
+ test_encode_int_big_number:
109
+ rencode.pyx: 0.011s (+0.019s) 264.32%
110
+ rencode.py: 0.030s
111
+
112
+ test_encode_float_64bit:
113
+ rencode.pyx: 0.003s (+0.011s) 416.19%
114
+ rencode.py: 0.014s
115
+
116
+ test_encode_bool:
117
+ rencode.pyx: 0.004s (+0.014s) 447.57%
118
+ rencode.py: 0.018s
119
+
120
+ test_encode_float_32bit:
121
+ rencode.pyx: 0.003s (+0.010s) 417.86%
122
+ rencode.py: 0.014s
123
+
124
+ Encode functions totals:
125
+ rencode.pyx: 0.412s (+0.888s) 315.49%
126
+ rencode.py: 1.301s
127
+ ```
128
+ ### Decode functions
129
+
130
+ ```
131
+ test_decode_fixed_list:
132
+ rencode.pyx: 0.003s (+0.020s) 848.67%
133
+ rencode.py: 0.022s
134
+
135
+ test_decode_int_long_long_size:
136
+ rencode.pyx: 0.003s (+0.013s) 484.80%
137
+ rencode.py: 0.016s
138
+
139
+ test_decode_dict:
140
+ rencode.pyx: 0.267s (+0.406s) 251.81%
141
+ rencode.py: 0.673s
142
+
143
+ test_decode_fixed_dict:
144
+ rencode.pyx: 0.087s (+0.123s) 241.32%
145
+ rencode.py: 0.211s
146
+
147
+ test_decode_float_32bit:
148
+ rencode.pyx: 0.002s (+0.007s) 536.88%
149
+ rencode.py: 0.009s
150
+
151
+ test_decode_int_big_number:
152
+ rencode.pyx: 0.007s (+0.010s) 256.05%
153
+ rencode.py: 0.017s
154
+
155
+ test_decode_int_char_size:
156
+ rencode.pyx: 0.002s (+0.014s) 754.12%
157
+ rencode.py: 0.016s
158
+
159
+ test_decode_fixed_neg_int:
160
+ rencode.pyx: 0.001s (+0.004s) 389.03%
161
+ rencode.py: 0.006s
162
+
163
+ test_decode_fixed_str:
164
+ rencode.pyx: 0.009s (+0.009s) 199.78%
165
+ rencode.py: 0.019s
166
+
167
+ test_decode_float_64bit:
168
+ rencode.pyx: 0.002s (+0.007s) 540.17%
169
+ rencode.py: 0.009s
170
+
171
+ test_decode_bool:
172
+ rencode.pyx: 0.002s (+0.004s) 369.49%
173
+ rencode.py: 0.006s
174
+
175
+ test_decode_fixed_pos_int:
176
+ rencode.pyx: 0.002s (+0.004s) 368.96%
177
+ rencode.py: 0.006s
178
+
179
+ test_decode_list:
180
+ rencode.pyx: 0.019s (+0.247s) 1403.77%
181
+ rencode.py: 0.266s
182
+
183
+ test_decode_none:
184
+ rencode.pyx: 0.002s (+0.004s) 367.05%
185
+ rencode.py: 0.006s
186
+
187
+ test_decode_int_short_size:
188
+ rencode.pyx: 0.002s (+0.014s) 716.47%
189
+ rencode.py: 0.016s
190
+
191
+ test_decode_str:
192
+ rencode.pyx: 0.010s (+0.026s) 364.51%
193
+ rencode.py: 0.036s
194
+
195
+ test_decode_int_int_size:
196
+ rencode.pyx: 0.002s (+0.014s) 705.92%
197
+ rencode.py: 0.016s
198
+
199
+ Decode functions totals:
200
+ rencode.pyx: 0.421s (+0.926s) 319.79%
201
+ rencode.py: 1.348s
202
+ ```
203
+
204
+ ### Overall functions
205
+
206
+ ```
207
+ test_overall_encode:
208
+ rencode.pyx: 0.069s (+0.120s) 274.42%
209
+ rencode.py: 0.189s
210
+
211
+ test_overall_decode:
212
+ rencode.pyx: 0.051s (+0.153s) 400.57%
213
+ rencode.py: 0.204s
214
+
215
+ Overall functions totals:
216
+ rencode.pyx: 0.120s (+0.273s) 327.98%
217
+ rencode.py: 0.393s
218
+ ```
219
+
220
+
221
+ ## Author
222
+ * Andrew Resch <andrewresch@gmail.com>
223
+ * Website: https://github.com/aresch/rencode
224
+
225
+ ## License
226
+ See [COPYING](https://github.com/aresch/rencode/blob/master/COPYING) for license information.
@@ -0,0 +1,194 @@
1
+ # rencode
2
+
3
+ The rencode module is similar to bencode from the BitTorrent project. For complex, heterogeneous data structures with many small elements, r-encodings take up significantly less space than b-encodings:
4
+
5
+ ```
6
+ >>> len(rencode.dumps({'a':0, 'b':[1,2], 'c':99}))
7
+ 13
8
+
9
+ >>> len(bencode.bencode({'a':0, 'b':[1,2], 'c':99}))
10
+ 26
11
+ ```
12
+
13
+ This version of rencode is a complete rewrite in Cython to attempt to increase the performance over the pure Python module written by Petru Paler, Connelly Barnes et al.
14
+
15
+ ## Data Format
16
+ See [SPEC](SPEC.md)
17
+
18
+ ## Performance Comparison
19
+ The test program used for these results is included in the repository:
20
+ https://github.com/aresch/rencode/blob/master/tests/timetest.py
21
+
22
+ ### Encode functions
23
+ ```
24
+ test_encode_fixed_pos_int:
25
+ rencode.pyx: 0.003s (+0.013s) 589.17%
26
+ rencode.py: 0.016s
27
+
28
+ test_encode_int_int_size:
29
+ rencode.pyx: 0.006s (+0.032s) 625.99%
30
+ rencode.py: 0.038s
31
+
32
+ test_encode_int_long_long_size:
33
+ rencode.pyx: 0.014s (+0.026s) 279.96%
34
+ rencode.py: 0.040s
35
+
36
+ test_encode_int_short_size:
37
+ rencode.pyx: 0.006s (+0.030s) 629.80%
38
+ rencode.py: 0.036s
39
+
40
+ test_encode_str:
41
+ rencode.pyx: 0.006s (+0.010s) 263.96%
42
+ rencode.py: 0.017s
43
+
44
+ test_encode_dict:
45
+ rencode.pyx: 0.135s (+0.302s) 324.68%
46
+ rencode.py: 0.437s
47
+
48
+ test_encode_fixed_list:
49
+ rencode.pyx: 0.012s (+0.025s) 307.78%
50
+ rencode.py: 0.037s
51
+
52
+ test_encode_fixed_neg_int:
53
+ rencode.pyx: 0.003s (+0.012s) 536.97%
54
+ rencode.py: 0.015s
55
+
56
+ test_encode_fixed_dict:
57
+ rencode.pyx: 0.046s (+0.105s) 331.07%
58
+ rencode.py: 0.151s
59
+
60
+ test_encode_int_char_size:
61
+ rencode.pyx: 0.005s (+0.029s) 687.64%
62
+ rencode.py: 0.034s
63
+
64
+ test_encode_fixed_str:
65
+ rencode.pyx: 0.003s (+0.011s) 438.07%
66
+ rencode.py: 0.015s
67
+
68
+ test_encode_list:
69
+ rencode.pyx: 0.148s (+0.228s) 253.68%
70
+ rencode.py: 0.376s
71
+
72
+ test_encode_none:
73
+ rencode.pyx: 0.004s (+0.011s) 386.06%
74
+ rencode.py: 0.014s
75
+
76
+ test_encode_int_big_number:
77
+ rencode.pyx: 0.011s (+0.019s) 264.32%
78
+ rencode.py: 0.030s
79
+
80
+ test_encode_float_64bit:
81
+ rencode.pyx: 0.003s (+0.011s) 416.19%
82
+ rencode.py: 0.014s
83
+
84
+ test_encode_bool:
85
+ rencode.pyx: 0.004s (+0.014s) 447.57%
86
+ rencode.py: 0.018s
87
+
88
+ test_encode_float_32bit:
89
+ rencode.pyx: 0.003s (+0.010s) 417.86%
90
+ rencode.py: 0.014s
91
+
92
+ Encode functions totals:
93
+ rencode.pyx: 0.412s (+0.888s) 315.49%
94
+ rencode.py: 1.301s
95
+ ```
96
+ ### Decode functions
97
+
98
+ ```
99
+ test_decode_fixed_list:
100
+ rencode.pyx: 0.003s (+0.020s) 848.67%
101
+ rencode.py: 0.022s
102
+
103
+ test_decode_int_long_long_size:
104
+ rencode.pyx: 0.003s (+0.013s) 484.80%
105
+ rencode.py: 0.016s
106
+
107
+ test_decode_dict:
108
+ rencode.pyx: 0.267s (+0.406s) 251.81%
109
+ rencode.py: 0.673s
110
+
111
+ test_decode_fixed_dict:
112
+ rencode.pyx: 0.087s (+0.123s) 241.32%
113
+ rencode.py: 0.211s
114
+
115
+ test_decode_float_32bit:
116
+ rencode.pyx: 0.002s (+0.007s) 536.88%
117
+ rencode.py: 0.009s
118
+
119
+ test_decode_int_big_number:
120
+ rencode.pyx: 0.007s (+0.010s) 256.05%
121
+ rencode.py: 0.017s
122
+
123
+ test_decode_int_char_size:
124
+ rencode.pyx: 0.002s (+0.014s) 754.12%
125
+ rencode.py: 0.016s
126
+
127
+ test_decode_fixed_neg_int:
128
+ rencode.pyx: 0.001s (+0.004s) 389.03%
129
+ rencode.py: 0.006s
130
+
131
+ test_decode_fixed_str:
132
+ rencode.pyx: 0.009s (+0.009s) 199.78%
133
+ rencode.py: 0.019s
134
+
135
+ test_decode_float_64bit:
136
+ rencode.pyx: 0.002s (+0.007s) 540.17%
137
+ rencode.py: 0.009s
138
+
139
+ test_decode_bool:
140
+ rencode.pyx: 0.002s (+0.004s) 369.49%
141
+ rencode.py: 0.006s
142
+
143
+ test_decode_fixed_pos_int:
144
+ rencode.pyx: 0.002s (+0.004s) 368.96%
145
+ rencode.py: 0.006s
146
+
147
+ test_decode_list:
148
+ rencode.pyx: 0.019s (+0.247s) 1403.77%
149
+ rencode.py: 0.266s
150
+
151
+ test_decode_none:
152
+ rencode.pyx: 0.002s (+0.004s) 367.05%
153
+ rencode.py: 0.006s
154
+
155
+ test_decode_int_short_size:
156
+ rencode.pyx: 0.002s (+0.014s) 716.47%
157
+ rencode.py: 0.016s
158
+
159
+ test_decode_str:
160
+ rencode.pyx: 0.010s (+0.026s) 364.51%
161
+ rencode.py: 0.036s
162
+
163
+ test_decode_int_int_size:
164
+ rencode.pyx: 0.002s (+0.014s) 705.92%
165
+ rencode.py: 0.016s
166
+
167
+ Decode functions totals:
168
+ rencode.pyx: 0.421s (+0.926s) 319.79%
169
+ rencode.py: 1.348s
170
+ ```
171
+
172
+ ### Overall functions
173
+
174
+ ```
175
+ test_overall_encode:
176
+ rencode.pyx: 0.069s (+0.120s) 274.42%
177
+ rencode.py: 0.189s
178
+
179
+ test_overall_decode:
180
+ rencode.pyx: 0.051s (+0.153s) 400.57%
181
+ rencode.py: 0.204s
182
+
183
+ Overall functions totals:
184
+ rencode.pyx: 0.120s (+0.273s) 327.98%
185
+ rencode.py: 0.393s
186
+ ```
187
+
188
+
189
+ ## Author
190
+ * Andrew Resch <andrewresch@gmail.com>
191
+ * Website: https://github.com/aresch/rencode
192
+
193
+ ## License
194
+ See [COPYING](https://github.com/aresch/rencode/blob/master/COPYING) for license information.
rencode-1.0.9/SPEC.md ADDED
@@ -0,0 +1,96 @@
1
+ # rencode Data Format Specification
2
+
3
+ ## Overview
4
+
5
+ rencode uses a single-byte type code system to identify different data types, with some types having their values embedded directly in the type code for space efficiency. The format is designed to be compact while maintaining good performance.
6
+
7
+ ## Type Codes
8
+
9
+ ### Fixed Integers (Positive)
10
+ - Range: 0 to 43
11
+ - Type code: `0x00` to `0x2B` (INT_POS_FIXED_START to INT_POS_FIXED_START + INT_POS_FIXED_COUNT - 1)
12
+ - Value is embedded in type code
13
+
14
+ ### Fixed Integers (Negative)
15
+ - Range: -1 to -32
16
+ - Type code: `0x46` to `0x65` (INT_NEG_FIXED_START to INT_NEG_FIXED_START + INT_NEG_FIXED_COUNT - 1)
17
+ - Value is embedded in type code
18
+
19
+ ### Variable Length Integers
20
+ - 8-bit signed integer: `0x3E` (CHR_INT1) followed by 1 byte
21
+ - 16-bit signed integer: `0x3F` (CHR_INT2) followed by 2 bytes
22
+ - 32-bit signed integer: `0x40` (CHR_INT4) followed by 4 bytes
23
+ - 64-bit signed integer: `0x41` (CHR_INT8) followed by 8 bytes
24
+ - Big number: `0x3D` (CHR_INT) followed by ASCII string and `0x7F` (CHR_TERM)
25
+
26
+ ### Floating Point Numbers
27
+ - 32-bit float: `0x42` (CHR_FLOAT32) followed by 4 bytes
28
+ - 64-bit float: `0x2C` (CHR_FLOAT64) followed by 8 bytes
29
+
30
+ ### Strings
31
+ - Fixed length strings (1-64 bytes): `0x80` to `0xBF` (STR_FIXED_START to STR_FIXED_START + STR_FIXED_COUNT - 1)
32
+ - Variable length strings: ASCII length followed by `:` and string data
33
+
34
+ ### Lists
35
+ - Fixed length lists (1-64 items): `0xC0` to `0xFF` (LIST_FIXED_START to LIST_FIXED_START + LIST_FIXED_COUNT - 1)
36
+ - Variable length lists: `0x3B` (CHR_LIST) followed by items and `0x7F` (CHR_TERM)
37
+
38
+ ### Dictionaries
39
+ - Fixed length dictionaries (1-25 items): `0x66` to `0x7E` (DICT_FIXED_START to DICT_FIXED_START + DICT_FIXED_COUNT - 1)
40
+ - Variable length dictionaries: `0x3C` (CHR_DICT) followed by key-value pairs and `0x7F` (CHR_TERM)
41
+
42
+ ### Special Values
43
+ - `None`: `0x45` (CHR_NONE)
44
+ - `True`: `0x43` (CHR_TRUE)
45
+ - `False`: `0x44` (CHR_FALSE)
46
+
47
+ ## Byte Order
48
+
49
+ All multi-byte values (integers, floats) are stored in network byte order (big-endian). The implementation automatically handles byte order conversion on little-endian systems.
50
+
51
+ ## String Encoding
52
+
53
+ - By default, strings (str) are stored as UTF-8 encoded bytes
54
+ - When `decode_utf8=True` is specified, bytes are decoded from UTF-8 to Python strings (str) during decoding
55
+
56
+ ## Limitations
57
+
58
+ - Maximum integer length when written as ASCII string: 64 characters
59
+ - Maximum fixed string length: 64 bytes
60
+ - Maximum fixed list length: 64 items
61
+ - Maximum fixed dictionary length: 25 items
62
+
63
+ ## Examples
64
+
65
+ ```
66
+ 1 -> 0x01
67
+ 40 -> 0x28
68
+ -10 -> 0x4F
69
+ -29 -> 0x62
70
+ 100 -> 0x3E 0x64
71
+ -100 -> 0x3E 0x9C
72
+ 27123 -> 0x3F 0x69 0xF3
73
+ -27123 -> 0x3F 0x96 0x0D
74
+ 7483648 -> 0x40 0x00 0x72 0x31 0x00
75
+ -7483648 -> 0x40 0xFF 0x8D 0xCF 0x00
76
+ 1234.56 -> 0x42 0x44 0x9A 0x51 0xEC
77
+ "foobar" -> 0x86 0x66 0x6F 0x6F 0x62 0x61 0x72
78
+ "f" * 255 -> "255:" + "f" * 255
79
+
80
+ # Fixed length list (3 items)
81
+ [1, 2, 3] -> 0xC3 0x01 0x02 0x03
82
+
83
+ # Variable length list (terminated)
84
+ [1, 2, 3] -> 0x3B 0x01 0x02 0x03 0x7F
85
+
86
+ # Fixed length dict (1 item)
87
+ {"a": 1} -> 0x67 0x81 0x61 0x01
88
+
89
+ # Variable length dict (terminated)
90
+ {"a": 1} -> 0x3C 0x81 0x61 0x01 0x7F
91
+
92
+ None -> 0x45
93
+ True -> 0x43
94
+ False -> 0x44
95
+ ```
96
+
@@ -0,0 +1,62 @@
1
+ [project]
2
+ name = "rencode"
3
+ version = "1.0.9"
4
+ description = "rencode is an object serialization library similar to bencode from the Bittorrent project."
5
+ readme = "README.md"
6
+ license = "GPL-3.0-only"
7
+ requires-python = ">=3.9"
8
+ authors = [
9
+ {name = "Andrew Resch", email = "andrewresch@gmail.com"},
10
+ ]
11
+ classifiers = [
12
+ "Development Status :: 5 - Production/Stable",
13
+ "Intended Audience :: Developers",
14
+ "Operating System :: OS Independent",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3 :: Only",
17
+ "Programming Language :: Python :: 3.9",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Programming Language :: Python :: 3.14",
23
+ "Programming Language :: Cython",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ ]
26
+ dependencies = []
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/aresch/rencode"
30
+ Repository = "https://github.com/aresch/rencode"
31
+ Issues = "https://github.com/aresch/rencode/issues"
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "cython>=3.0.0",
36
+ "pytest>=8.0.0",
37
+ "black>=24.0.0",
38
+ "line-profiler>=4.2.0",
39
+ ]
40
+
41
+ [dependency-groups]
42
+ dev = [
43
+ "cython>=3.0.0",
44
+ "pytest>=8.0.0",
45
+ "black>=24.0.0",
46
+ "line-profiler>=4.2.0",
47
+ ]
48
+
49
+ [build-system]
50
+ requires = ["setuptools>=64.0.0", "cython>=3.0.0"]
51
+ build-backend = "setuptools.build_meta"
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["."]
55
+ include = ["rencode*"]
56
+
57
+ [tool.setuptools.exclude-package-data]
58
+ rencode = ["*.c", "*.pyx"]
59
+
60
+ [tool.pytest.ini_options]
61
+ testpaths = ["tests"]
62
+