scipy-doctest 1.2.0__tar.gz → 1.4__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.
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/PKG-INFO +130 -105
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/README.md +127 -102
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/pyproject.toml +1 -1
- scipy_doctest-1.4/scipy_doctest/__init__.py +22 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/impl.py +36 -4
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/failure_cases.py +8 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/local_file_cases.py +1 -1
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/test_pytest_configuration.py +1 -3
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/test_skipmarkers.py +18 -1
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/test_testmod.py +10 -0
- scipy_doctest-1.2.0/scipy_doctest/__init__.py +0 -12
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/LICENSE +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/__main__.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/conftest.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/frontend.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/plugin.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/__init__.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/failure_cases_2.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/finder_cases.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/local_file.txt +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/module_cases.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/octave_a.mat +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/scipy_ndimage_tutorial_clone.rst +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/stopwords_cases.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/test_finder.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/test_parser.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/test_runner.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/test_testfile.py +0 -0
- {scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/util.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: scipy_doctest
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.4
|
|
4
|
+
Summary: Configurable, whitespace-insensitive, floating-point-aware doctest helpers.
|
|
5
5
|
Maintainer-email: SciPy developers <scipy-dev@python.org>
|
|
6
6
|
Requires-Python: >=3.8
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
@@ -14,7 +14,7 @@ Requires-Dist: numpy>=1.19.5
|
|
|
14
14
|
Requires-Dist: pytest
|
|
15
15
|
Requires-Dist: scipy ; extra == "test"
|
|
16
16
|
Requires-Dist: matplotlib ; extra == "test"
|
|
17
|
-
Project-URL: Home, https://github.com/
|
|
17
|
+
Project-URL: Home, https://github.com/scipy/scipy_doctest
|
|
18
18
|
Provides-Extra: test
|
|
19
19
|
|
|
20
20
|
# Floating-point aware, human readable, numpy-compatible doctesting.
|
|
@@ -67,8 +67,8 @@ Its main features are
|
|
|
67
67
|
>>> np.random.randint(100)
|
|
68
68
|
42 # may vary
|
|
69
69
|
```
|
|
70
|
-
Note that the markers (by default, `"# may vary"` and `"# random"`)
|
|
71
|
-
to an example's output,
|
|
70
|
+
Note that the markers (by default, `"# may vary"` and `"# random"`) can be applied
|
|
71
|
+
to either an example's output, or its source.
|
|
72
72
|
|
|
73
73
|
Also note a difference with respect to the standard `# doctest: +SKIP`: the latter
|
|
74
74
|
skips the example entirely, while these additional markers only skip checking
|
|
@@ -100,7 +100,7 @@ the output. Thus the example source needs to be valid python code still.
|
|
|
100
100
|
## Install and test
|
|
101
101
|
|
|
102
102
|
```
|
|
103
|
-
$ pip install -
|
|
103
|
+
$ pip install scipy-doctest
|
|
104
104
|
$ pytest --pyargs scipy_doctest
|
|
105
105
|
```
|
|
106
106
|
|
|
@@ -112,9 +112,56 @@ or nearly so.
|
|
|
112
112
|
|
|
113
113
|
The other layer is the `pytest` plugin.
|
|
114
114
|
|
|
115
|
+
### Run doctests via pytest
|
|
116
|
+
|
|
117
|
+
To run doctests on your package or project, follow these steps:
|
|
118
|
+
|
|
119
|
+
1. **Install the plugin**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pip install scipy-doctest
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
2. **Register or load the plugin**
|
|
126
|
+
|
|
127
|
+
Next, you need to register or load the pytest plugin within your test module or `conftest.py` file.
|
|
128
|
+
|
|
129
|
+
To do this, add the following line of code:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
# In your conftest.py file or test module
|
|
133
|
+
|
|
134
|
+
pytest_plugins = "scipy_doctest"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Check out the [pytest documentation](https://docs.pytest.org/en/stable/how-to/writing_plugins.html#requiring-loading-plugins-in-a-test-module-or-conftest-file) for more information on requiring/loading plugins in a test module or `conftest.py` file.
|
|
138
|
+
|
|
139
|
+
3. **Run doctests**
|
|
140
|
+
|
|
141
|
+
Once the plugin is registered, run the doctests by executing the following command:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
$ python -m pytest --doctest-modules
|
|
145
|
+
```
|
|
146
|
+
or
|
|
147
|
+
```bash
|
|
148
|
+
$ pytest --pyargs <your-package> --doctest-modules
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
By default, all doctests are collected. To only collect public objects, `strategy="api"`,
|
|
152
|
+
use the command flag
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
$ pytest --pyargs <your-package> --doctest-modules --doctest-collect=api
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
See [More fine-grained control](https://github.com/scipy/scipy_doctest#More-fine-grained-control) section
|
|
159
|
+
for details on how to customize the behavior.
|
|
160
|
+
|
|
115
161
|
|
|
116
162
|
### Basic usage
|
|
117
163
|
|
|
164
|
+
The use of `pytest` is optional, and you can use the `doctest` layer API.
|
|
118
165
|
For example,
|
|
119
166
|
|
|
120
167
|
```
|
|
@@ -131,7 +178,8 @@ For more details, see the `testmod` docstring. Other useful functions are
|
|
|
131
178
|
`find_doctests`, `run_docstring_examples` and `testfile` (the latter two mimic
|
|
132
179
|
the behavior of the eponymous functions of the `doctest` module).
|
|
133
180
|
|
|
134
|
-
|
|
181
|
+
|
|
182
|
+
### Command-line interface
|
|
135
183
|
|
|
136
184
|
There is a basic CLI, which also mimics that of the `doctest` module:
|
|
137
185
|
```
|
|
@@ -146,8 +194,10 @@ Text files can also be CLI-checked:
|
|
|
146
194
|
$ python -m scipy_doctest bar.rst
|
|
147
195
|
```
|
|
148
196
|
|
|
197
|
+
Notice that the command-line usage only uses the default `DTConfig` settings.
|
|
198
|
+
|
|
149
199
|
|
|
150
|
-
|
|
200
|
+
## More fine-grained control
|
|
151
201
|
|
|
152
202
|
More fine-grained control of the functionality is available via the following
|
|
153
203
|
classes
|
|
@@ -166,133 +216,98 @@ configuration is simply creating an instance, overriding an attribute and
|
|
|
166
216
|
passing the instance to `testmod` or constructors of `DT*` objects. Defaults
|
|
167
217
|
are provided, based on a long-term usage in SciPy.
|
|
168
218
|
|
|
219
|
+
See the [DTConfig docstring](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/impl.py#L24)
|
|
220
|
+
for the full set of attributes that allow you to fine-tune your doctesting experience.
|
|
169
221
|
|
|
170
|
-
|
|
222
|
+
To set any of these attributes, create an instance of `DTConfig` and assign the attributes
|
|
223
|
+
in a usual way.
|
|
171
224
|
|
|
172
|
-
|
|
225
|
+
If using the pytest plugin, it is convenient to use the default instance, which
|
|
226
|
+
is predefined in `scipy_doctest/conftest.py`. This instance will be automatically
|
|
227
|
+
passed around via an
|
|
228
|
+
[attribute of pytest's `Config` object](https://github.com/scipy/scipy_doctest/blob/58ff06a837b7bff1dbac6560013fc6fd07952ae2/scipy_doctest/plugin.py#L39).
|
|
173
229
|
|
|
174
|
-
|
|
230
|
+
### Examples
|
|
175
231
|
|
|
176
|
-
### Running Doctests on SciPy
|
|
177
|
-
|
|
178
|
-
1. **Install plugin**
|
|
179
|
-
|
|
180
|
-
```bash
|
|
181
|
-
pip install scipy-doctest
|
|
182
232
|
```
|
|
183
|
-
|
|
184
|
-
2. **Configure Your Doctesting Experience**
|
|
185
|
-
|
|
186
|
-
To tailor your doctesting experience, you can utilize an instance of `DTConfig`.
|
|
187
|
-
An in-depth explanation is given in the [tailoring your doctesting experience](https://github.com/scipy/scipy_doctest#tailoring-your-doctesting-experience) section.
|
|
188
|
-
|
|
189
|
-
3. **Run Doctests**
|
|
190
|
-
|
|
191
|
-
Doctesting is configured to execute on SciPy using the `dev.py` module.
|
|
192
|
-
|
|
193
|
-
To run all doctests, use the following command:
|
|
194
|
-
```bash
|
|
195
|
-
python dev.py smoke-docs
|
|
233
|
+
dt_config = DTConfig()
|
|
196
234
|
```
|
|
197
235
|
|
|
198
|
-
|
|
236
|
+
or, if using pytest,
|
|
199
237
|
|
|
200
|
-
```
|
|
201
|
-
|
|
238
|
+
```python
|
|
239
|
+
from scipy_doctest.conftest import dt_config # a DTConfig instance with default settings
|
|
202
240
|
```
|
|
203
241
|
|
|
204
|
-
|
|
242
|
+
and then
|
|
205
243
|
|
|
206
|
-
If you want to run doctests on packages or projects other than SciPy, follow these steps:
|
|
207
|
-
|
|
208
|
-
1. **Install the plugin**
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
pip install scipy-doctest
|
|
212
244
|
```
|
|
245
|
+
dt_config.rndm_markers = {'# unintialized'}
|
|
213
246
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
Next, you need to register or load the pytest plugin within your test module or `conftest.py` file.
|
|
217
|
-
|
|
218
|
-
To do this, add the following line of code:
|
|
247
|
+
dt_config.stopwords = {'plt.', 'plt.hist', 'plt.show'}
|
|
219
248
|
|
|
220
|
-
|
|
221
|
-
|
|
249
|
+
dt_config.local_resources = {
|
|
250
|
+
'scipy_doctest.tests.local_file_cases.local_files': ['scipy_doctest/tests/local_file.txt'],
|
|
251
|
+
'scipy_doctest.tests.local_file_cases.sio': ['scipy_doctest/tests/octave_a.mat']
|
|
252
|
+
}
|
|
222
253
|
|
|
223
|
-
|
|
254
|
+
dt_config.skiplist = {
|
|
255
|
+
'scipy.special.sinc',
|
|
256
|
+
'scipy.misc.who',
|
|
257
|
+
'scipy.optimize.show_options'
|
|
258
|
+
}
|
|
224
259
|
```
|
|
225
260
|
|
|
226
|
-
|
|
261
|
+
If you don't set these attributes, the [default settings](https://github.com/scipy/scipy_doctest/blob/58ff06a837b7bff1dbac6560013fc6fd07952ae2/scipy_doctest/impl.py#L94) of the attributes are used.
|
|
227
262
|
|
|
228
|
-
3. **Configure your doctesting experience**
|
|
229
263
|
|
|
230
|
-
|
|
264
|
+
#### Alternative Checkers
|
|
231
265
|
|
|
232
|
-
|
|
266
|
+
By default, we use the floating-point aware `DTChecker`. If you want to use an
|
|
267
|
+
alternative checker, all you need to do is to define the corresponding class,
|
|
268
|
+
and add an attribute to the `DTConfig` instance. For example,
|
|
233
269
|
|
|
234
|
-
Once the plugin is registered, you can run your doctests by executing the following command:
|
|
235
270
|
|
|
236
|
-
```bash
|
|
237
|
-
$ python -m pytest --doctest-modules
|
|
238
271
|
```
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
272
|
+
class VanillaOutputChecker(doctest.OutputChecker):
|
|
273
|
+
"""doctest.OutputChecker to drop in for DTChecker.
|
|
274
|
+
|
|
275
|
+
LSP break: OutputChecker does not have __init__,
|
|
276
|
+
here we add it to agree with DTChecker.
|
|
277
|
+
"""
|
|
278
|
+
def __init__(self, config):
|
|
279
|
+
pass
|
|
242
280
|
```
|
|
243
281
|
|
|
244
|
-
|
|
245
|
-
use the command flag
|
|
282
|
+
and
|
|
246
283
|
|
|
247
|
-
```
|
|
248
|
-
|
|
284
|
+
```
|
|
285
|
+
dt_config = DTConfig()
|
|
286
|
+
dt_config.CheckerKlass = VanillaOutputChecker
|
|
249
287
|
```
|
|
250
288
|
|
|
251
|
-
|
|
289
|
+
See [a pytest example](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/tests/test_pytest_configuration.py#L63)
|
|
290
|
+
and [a doctest example](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/tests/test_runner.py#L94)
|
|
291
|
+
for more details.
|
|
252
292
|
|
|
253
|
-
[DTConfig](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/impl.py#L23) offers a variety of attributes that allow you to fine-tune your doctesting experience.
|
|
254
293
|
|
|
255
|
-
|
|
256
|
-
1. **default_namespace (dict):** Defines the namespace in which examples are executed.
|
|
257
|
-
2. **check_namespace (dict):** Specifies the namespace for conducting checks.
|
|
258
|
-
3. **rndm_markers (set):** Provides additional directives which act like `# doctest: + SKIP`.
|
|
259
|
-
4. **atol (float) and rtol (float):** Sets absolute and relative tolerances for validating doctest examples.
|
|
260
|
-
Specifically, it governs the check using `np.allclose(want, got, atol=atol, rtol=rtol)`.
|
|
261
|
-
5. **optionflags (int):** These are doctest option flags.
|
|
262
|
-
The default setting includes `NORMALIZE_WHITESPACE` | `ELLIPSIS` | `IGNORE_EXCEPTION_DETAIL`.
|
|
263
|
-
6. **stopwords (set):** If an example contains any of these stopwords, the output is not checked (though the source's validity is still assessed).
|
|
264
|
-
7. **pseudocode (list):** Lists strings that, when found in an example, result in no doctesting. This resembles the `# doctest +SKIP` directive and is useful for pseudocode blocks or similar cases.
|
|
265
|
-
8. **skiplist (set):** A list of names of objects with docstrings known to fail doctesting and are intentionally excluded from testing.
|
|
266
|
-
9. **user_context_mgr:** A context manager for running tests.
|
|
267
|
-
Typically, it is entered for each DocTest (especially in API documentation), ensuring proper testing isolation.
|
|
268
|
-
10. **local_resources (dict):** Specifies local files needed for specific tests. The format is `{test.name: list-of-files}`. File paths are relative to the path of `test.filename`.
|
|
269
|
-
11. **parse_namedtuples (bool):** Determines whether to perform a literal comparison (e.g., `TTestResult(pvalue=0.9, statistic=42)`) or extract and compare the tuple values (e.g., `(0.9, 42)`). The default is `True`.
|
|
270
|
-
12. **nameerror_after_exception (bool):** Controls whether subsequent examples in the same test, after one has failed, may raise spurious NameErrors. Set to `True` if you want to observe these errors or if your test is expected to raise NameErrors. The default is `False`.
|
|
294
|
+
### NumPy and SciPy wrappers
|
|
271
295
|
|
|
272
|
-
To set any of these attributes, create an instance of `DTConfig` called `dt_config`.
|
|
273
|
-
This instance is already set as an [attribute of pytest's `Config` object](https://github.com/scipy/scipy_doctest/blob/58ff06a837b7bff1dbac6560013fc6fd07952ae2/scipy_doctest/plugin.py#L39).
|
|
274
296
|
|
|
275
|
-
|
|
297
|
+
NumPy wraps `scipy-doctest` with the `spin` command
|
|
276
298
|
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
dt_config.stopwords = {'plt.', '.hist', '.show'}
|
|
280
|
-
dt_config.local_resources = {
|
|
281
|
-
'scipy_doctest.tests.local_file_cases.local_files': ['scipy_doctest/tests/local_file.txt'],
|
|
282
|
-
'scipy_doctest.tests.local_file_cases.sio': ['scipy_doctest/tests/octave_a.mat']
|
|
283
|
-
}
|
|
284
|
-
dt_config.skiplist = {
|
|
285
|
-
'scipy.special.sinc',
|
|
286
|
-
'scipy.misc.who',
|
|
287
|
-
'scipy.optimize.show_options'
|
|
288
|
-
}
|
|
299
|
+
```
|
|
300
|
+
$ spin check-docs
|
|
289
301
|
```
|
|
290
302
|
|
|
291
|
-
|
|
303
|
+
SciPy wraps `scipy-doctest` with custom `dev.py` commands:
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
$ python dev.py smoke-docs # check docstrings
|
|
307
|
+
$ python dev.py smoke-tutorials # ReST user guide tutorials
|
|
308
|
+
```
|
|
292
309
|
|
|
293
|
-
By following these steps, you will be able to effectively use the SciPy Doctest pytest plugin for doctests in your Python projects.
|
|
294
310
|
|
|
295
|
-
Happy testing!
|
|
296
311
|
|
|
297
312
|
## Rough edges and sharp bits
|
|
298
313
|
|
|
@@ -326,7 +341,7 @@ being optional. So you either guard the imports in doctests (yikes!), or
|
|
|
326
341
|
the collections fails if dependencies are not available.
|
|
327
342
|
|
|
328
343
|
The solution is to explicitly `--ignore` the paths to modules with optionals.
|
|
329
|
-
(or use `DTConfig.pytest_extra_ignore` list):
|
|
344
|
+
(or, equivalently, use `DTConfig.pytest_extra_ignore` list):
|
|
330
345
|
|
|
331
346
|
```
|
|
332
347
|
$ pytest --ignore=/build-install/lib/scipy/python3.10/site-packages/scipy/_lib ...
|
|
@@ -361,6 +376,19 @@ leads to
|
|
|
361
376
|
- `scipy.linalg.det`, collected from `scipy/linalg/__init__.py`, is public.
|
|
362
377
|
|
|
363
378
|
|
|
379
|
+
- *`pytest`'s assertion rewriting*
|
|
380
|
+
|
|
381
|
+
In some rare cases you may need to either explicitly register the `scipy_doctest`
|
|
382
|
+
package with the `pytest` assertion rewriting machinery, or ask it to avoid rewriting
|
|
383
|
+
completely, via `pytest --assert=plain`.
|
|
384
|
+
See [the `pytest documentation`](https://docs.pytest.org/en/7.1.x/how-to/assert.html)
|
|
385
|
+
for more details.
|
|
386
|
+
|
|
387
|
+
In general, rewriting assertions is not very useful for doctests, as the
|
|
388
|
+
output on error is fixed by the doctest machinery anyway. Therefore, we believe
|
|
389
|
+
adding `--assert=plain` is reasonable.
|
|
390
|
+
|
|
391
|
+
|
|
364
392
|
## Prior art and related work
|
|
365
393
|
|
|
366
394
|
- `pytest` provides some limited floating-point aware `NumericLiteralChecker`.
|
|
@@ -370,20 +398,17 @@ leads to
|
|
|
370
398
|
differences are: (i) `pytest-doctestplus` is more sensitive to formatting,
|
|
371
399
|
including whitespace---thus if numpy tweaks its output formatting, doctests
|
|
372
400
|
may start failing; (ii) there is still a need for `# doctest: +FLOAT_CMP`
|
|
373
|
-
directives
|
|
374
|
-
coupled to `pytest`. It thus needs to follow `pytest` releases, and
|
|
375
|
-
some maintenance work may be required to adapt when `pytest` publishes a new
|
|
376
|
-
release.
|
|
401
|
+
directives.
|
|
377
402
|
|
|
378
403
|
This project takes a different approach: in addition to plugging into `pytest`,
|
|
379
404
|
we closely follow the `doctest` API and implementation, which are naturally
|
|
380
405
|
way more stable then `pytest`.
|
|
381
406
|
|
|
382
|
-
- `NumPy` and `SciPy`
|
|
407
|
+
- `NumPy` and `SciPy` were using modified doctesting in their `refguide-check` utilities.
|
|
383
408
|
These utilities are tightly coupled to their libraries, and have been reported
|
|
384
409
|
to be not easy to reason about, work with, and extend to other projects.
|
|
385
410
|
|
|
386
|
-
This project is
|
|
411
|
+
This project is mainly the core functionality of the modified
|
|
387
412
|
`refguide-check` doctesting, extracted to a separate package.
|
|
388
413
|
We believe having it separate simplifies both addressing the needs of these
|
|
389
414
|
two packages, and potential adoption by other projects.
|
|
@@ -48,8 +48,8 @@ Its main features are
|
|
|
48
48
|
>>> np.random.randint(100)
|
|
49
49
|
42 # may vary
|
|
50
50
|
```
|
|
51
|
-
Note that the markers (by default, `"# may vary"` and `"# random"`)
|
|
52
|
-
to an example's output,
|
|
51
|
+
Note that the markers (by default, `"# may vary"` and `"# random"`) can be applied
|
|
52
|
+
to either an example's output, or its source.
|
|
53
53
|
|
|
54
54
|
Also note a difference with respect to the standard `# doctest: +SKIP`: the latter
|
|
55
55
|
skips the example entirely, while these additional markers only skip checking
|
|
@@ -81,7 +81,7 @@ the output. Thus the example source needs to be valid python code still.
|
|
|
81
81
|
## Install and test
|
|
82
82
|
|
|
83
83
|
```
|
|
84
|
-
$ pip install -
|
|
84
|
+
$ pip install scipy-doctest
|
|
85
85
|
$ pytest --pyargs scipy_doctest
|
|
86
86
|
```
|
|
87
87
|
|
|
@@ -93,9 +93,56 @@ or nearly so.
|
|
|
93
93
|
|
|
94
94
|
The other layer is the `pytest` plugin.
|
|
95
95
|
|
|
96
|
+
### Run doctests via pytest
|
|
97
|
+
|
|
98
|
+
To run doctests on your package or project, follow these steps:
|
|
99
|
+
|
|
100
|
+
1. **Install the plugin**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pip install scipy-doctest
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
2. **Register or load the plugin**
|
|
107
|
+
|
|
108
|
+
Next, you need to register or load the pytest plugin within your test module or `conftest.py` file.
|
|
109
|
+
|
|
110
|
+
To do this, add the following line of code:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# In your conftest.py file or test module
|
|
114
|
+
|
|
115
|
+
pytest_plugins = "scipy_doctest"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Check out the [pytest documentation](https://docs.pytest.org/en/stable/how-to/writing_plugins.html#requiring-loading-plugins-in-a-test-module-or-conftest-file) for more information on requiring/loading plugins in a test module or `conftest.py` file.
|
|
119
|
+
|
|
120
|
+
3. **Run doctests**
|
|
121
|
+
|
|
122
|
+
Once the plugin is registered, run the doctests by executing the following command:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
$ python -m pytest --doctest-modules
|
|
126
|
+
```
|
|
127
|
+
or
|
|
128
|
+
```bash
|
|
129
|
+
$ pytest --pyargs <your-package> --doctest-modules
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
By default, all doctests are collected. To only collect public objects, `strategy="api"`,
|
|
133
|
+
use the command flag
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
$ pytest --pyargs <your-package> --doctest-modules --doctest-collect=api
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
See [More fine-grained control](https://github.com/scipy/scipy_doctest#More-fine-grained-control) section
|
|
140
|
+
for details on how to customize the behavior.
|
|
141
|
+
|
|
96
142
|
|
|
97
143
|
### Basic usage
|
|
98
144
|
|
|
145
|
+
The use of `pytest` is optional, and you can use the `doctest` layer API.
|
|
99
146
|
For example,
|
|
100
147
|
|
|
101
148
|
```
|
|
@@ -112,7 +159,8 @@ For more details, see the `testmod` docstring. Other useful functions are
|
|
|
112
159
|
`find_doctests`, `run_docstring_examples` and `testfile` (the latter two mimic
|
|
113
160
|
the behavior of the eponymous functions of the `doctest` module).
|
|
114
161
|
|
|
115
|
-
|
|
162
|
+
|
|
163
|
+
### Command-line interface
|
|
116
164
|
|
|
117
165
|
There is a basic CLI, which also mimics that of the `doctest` module:
|
|
118
166
|
```
|
|
@@ -127,8 +175,10 @@ Text files can also be CLI-checked:
|
|
|
127
175
|
$ python -m scipy_doctest bar.rst
|
|
128
176
|
```
|
|
129
177
|
|
|
178
|
+
Notice that the command-line usage only uses the default `DTConfig` settings.
|
|
179
|
+
|
|
130
180
|
|
|
131
|
-
|
|
181
|
+
## More fine-grained control
|
|
132
182
|
|
|
133
183
|
More fine-grained control of the functionality is available via the following
|
|
134
184
|
classes
|
|
@@ -147,133 +197,98 @@ configuration is simply creating an instance, overriding an attribute and
|
|
|
147
197
|
passing the instance to `testmod` or constructors of `DT*` objects. Defaults
|
|
148
198
|
are provided, based on a long-term usage in SciPy.
|
|
149
199
|
|
|
200
|
+
See the [DTConfig docstring](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/impl.py#L24)
|
|
201
|
+
for the full set of attributes that allow you to fine-tune your doctesting experience.
|
|
150
202
|
|
|
151
|
-
|
|
203
|
+
To set any of these attributes, create an instance of `DTConfig` and assign the attributes
|
|
204
|
+
in a usual way.
|
|
152
205
|
|
|
153
|
-
|
|
206
|
+
If using the pytest plugin, it is convenient to use the default instance, which
|
|
207
|
+
is predefined in `scipy_doctest/conftest.py`. This instance will be automatically
|
|
208
|
+
passed around via an
|
|
209
|
+
[attribute of pytest's `Config` object](https://github.com/scipy/scipy_doctest/blob/58ff06a837b7bff1dbac6560013fc6fd07952ae2/scipy_doctest/plugin.py#L39).
|
|
154
210
|
|
|
155
|
-
|
|
211
|
+
### Examples
|
|
156
212
|
|
|
157
|
-
### Running Doctests on SciPy
|
|
158
|
-
|
|
159
|
-
1. **Install plugin**
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
pip install scipy-doctest
|
|
163
213
|
```
|
|
164
|
-
|
|
165
|
-
2. **Configure Your Doctesting Experience**
|
|
166
|
-
|
|
167
|
-
To tailor your doctesting experience, you can utilize an instance of `DTConfig`.
|
|
168
|
-
An in-depth explanation is given in the [tailoring your doctesting experience](https://github.com/scipy/scipy_doctest#tailoring-your-doctesting-experience) section.
|
|
169
|
-
|
|
170
|
-
3. **Run Doctests**
|
|
171
|
-
|
|
172
|
-
Doctesting is configured to execute on SciPy using the `dev.py` module.
|
|
173
|
-
|
|
174
|
-
To run all doctests, use the following command:
|
|
175
|
-
```bash
|
|
176
|
-
python dev.py smoke-docs
|
|
214
|
+
dt_config = DTConfig()
|
|
177
215
|
```
|
|
178
216
|
|
|
179
|
-
|
|
217
|
+
or, if using pytest,
|
|
180
218
|
|
|
181
|
-
```
|
|
182
|
-
|
|
219
|
+
```python
|
|
220
|
+
from scipy_doctest.conftest import dt_config # a DTConfig instance with default settings
|
|
183
221
|
```
|
|
184
222
|
|
|
185
|
-
|
|
223
|
+
and then
|
|
186
224
|
|
|
187
|
-
If you want to run doctests on packages or projects other than SciPy, follow these steps:
|
|
188
|
-
|
|
189
|
-
1. **Install the plugin**
|
|
190
|
-
|
|
191
|
-
```bash
|
|
192
|
-
pip install scipy-doctest
|
|
193
225
|
```
|
|
226
|
+
dt_config.rndm_markers = {'# unintialized'}
|
|
194
227
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
Next, you need to register or load the pytest plugin within your test module or `conftest.py` file.
|
|
198
|
-
|
|
199
|
-
To do this, add the following line of code:
|
|
228
|
+
dt_config.stopwords = {'plt.', 'plt.hist', 'plt.show'}
|
|
200
229
|
|
|
201
|
-
|
|
202
|
-
|
|
230
|
+
dt_config.local_resources = {
|
|
231
|
+
'scipy_doctest.tests.local_file_cases.local_files': ['scipy_doctest/tests/local_file.txt'],
|
|
232
|
+
'scipy_doctest.tests.local_file_cases.sio': ['scipy_doctest/tests/octave_a.mat']
|
|
233
|
+
}
|
|
203
234
|
|
|
204
|
-
|
|
235
|
+
dt_config.skiplist = {
|
|
236
|
+
'scipy.special.sinc',
|
|
237
|
+
'scipy.misc.who',
|
|
238
|
+
'scipy.optimize.show_options'
|
|
239
|
+
}
|
|
205
240
|
```
|
|
206
241
|
|
|
207
|
-
|
|
242
|
+
If you don't set these attributes, the [default settings](https://github.com/scipy/scipy_doctest/blob/58ff06a837b7bff1dbac6560013fc6fd07952ae2/scipy_doctest/impl.py#L94) of the attributes are used.
|
|
208
243
|
|
|
209
|
-
3. **Configure your doctesting experience**
|
|
210
244
|
|
|
211
|
-
|
|
245
|
+
#### Alternative Checkers
|
|
212
246
|
|
|
213
|
-
|
|
247
|
+
By default, we use the floating-point aware `DTChecker`. If you want to use an
|
|
248
|
+
alternative checker, all you need to do is to define the corresponding class,
|
|
249
|
+
and add an attribute to the `DTConfig` instance. For example,
|
|
214
250
|
|
|
215
|
-
Once the plugin is registered, you can run your doctests by executing the following command:
|
|
216
251
|
|
|
217
|
-
```bash
|
|
218
|
-
$ python -m pytest --doctest-modules
|
|
219
252
|
```
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
253
|
+
class VanillaOutputChecker(doctest.OutputChecker):
|
|
254
|
+
"""doctest.OutputChecker to drop in for DTChecker.
|
|
255
|
+
|
|
256
|
+
LSP break: OutputChecker does not have __init__,
|
|
257
|
+
here we add it to agree with DTChecker.
|
|
258
|
+
"""
|
|
259
|
+
def __init__(self, config):
|
|
260
|
+
pass
|
|
223
261
|
```
|
|
224
262
|
|
|
225
|
-
|
|
226
|
-
use the command flag
|
|
263
|
+
and
|
|
227
264
|
|
|
228
|
-
```
|
|
229
|
-
|
|
265
|
+
```
|
|
266
|
+
dt_config = DTConfig()
|
|
267
|
+
dt_config.CheckerKlass = VanillaOutputChecker
|
|
230
268
|
```
|
|
231
269
|
|
|
232
|
-
|
|
270
|
+
See [a pytest example](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/tests/test_pytest_configuration.py#L63)
|
|
271
|
+
and [a doctest example](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/tests/test_runner.py#L94)
|
|
272
|
+
for more details.
|
|
233
273
|
|
|
234
|
-
[DTConfig](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/impl.py#L23) offers a variety of attributes that allow you to fine-tune your doctesting experience.
|
|
235
274
|
|
|
236
|
-
|
|
237
|
-
1. **default_namespace (dict):** Defines the namespace in which examples are executed.
|
|
238
|
-
2. **check_namespace (dict):** Specifies the namespace for conducting checks.
|
|
239
|
-
3. **rndm_markers (set):** Provides additional directives which act like `# doctest: + SKIP`.
|
|
240
|
-
4. **atol (float) and rtol (float):** Sets absolute and relative tolerances for validating doctest examples.
|
|
241
|
-
Specifically, it governs the check using `np.allclose(want, got, atol=atol, rtol=rtol)`.
|
|
242
|
-
5. **optionflags (int):** These are doctest option flags.
|
|
243
|
-
The default setting includes `NORMALIZE_WHITESPACE` | `ELLIPSIS` | `IGNORE_EXCEPTION_DETAIL`.
|
|
244
|
-
6. **stopwords (set):** If an example contains any of these stopwords, the output is not checked (though the source's validity is still assessed).
|
|
245
|
-
7. **pseudocode (list):** Lists strings that, when found in an example, result in no doctesting. This resembles the `# doctest +SKIP` directive and is useful for pseudocode blocks or similar cases.
|
|
246
|
-
8. **skiplist (set):** A list of names of objects with docstrings known to fail doctesting and are intentionally excluded from testing.
|
|
247
|
-
9. **user_context_mgr:** A context manager for running tests.
|
|
248
|
-
Typically, it is entered for each DocTest (especially in API documentation), ensuring proper testing isolation.
|
|
249
|
-
10. **local_resources (dict):** Specifies local files needed for specific tests. The format is `{test.name: list-of-files}`. File paths are relative to the path of `test.filename`.
|
|
250
|
-
11. **parse_namedtuples (bool):** Determines whether to perform a literal comparison (e.g., `TTestResult(pvalue=0.9, statistic=42)`) or extract and compare the tuple values (e.g., `(0.9, 42)`). The default is `True`.
|
|
251
|
-
12. **nameerror_after_exception (bool):** Controls whether subsequent examples in the same test, after one has failed, may raise spurious NameErrors. Set to `True` if you want to observe these errors or if your test is expected to raise NameErrors. The default is `False`.
|
|
275
|
+
### NumPy and SciPy wrappers
|
|
252
276
|
|
|
253
|
-
To set any of these attributes, create an instance of `DTConfig` called `dt_config`.
|
|
254
|
-
This instance is already set as an [attribute of pytest's `Config` object](https://github.com/scipy/scipy_doctest/blob/58ff06a837b7bff1dbac6560013fc6fd07952ae2/scipy_doctest/plugin.py#L39).
|
|
255
277
|
|
|
256
|
-
|
|
278
|
+
NumPy wraps `scipy-doctest` with the `spin` command
|
|
257
279
|
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
dt_config.stopwords = {'plt.', '.hist', '.show'}
|
|
261
|
-
dt_config.local_resources = {
|
|
262
|
-
'scipy_doctest.tests.local_file_cases.local_files': ['scipy_doctest/tests/local_file.txt'],
|
|
263
|
-
'scipy_doctest.tests.local_file_cases.sio': ['scipy_doctest/tests/octave_a.mat']
|
|
264
|
-
}
|
|
265
|
-
dt_config.skiplist = {
|
|
266
|
-
'scipy.special.sinc',
|
|
267
|
-
'scipy.misc.who',
|
|
268
|
-
'scipy.optimize.show_options'
|
|
269
|
-
}
|
|
280
|
+
```
|
|
281
|
+
$ spin check-docs
|
|
270
282
|
```
|
|
271
283
|
|
|
272
|
-
|
|
284
|
+
SciPy wraps `scipy-doctest` with custom `dev.py` commands:
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
$ python dev.py smoke-docs # check docstrings
|
|
288
|
+
$ python dev.py smoke-tutorials # ReST user guide tutorials
|
|
289
|
+
```
|
|
273
290
|
|
|
274
|
-
By following these steps, you will be able to effectively use the SciPy Doctest pytest plugin for doctests in your Python projects.
|
|
275
291
|
|
|
276
|
-
Happy testing!
|
|
277
292
|
|
|
278
293
|
## Rough edges and sharp bits
|
|
279
294
|
|
|
@@ -307,7 +322,7 @@ being optional. So you either guard the imports in doctests (yikes!), or
|
|
|
307
322
|
the collections fails if dependencies are not available.
|
|
308
323
|
|
|
309
324
|
The solution is to explicitly `--ignore` the paths to modules with optionals.
|
|
310
|
-
(or use `DTConfig.pytest_extra_ignore` list):
|
|
325
|
+
(or, equivalently, use `DTConfig.pytest_extra_ignore` list):
|
|
311
326
|
|
|
312
327
|
```
|
|
313
328
|
$ pytest --ignore=/build-install/lib/scipy/python3.10/site-packages/scipy/_lib ...
|
|
@@ -342,6 +357,19 @@ leads to
|
|
|
342
357
|
- `scipy.linalg.det`, collected from `scipy/linalg/__init__.py`, is public.
|
|
343
358
|
|
|
344
359
|
|
|
360
|
+
- *`pytest`'s assertion rewriting*
|
|
361
|
+
|
|
362
|
+
In some rare cases you may need to either explicitly register the `scipy_doctest`
|
|
363
|
+
package with the `pytest` assertion rewriting machinery, or ask it to avoid rewriting
|
|
364
|
+
completely, via `pytest --assert=plain`.
|
|
365
|
+
See [the `pytest documentation`](https://docs.pytest.org/en/7.1.x/how-to/assert.html)
|
|
366
|
+
for more details.
|
|
367
|
+
|
|
368
|
+
In general, rewriting assertions is not very useful for doctests, as the
|
|
369
|
+
output on error is fixed by the doctest machinery anyway. Therefore, we believe
|
|
370
|
+
adding `--assert=plain` is reasonable.
|
|
371
|
+
|
|
372
|
+
|
|
345
373
|
## Prior art and related work
|
|
346
374
|
|
|
347
375
|
- `pytest` provides some limited floating-point aware `NumericLiteralChecker`.
|
|
@@ -351,20 +379,17 @@ leads to
|
|
|
351
379
|
differences are: (i) `pytest-doctestplus` is more sensitive to formatting,
|
|
352
380
|
including whitespace---thus if numpy tweaks its output formatting, doctests
|
|
353
381
|
may start failing; (ii) there is still a need for `# doctest: +FLOAT_CMP`
|
|
354
|
-
directives
|
|
355
|
-
coupled to `pytest`. It thus needs to follow `pytest` releases, and
|
|
356
|
-
some maintenance work may be required to adapt when `pytest` publishes a new
|
|
357
|
-
release.
|
|
382
|
+
directives.
|
|
358
383
|
|
|
359
384
|
This project takes a different approach: in addition to plugging into `pytest`,
|
|
360
385
|
we closely follow the `doctest` API and implementation, which are naturally
|
|
361
386
|
way more stable then `pytest`.
|
|
362
387
|
|
|
363
|
-
- `NumPy` and `SciPy`
|
|
388
|
+
- `NumPy` and `SciPy` were using modified doctesting in their `refguide-check` utilities.
|
|
364
389
|
These utilities are tightly coupled to their libraries, and have been reported
|
|
365
390
|
to be not easy to reason about, work with, and extend to other projects.
|
|
366
391
|
|
|
367
|
-
This project is
|
|
392
|
+
This project is mainly the core functionality of the modified
|
|
368
393
|
`refguide-check` doctesting, extracted to a separate package.
|
|
369
394
|
We believe having it separate simplifies both addressing the needs of these
|
|
370
395
|
two packages, and potential adoption by other projects.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configurable, whitespace-insensitive, floating-point-aware doctest helpers.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
__version__ = "1.4"
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
# register internal modules with pytest; obscure errors galore otherwise
|
|
10
|
+
import pytest
|
|
11
|
+
pytest.register_assert_rewrite(
|
|
12
|
+
"scipy_doctest.conftest", "scipy_doctest.impl", "scipy_doctest.util",
|
|
13
|
+
"scipy_doctest.frontend", "scipy_doctest.plugin"
|
|
14
|
+
)
|
|
15
|
+
except ModuleNotFoundError:
|
|
16
|
+
# pytest is optional, so nothing to do
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
from .impl import DTChecker, DTFinder, DTParser, DTRunner, DebugDTRunner, DTConfig # noqa
|
|
21
|
+
from .frontend import testmod, testfile, find_doctests, run_docstring_examples # noqa
|
|
22
|
+
|
|
@@ -40,6 +40,11 @@ class DTConfig:
|
|
|
40
40
|
rtol : float
|
|
41
41
|
Absolute and relative tolerances to check doctest examples with.
|
|
42
42
|
Specifically, the check is ``np.allclose(want, got, atol=atol, rtol=rtol)``
|
|
43
|
+
strict_check : bool
|
|
44
|
+
Whether to check that dtypes match or rely on the lax definition of
|
|
45
|
+
equality of numpy objects. For instance, `3 == np.float64(3)`, but
|
|
46
|
+
dtypes do not match.
|
|
47
|
+
Default is False.
|
|
43
48
|
optionflags : int
|
|
44
49
|
doctest optionflags
|
|
45
50
|
Default is ``NORMALIZE_WHITESPACE | ELLIPSIS | IGNORE_EXCEPTION_DETAIL``
|
|
@@ -91,6 +96,14 @@ class DTConfig:
|
|
|
91
96
|
adding `# may vary` to the outputs of all examples.
|
|
92
97
|
Each key is a doctest name to skip, and the corresponding value is
|
|
93
98
|
a string. If not empty, the string value is used as the skip reason.
|
|
99
|
+
CheckerKlass : object, optional
|
|
100
|
+
The class for the Checker object. Must mimic the ``DTChecker`` API:
|
|
101
|
+
subclass the `doctest.OutputChecker` and make the constructor signature
|
|
102
|
+
read ``__init__(self, config=None)``, where `config` is a ``DTConfig``
|
|
103
|
+
instance.
|
|
104
|
+
This class will be instantiated by ``DTRunner``.
|
|
105
|
+
Defaults to `DTChecker`.
|
|
106
|
+
|
|
94
107
|
"""
|
|
95
108
|
def __init__(self, *, # DTChecker configuration
|
|
96
109
|
CheckerKlass=None,
|
|
@@ -99,6 +112,7 @@ class DTConfig:
|
|
|
99
112
|
rndm_markers=None,
|
|
100
113
|
atol=1e-8,
|
|
101
114
|
rtol=1e-2,
|
|
115
|
+
strict_check=False,
|
|
102
116
|
# DTRunner configuration
|
|
103
117
|
optionflags=None,
|
|
104
118
|
# DTFinder/DTParser configuration
|
|
@@ -153,8 +167,8 @@ class DTConfig:
|
|
|
153
167
|
'#random', '#Random',
|
|
154
168
|
"# may vary"}
|
|
155
169
|
self.rndm_markers = rndm_markers
|
|
156
|
-
|
|
157
170
|
self.atol, self.rtol = atol, rtol
|
|
171
|
+
self.strict_check = strict_check
|
|
158
172
|
|
|
159
173
|
### DTRunner configuration ###
|
|
160
174
|
|
|
@@ -355,23 +369,35 @@ class DTChecker(doctest.OutputChecker):
|
|
|
355
369
|
return False
|
|
356
370
|
|
|
357
371
|
# ... and defer to numpy
|
|
372
|
+
strict = self.config.strict_check
|
|
358
373
|
try:
|
|
359
|
-
return self._do_check(a_want, a_got)
|
|
374
|
+
return self._do_check(a_want, a_got, strict)
|
|
360
375
|
except Exception:
|
|
361
376
|
# heterog tuple, eg (1, np.array([1., 2.]))
|
|
362
377
|
try:
|
|
363
|
-
return all(
|
|
378
|
+
return all(
|
|
379
|
+
self._do_check(w, g, strict) for w, g in zip_longest(a_want, a_got)
|
|
380
|
+
)
|
|
364
381
|
except (TypeError, ValueError):
|
|
365
382
|
return False
|
|
366
383
|
|
|
367
|
-
def _do_check(self, want, got):
|
|
384
|
+
def _do_check(self, want, got, strict_check):
|
|
368
385
|
# This should be done exactly as written to correctly handle all of
|
|
369
386
|
# numpy-comparable objects, strings, and heterogeneous tuples
|
|
387
|
+
|
|
388
|
+
# NB: 3 == np.float64(3.0) but dtypes differ
|
|
389
|
+
if strict_check:
|
|
390
|
+
want_dtype = np.asarray(want).dtype
|
|
391
|
+
got_dtype = np.asarray(got).dtype
|
|
392
|
+
if want_dtype != got_dtype:
|
|
393
|
+
return False
|
|
394
|
+
|
|
370
395
|
try:
|
|
371
396
|
if want == got:
|
|
372
397
|
return True
|
|
373
398
|
except Exception:
|
|
374
399
|
pass
|
|
400
|
+
|
|
375
401
|
with warnings.catch_warnings():
|
|
376
402
|
# NumPy's ragged array deprecation of np.array([1, (2, 3)])
|
|
377
403
|
warnings.simplefilter('ignore', VisibleDeprecationWarning)
|
|
@@ -506,6 +532,7 @@ class DTParser(doctest.DocTestParser):
|
|
|
506
532
|
"""
|
|
507
533
|
stopwords = self.config.stopwords
|
|
508
534
|
pseudocode = self.config.pseudocode
|
|
535
|
+
rndm_markers = self.config.rndm_markers
|
|
509
536
|
|
|
510
537
|
SKIP = doctest.OPTIONFLAGS_BY_NAME['SKIP']
|
|
511
538
|
keep_skipping_this_block = False
|
|
@@ -529,6 +556,11 @@ class DTParser(doctest.DocTestParser):
|
|
|
529
556
|
# NB: Could have just skipped it via `continue`.
|
|
530
557
|
example.options[SKIP] = True
|
|
531
558
|
|
|
559
|
+
if any(word in example.source for word in rndm_markers):
|
|
560
|
+
# Found a `# may vary`. Do not check the output (but do check
|
|
561
|
+
# that the source is valid python).
|
|
562
|
+
example.want += " # _ignore\n"
|
|
563
|
+
|
|
532
564
|
if any(word in example.source for word in stopwords):
|
|
533
565
|
# Found a stopword. Do not check the output (but do check
|
|
534
566
|
# that the source is valid python).
|
|
@@ -3,7 +3,7 @@ from ..conftest import dt_config
|
|
|
3
3
|
# Specify local files required by doctests
|
|
4
4
|
dt_config.local_resources = {
|
|
5
5
|
'scipy_doctest.tests.local_file_cases.local_files': ['local_file.txt'],
|
|
6
|
-
'scipy_doctest.local_file_cases.sio': ['octave_a.mat']
|
|
6
|
+
'scipy_doctest.tests.local_file_cases.sio': ['octave_a.mat']
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
|
|
@@ -49,11 +49,9 @@ def test_stopword_cases(pytester):
|
|
|
49
49
|
assert result.ret == pytest.ExitCode.OK
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
@pytest.mark.xfail(reason="XXX: passes locally, fails on CI")
|
|
53
52
|
@pytest.mark.skipif(not HAVE_SCIPY, reason='need scipy')
|
|
54
53
|
def test_local_file_cases(pytester):
|
|
55
|
-
"""Test that local files are found for use in doctests.
|
|
56
|
-
"""
|
|
54
|
+
"""Test that local files are found for use in doctests."""
|
|
57
55
|
path_str = local_file_cases.__file__
|
|
58
56
|
python_file = Path(path_str)
|
|
59
57
|
result = pytester.inline_run(python_file, "--doctest-modules")
|
|
@@ -161,8 +161,25 @@ class TestMayVary:
|
|
|
161
161
|
filename='none', lineno=0)
|
|
162
162
|
|
|
163
163
|
runner = DebugDTRunner()
|
|
164
|
-
|
|
164
|
+
runner.run(test)
|
|
165
|
+
|
|
166
|
+
# one example tried, of which zero failed
|
|
167
|
+
assert runner.get_history() == {'may_vary_source': (0, 1)}
|
|
168
|
+
|
|
169
|
+
def test_may_vary_syntax_error(self):
|
|
170
|
+
# `# may vary` markers do not mask syntax errors, unlike `# doctest: +SKIP`
|
|
171
|
+
string = ">>> 1 += 2 # may vary\n"
|
|
172
|
+
string += "42\n"
|
|
173
|
+
|
|
174
|
+
parser = DTParser()
|
|
175
|
+
test = parser.get_doctest(string, globs={},
|
|
176
|
+
name='may_vary_err',
|
|
177
|
+
filename='none', lineno=0)
|
|
178
|
+
|
|
179
|
+
runner = DebugDTRunner()
|
|
180
|
+
with pytest.raises(Exception) as exc_info:
|
|
165
181
|
runner.run(test)
|
|
182
|
+
assert exc_info.type == doctest.UnexpectedException
|
|
166
183
|
|
|
167
184
|
|
|
168
185
|
string='''\
|
|
@@ -117,6 +117,16 @@ def test_tuple_and_list():
|
|
|
117
117
|
assert res.failed == 2
|
|
118
118
|
|
|
119
119
|
|
|
120
|
+
@pytest.mark.parametrize('strict, num_fails', [(True, 1), (False, 0)])
|
|
121
|
+
class TestStrictDType:
|
|
122
|
+
def test_np_fix(self, strict, num_fails):
|
|
123
|
+
config = DTConfig(strict_check=strict)
|
|
124
|
+
res, _ = _testmod(failure_cases,
|
|
125
|
+
strategy=[failure_cases.dtype_mismatch],
|
|
126
|
+
config=config)
|
|
127
|
+
assert res.failed == num_fails
|
|
128
|
+
|
|
129
|
+
|
|
120
130
|
class TestLocalFiles:
|
|
121
131
|
def test_local_files(self):
|
|
122
132
|
# A doctest tries to open a local file. Test that it works
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Doctests on steroids.
|
|
3
|
-
|
|
4
|
-
Whitespace-insensitive, numpy-aware, floating-point-aware doctest helpers.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
__version__ = "1.2.0"
|
|
9
|
-
|
|
10
|
-
from .impl import DTChecker, DTFinder, DTParser, DTRunner, DebugDTRunner, DTConfig # noqa
|
|
11
|
-
from .frontend import testmod, testfile, find_doctests, run_docstring_examples # noqa
|
|
12
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scipy_doctest-1.2.0 → scipy_doctest-1.4}/scipy_doctest/tests/scipy_ndimage_tutorial_clone.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|