scipy-doctest 1.5.1__py3-none-any.whl → 1.7__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.
@@ -0,0 +1,2 @@
1
+ # Automatically created by ruff.
2
+ *
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
scipy_doctest/__init__.py CHANGED
@@ -3,7 +3,7 @@ Configurable, whitespace-insensitive, floating-point-aware doctest helpers.
3
3
  """
4
4
 
5
5
 
6
- __version__ = "1.5.1"
6
+ __version__ = "1.7"
7
7
 
8
8
  try:
9
9
  # register internal modules with pytest; obscure errors galore otherwise
@@ -19,4 +19,3 @@ except ModuleNotFoundError:
19
19
 
20
20
  from .impl import DTChecker, DTFinder, DTParser, DTRunner, DebugDTRunner, DTConfig # noqa
21
21
  from .frontend import testmod, testfile, find_doctests, run_docstring_examples # noqa
22
-
scipy_doctest/conftest.py CHANGED
@@ -2,4 +2,3 @@ from .impl import DTConfig
2
2
 
3
3
 
4
4
  dt_config = DTConfig()
5
-
scipy_doctest/frontend.py CHANGED
@@ -46,7 +46,7 @@ def find_doctests(module, strategy=None,
46
46
  Returns
47
47
  -------
48
48
  tests : list
49
- A list of `doctest.DocTest`s that are defined by the module docstring,
49
+ A list of `doctest.DocTest` s that are defined by the module docstring,
50
50
  and by its contained objects’ docstrings. The selection is controlled
51
51
  by the `strategy` argument.
52
52
 
@@ -90,14 +90,24 @@ def find_doctests(module, strategy=None,
90
90
  # Having collected the list of objects, extract doctests
91
91
  tests = []
92
92
  for item, name in zip(items, names):
93
- full_name = module.__name__ + '.' + name
94
93
  if inspect.ismodule(item):
95
94
  # do not recurse, only inspect the module docstring
96
95
  _finder = DTFinder(recurse=False, config=config)
97
96
  t = _finder.find(item, name, globs=globs, extraglobs=extraglobs)
97
+ unique_t = set(t)
98
98
  else:
99
+ full_name = module.__name__ + '.' + name
99
100
  t = finder.find(item, full_name, globs=globs, extraglobs=extraglobs)
100
- tests += t
101
+
102
+ unique_t = set(t)
103
+ if hasattr(item, '__mro__'):
104
+ # is a class, inspect superclasses
105
+ # cf https://github.com/scipy/scipy_doctest/issues/177
106
+ # item.__mro__ starts with itself, ends with `object`
107
+ for item_ in item.__mro__[1:-1]:
108
+ t_ = finder.find(item_, full_name, globs=globs, extraglobs=extraglobs)
109
+ unique_t.update(set(t_))
110
+ tests += list(unique_t)
101
111
 
102
112
  # If the skiplist contains methods of objects, their doctests may have been
103
113
  # left in the `tests` list. Remove them.
@@ -131,7 +141,7 @@ def testmod(m=None, name=None, globs=None, verbose=None,
131
141
  In verbose mode, the summary is detailed, else very brief (in fact,
132
142
  empty if all tests passed)
133
143
  Default is True.
134
- verbose : int
144
+ verbose : int
135
145
  Control the run verbosity:
136
146
  0 means only report failures,
137
147
  1 means emit object names,
@@ -165,7 +175,7 @@ def testmod(m=None, name=None, globs=None, verbose=None,
165
175
  (result, history)
166
176
  `result` is a namedtuple ``TestResult(failed, attempted)``
167
177
  `history` is a dict with details of which objects were examined (the
168
- keys are object names and values are individual objects' ``TestResult``s)
178
+ keys are object names and values are individual objects' ``TestResult`` s)
169
179
 
170
180
  Examples
171
181
  --------
@@ -194,7 +204,7 @@ def testmod(m=None, name=None, globs=None, verbose=None,
194
204
  For complex packages, prefer `strategy='api'`, which works as follows:
195
205
  - take the names of public objects from the `__all__` attribute of the package.
196
206
  - if `__all__` is not defined, take `dir(module)` and filter out names
197
- which start with a leading underscore and dunders.
207
+ which start with a leading underscore and dunders.
198
208
  - filter out deprecated items, i.e. those which raise `DeprecationWarning`.
199
209
 
200
210
  """
