optimism 3.1.3__tar.gz → 3.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.
- {optimism-3.1.3 → optimism-3.1.4}/PKG-INFO +3 -2
- {optimism-3.1.3 → optimism-3.1.4}/optimism/__init__.py +1 -1
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/code.py +16 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/optimism.py +34 -11
- {optimism-3.1.3 → optimism-3.1.4}/optimism/test_examples.py +82 -59
- {optimism-3.1.3 → optimism-3.1.4}/optimism.egg-info/PKG-INFO +3 -2
- {optimism-3.1.3 → optimism-3.1.4}/LICENSE.txt +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/README.md +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/a.txt +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/b.txt +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/bad.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/basic.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/bits.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/block.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/catch_and_release.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/core.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/doc_example.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/doctests.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/errors.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/files.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/fragments.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/io_example.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/literals.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/memoryReports.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/multi.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/reverse_tracing.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/runfile.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/skip.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/structure.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/suites.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/examples/tracing.py +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism/py.typed +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism.egg-info/SOURCES.txt +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism.egg-info/dependency_links.txt +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism.egg-info/requires.txt +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/optimism.egg-info/top_level.txt +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/pyproject.toml +0 -0
- {optimism-3.1.3 → optimism-3.1.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: optimism
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.4
|
|
4
4
|
Summary: Very simple testing framework suitable for beginner programmers, with easy functions for accomplishing most common testing tasks like providing input. Requires Python 3.8+.
|
|
5
5
|
Home-page: https://cs.wellesley.edu/~pmwh/optimism/docs/optimism.html
|
|
6
6
|
Author: Peter Mawhorter
|
|
@@ -19,6 +19,7 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
License-File: LICENSE.txt
|
|
20
20
|
Provides-Extra: test
|
|
21
21
|
Requires-Dist: pytest; extra == "test"
|
|
22
|
+
Dynamic: license-file
|
|
22
23
|
|
|
23
24
|
# `optimism`
|
|
24
25
|
|
|
@@ -13,7 +13,7 @@ from .optimism import *
|
|
|
13
13
|
# version from optimism, but we want the version to be defined in that
|
|
14
14
|
# file so that a single-file distribution is equivalent to this packaged
|
|
15
15
|
# distribution. So we define a version here as well, but...
|
|
16
|
-
__version__ = "3.1.
|
|
16
|
+
__version__ = "3.1.4"
|
|
17
17
|
|
|
18
18
|
# ...then we assert it matches so testing will catch it if I forget to
|
|
19
19
|
# keep them in sync before a release. T_T
|
|
@@ -94,3 +94,19 @@ fileTester.checkCodeContains(optimism.Constant(4.0 / 2, float)) # ✗
|
|
|
94
94
|
fileTester.checkCodeContains(optimism.Constant(4.0 / 2, int)) # ✓
|
|
95
95
|
fileTester.checkCodeContains(optimism.Constant(5.0, int)) # ✗
|
|
96
96
|
fileTester.checkCodeContains(optimism.Constant(5.0, float)) # ✓
|
|
97
|
+
|
|
98
|
+
# Test augmented assignment matching
|
|
99
|
+
def aug():
|
|
100
|
+
x = 3
|
|
101
|
+
x += 4
|
|
102
|
+
x /= 10
|
|
103
|
+
|
|
104
|
+
fileTester.checkCodeContains(
|
|
105
|
+
optimism.Def().contains(optimism.Operator('+'))
|
|
106
|
+
) # ✓
|
|
107
|
+
fileTester.checkCodeContains(
|
|
108
|
+
optimism.Def().contains(optimism.Operator('/'))
|
|
109
|
+
) # ✓
|
|
110
|
+
fileTester.checkCodeContains(
|
|
111
|
+
optimism.Def(name="aug").contains(optimism.Operator('/', max=0))
|
|
112
|
+
) # ✗
|
|
@@ -200,6 +200,11 @@ TODO: Workaround for tracing in interactive console?
|
|
|
200
200
|
|
|
201
201
|
## Changelog
|
|
202
202
|
|
|
203
|
+
- Version 3.1.4 treats augmented assignments as operators for
|
|
204
|
+
`checkCodeContains` purposes, as they should have been all along. It
|
|
205
|
+
adds a new test for that in the `code.py` example file, and also fixes
|
|
206
|
+
up some modern mypy type warnings (even though they were mostly
|
|
207
|
+
spurious).
|
|
203
208
|
- Version 3.1.3 Fixes a numbering bug with memory reports and also fixes
|
|
204
209
|
a pernicious `deepish_copy` bug: Structures that were supposed to be
|
|
205
210
|
duplicated would have their top levels duplicated twice separately
|
|
@@ -353,7 +358,7 @@ TODO: Workaround for tracing in interactive console?
|
|
|
353
358
|
|
|
354
359
|
# TODO: Cache compiled ASTs!
|
|
355
360
|
|
|
356
|
-
__version__ = "3.1.
|
|
361
|
+
__version__ = "3.1.4"
|
|
357
362
|
|
|
358
363
|
from typing import (
|
|
359
364
|
Any, Dict, List, Optional, Tuple, Literal as LiteralType, Callable,
|
|
@@ -378,7 +383,7 @@ SPLIT_CONSTANTS = hasattr(ast, "Num")
|
|
|
378
383
|
|
|
379
384
|
# Type is required before 3.9 but deprecated in that version
|
|
380
385
|
if sys.version_info >= (3, 9):
|
|
381
|
-
|
|
386
|
+
from builtins import type as Type
|
|
382
387
|
else:
|
|
383
388
|
from typing import Type
|
|
384
389
|
|
|
@@ -397,19 +402,19 @@ except ImportError:
|
|
|
397
402
|
def __getitem__(self, _):
|
|
398
403
|
return Any
|
|
399
404
|
|
|
400
|
-
Unpack = UnpackShim()
|
|
405
|
+
Unpack = UnpackShim() # type: ignore
|
|
401
406
|
|
|
402
407
|
# Versions of Python before 3.10 don't support TypeAlias
|
|
403
408
|
try:
|
|
404
409
|
from typing import TypeAlias
|
|
405
410
|
except ImportError:
|
|
406
|
-
TypeAlias = Type
|
|
411
|
+
TypeAlias = Type # type: ignore
|
|
407
412
|
|
|
408
413
|
# Versions of Python before 3.10 don't support NoneType
|
|
409
414
|
try:
|
|
410
415
|
from types import NoneType
|
|
411
416
|
except ImportError:
|
|
412
|
-
NoneType = type(None)
|
|
417
|
+
NoneType = type(None) # type: ignore
|
|
413
418
|
|
|
414
419
|
#----------------#
|
|
415
420
|
# Monkey Patches #
|
|
@@ -730,7 +735,11 @@ Type variable for `ClassInfo` definition.
|
|
|
730
735
|
|
|
731
736
|
|
|
732
737
|
if sys.version_info > (3, 10):
|
|
733
|
-
ClassInfo: TypeAlias = Union[
|
|
738
|
+
ClassInfo: TypeAlias = Union[
|
|
739
|
+
Type[T],
|
|
740
|
+
Tuple['ClassInfo', ...],
|
|
741
|
+
Type[Union]
|
|
742
|
+
]
|
|
734
743
|
else:
|
|
735
744
|
ClassInfo: TypeAlias = Union[Type[T], Tuple['ClassInfo', ...]]
|
|
736
745
|
"""
|
|
@@ -3913,7 +3922,7 @@ class QuietSkipManager(TestManager[SilentCase]):
|
|
|
3913
3922
|
# Test factories #
|
|
3914
3923
|
#----------------#
|
|
3915
3924
|
|
|
3916
|
-
def testFunction(fn: FunctionType) -> FunctionManager:
|
|
3925
|
+
def testFunction(fn: Union[FunctionType, Callable]) -> FunctionManager:
|
|
3917
3926
|
"""
|
|
3918
3927
|
Creates a test-manager for the given function.
|
|
3919
3928
|
"""
|
|
@@ -6005,7 +6014,9 @@ class Loop(ASTRequirement):
|
|
|
6005
6014
|
"""
|
|
6006
6015
|
def __init__(
|
|
6007
6016
|
self,
|
|
6008
|
-
only: Optional[
|
|
6017
|
+
only: Optional[
|
|
6018
|
+
Union[ExtendedLoopType, Iterable[ExtendedLoopType]]
|
|
6019
|
+
] = None,
|
|
6009
6020
|
**kwargs: Unpack[NumArgs]
|
|
6010
6021
|
) -> None:
|
|
6011
6022
|
"""
|
|
@@ -6867,7 +6878,13 @@ class Operator(ASTRequirement):
|
|
|
6867
6878
|
) -> Iterator[Tuple[ast.AST, bool]]:
|
|
6868
6879
|
for node in self._walkNodesOfType(
|
|
6869
6880
|
syntax_tree,
|
|
6870
|
-
(
|
|
6881
|
+
(
|
|
6882
|
+
ast.UnaryOp,
|
|
6883
|
+
ast.BinOp,
|
|
6884
|
+
ast.BoolOp,
|
|
6885
|
+
ast.Compare,
|
|
6886
|
+
ast.AugAssign
|
|
6887
|
+
)
|
|
6871
6888
|
):
|
|
6872
6889
|
# Determine not/partial/full status of match...
|
|
6873
6890
|
match: LiteralType[True, "partial", False] = False
|
|
@@ -7146,7 +7163,7 @@ which has slots that used to contain complex sub-objects replaced with
|
|
|
7146
7163
|
`MemReference` objects. See `memoryMap`.
|
|
7147
7164
|
"""
|
|
7148
7165
|
|
|
7149
|
-
SmallTypes: Tuple[Type] = (int, float, complex, bool, NoneType)
|
|
7166
|
+
SmallTypes: Tuple[Type, ...] = (int, float, complex, bool, NoneType)
|
|
7150
7167
|
"""
|
|
7151
7168
|
The object types which are small enough to fit into a single field
|
|
7152
7169
|
without using a pointer in theory, which we thus represent without using
|
|
@@ -7157,7 +7174,7 @@ with `isinstance`.
|
|
|
7157
7174
|
# later so it cannot just be None. If we only wanted to support Python
|
|
7158
7175
|
# 3.10+, we could use the union directly in isinstance.
|
|
7159
7176
|
|
|
7160
|
-
SmallType: TypeAlias = Union[int, float, complex, bool,
|
|
7177
|
+
SmallType: TypeAlias = Union[int, float, complex, bool, None]
|
|
7161
7178
|
"""
|
|
7162
7179
|
A union of the `SmallTypes`.
|
|
7163
7180
|
"""
|
|
@@ -7231,6 +7248,7 @@ def memoryMap(
|
|
|
7231
7248
|
or (INLINE_STRINGS_IN_MEMORY_REPORTS and isinstance(obj, str))
|
|
7232
7249
|
):
|
|
7233
7250
|
# Simple values are used as-is:
|
|
7251
|
+
obj = cast(SmallType, obj)
|
|
7234
7252
|
return None, obj
|
|
7235
7253
|
elif isinstance(obj, (tuple, list, set)):
|
|
7236
7254
|
# Structures are made shallow and referenced
|
|
@@ -9881,6 +9899,11 @@ def get_ref_src(src: str, node: ast.AST) -> str:
|
|
|
9881
9899
|
|
|
9882
9900
|
# We're going to have to do this ourself: find the start of the
|
|
9883
9901
|
# expression and state-machine to find its end
|
|
9902
|
+
if not hasattr(node, "lineno") or not hasattr(node, "col_offset"):
|
|
9903
|
+
raise TypeError(
|
|
9904
|
+
f"Node {node!r} is missing lineno and/or col_offset"
|
|
9905
|
+
f" attribute(s)."
|
|
9906
|
+
)
|
|
9884
9907
|
start = get_src_index(src, node.lineno, node.col_offset)
|
|
9885
9908
|
|
|
9886
9909
|
# Figure out the end point
|
|
@@ -518,8 +518,9 @@ All 4 expectation(s) were met.
|
|
|
518
518
|
Code does not contain the expected structure:
|
|
519
519
|
at least 1 definition(s) of functionName
|
|
520
520
|
Although it does partially satisfy the requirement:
|
|
521
|
-
Requirement partially satisfied via 0 full and
|
|
521
|
+
Requirement partially satisfied via 0 full and 2 partial match(es):
|
|
522
522
|
Partial match: FunctionDef on line 10
|
|
523
|
+
Partial match: FunctionDef on line 99
|
|
523
524
|
checked code in file '{full_file}'""",
|
|
524
525
|
"✓ {file}:44",
|
|
525
526
|
"""\
|
|
@@ -528,8 +529,9 @@ All 4 expectation(s) were met.
|
|
|
528
529
|
at least 1 function definition(s) that also contain(s):
|
|
529
530
|
at least 1 loop(s) or generator expression(s)
|
|
530
531
|
Although it does partially satisfy the requirement:
|
|
531
|
-
Requirement partially satisfied via 0 full and
|
|
532
|
+
Requirement partially satisfied via 0 full and 2 partial match(es):
|
|
532
533
|
Partial match: FunctionDef on line 10
|
|
534
|
+
Partial match: FunctionDef on line 99
|
|
533
535
|
checked code in file '{full_file}'""",
|
|
534
536
|
"""\
|
|
535
537
|
✗ {file}:46
|
|
@@ -601,24 +603,36 @@ All 4 expectation(s) were met.
|
|
|
601
603
|
Code does not contain the expected structure:
|
|
602
604
|
at least 1 constant 2.0
|
|
603
605
|
Although it does partially satisfy the requirement:
|
|
604
|
-
Requirement partially satisfied via 0 full and
|
|
606
|
+
Requirement partially satisfied via 0 full and 60 partial match(es):
|
|
605
607
|
""" + ("""\
|
|
606
608
|
Partial match: Constant on line 1
|
|
607
609
|
Partial match: Constant on line 7""" if better_line_numbers else """\
|
|
608
610
|
Partial match: Str on line 3
|
|
609
|
-
Partial match: NameConstant on line 7"""), # not listing all
|
|
611
|
+
Partial match: NameConstant on line 7"""), # not listing all 60...
|
|
610
612
|
"✓ {file}:94",
|
|
611
613
|
"""\
|
|
612
614
|
✗ {file}:95
|
|
613
615
|
Code does not contain the expected structure:
|
|
614
616
|
at least 1 constant 5.0
|
|
615
617
|
Although it does partially satisfy the requirement:
|
|
616
|
-
Requirement partially satisfied via 0 full and
|
|
618
|
+
Requirement partially satisfied via 0 full and 60 partial match(es):
|
|
617
619
|
""" + ("""\
|
|
618
620
|
Partial match: Constant on line 1
|
|
619
621
|
Partial match: Constant on line 7""" if better_line_numbers else """\
|
|
620
622
|
Partial match: Str on line 3
|
|
621
|
-
Partial match: NameConstant on line 7"""), # not listing all
|
|
623
|
+
Partial match: NameConstant on line 7"""), # not listing all 60...
|
|
624
|
+
"✓ {file}:104",
|
|
625
|
+
"✓ {file}:107",
|
|
626
|
+
"""\
|
|
627
|
+
✗ {file}:110
|
|
628
|
+
Code does not contain the expected structure:
|
|
629
|
+
at least 1 definition(s) of aug that also contain(s):
|
|
630
|
+
no operator '/'
|
|
631
|
+
Although it does partially satisfy the requirement:
|
|
632
|
+
Requirement partially satisfied via 0 full and 2 partial match(es):
|
|
633
|
+
Partial match: FunctionDef on line 99
|
|
634
|
+
Partial match: FunctionDef on line 10
|
|
635
|
+
"""
|
|
622
636
|
],
|
|
623
637
|
|
|
624
638
|
"reverse_tracing": [
|
|
@@ -1360,63 +1374,72 @@ def test_all():
|
|
|
1360
1374
|
Tests each example file. The `examples` directory must be in the
|
|
1361
1375
|
same place that this `test_examples.py` file lives.
|
|
1362
1376
|
"""
|
|
1363
|
-
os.
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
r"Traceback \(most recent call last\):.*?^([ a-zA-Z]*Error:)",
|
|
1381
|
-
"Traceback omitted\n\\1",
|
|
1382
|
-
output,
|
|
1383
|
-
flags=re.MULTILINE | re.DOTALL
|
|
1384
|
-
)
|
|
1385
|
-
#output = re.sub(r"Traceback \(most recent call last\).*?NameError:", "HAHAHA", output, flags=re.MULTILINE | re.DOTALL)
|
|
1386
|
-
# Scrub line numbers from tracebacks so our expectations don't
|
|
1387
|
-
# become hopelessly fragile
|
|
1388
|
-
stdout = re.sub(r", line \d+,", ", line X,", stdout)
|
|
1389
|
-
output = re.sub(r", line \d+,", ", line X,", output)
|
|
1390
|
-
for ex in EXPECTATIONS[mname]:
|
|
1391
|
-
exp = ex.format(
|
|
1392
|
-
file=os.path.basename(module.__file__),
|
|
1393
|
-
dir=(
|
|
1394
|
-
os.path.split(module.__file__)[0] + '/'
|
|
1395
|
-
if better_line_numbers
|
|
1396
|
-
else ''
|
|
1397
|
-
),
|
|
1398
|
-
full_file=module.__file__,
|
|
1399
|
-
opt_file=optimism.__file__,
|
|
1377
|
+
olddir = os.getcwd()
|
|
1378
|
+
try:
|
|
1379
|
+
os.chdir(os.path.join(os.path.dirname(__file__), "examples"))
|
|
1380
|
+
sys.path.insert(0, '.')
|
|
1381
|
+
for (mname, inputs) in EXAMPLES:
|
|
1382
|
+
optimism.detailLevel(0)
|
|
1383
|
+
optimism.deleteAllTestSuites()
|
|
1384
|
+
optimism.colors(False)
|
|
1385
|
+
module, output, stdout = run_example(mname, inputs)
|
|
1386
|
+
# Replace tracebacks with generic forms so we can match on
|
|
1387
|
+
# specific errors being reported while ignoring the files & lines
|
|
1388
|
+
# where they are reported.
|
|
1389
|
+
stdout = re.sub(
|
|
1390
|
+
r"Traceback \(most recent call last\):.*?^([ a-zA-Z]*Error:)",
|
|
1391
|
+
"Traceback omitted\n\\1",
|
|
1392
|
+
stdout,
|
|
1393
|
+
flags=re.MULTILINE | re.DOTALL
|
|
1400
1394
|
)
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
for ex in
|
|
1395
|
+
output = re.sub(
|
|
1396
|
+
r"Traceback \(most recent call last\):.*?^([ a-zA-Z]*Error:)",
|
|
1397
|
+
"Traceback omitted\n\\1",
|
|
1398
|
+
output,
|
|
1399
|
+
flags=re.MULTILINE | re.DOTALL
|
|
1400
|
+
)
|
|
1401
|
+
#output = re.sub(r"Traceback \(most recent call last\).*?NameError:", "HAHAHA", output, flags=re.MULTILINE | re.DOTALL)
|
|
1402
|
+
# Scrub line numbers from tracebacks so our expectations don't
|
|
1403
|
+
# become hopelessly fragile
|
|
1404
|
+
stdout = re.sub(r", line \d+,", ", line X,", stdout)
|
|
1405
|
+
output = re.sub(r", line \d+,", ", line X,", output)
|
|
1406
|
+
for ex in EXPECTATIONS[mname]:
|
|
1413
1407
|
exp = ex.format(
|
|
1414
1408
|
file=os.path.basename(module.__file__),
|
|
1415
|
-
dir=
|
|
1409
|
+
dir=(
|
|
1410
|
+
os.path.split(module.__file__)[0] + '/'
|
|
1411
|
+
if better_line_numbers
|
|
1412
|
+
else ''
|
|
1413
|
+
),
|
|
1416
1414
|
full_file=module.__file__,
|
|
1417
1415
|
opt_file=optimism.__file__,
|
|
1418
1416
|
)
|
|
1417
|
+
# Redundant, but makes issues easier to diagnose
|
|
1419
1418
|
for line in exp.splitlines():
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1419
|
+
if line not in output:
|
|
1420
|
+
print("\n\nLINE:\n" + line)
|
|
1421
|
+
print("\n\nOUTPUT:\n" + output)
|
|
1422
|
+
assert (line in output), (line, output)
|
|
1423
|
+
if exp not in output:
|
|
1424
|
+
print("\n\nEXP:\n" + exp)
|
|
1425
|
+
print("\n\nOUTPUT:\n" + output)
|
|
1426
|
+
assert (exp in output), (exp, output)
|
|
1427
|
+
if mname in STDOUT_EXPECT:
|
|
1428
|
+
for ex in STDOUT_EXPECT[mname]:
|
|
1429
|
+
exp = ex.format(
|
|
1430
|
+
file=os.path.basename(module.__file__),
|
|
1431
|
+
dir=os.path.split(module.__file__)[0],
|
|
1432
|
+
full_file=module.__file__,
|
|
1433
|
+
opt_file=optimism.__file__,
|
|
1434
|
+
)
|
|
1435
|
+
for line in exp.splitlines():
|
|
1436
|
+
assert (line in stdout), stdout
|
|
1437
|
+
assert (exp in stdout), stdout
|
|
1438
|
+
finally:
|
|
1439
|
+
os.chdir(olddir)
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
if __name__ == "__main__":
|
|
1443
|
+
print('Testing example files...')
|
|
1444
|
+
test_all()
|
|
1445
|
+
print('...all tests passed.')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: optimism
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.4
|
|
4
4
|
Summary: Very simple testing framework suitable for beginner programmers, with easy functions for accomplishing most common testing tasks like providing input. Requires Python 3.8+.
|
|
5
5
|
Home-page: https://cs.wellesley.edu/~pmwh/optimism/docs/optimism.html
|
|
6
6
|
Author: Peter Mawhorter
|
|
@@ -19,6 +19,7 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
License-File: LICENSE.txt
|
|
20
20
|
Provides-Extra: test
|
|
21
21
|
Requires-Dist: pytest; extra == "test"
|
|
22
|
+
Dynamic: license-file
|
|
22
23
|
|
|
23
24
|
# `optimism`
|
|
24
25
|
|
|
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
|
|
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
|
|
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
|