Skip to content

Commit 1a0aa54

Browse files
authored
Merge pull request #201 from scipy/tweak_readme
DOC: minor README tweaks
2 parents 1b3dff5 + f9df562 commit 1a0aa54

File tree

1 file changed

+43
-22
lines changed

1 file changed

+43
-22
lines changed

README.md

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ $ pytest --pyargs <your-package> --doctest-modules --doctest-collect=api
151151
See [More fine-grained control](#more-fine-grained-control) section
152152
for details on how to customize the behavior.
153153

154-
**NOTE ** Currently, `pytest --doctest-modules` only collects doctests and skips
154+
**NOTE** Currently, `pytest --doctest-modules` only collects doctests and skips
155155
'regular' unit tests. This differs from the vanilla `pytest` behavior, which collects
156156
both doctests and unit tests.
157157
The behavior will change in a future version: `scipy-doctest==2.0` **will change the
@@ -318,7 +318,7 @@ $ spin smoke-tutorials # ReST user guide tutorials
318318

319319
Here is a (non-exhaustive) list of possible gotchas:
320320

321-
- _In-place development builds_.
321+
#### _In-place development builds_.
322322

323323
Some tools (looking at you `meson-python`) simulate in-place builds with a
324324
`build-install` directory. If this directory is located under the project root,
@@ -342,10 +342,10 @@ If push really comes to shove, you may try using the magic env variable:
342342
however the need usually indicates an issue with the package itself.
343343
(see [gh-107](https://github.com/scipy/scipy_doctest/pull/107) for an example).
344344

345-
- _Optional dependencies are not that optional_
345+
#### _Optional dependencies are not that optional_
346346

347347
If your package contains optional dependencies, doctests do not know about them
348-
being optional. So you either guard the imports in doctests (yikes!), or
348+
being optional. So you either guard the imports in doctests themselves (yikes!), or
349349
the collections fails if dependencies are not available.
350350

351351
The solution is to explicitly `--ignore` the paths to modules with optionals.
@@ -361,7 +361,7 @@ Note that installed packages are no different:
361361
$ pytest --pyargs scipy --doctest-modules --ignore=/path/to/installed/scipy/_lib
362362
```
363363

364-
- _Doctest collection strategies_
364+
#### _Doctest collection strategies_
365365

366366
The default collection strategy follows `doctest` module and `pytest`. This leads
367367
to duplicates if your package has the split between public and \_private modules,
@@ -371,19 +371,19 @@ objects will be collected.
371371

372372
The decision on what is public is as follows: an object is public iff
373373

374-
- it is included into the `__all__` list of a public module;
375-
- the name of the object does not have a leading underscore;
376-
- the name of the module from which the object is collected does not have
374+
- it is included into the `__all__` list of a public module;
375+
- the name of the object does not have a leading underscore;
376+
- the name of the module from which the object is collected does not have
377377
a leading underscore.
378378

379379
Consider an example: `scipy.linalg.det` is defined in `scipy/linalg/_basic.py`,
380380
so it is collected twice, from `_basic.py` and from `__init__.py`. The rule above
381381
leads to
382382

383-
- `scipy.linalg._basic.det`, collected from `scipy/linalg/_basic.py`, is private.
384-
- `scipy.linalg.det`, collected from `scipy/linalg/__init__.py`, is public.
383+
- `scipy.linalg._basic.det`, collected from `scipy/linalg/_basic.py`, is private.
384+
- `scipy.linalg.det`, collected from `scipy/linalg/__init__.py`, is public.
385385

386-
- _`pytest`'s assertion rewriting_
386+
#### _`pytest`'s assertion rewriting_
387387

388388
In some rare cases you may need to either explicitly register the `scipy_doctest`
389389
package with the `pytest` assertion rewriting machinery, or ask it to avoid rewriting
@@ -395,31 +395,52 @@ In general, rewriting assertions is not very useful for doctests, as the
395395
output on error is fixed by the doctest machinery anyway. Therefore, we believe
396396
adding `--assert=plain` is reasonable.
397397

398+
#### _Mixing strings and numbers_
399+
400+
Generally, we aim to handle mixtures of strings and numeric data. Deeply nested data
401+
structures, however, may cause the checker to fall back to the vanilla `doctest` literal
402+
checking. For instance, `["value", 1/3]` will use the floating-point aware checker, and
403+
so will `{"value": 1/3, "other value": 2/3}` or `[(1, 2), (3, 4)]`; Meanwhile, nested
404+
dictionaries, `{"a": dict(value=1/3)}`, or lists of tuples with mixed entries,
405+
`[("a", 1/3), ("b", 2/3)]`, will currently fall back to vanilla `doctest` literal
406+
comparisons.
407+
408+
We stress that no matter how tricky or deeply nested the output is, the worst case
409+
scenario is that the floating-point aware checker is not used. If you have a case where
410+
`doctest` works correctly and `scipy_doctest` does not, please report it as a bug.
411+
412+
398413
## Prior art and related work
399414

400415
- `pytest` provides some limited floating-point aware `NumericLiteralChecker`.
401416

402417
- `pytest-doctestplus` plugin from the `AstroPy` project has similar goals.
403418
The package is well established and widely used. From a user perspective, main
404419
differences are: (i) `pytest-doctestplus` is more sensitive to formatting,
405-
including whitespace---thus if numpy tweaks its output formatting, doctests
406-
may start failing; (ii) there is still a need for `# doctest: +FLOAT_CMP`
420+
including whitespace; (ii) there is still a need for `# doctest: +FLOAT_CMP`
407421
directives.
408422

409-
This project takes a different approach: in addition to plugging into `pytest`,
410-
we closely follow the `doctest` API and implementation, which are naturally
411-
way more stable then `pytest`.
423+
This project takes a slightly different approach: we strive to make numeric comparisons
424+
whitespace insensitive and automatic, without a need for explicit markup. For rare cases
425+
which require additional configuration, we either keep it in the tool (thus out of
426+
reader-visible docstrings), or provide human-readable markers (hence `# may vary`
427+
not `# doctest +SKIP`).
428+
Furthermore, in addition to plugging into `pytest`, we provide an API layer which closely
429+
follows the `doctest` API. Essentially all aspects of doctesting are user-configurable.
430+
431+
- `xdoctest` package relies on a deeper rewrite of the standard-library `doctest`
432+
functionality, and uses an AST-based analysis to parse code examples out of docstrings.
412433

413434
- `NumPy` and `SciPy` were using modified doctesting in their `refguide-check` utilities.
414-
These utilities are tightly coupled to their libraries, and have been reported
435+
These utilities were tightly coupled to their libraries, and have been reported
415436
to be not easy to reason about, work with, and extend to other projects.
416437

417-
This project is mainly the core functionality of the modified
418-
`refguide-check` doctesting, extracted to a separate package.
419-
We believe having it separate simplifies both addressing the needs of these
420-
two packages, and potential adoption by other projects.
438+
This project is mainly the core functionality of the modified `refguide-check` doctesting,
439+
extracted to a separate package. We believe having it separate simplifies both
440+
addressing the needs of these two packages, and adoption by other projects.
441+
421442

422-
### Bug reports, feature requests and contributions
443+
## Bug reports, feature requests and contributions
423444

424445
This package is work in progress. Contributions are most welcome!
425446
Please don't hesitate to open an issue in the tracker or send a pull request.

0 commit comments

Comments
 (0)