@@ -296,7 +306,7 @@ def testfile(filename, module_relative=True, name=None, package=None,
296
306
  In verbose mode, the summary is detailed, else very brief (in fact,
297
307
  empty if all tests passed)
298
308
  Default is True.
299
- verbose : int
309
+ verbose : int
300
310
  Control the run verbosity:
301
311
  0 means only report failures,
302
312
  1 means emit object names,
@@ -325,7 +335,7 @@ def testfile(filename, module_relative=True, name=None, package=None,
325
335
  (result, history)
326
336
  `result` is a namedtuple ``TestResult(failed, attempted)``
327
337
  `history` is a dict with details of which objects were examined (the
328
- keys are object names and values are individual objects' ``TestResult``s)
338
+ keys are object names and values are individual objects' ``TestResult`` s)
329
339
  """
330
340
  # initial configuration
331
341
  if config is None:
@@ -468,4 +478,3 @@ def _main():
468
478
  if result.failed:
469
479
  return 1
470
480
  return 0
471
-
scipy_doctest/impl.py CHANGED
@@ -1,21 +1,15 @@
1
1
  import re
2
2
  import warnings
3
+ import inspect
3
4
  import doctest
4
5
  from doctest import NORMALIZE_WHITESPACE, ELLIPSIS, IGNORE_EXCEPTION_DETAIL
5
6
  from itertools import zip_longest
7
+ from sys import version_info
6
8
 
7
9
  import numpy as np
8
10
 
9
11
  from . import util
10
12
 
11
-
12
- ## shim numpy 1.x vs 2.0
13
- if np.__version__ < "2":
14
- VisibleDeprecationWarning = np.VisibleDeprecationWarning
15
- else:
16
- VisibleDeprecationWarning = np.exceptions.VisibleDeprecationWarning
17
-
18
-
19
13
  # Register the optionflag to skip whole blocks, i.e.
20
14
  # sequences of Examples without an intervening text.
21
15
  SKIPBLOCK = doctest.register_optionflag('SKIPBLOCK')
@@ -67,6 +61,7 @@ class DTConfig:
67
61
  >>> for test in tests:
68
62
  ... with user_context(test):
69
63
  ... runner.run(test)
64
+
70
65
  Default is a noop.
71
66
  local_resources: dict
72
67
  If a test needs some local files, list them here. The format is
@@ -189,7 +184,8 @@ class DTConfig:
189
184
  '.bar(', '.title', '.ylabel', '.xlabel', 'set_ylim', 'set_xlim',
190
185
  '# reformatted', '.set_xlabel(', '.set_ylabel(', '.set_zlabel(',
191
186
  '.set(xlim=', '.set(ylim=', '.set(xlabel=', '.set(ylabel=', '.xlim(',
192
- 'ax.set('}
187
+ 'ax.set(', '.text(',
188
+ }
193
189
  self.stopwords = stopwords
194
190
 
195
191
  if pseudocode is None:
@@ -223,8 +219,13 @@ class DTConfig:
223
219
 
224
220
 
225
221
  def try_convert_namedtuple(got):
226
- # suppose that "got" is smth like MoodResult(statistic=10, pvalue=0.1).
227
- # Then convert it to the tuple (10, 0.1), so that can later compare tuples.
222
+ """
223
+ Converts a string representation of a named tuple into a plain tuple.
224
+
225
+ Suppose that "got" is smth like MoodResult(statistic=10, pvalue=0.1).
226
+ Then convert it to the tuple (10, 0.1), so that can later compare tuples.
227
+ """
228
+
228
229
  num = got.count('=')
229
230
  if num == 0:
230
231
  # not a nameduple, bail out
@@ -263,6 +264,8 @@ def try_convert_printed_array(got):
263
264
 
264
265
 
265
266
  def has_masked(got):
267
+ """Check if a given string represents a NumPy masked array.
268
+ """
266
269
  return 'masked_array' in got and '--' in got
267
270
 
268
271
 
@@ -290,6 +293,20 @@ def try_split_shape_from_abbrv(s_got):
290
293
 
291
294
 
292
295
  class DTChecker(doctest.OutputChecker):
296
+ """
297
+ A drop-in replacement for `doctest.OutputChecker`.
298
+
299
+ Allows robust output comparison for numerical values and special
300
+ cases involving NumPy arrays, masked arrays, namedtuples, and object
301
+ memory addresses. It is configurable via a `DTConfig` object.
302
+
303
+ Parameters:
304
+ -----------
305
+ config : DTConfig, optional
306
+ Configuration object that controls various aspects of output checking.
307
+ If not provided, a default `DTConfig` instance is used.
308
+
309
+ """
293
310
  obj_pattern = re.compile(r'at 0x[0-9a-fA-F]+>')
294
311
  vanilla = doctest.OutputChecker()
295
312
 
@@ -330,13 +347,8 @@ class DTChecker(doctest.OutputChecker):
330
347
  # OK then, convert strings to objects
331
348
  ns = dict(self.config.check_namespace)
332
349
  try:
333
- with warnings.catch_warnings():
334
- # NumPy's ragged array deprecation of np.array([1, (2, 3)]);
335
- # also array abbreviations: try `np.diag(np.arange(1000))`
336
- warnings.simplefilter('ignore', VisibleDeprecationWarning)
337
-
338
- a_want = eval(want, dict(ns))
339
- a_got = eval(got, dict(ns))
350
+ a_want = eval(want, dict(ns))
351
+ a_got = eval(got, dict(ns))
340
352
  except Exception:
341
353
  # Maybe we're printing a numpy array? This produces invalid python
342
354
  # code: `print(np.arange(3))` produces "[0 1 2]" w/o commas between
@@ -350,9 +362,9 @@ class DTChecker(doctest.OutputChecker):
350
362
  s_got = try_convert_printed_array(s_got)
351
363
 
352
364
  return self.check_output(s_want, s_got, optionflags)
353
-
365
+
354
366
  #handle array abbreviation for n-dimensional arrays, n >= 1
355
- ndim_array = (s_want.startswith("array([") and "..." in s_want and
367
+ ndim_array = (s_want.startswith("array([") and "..." in s_want and
356
368
  s_got.startswith("array([") and "..." in s_got)
357
369
  if ndim_array:
358
370
  s_want, want_shape = try_split_shape_from_abbrv(s_want)
@@ -431,16 +443,31 @@ class DTChecker(doctest.OutputChecker):
431
443
  except Exception:
432
444
  pass
433
445
 
434
- with warnings.catch_warnings():
435
- # NumPy's ragged array deprecation of np.array([1, (2, 3)])
436
- warnings.simplefilter('ignore', VisibleDeprecationWarning)
437
-
438
- # This line is the crux of the whole thing. The rest is mostly scaffolding.
439
- result = np.allclose(want, got, atol=self.atol, rtol=self.rtol, equal_nan=True)
446
+ # This line is the crux of the whole thing. The rest is mostly scaffolding.
447
+ result = np.allclose(want, got, atol=self.atol, rtol=self.rtol, equal_nan=True)
440
448
  return result
441
449
 
442
450
 
443
451
  class DTRunner(doctest.DocTestRunner):
452
+ """
453
+ A drop-in replacement for `doctest.DocTestRunner`.
454
+
455
+ Improves how test names are reported and allows better control over exception handling.
456
+ It integrates with `DTConfig` to apply customized settings for doctest execution.
457
+
458
+ Parameters:
459
+ -----------
460
+ checker : doctest.OutputChecker, optional
461
+ A custom output checker, defaults to `DTConfig.CheckerKlass(config)`.
462
+ verbose : bool, optional
463
+ If `True`, enables verbose output.
464
+ optionflags : int, optional
465
+ Bitwise OR of `doctest` option flags; defaults to `DTConfig.optionflags`.
466
+ config : DTConfig, optional
467
+ A configuration object controlling doctest behavior; a default instance is used if not provided.
468
+
469
+ """
470
+
444
471
  DIVIDER = "\n"
445
472
 
446
473
  def __init__(self, checker=None, verbose=None, optionflags=None, config=None):
@@ -488,15 +515,20 @@ class DTRunner(doctest.DocTestRunner):
488
515
  def get_history(self):
489
516
  """Return a dict with names of items which were run.
490
517
 
491
- Actually the dict is `{name : (f, t)}`, where `name` is the name of
492
- an object, and the value is a tuple of the numbers of examples which
493
- failed and which were tried.
518
+ Actually the dict is `{name : (failures, tries, skips)}` (before Python
519
+ 3.13, just `{name : (failures, tries, skips)}`) where `name` is the
520
+ name of an object, and the value is a tuple of the numbers of examples
521
+ which failed, were tried, and were skipped, respectively.
494
522
  """
495
- return self._name2ft
523
+ if version_info >= (3, 13):
524
+ return self._stats
525
+ else:
526
+ return self._name2ft
496
527
 
497
528
 
498
529
  class DebugDTRunner(DTRunner):
499
- """Doctest runner which raises on a first error.
530
+ """
531
+ Doctest runner which raises an exception on the first error.
500
532
 
501
533
  Almost verbatim copy of `doctest.DebugRunner`.
502
534
  """
@@ -520,8 +552,24 @@ class DebugDTRunner(DTRunner):
520
552
 
521
553
 
522
554
  class DTFinder(doctest.DocTestFinder):
523
- """A Finder with helpful defaults.
524
555
  """
556
+ A drop-in replacement for `doctest.DocTestFinder` with helpful defaults.
557
+
558
+ Parameters:
559
+ -----------
560
+ verbose : bool, optional
561
+ If `True`, enables verbose output during doctest discovery.
562
+ parser : doctest.DocTestParser, optional
563
+ A custom parser for extracting doctests; defaults to `DTParser(config)`.
564
+ recurse : bool, default=True
565
+ Whether to recursively search for doctests in nested objects.
566
+ exclude_empty : bool, default=True
567
+ Whether to exclude objects that have no doctests.
568
+ config : DTConfig, optional
569
+ A configuration object controlling doctest behavior; a default instance is used if not provided.
570
+
571
+ """
572
+
525
573
  def __init__(self, verbose=None, parser=None, recurse=True,
526
574
  exclude_empty=True, config=None):
527
575
  if config is None:
@@ -536,14 +584,34 @@ class DTFinder(doctest.DocTestFinder):
536
584
  if globs is None:
537
585
  globs = dict(self.config.default_namespace)
538
586
  # XXX: does this make similar checks in testmod/testfile duplicate?
539
- if module not in self.config.skiplist:
587
+ if module not in self.config.skiplist:
540
588
  tests = super().find(obj, name, module, globs, extraglobs)
589
+
590
+ if inspect.isclass(obj):
591
+ for name_, method in inspect.getmembers(obj):
592
+ if inspect.isdatadescriptor(method):
593
+ tests += super().find(
594
+ method, f'{name}.{name_}', module, globs, extraglobs
595
+ )
541
596
  return tests
542
597
 
543
598
 
544
599
  class DTParser(doctest.DocTestParser):
545
- """A Parser with a stopword list.
546
600
  """
601
+ A drop-in replacement for `doctest.DocTestParser` with a stopword list.
602
+
603
+ It filters out stopwords, pseudocode, and random markers from doctests.
604
+
605
+ Parameters:
606
+ -----------
607
+ config : DTConfig, optional
608
+ A configuration object containing:
609
+ - `stopwords`: A list of words that signal a doctest should be ignored.
610
+ - `pseudocode`: A list of markers indicating non-executable code.
611
+ - `rndm_markers`: A list of markers indicating results may vary.
612
+
613
+ """
614
+
547
615
  def __init__(self, config=None):
548
616
  if config is None:
549
617
  config = DTConfig()
@@ -600,4 +668,3 @@ class DTParser(doctest.DocTestParser):
600
668
  example.want += " # _ignore\n"
601
669
  examples.append(example)
602
670
  return examples
603
-
scipy_doctest/plugin.py CHANGED
@@ -47,7 +47,7 @@ def pytest_ignore_collect(collection_path, config):
47
47
  """
48
48
  Determine whether to ignore the specified collection path.
49
49
  This function is used to exclude the 'tests' directory and test modules when
50
- the '--doctest-modules' option is used.
50
+ the `--doctest-modules` option is used.
51
51
  """
52
52
  if config.getoption("--doctest-modules"):
53
53
  path_str = str(collection_path)
@@ -62,7 +62,7 @@ def pytest_ignore_collect(collection_path, config):
62
62
  def is_private(item):
63
63
  """Decide if an DocTestItem `item` is private.
64
64
 
65
- Private items are ignored in pytest_collect_modifyitem`.
65
+ Private items are ignored in `pytest_collect_modifyitem`.
66
66
  """
67
67
  # Here we look at the name of a test module/object. A seemingly less
68
68
  # hacky alternative is to populate a set of seen `item.dtest` attributes
@@ -174,7 +174,7 @@ def _is_deprecated(module):
174
174
  class DTModule(DoctestModule):
175
175
  """
176
176
  This class extends the DoctestModule class provided by pytest.
177
-
177
+
178
178
  DTModule is responsible for overriding the behavior of the collect method.
179
179
  The collect method is called by pytest to collect and generate test items for doctests
180
180
  in the specified module or file.
@@ -222,7 +222,7 @@ class DTModule(DoctestModule):
222
222
 
223
223
  optionflags = dt_config.optionflags
224
224
 
225
- # Plug in the custom runner: `PytestDTRunner`
225
+ # Plug in the custom runner: `PytestDTRunner`
226
226
  runner = _get_runner(self.config,
227
227
  verbose=False,
228
228
  optionflags=optionflags,
@@ -245,7 +245,7 @@ class DTModule(DoctestModule):
245
245
  class DTTextfile(DoctestTextfile):
246
246
  """
247
247
  This class extends the DoctestTextfile class provided by pytest.
248
-
248
+
249
249
  DTTextfile is responsible for overriding the behavior of the collect method.
250
250
  The collect method is called by pytest to collect and generate test items for doctests
251
251
  in the specified text files.
@@ -282,7 +282,7 @@ class DTTextfile(DoctestTextfile):
282
282
  def _get_runner(config, verbose, optionflags):
283
283
  """
284
284
  Override function to return an instance of PytestDTRunner.
285
-
285
+
286
286
  This function creates and returns an instance of PytestDTRunner, a custom runner class
287
287
  that extends the behavior of DebugDTRunner for running doctests in pytest.
288
288
  """
@@ -290,13 +290,13 @@ def _get_runner(config, verbose, optionflags):
290
290
  def run(self, test, compileflags=None, out=None, clear_globs=False):
291
291
  """
292
292
  Run tests in context managers.
293
-
293
+
294
294
  Restore the errstate/print state after each docstring.
295
295
  Also, make MPL backend non-GUI and close the figures.
296
-
296
+
297
297
  The order of context managers is actually relevant. Consider
298
298
  user_context_mgr that turns warnings into errors.
299
-
299
+
300
300
  Additionally, suppose that MPL deprecates something and plt.something
301
301
  starts issuing warnings. Now all of those become errors
302
302
  *unless* the `mpl()` context mgr has a chance to filter them out
@@ -24,4 +24,3 @@ def func_name_error():
24
24
  Further name errors are also suppressed (which is a bug, too):
25
25
  >>> raise NameError('Also legit')
26
26
  """
27
-
@@ -61,5 +61,3 @@ def _underscored_private_func():
61
61
  >>> 9 + 12
62
62
  21
63
63
  """
64
-
65
-
@@ -0,0 +1,22 @@
1
+ """
2
+ Private method in subclasses
3
+ """
4
+
5
+ __all__ = ["Klass"]
6
+
7
+ class _PrivateKlass:
8
+ def private_method(self):
9
+ """
10
+ >>> 2 / 3
11
+ 0.667
12
+ """
13
+ pass
14
+
15
+
16
+ class Klass(_PrivateKlass):
17
+ def public_method(self):
18
+ """
19
+ >>> 3 / 4
20
+ 0.74
21
+ """
22
+ pass
@@ -33,5 +33,3 @@ def sio():
33
33
  [ 2., 5., 8., 11.],
34
34
  [ 3., 6., 9., 12.]]])}
35
35
  """
36
-
37
-
@@ -3,8 +3,6 @@ __all__ = [
3
3
  'func7', 'manip_printoptions', 'array_abbreviation'
4
4
  ]
5
5
 
6
- import numpy as np
7
- import pytest
8
6
 
9
7
  def func():
10
8
  """
@@ -215,7 +215,7 @@ Smoothing filters
215
215
  corresponds to convolution with a Gaussian kernel. An order of 1, 2,
216
216
  or 3 corresponds to convolution with the first, second, or third
217
217
  derivatives of a Gaussian. Higher-order derivatives are not
218
- implemented.
218
+ implemented.
219
219
 
220
220
 
221
221
 
@@ -232,7 +232,7 @@ Smoothing filters
232
232
  number, to specify the same order for all axes, or a sequence of
233
233
  numbers to specify a different order for each axis. The example below
234
234
  shows the filter applied on test data with different values of *sigma*.
235
- The *order* parameter is kept at 0.
235
+ The *order* parameter is kept at 0.
236
236
 
237
237
  .. plot:: tutorial/examples/gaussian_filter_plot1.py
238
238
  :align: center
@@ -1,10 +1,14 @@
1
1
  import pytest
2
2
 
3
+ import numpy as np
4
+
3
5
  from . import finder_cases
6
+ from . import finder_cases_2
4
7
  from ..util import get_all_list, get_public_objects
5
8
  from ..impl import DTFinder, DTConfig
6
9
  from ..frontend import find_doctests
7
10
 
11
+
8
12
  def test_get_all_list():
9
13
  items, depr, other = get_all_list(finder_cases)
10
14
  assert sorted(items) == ['Klass', 'func']
@@ -82,8 +86,8 @@ class TestSkiplist:
82
86
  assert sorted(names) == sorted(wanted_names)
83
87
 
84
88
  def test_get_doctests_strategy_None(self):
85
- # Add a skiplist: strategy=None skips listed items
86
- base = finder_cases.__name__
89
+ # Add a skiplist: strategy=None skips listed items
90
+ base = finder_cases.__name__
87
91
  skips = [base + '.func', base + '.Klass.meth_2']
88
92
  config = DTConfig(skiplist=skips)
89
93
 
@@ -98,8 +102,8 @@ class TestSkiplist:
98
102
  assert sorted(names) == sorted(wanted_names)
99
103
 
100
104
  def test_get_doctests_strategy_api(self):
101
- # Add a skiplist: strategy='api' skips listed items
102
- base = finder_cases.__name__
105
+ # Add a skiplist: strategy='api' skips listed items
106
+ base = finder_cases.__name__
103
107
  skips = [base + '.func', base + '.Klass.meth_2']
104
108
  config = DTConfig(skiplist=skips)
105
109
 
@@ -111,12 +115,13 @@ class TestSkiplist:
111
115
  # - *private* stuff, which is not in `__all__`
112
116
  wanted_names = ['Klass', 'Klass.meth']
113
117
  wanted_names = [base] + [base + '.' + n for n in wanted_names]
118
+ wanted_names += [f'{base}.Klass.__weakref__']
114
119
 
115
120
  assert sorted(names) == sorted(wanted_names)
116
121
 
117
122
  def test_get_doctests_strategy_list(self):
118
- # Add a skiplist: strategy=<list> skips listed items
119
- base = finder_cases.__name__
123
+ # Add a skiplist: strategy=<list> skips listed items
124
+ base = finder_cases.__name__
120
125
  skips = [base + '.func', base + '.Klass.meth_2']
121
126
  config = DTConfig(skiplist=skips)
122
127
 
@@ -129,6 +134,7 @@ class TestSkiplist:
129
134
  # - the 'base' module (via the strategy=<list>)
130
135
  wanted_names = ['Klass', 'Klass.meth']
131
136
  wanted_names = [base + '.' + n for n in wanted_names]
137
+ wanted_names += [f'{base}.Klass.__weakref__']
132
138
 
133
139
  assert sorted(names) == sorted(wanted_names)
134
140
 
@@ -137,9 +143,13 @@ def test_explicit_object_list():
137
143
  objs = [finder_cases.Klass]
138
144
  tests = find_doctests(finder_cases, strategy=objs)
139
145
 
146
+ names = sorted([test.name for test in tests])
147
+
140
148
  base = 'scipy_doctest.tests.finder_cases'
141
- assert ([test.name for test in tests] ==
142
- [base + '.Klass', base + '.Klass.meth', base + '.Klass.meth_2'])
149
+ expected = sorted([f'{base}.Klass', f'{base}.Klass.__weakref__',
150
+ f'{base}.Klass.meth', f'{base}.Klass.meth_2',])
151
+
152
+ assert names == expected
143
153
 
144
154
 
145
155
  def test_explicit_object_list_with_module():
@@ -149,22 +159,61 @@ def test_explicit_object_list_with_module():
149
159
  objs = [finder_cases, finder_cases.Klass]
150
160
  tests = find_doctests(finder_cases, strategy=objs)
151
161
 
162
+ names = sorted([test.name for test in tests])
163
+
152
164
  base = 'scipy_doctest.tests.finder_cases'
153
- assert ([test.name for test in tests] ==
154
- [base, base + '.Klass', base + '.Klass.meth', base + '.Klass.meth_2'])
165
+ expected = sorted([base, f'{base}.Klass', f'{base}.Klass.__weakref__',
166
+ f'{base}.Klass.meth', f'{base}.Klass.meth_2'])
167
+
168
+ assert names == expected
155
169
 
156
170
 
157
171
  def test_find_doctests_api():
158
172
  # Test that the module itself is included with strategy='api'
159
173
  tests = find_doctests(finder_cases, strategy='api')
160
174
 
175
+ names = sorted([test.name for test in tests])
176
+
161
177
  base = 'scipy_doctest.tests.finder_cases'
162
- assert ([test.name for test in tests] ==
163
- [base + '.func', base + '.Klass', base + '.Klass.meth',
164
- base + '.Klass.meth_2', base])
178
+ expected = sorted([base + '.func', base + '.Klass', base + '.Klass.meth',
179
+ base + '.Klass.meth_2', base + '.Klass.__weakref__', base])
180
+
181
+ assert names == expected
165
182
 
166
183
 
167
184
  def test_dtfinder_config():
168
185
  config = DTConfig()
169
186
  finder = DTFinder(config=config)
170
187
  assert finder.config is config
188
+
189
+
190
+ @pytest.mark.skipif(np.__version__ < '2', reason="XXX check if works on numpy 1.x")
191
+ def test_descriptors_get_collected():
192
+ tests = find_doctests(np, strategy=[np.dtype])
193
+ names = [test.name for test in tests]
194
+ assert 'numpy.dtype.kind' in names # was previously missing
195
+
196
+
197
+ @pytest.mark.parametrize('strategy', [None, 'api'])
198
+ def test_private_superclasses(strategy):
199
+ # Test that methods from inherited private superclasses get collected
200
+ tests = find_doctests(finder_cases_2, strategy=strategy)
201
+
202
+ names = set(test.name.split('.')[-1] for test in tests)
203
+ expected_names = ['finder_cases_2', 'public_method', 'private_method']
204
+ if strategy == 'api':
205
+ expected_names += ['__weakref__']
206
+
207
+ assert len(tests) == len(expected_names)
208
+ assert names == set(expected_names)
209
+
210
+
211
+ def test_private_superclasses_2():
212
+ # similar to test_private_superclass, only with an explicit strategy=list
213
+ tests = find_doctests(finder_cases_2, strategy=[finder_cases_2.Klass])
214
+
215
+ names = set(test.name.split('.')[-1] for test in tests)
216
+ expected_names = ['public_method', 'private_method', '__weakref__']
217
+
218
+ assert len(tests) == len(expected_names)
219
+ assert names == set(expected_names)
@@ -31,6 +31,3 @@ def test_config_nocopy():
31
31
  config = DTConfig()
32
32
  parser = DTParser(config)
33
33
  assert parser.config is config
34
-
35
-
36
-
@@ -39,7 +39,7 @@ def test_failure_cases(pytester):
39
39
  result = pytester.inline_run(python_file, "--doctest-modules")
40
40
  assert result.ret == pytest.ExitCode.TESTS_FAILED
41
41
 
42
-
42
+
43
43
  @pytest.mark.skipif(not HAVE_MATPLOTLIB, reason='need matplotlib')
44
44
  def test_stopword_cases(pytester):
45
45
  """Test that pytest uses the DTParser for doctests."""
@@ -90,4 +90,3 @@ def test_alt_checker(pytester):
90
90
  # run all tests with pytest
91
91
  result = pytester.inline_run(f, '--doctest-modules')
92
92
  assert result.ret == pytest.ExitCode.TESTS_FAILED
93
-
@@ -102,4 +102,3 @@ class TestCheckerDropIn:
102
102
  with pytest.raises(doctest.DocTestFailure):
103
103
  for t in tests:
104
104
  runner.run(t)
105
-
@@ -1,4 +1,5 @@
1
1
  import doctest
2
+ from sys import version_info
2
3
 
3
4
  try:
4
5
  import matplotlib.pyplot as plt # noqa
@@ -57,7 +58,8 @@ class TestSyntaxErrors:
57
58
  lineno=0)
58
59
  runner = DebugDTRunner()
59
60
  runner.run(test)
60
- assert runner.get_history() == {'none : +SKIP': (0, 0)}
61
+ stats = (0, 1, 1) if version_info >= (3, 13) else (0, 0)
62
+ assert runner.get_history() == {'none : +SKIP': stats}
61
63
 
62
64
  def test_invalid_python_pseudocode(self):
63
65
  # Marking a test as pseudocode is equivalent to a +SKIP:
@@ -74,7 +76,8 @@ class TestSyntaxErrors:
74
76
  lineno=0)
75
77
  runner = DebugDTRunner()
76
78
  runner.run(test)
77
- assert runner.get_history() == {'none : pseudocode': (0, 0)}
79
+ stats = (0, 1, 1) if version_info >= (3, 13) else (0, 0)
80
+ assert runner.get_history() == {'none : pseudocode': stats}
78
81
 
79
82
 
80
83
  class TestPseudocodeMarkers:
@@ -125,7 +128,8 @@ class TestStopwords:
125
128
  runner.run(test)
126
129
 
127
130
  # one example tried, of which zero failed
128
- assert runner.get_history() == {'stopwords_bogus_output': (0, 1)}
131
+ stats = (0, 1, 0) if version_info >= (3, 13) else (0, 1)
132
+ assert runner.get_history() == {'stopwords_bogus_output': stats}
129
133
 
130
134
 
131
135
  class TestMayVary:
@@ -148,7 +152,8 @@ class TestMayVary:
148
152
  runner.run(test)
149
153
 
150
154
  # one example tried, of which zero failed
151
- assert runner.get_history() == {'may_vary_markers': (0, 1)}
155
+ stats = (0, 1, 0) if version_info >= (3, 13) else (0, 1)
156
+ assert runner.get_history() == {'may_vary_markers': stats}
152
157
 
153
158
  def test_may_vary_source(self):
154
159
  # The marker needs to be added to the example output, not source.
@@ -164,7 +169,8 @@ class TestMayVary:
164
169
  runner.run(test)
165
170
 
166
171
  # one example tried, of which zero failed
167
- assert runner.get_history() == {'may_vary_source': (0, 1)}
172
+ stats = (0, 1, 0) if version_info >= (3, 13) else (0, 1)
173
+ assert runner.get_history() == {'may_vary_source': stats}
168
174
 
169
175
  def test_may_vary_syntax_error(self):
170
176
  # `# may vary` markers do not mask syntax errors, unlike `# doctest: +SKIP`
@@ -193,7 +199,7 @@ below
193
199
 
194
200
  Note how the block above will fail doctesting unless the second line is
195
201
  skipped. A standard solution is to add a +SKIP marker to every line, but this
196
- is ugly and we skip the whole block instead.
202
+ is ugly and we skip the whole block instead.
197
203
 
198
204
  Once the block is over, we get back to usual doctests, which are not skipped
199
205
 
@@ -216,4 +222,3 @@ def test_SKIPBLOCK():
216
222
  assert test.examples[0].options[SKIP] is True
217
223
  assert test.examples[1].options[SKIP] is True
218
224
  assert test.examples[2].options == {} # not skipped
219
-
@@ -53,7 +53,7 @@ def test_stopwords():
53
53
  res, _ = _testmod(stopwords, verbose=_VERBOSE)
54
54
  assert res.failed == 0
55
55
  assert res.attempted != 0
56
-
56
+
57
57
 
58
58
  @pytest.mark.skipif(not HAVE_SCIPY, reason='need scipy')
59
59
  def test_public_obj_discovery():
scipy_doctest/util.py CHANGED
@@ -260,9 +260,9 @@ modules = []
260
260
  def generate_log(module, test):
261
261
  """
262
262
  Generate a log of the doctested items.
263
-
263
+
264
264
  This function logs the items being doctested to a file named 'doctest.log'.
265
-
265
+
266
266
  Args:
267
267
  module (module): The module being doctested.
268
268
  test (str): The name of the doctest item.
@@ -276,4 +276,3 @@ def generate_log(module, test):
276
276
  LOGFILE.write(f"{test}\n")
277
277
  except AttributeError:
278
278
  LOGFILE.write(f"{test}\n")
279
-
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: scipy_doctest
3
- Version: 1.5.1
3
+ Version: 1.7
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
@@ -10,20 +10,36 @@ Classifier: License :: OSI Approved :: BSD License
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Framework :: Pytest
13
+ License-File: LICENSE
13
14
  Requires-Dist: numpy>=1.19.5
14
15
  Requires-Dist: pytest
15
- Requires-Dist: scipy ; extra == "test"
16
+ Requires-Dist: furo==2024.8.6 ; extra == "doc"
17
+ Requires-Dist: myst-parser==4.0.0 ; extra == "doc"
18
+ Requires-Dist: sphinx==8.1.3 ; extra == "doc"
19
+ Requires-Dist: sphinx-copybutton==0.5.2 ; extra == "doc"
20
+ Requires-Dist: scipy <= 1.14.1 ; extra == "test"
16
21
  Requires-Dist: matplotlib ; extra == "test"
17
22
  Project-URL: Home, https://github.com/scipy/scipy_doctest
23
+ Provides-Extra: doc
18
24
  Provides-Extra: test
19
25
 
20
26
  # Floating-point aware, human readable, numpy-compatible doctesting.
21
27
 
28
+ [![PyPI version][pypi-version]][pypi-link]
29
+ [![Conda-Forge][conda-badge]][conda-link]
30
+
31
+ <!-- prettier-ignore-start -->
32
+ [conda-badge]: https://img.shields.io/conda/vn/conda-forge/scipy-doctest
33
+ [conda-link]: https://anaconda.org/conda-forge/scipy-doctest
34
+ [pypi-link]: https://pypi.org/project/scipy-doctest/
35
+ [pypi-version]: https://img.shields.io/pypi/v/scipy-doctest
36
+ <!-- prettier-ignore-end -->
37
+
22
38
  ## TL;DR
23
39
 
24
40
  This project extends the standard library `doctest` module to allow flexibility
25
41
  and easy customization of finding, parsing and checking code examples in
26
- documentation.
42
+ documentation.
27
43
 
28
44
  Can be used either as drop-in `doctest` replacement or through the `pytest`
29
45
  integration. Uses a floating-point aware doctest checker by default.
@@ -31,7 +47,7 @@ integration. Uses a floating-point aware doctest checker by default.
31
47
  ## Motivation and scope
32
48
 
33
49
  Having examples in the documentation is great. Having wrong examples in the
34
- documentation is not that great however.
50
+ documentation is not that great however.
35
51
 
36
52
  The standard library `doctest` module is great for making sure that docstring
37
53
  examples are correct. However, the `doctest` module is limited in several
@@ -46,7 +62,7 @@ This looks reasonably clear but does not work, in three different ways.
46
62
  _First_, `1/3` is not equal to 0.333 because floating-point arithmetic.
47
63
  _Second_, `numpy` adds whitespace to its output, this whitespace confuses the
48
64
  `doctest`, which is whitespace-sensitive. Therefore, we added a magic directive,
49
- `+SKIP` to avoid a doctest error. _Third_, the example is actually
65
+ `+SKIP` to avoid a doctest error. _Third_, the example is actually
50
66
  wrong---notice `0.669` which is not equal to `2/3` to three sig figs. The error
51
67
  went unnoticed by the doctester also because of the `+SKIP` directive.
52
68
 
@@ -56,44 +72,44 @@ a human reader, and should not be present in the documentation.
56
72
  This package defines modified doctesting routines which fix these deficiencies.
57
73
  Its main features are
58
74
 
59
- - *Doctesting is floating-point aware.* In a nutshell, the core check is
75
+ - _Doctesting is floating-point aware._ In a nutshell, the core check is
60
76
  `np.allclose(want, got, atol=..., rtol=...)`, with user-controllable abs
61
77
  and relative tolerances. In the example above (_sans_ `# doctest: +SKIP`),
62
78
  `want` is the desired output, `array([0.333, 0.669, 1])` and `got` is the
63
79
  actual output from numpy: `array([0.33333333, 0.66666667, 1. ])`.
64
80
 
65
- - *Human-readable skip markers.* Consider
81
+ - _Human-readable skip markers._ Consider
66
82
  ```
67
83
  >>> np.random.randint(100)
68
84
  42 # may vary
69
85
  ```
70
- Note that the markers (by default, `"# may vary"` and `"# random"`) can be applied
71
- to either an example's output, or its source.
86
+ Note that the markers (by default, `"# may vary"` and `"# random"`) can be applied
87
+ to either an example's output, or its source.
72
88
 
73
89
  Also note a difference with respect to the standard `# doctest: +SKIP`: the latter
74
90
  skips the example entirely, while these additional markers only skip checking
75
91
  the output. Thus the example source needs to be valid python code still.
76
92
 
77
- - A user-configurable list of *stopwords*. If an example contains a stopword,
93
+ - A user-configurable list of _stopwords_. If an example contains a stopword,
78
94
  it is checked to be valid python, but the output is not checked. This can
79
95
  be useful e.g. for not littering the documentation with the output of
80
96
  `import matplotlib.pyplot as plt; plt.xlim([2.3, 4.5])`.
81
97
 
82
- - A user-configurable list of *pseudocode* markers. If an example contains one
98
+ - A user-configurable list of _pseudocode_ markers. If an example contains one
83
99
  of these markers, it is considered pseudocode and is not checked.
84
100
  This is useful for `from example import some_functions` and similar stanzas.
85
101
 
86
102
  - A `# doctest: +SKIPBLOCK` option flag to skip whole blocks of pseudocode. Here
87
103
  a 'block' is a sequence of doctest examples without any intervening text.
88
104
 
89
- - *Doctest discovery* is somewhat more flexible then the standard library
105
+ - _Doctest discovery_ is somewhat more flexible then the standard library
90
106
  `doctest` module. Specifically, one can use `testmod(module, strategy='api')`
91
107
  to only examine public objects of a module. This is helpful for complex
92
108
  packages, with non-trivial internal file structure. Alternatively, the default
93
109
  value of `strategy=None` is equivalent to the standard `doctest` module
94
110
  behavior.
95
111
 
96
- - *User configuration*. Essentially all aspects of the behavior are user
112
+ - _User configuration_. Essentially all aspects of the behavior are user
97
113
  configurable via a `DTConfig` instance attributes. See the `DTConfig`
98
114
  docstring for details.
99
115
 
@@ -124,7 +140,7 @@ pip install scipy-doctest
124
140
 
125
141
  2. **Register or load the plugin**
126
142
 
127
- Next, you need to register or load the pytest plugin within your test module or `conftest.py` file.
143
+ Next, you need to register or load the pytest plugin within your test module or `conftest.py` file.
128
144
 
129
145
  To do this, add the following line of code:
130
146
 
@@ -136,14 +152,16 @@ pytest_plugins = "scipy_doctest"
136
152
 
137
153
  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
154
 
139
- 3. **Run doctests**
155
+ 3. **Run doctests**
140
156
 
141
157
  Once the plugin is registered, run the doctests by executing the following command:
142
158
 
143
159
  ```bash
144
160
  $ python -m pytest --doctest-modules
145
161
  ```
162
+
146
163
  or
164
+
147
165
  ```bash
148
166
  $ pytest --pyargs <your-package> --doctest-modules
149
167
  ```
@@ -155,10 +173,9 @@ use the command flag
155
173
  $ pytest --pyargs <your-package> --doctest-modules --doctest-collect=api
156
174
  ```
157
175
 
158
- See [More fine-grained control](https://github.com/scipy/scipy_doctest#More-fine-grained-control) section
176
+ See [More fine-grained control](#more-fine-grained-control) section
159
177
  for details on how to customize the behavior.
160
178
 
161
-
162
179
  ### Basic usage
163
180
 
164
181
  The use of `pytest` is optional, and you can use the `doctest` layer API.
@@ -171,6 +188,7 @@ For example,
171
188
  >>> res
172
189
  TestResults(failed=0, attempted=764)
173
190
  ```
191
+
174
192
  The second return value, `hist` is a dict which maps the names of the objects
175
193
  to the numbers of failures and attempts for individual examples.
176
194
 
@@ -178,10 +196,10 @@ For more details, see the `testmod` docstring. Other useful functions are
178
196
  `find_doctests`, `run_docstring_examples` and `testfile` (the latter two mimic
179
197
  the behavior of the eponymous functions of the `doctest` module).
180
198
 
181
-
182
199
  ### Command-line interface
183
200
 
184
201
  There is a basic CLI, which also mimics that of the `doctest` module:
202
+
185
203
  ```
186
204
  $ python -m scipy_doctest foo.py
187
205
  ```
@@ -190,28 +208,30 @@ Note that, just like `$ python -m doctest foo.py`, this may
190
208
  fail if `foo.py` is a part of a package due to package imports.
191
209
 
192
210
  Text files can also be CLI-checked:
211
+
193
212
  ```
194
213
  $ python -m scipy_doctest bar.rst
195
214
  ```
196
215
 
197
216
  Notice that the command-line usage only uses the default `DTConfig` settings.
198
217
 
218
+ (more-fine-grained-control)=
199
219
 
200
220
  ## More fine-grained control
201
221
 
202
222
  More fine-grained control of the functionality is available via the following
203
223
  classes
204
224
 
205
- | Class | `doctest` analog |
206
- |-------------|--------------------|
207
- | `DTChecker` | `DocTestChecker` |
208
- | `DTParser` | `DocTestParser` |
209
- | `DTRunner` | `DocTestRunner` |
210
- | `DTFinder` | `DocTestFinder` |
211
- | `DTContext` | -- |
225
+ | Class | `doctest` analog |
226
+ | ----------- | ---------------- |
227
+ | `DTChecker` | `DocTestChecker` |
228
+ | `DTParser` | `DocTestParser` |
229
+ | `DTRunner` | `DocTestRunner` |
230
+ | `DTFinder` | `DocTestFinder` |
231
+ | `DTContext` | -- |
212
232
 
213
233
  The `DTContext` class is just a bag class which holds various configuration
214
- settings as attributes. An instance of this class is passed around, so user
234
+ settings as attributes. An instance of this class is passed around, so user
215
235
  configuration is simply creating an instance, overriding an attribute and
216
236
  passing the instance to `testmod` or constructors of `DT*` objects. Defaults
217
237
  are provided, based on a long-term usage in SciPy.
@@ -220,7 +240,7 @@ See the [DTConfig docstring](https://github.com/scipy/scipy_doctest/blob/main/sc
220
240
  for the full set of attributes that allow you to fine-tune your doctesting experience.
221
241
 
222
242
  To set any of these attributes, create an instance of `DTConfig` and assign the attributes
223
- in a usual way.
243
+ in a usual way.
224
244
 
225
245
  If using the pytest plugin, it is convenient to use the default instance, which
226
246
  is predefined in `scipy_doctest/conftest.py`. This instance will be automatically
@@ -260,14 +280,12 @@ dt_config.skiplist = {
260
280
 
261
281
  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.
262
282
 
263
-
264
283
  #### Alternative Checkers
265
284
 
266
285
  By default, we use the floating-point aware `DTChecker`. If you want to use an
267
286
  alternative checker, all you need to do is to define the corresponding class,
268
287
  and add an attribute to the `DTConfig` instance. For example,
269
288
 
270
-
271
289
  ```
272
290
  class VanillaOutputChecker(doctest.OutputChecker):
273
291
  """doctest.OutputChecker to drop in for DTChecker.
@@ -290,10 +308,8 @@ See [a pytest example](https://github.com/scipy/scipy_doctest/blob/main/scipy_do
290
308
  and [a doctest example](https://github.com/scipy/scipy_doctest/blob/main/scipy_doctest/tests/test_runner.py#L94)
291
309
  for more details.
292
310
 
293
-
294
311
  ### NumPy and SciPy wrappers
295
312
 
296
-
297
313
  NumPy wraps `scipy-doctest` with the `spin` command
298
314
 
299
315
  ```
@@ -307,13 +323,11 @@ $ python dev.py smoke-docs # check docstrings
307
323
  $ python dev.py smoke-tutorials # ReST user guide tutorials
308
324
  ```
309
325
 
310
-
311
-
312
326
  ## Rough edges and sharp bits
313
327
 
314
328
  Here is a (non-exhaustive) list of possible gotchas:
315
329
 
316
- - *In-place development builds*.
330
+ - _In-place development builds_.
317
331
 
318
332
  Some tools (looking at you `meson-python`) simulate in-place builds with a
319
333
  `build-install` directory. If this directory is located under the project root,
@@ -329,12 +343,15 @@ $ pytest build-install/lib/python3.10/site-packages/scipy/ --doctest-modules
329
343
 
330
344
  instead of `$ pytest --pyargs scipy`.
331
345
 
332
- If push comes to shove, you may try using the magic env variable:
346
+ If you use actual editable installs, of the `pip install --no-build-isolation -e .` variety, you may
347
+ need to add `--import-mode=importlib` to the `pytest` invocation.
348
+
349
+ If push really comes to shove, you may try using the magic env variable:
333
350
  ` PY_IGNORE_IMPORTMISMATCH=1 pytest ...`,
334
351
  however the need usually indicates an issue with the package itself.
335
352
  (see [gh-107](https://github.com/scipy/scipy_doctest/pull/107) for an example).
336
353
 
337
- - *Optional dependencies are not that optional*
354
+ - _Optional dependencies are not that optional_
338
355
 
339
356
  If your package contains optional dependencies, doctests do not know about them
340
357
  being optional. So you either guard the imports in doctests (yikes!), or
@@ -353,11 +370,11 @@ Note that installed packages are no different:
353
370
  $ pytest --pyargs scipy --doctest-modules --ignore=/path/to/installed/scipy/_lib
354
371
  ```
355
372
 
356
- - *Doctest collection strategies*
373
+ - _Doctest collection strategies_
357
374
 
358
375
  The default collection strategy follows `doctest` module and `pytest`. This leads
359
376
  to duplicates if your package has the split between public and \_private modules,
360
- where public modules re-export things from private ones. The solution is to
377
+ where public modules re-export things from private ones. The solution is to
361
378
  use `$ pytest --doctest-collect=api` CLI switch: with this, only public
362
379
  objects will be collected.
363
380
 
@@ -375,8 +392,7 @@ leads to
375
392
  - `scipy.linalg._basic.det`, collected from `scipy/linalg/_basic.py`, is private.
376
393
  - `scipy.linalg.det`, collected from `scipy/linalg/__init__.py`, is public.
377
394
 
378
-
379
- - *`pytest`'s assertion rewriting*
395
+ - _`pytest`'s assertion rewriting_
380
396
 
381
397
  In some rare cases you may need to either explicitly register the `scipy_doctest`
382
398
  package with the `pytest` assertion rewriting machinery, or ask it to avoid rewriting
@@ -388,7 +404,6 @@ In general, rewriting assertions is not very useful for doctests, as the
388
404
  output on error is fixed by the doctest machinery anyway. Therefore, we believe
389
405
  adding `--assert=plain` is reasonable.
390
406
 
391
-
392
407
  ## Prior art and related work
393
408
 
394
409
  - `pytest` provides some limited floating-point aware `NumericLiteralChecker`.
@@ -409,15 +424,14 @@ adding `--assert=plain` is reasonable.
409
424
  to be not easy to reason about, work with, and extend to other projects.
410
425
 
411
426
  This project is mainly the core functionality of the modified
412
- `refguide-check` doctesting, extracted to a separate package.
427
+ `refguide-check` doctesting, extracted to a separate package.
413
428
  We believe having it separate simplifies both addressing the needs of these
414
429
  two packages, and potential adoption by other projects.
415
430
 
416
-
417
431
  ### Bug reports, feature requests and contributions
418
432
 
419
433
  This package is work in progress. Contributions are most welcome!
420
434
  Please don't hesitate to open an issue in the tracker or send a pull request.
421
435
 
422
- The current location of the issue tracker is https://github.com/scipy/scipy_doctest.
436
+ The current location of the issue tracker is <https://github.com/scipy/scipy_doctest>.
423
437
 
@@ -0,0 +1,33 @@
1
+ scipy_doctest/__init__.py,sha256=KwjnUgFMzyn5AXQBP39C0zuq2JQOiT1aNDXajOu3APs,648
2
+ scipy_doctest/__main__.py,sha256=H8jTO13GlOLzexbgu7lHMJW1y3_NhLOSArARFZ5WS7o,90
3
+ scipy_doctest/conftest.py,sha256=rOkdrpmq95vzvMGMqm88c4HTrbpxLOvANtEuiD6suCg,52
4
+ scipy_doctest/frontend.py,sha256=wl0-8I6epZ49TwxKVSuZbizS6J_pxea99z0vAv2EdbY,19126
5
+ scipy_doctest/impl.py,sha256=kp8W2p7mTvQR-TwYc2EXA3JiXo1Z9t98XDzFsoOUVSc,26480
6
+ scipy_doctest/plugin.py,sha256=8g2Jyoa69ezQ22RrVBcD42HGNZ6z3oqaPITBDHzJSiY,12852
7
+ scipy_doctest/util.py,sha256=NQaJWfpUCqB8khIRJnTZz8ktKFqd0xT2sipFlv4RIhA,8048
8
+ scipy_doctest/.ruff_cache/.gitignore,sha256=njpg8ebsSuYCFcEdVLFxOSdF7CXp3e1DPVvZITY68xY,35
9
+ scipy_doctest/.ruff_cache/CACHEDIR.TAG,sha256=WVMVbX4MVkpCclExbq8m-IcOZIOuIZf5FrYw5Pk-Ma4,43
10
+ scipy_doctest/.ruff_cache/0.9.4/12495833369255784944,sha256=w5fjZj_--UXMu8x8t41NSb7Od5tJMg9juUSF1Po7VV0,1442
11
+ scipy_doctest/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ scipy_doctest/tests/failure_cases.py,sha256=ReSRSugjKDNoWO5M4h-vwCbX_7BwkktlwEjFiGWI3F4,732
13
+ scipy_doctest/tests/failure_cases_2.py,sha256=p2Qg_eKh35-gavFS25hRNkYW22w8kwNRlAg0Vrq4MtM,783
14
+ scipy_doctest/tests/finder_cases.py,sha256=-aWcIyKsW1GAOEhuqEYUVYGLYsVi2FU8HgZG2x7Nmyc,870
15
+ scipy_doctest/tests/finder_cases_2.py,sha256=Z5pnvVQKk3Z8bWpnQyBSnM02qk-80R0doi7DYUbMBaU,306
16
+ scipy_doctest/tests/local_file.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ scipy_doctest/tests/local_file_cases.py,sha256=8gIEwIJOwwWo0ii2I2gMbcg_8ZhH5XoWqqRFWxnVpd8,912
18
+ scipy_doctest/tests/module_cases.py,sha256=kApmKDYImEHbgm-hiCSG7HpDzHhvwqOM8d1J9Dq7Gk4,5827
19
+ scipy_doctest/tests/octave_a.mat,sha256=lOfXBSOdMG7_kruTnOHjixXkPy3zSUt10A1FSVjfngI,288
20
+ scipy_doctest/tests/scipy_ndimage_tutorial_clone.rst,sha256=gw5YfCNuq1I-Pwu2XUYlOFLg4Qk8E0n9A8APXmcBh1w,81592
21
+ scipy_doctest/tests/stopwords_cases.py,sha256=OEZkoFW3B9nHUCG_5adSkLI91avSwNjw-NeUS0D6Yz0,156
22
+ scipy_doctest/tests/test_finder.py,sha256=8upZaULq8LhhQQyM1eriKhg2I48eGXm3cSJ0s7SkXzw,7769
23
+ scipy_doctest/tests/test_parser.py,sha256=jF32p7PDrxKrdMdX91VTkkjiMhYrjCbPkxWq1RKMryA,922
24
+ scipy_doctest/tests/test_pytest_configuration.py,sha256=Fou_WthuWwh0q-o2zZD92HLPwbWOjxcJAV_s_ymbP20,2568
25
+ scipy_doctest/tests/test_runner.py,sha256=cXDY51lRP7fG-5C_6Y69e8fFsB6mLr0NWauH4sCOWHs,2935
26
+ scipy_doctest/tests/test_skipmarkers.py,sha256=dLcoy1F0e1GrLLAi2CqJQLapFB8uUBoqkTT-n5oFWbY,8182
27
+ scipy_doctest/tests/test_testfile.py,sha256=66ZHUpEGGg8MfQT8EKSZ8Zx5pV55gP__TZejGMYwBHA,733
28
+ scipy_doctest/tests/test_testmod.py,sha256=We1LBz3rKD5VDkcB8ssQehEr5aQRy2riBJwGwJWGgzs,5870
29
+ scipy_doctest-1.7.dist-info/entry_points.txt,sha256=dFda3z6PjFL7pEWokv_QmoLwE8X1HETCY1H60xopQ-s,47
30
+ scipy_doctest-1.7.dist-info/licenses/LICENSE,sha256=xH5PVX8bm8e1JxkmJ-e5FsZsOa7FsNOMfepmCvMoR9g,1523
31
+ scipy_doctest-1.7.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
32
+ scipy_doctest-1.7.dist-info/METADATA,sha256=72XdHKgkfz2s6ewsg8sn-eibj25d4vktcz-fLrzvLHo,15711
33
+ scipy_doctest-1.7.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: flit 3.10.1
2
+ Generator: flit 3.12.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,29 +0,0 @@
1
- scipy_doctest/__init__.py,sha256=-RFBEAnfRqgEUJmvLL5MBc6HfuyqetcTQgPsRcVFREU,651
2
- scipy_doctest/__main__.py,sha256=H8jTO13GlOLzexbgu7lHMJW1y3_NhLOSArARFZ5WS7o,90
3
- scipy_doctest/conftest.py,sha256=5vZxzuH042urYIToiKWANDJHQPoGkfQI-ppQ_cuHgM0,53
4
- scipy_doctest/frontend.py,sha256=7Vz9VIRmzdkmwPD1OtI9sJSxCXIF7jmSxXyt6asjaI0,18628
5
- scipy_doctest/impl.py,sha256=NC61Qy-4VXd3Vjk9WXyTf0oPcm6ZdIiv7WxeVSffTrw,24083
6
- scipy_doctest/plugin.py,sha256=DzTPBCDIre5b2e8JLiTGw7d9zhCP9hYqXcxeKpFTtys,12900
7
- scipy_doctest/util.py,sha256=R-pS9FSL5hQNmOA0nhRDLOL1riFVAoK-OhG70ilaKhw,8057
8
- scipy_doctest/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- scipy_doctest/tests/failure_cases.py,sha256=ReSRSugjKDNoWO5M4h-vwCbX_7BwkktlwEjFiGWI3F4,732
10
- scipy_doctest/tests/failure_cases_2.py,sha256=gupqwSICvzurGIiKVNJRJX9jkmtFR7_Rf3snWU-4Nac,784
11
- scipy_doctest/tests/finder_cases.py,sha256=s4sq5HZ7m5mXEi1N8dbkgCRY6AxEGcirFRYhEyEG7rw,872
12
- scipy_doctest/tests/local_file.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- scipy_doctest/tests/local_file_cases.py,sha256=xQeD809EoLxY-QIb0X7ZPl6Ecyme3zjnf95AHJ_8gp0,914
14
- scipy_doctest/tests/module_cases.py,sha256=W3u97oMJ8yf0rqrsiQbB1yMMTkKAVz4gNpBLDhijHek,5860
15
- scipy_doctest/tests/octave_a.mat,sha256=lOfXBSOdMG7_kruTnOHjixXkPy3zSUt10A1FSVjfngI,288
16
- scipy_doctest/tests/scipy_ndimage_tutorial_clone.rst,sha256=uCtH99RQM0hvDK2_5lgBO2hqtMUOUQhPKxWn4zwHjSs,81594
17
- scipy_doctest/tests/stopwords_cases.py,sha256=OEZkoFW3B9nHUCG_5adSkLI91avSwNjw-NeUS0D6Yz0,156
18
- scipy_doctest/tests/test_finder.py,sha256=9bBa3OvB8aTPixMkAFAPlCul7Bm7J95GKri0npOMp9M,6136
19
- scipy_doctest/tests/test_parser.py,sha256=cmK5kXqTWPUdSVor4bPu6yoikIukDIkVXjIjk1TTPI8,925
20
- scipy_doctest/tests/test_pytest_configuration.py,sha256=2aesrRyHFdMcRMjARXJ5g8nMtaYC0gb_48Mh8U58RzE,2573
21
- scipy_doctest/tests/test_runner.py,sha256=qP4u8ngbUK946HhMM6Py70hi0W0DcZGcCN258phhM7g,2936
22
- scipy_doctest/tests/test_skipmarkers.py,sha256=C5U8BKF3Ti-nPWekt2yK6a3j3Tcg_pq-Z5IuiR-F9eU,7835
23
- scipy_doctest/tests/test_testfile.py,sha256=66ZHUpEGGg8MfQT8EKSZ8Zx5pV55gP__TZejGMYwBHA,733
24
- scipy_doctest/tests/test_testmod.py,sha256=PoOI0o2_dXjWDmDkUUKqcJiyZvh46YpjlmMxyW6PXyI,5874
25
- scipy_doctest-1.5.1.dist-info/entry_points.txt,sha256=dFda3z6PjFL7pEWokv_QmoLwE8X1HETCY1H60xopQ-s,47
26
- scipy_doctest-1.5.1.dist-info/LICENSE,sha256=xH5PVX8bm8e1JxkmJ-e5FsZsOa7FsNOMfepmCvMoR9g,1523
27
- scipy_doctest-1.5.1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
28
- scipy_doctest-1.5.1.dist-info/METADATA,sha256=r7zprKH8IAsQde_mAkhp8SOYdlpV6iUc9pttsYu7wu4,14869
29
- scipy_doctest-1.5.1.dist-info/RECORD,,