Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
67f3e67
Merge pull request #4 from CodeSteak/untypy
skogsbaer Sep 21, 2021
7434862
update untypy
skogsbaer Sep 21, 2021
2459169
update untypy
skogsbaer Sep 21, 2021
b6e440b
do not import a test module from some other test module
skogsbaer Sep 21, 2021
ee7b63c
update untypy
skogsbaer Sep 21, 2021
467b4f7
fix execution of integration tests
skogsbaer Sep 21, 2021
2a2b484
unskip to tests that now succeed
skogsbaer Sep 21, 2021
a23a8d0
update README
skogsbaer Sep 21, 2021
bdb0d96
remove leftover from implicit wypp import
skogsbaer Sep 21, 2021
55e0df9
improved repl tester and renamed some files
skogsbaer Sep 21, 2021
6349976
symlink for using wypp without installing
skogsbaer Sep 21, 2021
f4bb18e
test for replTester (fails!)
skogsbaer Sep 21, 2021
150c7a5
fix for failing replTester test
skogsbaer Sep 21, 2021
5da45e9
update TODO
skogsbaer Sep 21, 2021
e9504ab
update untypy
skogsbaer Sep 22, 2021
8f9ec73
fix tests
skogsbaer Sep 22, 2021
e8e2b9d
update untypy
skogsbaer Sep 22, 2021
febdc01
some new tests
skogsbaer Sep 22, 2021
4ad786e
export type vars from wypp
skogsbaer Sep 22, 2021
6a3854b
add github issues to failing tests
skogsbaer Sep 22, 2021
f84f048
update untypy
skogsbaer Sep 22, 2021
7ac53ac
tests for forward refs
skogsbaer Sep 23, 2021
ba89fb1
refer to github issue
skogsbaer Sep 23, 2021
96b5fa4
do not re-export internal ForwardRef type
skogsbaer Sep 23, 2021
1ba6f54
improve formatting of exceptions
skogsbaer Sep 23, 2021
6da4d25
test for return type
skogsbaer Sep 23, 2021
5b66956
update untypy
skogsbaer Sep 23, 2021
a47f8b4
script for invoking runYourProgram.py
skogsbaer Sep 23, 2021
9f311a1
add .ignore file for vscode
skogsbaer Sep 23, 2021
d72343b
update untypy
skogsbaer Sep 23, 2021
55570ef
make run script more powerful
skogsbaer Sep 23, 2021
fbdfd01
test for sequences
skogsbaer Sep 23, 2021
9762370
update untypy
skogsbaer Sep 23, 2021
5d63a48
test for variadic tuples
skogsbaer Sep 23, 2021
14f5570
failing test for sequence
skogsbaer Sep 23, 2021
3091c20
update untypy
skogsbaer Sep 23, 2021
50340ac
test for Sequence
skogsbaer Sep 23, 2021
4b3963e
update untypy
skogsbaer Sep 23, 2021
5a78f79
new failing test
skogsbaer Sep 23, 2021
f488566
another failing test
skogsbaer Sep 23, 2021
939f11e
update untypy
skogsbaer Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion TODO.org
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
* untypy
** add tests with type annotations
*** for records
**** construction
**** write access
**** test for correct location
** understand why commit 150c7a5b209ddb264fd104feae42eba4905c2be7 is necessary to fix the replTester test
* other
** mode where all functions or methods without type signatures are reported as errors
** upload dist to pypi
** update README
*** python version
*** pip
*** records
*** import
2 changes: 2 additions & 0 deletions python/.ignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
site-lib/wypp
site-lib/untypy
1 change: 0 additions & 1 deletion python/file-tests/testArgs.out

This file was deleted.

7 changes: 0 additions & 7 deletions python/file-tests/testTraceback.err

This file was deleted.

5 changes: 0 additions & 5 deletions python/file-tests/testTraceback2.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes1.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes2.err

This file was deleted.

8 changes: 5 additions & 3 deletions python/integration-tests/shell.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,10 +322,12 @@ def hook(self):

def exit(self, code=0):
if code is None:
code = 0
myCode = 0
elif type(code) != int:
code = 1
self.exitCode = code
myCode = 1
else:
myCode = code
self.exitCode = myCode
self._origExit(code)

def exc_handler(self, exc_type, exc, *args):
Expand Down
113 changes: 61 additions & 52 deletions python/integration-tests/testIntegration.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,140 +32,149 @@ def stripTrailingWs(s):

LOG_FILE = shell.mkTempFile(prefix="wypp-tests", suffix=".log", deleteAtExit='ifSuccess')
print(f'Output of integration tests goes to {LOG_FILE}')
LOG_REDIR = f'> {LOG_FILE} 2>&1'
LOG_REDIR = f'>> {LOG_FILE} 2>&1'

class TypeTests(unittest.TestCase):
def test_enumOk(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber("red")')
out = runInteractive('test-data/typeEnums.py', 'colorToNumber("red")')
self.assertEqual(['0'], out)

def test_enumTypeError(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: Literal['red', 'yellow', 'green']", out)
out = runInteractive('test-data/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: value of type Literal['red', 'yellow', 'green']", out)

def test_recordOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'Person("stefan", 42)')
self.assertEqual(["Person(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'incAge(Person("stefan", 42))')
self.assertEqual(["Person(name='stefan', age=43)"], out2)

@unittest.skip
def test_recordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'Person("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_recordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'mutableIncAge(Person("stefan", 42))')[0]
self.assertIn('expected: MutablePerson', out)
self.assertIn('expected: value of type MutablePerson', out)

def test_recordMutableOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'MutablePerson("stefan", 42)')
self.assertEqual(["MutablePerson(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'p = MutablePerson("stefan", 42)\nmutableIncAge(p)\np')
self.assertEqual(['', '', "MutablePerson(name='stefan', age=43)"], out2)

@unittest.skip
def test_mutableRecordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'MutablePerson("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_mutableRecordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'incAge(MutablePerson("stefan", 42))')[0]
self.assertIn('expected: Person', out)
self.assertIn('expected: value of type Person', out)

@unittest.skip
def test_mutableRecordFail3(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'p = MutablePerson("stefan", 42)\np.age = 42.4')
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_union(self):
out = runInteractive('file-tests/typeUnion.py', """formatAnimal(myCat)
out = runInteractive('test-data/typeUnion.py', """formatAnimal(myCat)
formatAnimal(myParrot)
formatAnimal(None)
""")
self.assertEqual("'Cat Pumpernickel'", out[0])
self.assertEqual("\"Parrot Mike says: Let's go to the punkrock show\"", out[1])
self.assertIn('given: None\nexpected: Union[Cat, Parrot]', out[2])
self.assertIn('given: None\nexpected: value of type Union[Cat, Parrot]', out[2])

class StudentSubmissionTests(unittest.TestCase):
def check(self, file, testFile, ecode, tycheck=True):
flags = ['--check']
if not tycheck:
flags.append('--no-typechecking')
cmd = f"python3 src/runYourProgram.py {' '.join(flags)} --test-file {testFile} {file} {LOG_REDIR}"
print(cmd)
res = shell.run(cmd, onError='ignore')
self.assertEqual(ecode, res.exitcode)

def test_goodSubmission(self):
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0)
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0,
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0)
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0,
tycheck=False)

def test_badSubmission(self):
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1, tycheck=False)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1, tycheck=False)

def test_submissionWithTypeErrors(self):
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 0, tycheck=False)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 1)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 0, tycheck=False)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 0, tycheck=False)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 1)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 0, tycheck=False)

class InteractiveTests(unittest.TestCase):

def test_scopeBugPeter(self):
out = runInteractive('file-tests/scope-bug-peter.py', 'local_test()\nprint(spam)')
out = runInteractive('test-data/scope-bug-peter.py', 'local_test()\nprint(spam)')
self.assertIn('IT WORKS', out)

def test_types1(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc(3)')
out = runInteractive('test-data/testTypesInteractive.py', 'inc(3)')
self.assertEqual(['4'], out)

def test_types2(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc("3")')[0]
expected = """given: '3'
expected: int
^^^
out = runInteractive('test-data/testTypesInteractive.py', 'inc("3")')[0]
expected = """untypy.error.UntypyTypeError
given: '3'
expected: value of type int

context: inc(x: int) -> int
^^^
declared at: /Users/swehr/devel/write-your-python-program/python/test-data/testTypesInteractive.py:1
1 | def inc(x: int) -> int:
2 | return x + 1

inside of inc(x: int) -> int
^^^
declared at:"""
self.assertIn(expected, stripTrailingWs(out))
caused by: <console>:1"""
self.assertEqual(expected, out)

def test_types3(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")')[1]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_types4(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf(3)')
self.assertEqual(['...', '3'], out)

def test_types5(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")',
tycheck=False)
self.assertEqual(['...', "'x'"], out)

def test_typesInImportedModule1(self):
out = run('file-tests/testTypes3.py', ecode=1)
self.assertIn('expected: int', out)
out = run('test-data/testTypes3.py', ecode=1)
self.assertIn('expected: value of type int', out)

def test_typesInImportedModule2(self):
out = run('file-tests/testTypes3.py', tycheck=False)
out = run('test-data/testTypes3.py', tycheck=False)
self.assertEqual('END', out)

class ReplTesterTests(unittest.TestCase):

def test_replTester(self):
d = shell.pwd()
cmd = f'python3 {d}/src/replTester.py {d}/test-data/repl-test-lib.py --repl {d}/test-data/repl-test-checks.py'
res = shell.run(cmd, captureStdout=True, onError='die', cwd='/tmp')
self.assertIn('All 1 tests succeded. Great!', res.stdout)
5 changes: 5 additions & 0 deletions python/run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PYTHONPATH="$SCRIPT_DIR"/site-lib/ python3 "$SCRIPT_DIR"/src/runYourProgram.py "$@"
49 changes: 36 additions & 13 deletions python/runFileTests.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ d=$(pwd)
siteDir=$(python3 -c 'import site; print(site.USER_SITE)')
t=$(mktemp)

echo
echo "Running file tests, siteDir=$siteDir ..."
echo "Writing logs to $t"
function check()
Expand All@@ -23,10 +22,10 @@ function check()
python3 $d/src/runYourProgram.py --check --install-mode assertInstall $d/"$1" >> "$t"
popd > /dev/null
}
check file-tests/fileWithImport.py
check file-tests/fileWithoutImport.py
check file-tests/fileWithBothImports.py
check file-tests/fileWithRecursiveTypes.py
check test-data/fileWithImport.py
check test-data/fileWithoutImport.py
check test-data/fileWithBothImports.py
check test-data/fileWithRecursiveTypes.py

# First argument: whether to do type checking or not
# Second argument: expected exit code. If given as X:Y, then X is the exit code with active
Expand All@@ -37,6 +36,7 @@ function checkWithOutputAux()
local tycheck="$1"
local expectedEcode=$2
local file="$3"
echo "Checking $file"
shift 3
tycheckOpt=""
suffixes="${PYENV_VERSION}"
Expand DownExpand Up@@ -101,11 +101,34 @@ function checkWithOutput()
checkWithOutputAux no "$@"
}

checkWithOutput 1 file-tests/testTraceback.py
checkWithOutput 1 file-tests/testTraceback2.py
checkWithOutput 1 file-tests/testTraceback3.py
checkWithOutput 0 file-tests/testArgs.py ARG_1 ARG_2
checkWithOutput 0 file-tests/printModuleName.py
checkWithOutput 0 file-tests/printModuleNameImport.py
checkWithOutput 1 file-tests/testTypes1.py
checkWithOutput 1:0 file-tests/testTypes2.py
checkWithOutput 1 test-data/testTraceback.py
checkWithOutput 1 test-data/testTraceback2.py
checkWithOutput 1 test-data/testTraceback3.py
checkWithOutput 0 test-data/testArgs.py ARG_1 ARG_2
checkWithOutput 0 test-data/printModuleName.py
checkWithOutput 0 test-data/printModuleNameImport.py
checkWithOutput 1 test-data/testTypes1.py
checkWithOutput 1:0 test-data/testTypes2.py
checkWithOutputAux yes 1 test-data/testTypesCollections1.py
checkWithOutputAux yes 1 test-data/testTypesCollections2.py
# checkWithOutputAux yes 1 test-data/testTypesCollections3.py See #5
# checkWithOutputAux yes 1 test-data/testTypesCollections4.py See #6
checkWithOutputAux yes 1 test-data/testTypesProtos1.py
# checkWithOutputAux yes 1 test-data/testTypesProtos2.py See #8
checkWithOutputAux yes 1 test-data/testTypesProtos3.py
# checkWithOutputAux yes 1 test-data/testTypesProtos4.py See #9
# checkWithOutputAux yes 1 test-data/testTypesSubclassing1.py See #10
# checkWithOutputAux yes 1 test-data/testTypesHigherOrderFuns.py See #7
# checkWithOutputAux yes 1 test-data/testTypesRecordInheritance.py See #11
checkWithOutputAux yes 0 test-data/testForwardRef1.py
# checkWithOutputAux yes 1 test-data/testForwardRef2.py See #14
checkWithOutputAux yes 0 test-data/testForwardRef3.py
# checkWithOutputAux yes 1 test-data/testForwardRef4.py See #14
# checkWithOutputAux yes 1 test-data/testTypesReturn.py See #15
checkWithOutputAux yes 1 test-data/testTypesSequence1.py
checkWithOutputAux yes 1 test-data/testTypesSequence2.py
checkWithOutputAux yes 1 test-data/testTypesTuple1.py
# checkWithOutputAux yes 1 test-data/wrong-caused-by.py See #17
# checkWithOutputAux yes 1 test-data/declared-aty.py See #18


Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
67f3e67
Merge pull request #4 from CodeSteak/untypy
skogsbaer Sep 21, 2021
7434862
update untypy
skogsbaer Sep 21, 2021
2459169
update untypy
skogsbaer Sep 21, 2021
b6e440b
do not import a test module from some other test module
skogsbaer Sep 21, 2021
ee7b63c
update untypy
skogsbaer Sep 21, 2021
467b4f7
fix execution of integration tests
skogsbaer Sep 21, 2021
2a2b484
unskip to tests that now succeed
skogsbaer Sep 21, 2021
a23a8d0
update README
skogsbaer Sep 21, 2021
bdb0d96
remove leftover from implicit wypp import
skogsbaer Sep 21, 2021
55e0df9
improved repl tester and renamed some files
skogsbaer Sep 21, 2021
6349976
symlink for using wypp without installing
skogsbaer Sep 21, 2021
f4bb18e
test for replTester (fails!)
skogsbaer Sep 21, 2021
150c7a5
fix for failing replTester test
skogsbaer Sep 21, 2021
5da45e9
update TODO
skogsbaer Sep 21, 2021
e9504ab
update untypy
skogsbaer Sep 22, 2021
8f9ec73
fix tests
skogsbaer Sep 22, 2021
e8e2b9d
update untypy
skogsbaer Sep 22, 2021
febdc01
some new tests
skogsbaer Sep 22, 2021
4ad786e
export type vars from wypp
skogsbaer Sep 22, 2021
6a3854b
add github issues to failing tests
skogsbaer Sep 22, 2021
f84f048
update untypy
skogsbaer Sep 22, 2021
7ac53ac
tests for forward refs
skogsbaer Sep 23, 2021
ba89fb1
refer to github issue
skogsbaer Sep 23, 2021
96b5fa4
do not re-export internal ForwardRef type
skogsbaer Sep 23, 2021
1ba6f54
improve formatting of exceptions
skogsbaer Sep 23, 2021
6da4d25
test for return type
skogsbaer Sep 23, 2021
5b66956
update untypy
skogsbaer Sep 23, 2021
a47f8b4
script for invoking runYourProgram.py
skogsbaer Sep 23, 2021
9f311a1
add .ignore file for vscode
skogsbaer Sep 23, 2021
d72343b
update untypy
skogsbaer Sep 23, 2021
55570ef
make run script more powerful
skogsbaer Sep 23, 2021
fbdfd01
test for sequences
skogsbaer Sep 23, 2021
9762370
update untypy
skogsbaer Sep 23, 2021
5d63a48
test for variadic tuples
skogsbaer Sep 23, 2021
14f5570
failing test for sequence
skogsbaer Sep 23, 2021
3091c20
update untypy
skogsbaer Sep 23, 2021
50340ac
test for Sequence
skogsbaer Sep 23, 2021
4b3963e
update untypy
skogsbaer Sep 23, 2021
5a78f79
new failing test
skogsbaer Sep 23, 2021
f488566
another failing test
skogsbaer Sep 23, 2021
939f11e
update untypy
skogsbaer Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion TODO.org
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
* untypy
** add tests with type annotations
*** for records
**** construction
**** write access
**** test for correct location
** understand why commit 150c7a5b209ddb264fd104feae42eba4905c2be7 is necessary to fix the replTester test
* other
** mode where all functions or methods without type signatures are reported as errors
** upload dist to pypi
** update README
*** python version
*** pip
*** records
*** import
2 changes: 2 additions & 0 deletions python/.ignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
site-lib/wypp
site-lib/untypy
1 change: 0 additions & 1 deletion python/file-tests/testArgs.out

This file was deleted.

7 changes: 0 additions & 7 deletions python/file-tests/testTraceback.err

This file was deleted.

5 changes: 0 additions & 5 deletions python/file-tests/testTraceback2.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes1.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes2.err

This file was deleted.

8 changes: 5 additions & 3 deletions python/integration-tests/shell.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,10 +322,12 @@ def hook(self):

def exit(self, code=0):
if code is None:
code = 0
myCode = 0
elif type(code) != int:
code = 1
self.exitCode = code
myCode = 1
else:
myCode = code
self.exitCode = myCode
self._origExit(code)

def exc_handler(self, exc_type, exc, *args):
Expand Down
113 changes: 61 additions & 52 deletions python/integration-tests/testIntegration.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,140 +32,149 @@ def stripTrailingWs(s):

LOG_FILE = shell.mkTempFile(prefix="wypp-tests", suffix=".log", deleteAtExit='ifSuccess')
print(f'Output of integration tests goes to {LOG_FILE}')
LOG_REDIR = f'> {LOG_FILE} 2>&1'
LOG_REDIR = f'>> {LOG_FILE} 2>&1'

class TypeTests(unittest.TestCase):
def test_enumOk(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber("red")')
out = runInteractive('test-data/typeEnums.py', 'colorToNumber("red")')
self.assertEqual(['0'], out)

def test_enumTypeError(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: Literal['red', 'yellow', 'green']", out)
out = runInteractive('test-data/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: value of type Literal['red', 'yellow', 'green']", out)

def test_recordOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'Person("stefan", 42)')
self.assertEqual(["Person(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'incAge(Person("stefan", 42))')
self.assertEqual(["Person(name='stefan', age=43)"], out2)

@unittest.skip
def test_recordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'Person("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_recordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'mutableIncAge(Person("stefan", 42))')[0]
self.assertIn('expected: MutablePerson', out)
self.assertIn('expected: value of type MutablePerson', out)

def test_recordMutableOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'MutablePerson("stefan", 42)')
self.assertEqual(["MutablePerson(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'p = MutablePerson("stefan", 42)\nmutableIncAge(p)\np')
self.assertEqual(['', '', "MutablePerson(name='stefan', age=43)"], out2)

@unittest.skip
def test_mutableRecordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'MutablePerson("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_mutableRecordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'incAge(MutablePerson("stefan", 42))')[0]
self.assertIn('expected: Person', out)
self.assertIn('expected: value of type Person', out)

@unittest.skip
def test_mutableRecordFail3(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'p = MutablePerson("stefan", 42)\np.age = 42.4')
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_union(self):
out = runInteractive('file-tests/typeUnion.py', """formatAnimal(myCat)
out = runInteractive('test-data/typeUnion.py', """formatAnimal(myCat)
formatAnimal(myParrot)
formatAnimal(None)
""")
self.assertEqual("'Cat Pumpernickel'", out[0])
self.assertEqual("\"Parrot Mike says: Let's go to the punkrock show\"", out[1])
self.assertIn('given: None\nexpected: Union[Cat, Parrot]', out[2])
self.assertIn('given: None\nexpected: value of type Union[Cat, Parrot]', out[2])

class StudentSubmissionTests(unittest.TestCase):
def check(self, file, testFile, ecode, tycheck=True):
flags = ['--check']
if not tycheck:
flags.append('--no-typechecking')
cmd = f"python3 src/runYourProgram.py {' '.join(flags)} --test-file {testFile} {file} {LOG_REDIR}"
print(cmd)
res = shell.run(cmd, onError='ignore')
self.assertEqual(ecode, res.exitcode)

def test_goodSubmission(self):
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0)
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0,
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0)
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0,
tycheck=False)

def test_badSubmission(self):
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1, tycheck=False)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1, tycheck=False)

def test_submissionWithTypeErrors(self):
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 0, tycheck=False)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 1)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 0, tycheck=False)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 0, tycheck=False)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 1)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 0, tycheck=False)

class InteractiveTests(unittest.TestCase):

def test_scopeBugPeter(self):
out = runInteractive('file-tests/scope-bug-peter.py', 'local_test()\nprint(spam)')
out = runInteractive('test-data/scope-bug-peter.py', 'local_test()\nprint(spam)')
self.assertIn('IT WORKS', out)

def test_types1(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc(3)')
out = runInteractive('test-data/testTypesInteractive.py', 'inc(3)')
self.assertEqual(['4'], out)

def test_types2(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc("3")')[0]
expected = """given: '3'
expected: int
^^^
out = runInteractive('test-data/testTypesInteractive.py', 'inc("3")')[0]
expected = """untypy.error.UntypyTypeError
given: '3'
expected: value of type int

context: inc(x: int) -> int
^^^
declared at: /Users/swehr/devel/write-your-python-program/python/test-data/testTypesInteractive.py:1
1 | def inc(x: int) -> int:
2 | return x + 1

inside of inc(x: int) -> int
^^^
declared at:"""
self.assertIn(expected, stripTrailingWs(out))
caused by: <console>:1"""
self.assertEqual(expected, out)

def test_types3(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")')[1]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_types4(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf(3)')
self.assertEqual(['...', '3'], out)

def test_types5(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")',
tycheck=False)
self.assertEqual(['...', "'x'"], out)

def test_typesInImportedModule1(self):
out = run('file-tests/testTypes3.py', ecode=1)
self.assertIn('expected: int', out)
out = run('test-data/testTypes3.py', ecode=1)
self.assertIn('expected: value of type int', out)

def test_typesInImportedModule2(self):
out = run('file-tests/testTypes3.py', tycheck=False)
out = run('test-data/testTypes3.py', tycheck=False)
self.assertEqual('END', out)

class ReplTesterTests(unittest.TestCase):

def test_replTester(self):
d = shell.pwd()
cmd = f'python3 {d}/src/replTester.py {d}/test-data/repl-test-lib.py --repl {d}/test-data/repl-test-checks.py'
res = shell.run(cmd, captureStdout=True, onError='die', cwd='/tmp')
self.assertIn('All 1 tests succeded. Great!', res.stdout)
5 changes: 5 additions & 0 deletions python/run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PYTHONPATH="$SCRIPT_DIR"/site-lib/ python3 "$SCRIPT_DIR"/src/runYourProgram.py "$@"
49 changes: 36 additions & 13 deletions python/runFileTests.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ d=$(pwd)
siteDir=$(python3 -c 'import site; print(site.USER_SITE)')
t=$(mktemp)

echo
echo "Running file tests, siteDir=$siteDir ..."
echo "Writing logs to $t"
function check()
Expand All@@ -23,10 +22,10 @@ function check()
python3 $d/src/runYourProgram.py --check --install-mode assertInstall $d/"$1" >> "$t"
popd > /dev/null
}
check file-tests/fileWithImport.py
check file-tests/fileWithoutImport.py
check file-tests/fileWithBothImports.py
check file-tests/fileWithRecursiveTypes.py
check test-data/fileWithImport.py
check test-data/fileWithoutImport.py
check test-data/fileWithBothImports.py
check test-data/fileWithRecursiveTypes.py

# First argument: whether to do type checking or not
# Second argument: expected exit code. If given as X:Y, then X is the exit code with active
Expand All@@ -37,6 +36,7 @@ function checkWithOutputAux()
local tycheck="$1"
local expectedEcode=$2
local file="$3"
echo "Checking $file"
shift 3
tycheckOpt=""
suffixes="${PYENV_VERSION}"
Expand DownExpand Up@@ -101,11 +101,34 @@ function checkWithOutput()
checkWithOutputAux no "$@"
}

checkWithOutput 1 file-tests/testTraceback.py
checkWithOutput 1 file-tests/testTraceback2.py
checkWithOutput 1 file-tests/testTraceback3.py
checkWithOutput 0 file-tests/testArgs.py ARG_1 ARG_2
checkWithOutput 0 file-tests/printModuleName.py
checkWithOutput 0 file-tests/printModuleNameImport.py
checkWithOutput 1 file-tests/testTypes1.py
checkWithOutput 1:0 file-tests/testTypes2.py
checkWithOutput 1 test-data/testTraceback.py
checkWithOutput 1 test-data/testTraceback2.py
checkWithOutput 1 test-data/testTraceback3.py
checkWithOutput 0 test-data/testArgs.py ARG_1 ARG_2
checkWithOutput 0 test-data/printModuleName.py
checkWithOutput 0 test-data/printModuleNameImport.py
checkWithOutput 1 test-data/testTypes1.py
checkWithOutput 1:0 test-data/testTypes2.py
checkWithOutputAux yes 1 test-data/testTypesCollections1.py
checkWithOutputAux yes 1 test-data/testTypesCollections2.py
# checkWithOutputAux yes 1 test-data/testTypesCollections3.py See #5
# checkWithOutputAux yes 1 test-data/testTypesCollections4.py See #6
checkWithOutputAux yes 1 test-data/testTypesProtos1.py
# checkWithOutputAux yes 1 test-data/testTypesProtos2.py See #8
checkWithOutputAux yes 1 test-data/testTypesProtos3.py
# checkWithOutputAux yes 1 test-data/testTypesProtos4.py See #9
# checkWithOutputAux yes 1 test-data/testTypesSubclassing1.py See #10
# checkWithOutputAux yes 1 test-data/testTypesHigherOrderFuns.py See #7
# checkWithOutputAux yes 1 test-data/testTypesRecordInheritance.py See #11
checkWithOutputAux yes 0 test-data/testForwardRef1.py
# checkWithOutputAux yes 1 test-data/testForwardRef2.py See #14
checkWithOutputAux yes 0 test-data/testForwardRef3.py
# checkWithOutputAux yes 1 test-data/testForwardRef4.py See #14
# checkWithOutputAux yes 1 test-data/testTypesReturn.py See #15
checkWithOutputAux yes 1 test-data/testTypesSequence1.py
checkWithOutputAux yes 1 test-data/testTypesSequence2.py
checkWithOutputAux yes 1 test-data/testTypesTuple1.py
# checkWithOutputAux yes 1 test-data/wrong-caused-by.py See #17
# checkWithOutputAux yes 1 test-data/declared-aty.py See #18


Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
67f3e67
Merge pull request #4 from CodeSteak/untypy
skogsbaer Sep 21, 2021
7434862
update untypy
skogsbaer Sep 21, 2021
2459169
update untypy
skogsbaer Sep 21, 2021
b6e440b
do not import a test module from some other test module
skogsbaer Sep 21, 2021
ee7b63c
update untypy
skogsbaer Sep 21, 2021
467b4f7
fix execution of integration tests
skogsbaer Sep 21, 2021
2a2b484
unskip to tests that now succeed
skogsbaer Sep 21, 2021
a23a8d0
update README
skogsbaer Sep 21, 2021
bdb0d96
remove leftover from implicit wypp import
skogsbaer Sep 21, 2021
55e0df9
improved repl tester and renamed some files
skogsbaer Sep 21, 2021
6349976
symlink for using wypp without installing
skogsbaer Sep 21, 2021
f4bb18e
test for replTester (fails!)
skogsbaer Sep 21, 2021
150c7a5
fix for failing replTester test
skogsbaer Sep 21, 2021
5da45e9
update TODO
skogsbaer Sep 21, 2021
e9504ab
update untypy
skogsbaer Sep 22, 2021
8f9ec73
fix tests
skogsbaer Sep 22, 2021
e8e2b9d
update untypy
skogsbaer Sep 22, 2021
febdc01
some new tests
skogsbaer Sep 22, 2021
4ad786e
export type vars from wypp
skogsbaer Sep 22, 2021
6a3854b
add github issues to failing tests
skogsbaer Sep 22, 2021
f84f048
update untypy
skogsbaer Sep 22, 2021
7ac53ac
tests for forward refs
skogsbaer Sep 23, 2021
ba89fb1
refer to github issue
skogsbaer Sep 23, 2021
96b5fa4
do not re-export internal ForwardRef type
skogsbaer Sep 23, 2021
1ba6f54
improve formatting of exceptions
skogsbaer Sep 23, 2021
6da4d25
test for return type
skogsbaer Sep 23, 2021
5b66956
update untypy
skogsbaer Sep 23, 2021
a47f8b4
script for invoking runYourProgram.py
skogsbaer Sep 23, 2021
9f311a1
add .ignore file for vscode
skogsbaer Sep 23, 2021
d72343b
update untypy
skogsbaer Sep 23, 2021
55570ef
make run script more powerful
skogsbaer Sep 23, 2021
fbdfd01
test for sequences
skogsbaer Sep 23, 2021
9762370
update untypy
skogsbaer Sep 23, 2021
5d63a48
test for variadic tuples
skogsbaer Sep 23, 2021
14f5570
failing test for sequence
skogsbaer Sep 23, 2021
3091c20
update untypy
skogsbaer Sep 23, 2021
50340ac
test for Sequence
skogsbaer Sep 23, 2021
4b3963e
update untypy
skogsbaer Sep 23, 2021
5a78f79
new failing test
skogsbaer Sep 23, 2021
f488566
another failing test
skogsbaer Sep 23, 2021
939f11e
update untypy
skogsbaer Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion TODO.org
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
* untypy
** add tests with type annotations
*** for records
**** construction
**** write access
**** test for correct location
** understand why commit 150c7a5b209ddb264fd104feae42eba4905c2be7 is necessary to fix the replTester test
* other
** mode where all functions or methods without type signatures are reported as errors
** upload dist to pypi
** update README
*** python version
*** pip
*** records
*** import
2 changes: 2 additions & 0 deletions python/.ignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
site-lib/wypp
site-lib/untypy
1 change: 0 additions & 1 deletion python/file-tests/testArgs.out

This file was deleted.

7 changes: 0 additions & 7 deletions python/file-tests/testTraceback.err

This file was deleted.

5 changes: 0 additions & 5 deletions python/file-tests/testTraceback2.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes1.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes2.err

This file was deleted.

8 changes: 5 additions & 3 deletions python/integration-tests/shell.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,10 +322,12 @@ def hook(self):

def exit(self, code=0):
if code is None:
code = 0
myCode = 0
elif type(code) != int:
code = 1
self.exitCode = code
myCode = 1
else:
myCode = code
self.exitCode = myCode
self._origExit(code)

def exc_handler(self, exc_type, exc, *args):
Expand Down
113 changes: 61 additions & 52 deletions python/integration-tests/testIntegration.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,140 +32,149 @@ def stripTrailingWs(s):

LOG_FILE = shell.mkTempFile(prefix="wypp-tests", suffix=".log", deleteAtExit='ifSuccess')
print(f'Output of integration tests goes to {LOG_FILE}')
LOG_REDIR = f'> {LOG_FILE} 2>&1'
LOG_REDIR = f'>> {LOG_FILE} 2>&1'

class TypeTests(unittest.TestCase):
def test_enumOk(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber("red")')
out = runInteractive('test-data/typeEnums.py', 'colorToNumber("red")')
self.assertEqual(['0'], out)

def test_enumTypeError(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: Literal['red', 'yellow', 'green']", out)
out = runInteractive('test-data/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: value of type Literal['red', 'yellow', 'green']", out)

def test_recordOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'Person("stefan", 42)')
self.assertEqual(["Person(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'incAge(Person("stefan", 42))')
self.assertEqual(["Person(name='stefan', age=43)"], out2)

@unittest.skip
def test_recordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'Person("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_recordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'mutableIncAge(Person("stefan", 42))')[0]
self.assertIn('expected: MutablePerson', out)
self.assertIn('expected: value of type MutablePerson', out)

def test_recordMutableOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'MutablePerson("stefan", 42)')
self.assertEqual(["MutablePerson(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'p = MutablePerson("stefan", 42)\nmutableIncAge(p)\np')
self.assertEqual(['', '', "MutablePerson(name='stefan', age=43)"], out2)

@unittest.skip
def test_mutableRecordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'MutablePerson("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_mutableRecordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'incAge(MutablePerson("stefan", 42))')[0]
self.assertIn('expected: Person', out)
self.assertIn('expected: value of type Person', out)

@unittest.skip
def test_mutableRecordFail3(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'p = MutablePerson("stefan", 42)\np.age = 42.4')
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_union(self):
out = runInteractive('file-tests/typeUnion.py', """formatAnimal(myCat)
out = runInteractive('test-data/typeUnion.py', """formatAnimal(myCat)
formatAnimal(myParrot)
formatAnimal(None)
""")
self.assertEqual("'Cat Pumpernickel'", out[0])
self.assertEqual("\"Parrot Mike says: Let's go to the punkrock show\"", out[1])
self.assertIn('given: None\nexpected: Union[Cat, Parrot]', out[2])
self.assertIn('given: None\nexpected: value of type Union[Cat, Parrot]', out[2])

class StudentSubmissionTests(unittest.TestCase):
def check(self, file, testFile, ecode, tycheck=True):
flags = ['--check']
if not tycheck:
flags.append('--no-typechecking')
cmd = f"python3 src/runYourProgram.py {' '.join(flags)} --test-file {testFile} {file} {LOG_REDIR}"
print(cmd)
res = shell.run(cmd, onError='ignore')
self.assertEqual(ecode, res.exitcode)

def test_goodSubmission(self):
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0)
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0,
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0)
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0,
tycheck=False)

def test_badSubmission(self):
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1, tycheck=False)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1, tycheck=False)

def test_submissionWithTypeErrors(self):
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 0, tycheck=False)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 1)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 0, tycheck=False)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 0, tycheck=False)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 1)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 0, tycheck=False)

class InteractiveTests(unittest.TestCase):

def test_scopeBugPeter(self):
out = runInteractive('file-tests/scope-bug-peter.py', 'local_test()\nprint(spam)')
out = runInteractive('test-data/scope-bug-peter.py', 'local_test()\nprint(spam)')
self.assertIn('IT WORKS', out)

def test_types1(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc(3)')
out = runInteractive('test-data/testTypesInteractive.py', 'inc(3)')
self.assertEqual(['4'], out)

def test_types2(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc("3")')[0]
expected = """given: '3'
expected: int
^^^
out = runInteractive('test-data/testTypesInteractive.py', 'inc("3")')[0]
expected = """untypy.error.UntypyTypeError
given: '3'
expected: value of type int

context: inc(x: int) -> int
^^^
declared at: /Users/swehr/devel/write-your-python-program/python/test-data/testTypesInteractive.py:1
1 | def inc(x: int) -> int:
2 | return x + 1

inside of inc(x: int) -> int
^^^
declared at:"""
self.assertIn(expected, stripTrailingWs(out))
caused by: <console>:1"""
self.assertEqual(expected, out)

def test_types3(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")')[1]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_types4(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf(3)')
self.assertEqual(['...', '3'], out)

def test_types5(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")',
tycheck=False)
self.assertEqual(['...', "'x'"], out)

def test_typesInImportedModule1(self):
out = run('file-tests/testTypes3.py', ecode=1)
self.assertIn('expected: int', out)
out = run('test-data/testTypes3.py', ecode=1)
self.assertIn('expected: value of type int', out)

def test_typesInImportedModule2(self):
out = run('file-tests/testTypes3.py', tycheck=False)
out = run('test-data/testTypes3.py', tycheck=False)
self.assertEqual('END', out)

class ReplTesterTests(unittest.TestCase):

def test_replTester(self):
d = shell.pwd()
cmd = f'python3 {d}/src/replTester.py {d}/test-data/repl-test-lib.py --repl {d}/test-data/repl-test-checks.py'
res = shell.run(cmd, captureStdout=True, onError='die', cwd='/tmp')
self.assertIn('All 1 tests succeded. Great!', res.stdout)
5 changes: 5 additions & 0 deletions python/run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PYTHONPATH="$SCRIPT_DIR"/site-lib/ python3 "$SCRIPT_DIR"/src/runYourProgram.py "$@"
49 changes: 36 additions & 13 deletions python/runFileTests.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ d=$(pwd)
siteDir=$(python3 -c 'import site; print(site.USER_SITE)')
t=$(mktemp)

echo
echo "Running file tests, siteDir=$siteDir ..."
echo "Writing logs to $t"
function check()
Expand All@@ -23,10 +22,10 @@ function check()
python3 $d/src/runYourProgram.py --check --install-mode assertInstall $d/"$1" >> "$t"
popd > /dev/null
}
check file-tests/fileWithImport.py
check file-tests/fileWithoutImport.py
check file-tests/fileWithBothImports.py
check file-tests/fileWithRecursiveTypes.py
check test-data/fileWithImport.py
check test-data/fileWithoutImport.py
check test-data/fileWithBothImports.py
check test-data/fileWithRecursiveTypes.py

# First argument: whether to do type checking or not
# Second argument: expected exit code. If given as X:Y, then X is the exit code with active
Expand All@@ -37,6 +36,7 @@ function checkWithOutputAux()
local tycheck="$1"
local expectedEcode=$2
local file="$3"
echo "Checking $file"
shift 3
tycheckOpt=""
suffixes="${PYENV_VERSION}"
Expand DownExpand Up@@ -101,11 +101,34 @@ function checkWithOutput()
checkWithOutputAux no "$@"
}

checkWithOutput 1 file-tests/testTraceback.py
checkWithOutput 1 file-tests/testTraceback2.py
checkWithOutput 1 file-tests/testTraceback3.py
checkWithOutput 0 file-tests/testArgs.py ARG_1 ARG_2
checkWithOutput 0 file-tests/printModuleName.py
checkWithOutput 0 file-tests/printModuleNameImport.py
checkWithOutput 1 file-tests/testTypes1.py
checkWithOutput 1:0 file-tests/testTypes2.py
checkWithOutput 1 test-data/testTraceback.py
checkWithOutput 1 test-data/testTraceback2.py
checkWithOutput 1 test-data/testTraceback3.py
checkWithOutput 0 test-data/testArgs.py ARG_1 ARG_2
checkWithOutput 0 test-data/printModuleName.py
checkWithOutput 0 test-data/printModuleNameImport.py
checkWithOutput 1 test-data/testTypes1.py
checkWithOutput 1:0 test-data/testTypes2.py
checkWithOutputAux yes 1 test-data/testTypesCollections1.py
checkWithOutputAux yes 1 test-data/testTypesCollections2.py
# checkWithOutputAux yes 1 test-data/testTypesCollections3.py See #5
# checkWithOutputAux yes 1 test-data/testTypesCollections4.py See #6
checkWithOutputAux yes 1 test-data/testTypesProtos1.py
# checkWithOutputAux yes 1 test-data/testTypesProtos2.py See #8
checkWithOutputAux yes 1 test-data/testTypesProtos3.py
# checkWithOutputAux yes 1 test-data/testTypesProtos4.py See #9
# checkWithOutputAux yes 1 test-data/testTypesSubclassing1.py See #10
# checkWithOutputAux yes 1 test-data/testTypesHigherOrderFuns.py See #7
# checkWithOutputAux yes 1 test-data/testTypesRecordInheritance.py See #11
checkWithOutputAux yes 0 test-data/testForwardRef1.py
# checkWithOutputAux yes 1 test-data/testForwardRef2.py See #14
checkWithOutputAux yes 0 test-data/testForwardRef3.py
# checkWithOutputAux yes 1 test-data/testForwardRef4.py See #14
# checkWithOutputAux yes 1 test-data/testTypesReturn.py See #15
checkWithOutputAux yes 1 test-data/testTypesSequence1.py
checkWithOutputAux yes 1 test-data/testTypesSequence2.py
checkWithOutputAux yes 1 test-data/testTypesTuple1.py
# checkWithOutputAux yes 1 test-data/wrong-caused-by.py See #17
# checkWithOutputAux yes 1 test-data/declared-aty.py See #18


Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
67f3e67
Merge pull request #4 from CodeSteak/untypy
skogsbaer Sep 21, 2021
7434862
update untypy
skogsbaer Sep 21, 2021
2459169
update untypy
skogsbaer Sep 21, 2021
b6e440b
do not import a test module from some other test module
skogsbaer Sep 21, 2021
ee7b63c
update untypy
skogsbaer Sep 21, 2021
467b4f7
fix execution of integration tests
skogsbaer Sep 21, 2021
2a2b484
unskip to tests that now succeed
skogsbaer Sep 21, 2021
a23a8d0
update README
skogsbaer Sep 21, 2021
bdb0d96
remove leftover from implicit wypp import
skogsbaer Sep 21, 2021
55e0df9
improved repl tester and renamed some files
skogsbaer Sep 21, 2021
6349976
symlink for using wypp without installing
skogsbaer Sep 21, 2021
f4bb18e
test for replTester (fails!)
skogsbaer Sep 21, 2021
150c7a5
fix for failing replTester test
skogsbaer Sep 21, 2021
5da45e9
update TODO
skogsbaer Sep 21, 2021
e9504ab
update untypy
skogsbaer Sep 22, 2021
8f9ec73
fix tests
skogsbaer Sep 22, 2021
e8e2b9d
update untypy
skogsbaer Sep 22, 2021
febdc01
some new tests
skogsbaer Sep 22, 2021
4ad786e
export type vars from wypp
skogsbaer Sep 22, 2021
6a3854b
add github issues to failing tests
skogsbaer Sep 22, 2021
f84f048
update untypy
skogsbaer Sep 22, 2021
7ac53ac
tests for forward refs
skogsbaer Sep 23, 2021
ba89fb1
refer to github issue
skogsbaer Sep 23, 2021
96b5fa4
do not re-export internal ForwardRef type
skogsbaer Sep 23, 2021
1ba6f54
improve formatting of exceptions
skogsbaer Sep 23, 2021
6da4d25
test for return type
skogsbaer Sep 23, 2021
5b66956
update untypy
skogsbaer Sep 23, 2021
a47f8b4
script for invoking runYourProgram.py
skogsbaer Sep 23, 2021
9f311a1
add .ignore file for vscode
skogsbaer Sep 23, 2021
d72343b
update untypy
skogsbaer Sep 23, 2021
55570ef
make run script more powerful
skogsbaer Sep 23, 2021
fbdfd01
test for sequences
skogsbaer Sep 23, 2021
9762370
update untypy
skogsbaer Sep 23, 2021
5d63a48
test for variadic tuples
skogsbaer Sep 23, 2021
14f5570
failing test for sequence
skogsbaer Sep 23, 2021
3091c20
update untypy
skogsbaer Sep 23, 2021
50340ac
test for Sequence
skogsbaer Sep 23, 2021
4b3963e
update untypy
skogsbaer Sep 23, 2021
5a78f79
new failing test
skogsbaer Sep 23, 2021
f488566
another failing test
skogsbaer Sep 23, 2021
939f11e
update untypy
skogsbaer Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion TODO.org
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
* untypy
** add tests with type annotations
*** for records
**** construction
**** write access
**** test for correct location
** understand why commit 150c7a5b209ddb264fd104feae42eba4905c2be7 is necessary to fix the replTester test
* other
** mode where all functions or methods without type signatures are reported as errors
** upload dist to pypi
** update README
*** python version
*** pip
*** records
*** import
2 changes: 2 additions & 0 deletions python/.ignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
site-lib/wypp
site-lib/untypy
1 change: 0 additions & 1 deletion python/file-tests/testArgs.out

This file was deleted.

7 changes: 0 additions & 7 deletions python/file-tests/testTraceback.err

This file was deleted.

5 changes: 0 additions & 5 deletions python/file-tests/testTraceback2.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes1.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes2.err

This file was deleted.

8 changes: 5 additions & 3 deletions python/integration-tests/shell.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,10 +322,12 @@ def hook(self):

def exit(self, code=0):
if code is None:
code = 0
myCode = 0
elif type(code) != int:
code = 1
self.exitCode = code
myCode = 1
else:
myCode = code
self.exitCode = myCode
self._origExit(code)

def exc_handler(self, exc_type, exc, *args):
Expand Down
113 changes: 61 additions & 52 deletions python/integration-tests/testIntegration.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,140 +32,149 @@ def stripTrailingWs(s):

LOG_FILE = shell.mkTempFile(prefix="wypp-tests", suffix=".log", deleteAtExit='ifSuccess')
print(f'Output of integration tests goes to {LOG_FILE}')
LOG_REDIR = f'> {LOG_FILE} 2>&1'
LOG_REDIR = f'>> {LOG_FILE} 2>&1'

class TypeTests(unittest.TestCase):
def test_enumOk(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber("red")')
out = runInteractive('test-data/typeEnums.py', 'colorToNumber("red")')
self.assertEqual(['0'], out)

def test_enumTypeError(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: Literal['red', 'yellow', 'green']", out)
out = runInteractive('test-data/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: value of type Literal['red', 'yellow', 'green']", out)

def test_recordOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'Person("stefan", 42)')
self.assertEqual(["Person(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'incAge(Person("stefan", 42))')
self.assertEqual(["Person(name='stefan', age=43)"], out2)

@unittest.skip
def test_recordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'Person("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_recordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'mutableIncAge(Person("stefan", 42))')[0]
self.assertIn('expected: MutablePerson', out)
self.assertIn('expected: value of type MutablePerson', out)

def test_recordMutableOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'MutablePerson("stefan", 42)')
self.assertEqual(["MutablePerson(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'p = MutablePerson("stefan", 42)\nmutableIncAge(p)\np')
self.assertEqual(['', '', "MutablePerson(name='stefan', age=43)"], out2)

@unittest.skip
def test_mutableRecordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'MutablePerson("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_mutableRecordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'incAge(MutablePerson("stefan", 42))')[0]
self.assertIn('expected: Person', out)
self.assertIn('expected: value of type Person', out)

@unittest.skip
def test_mutableRecordFail3(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'p = MutablePerson("stefan", 42)\np.age = 42.4')
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_union(self):
out = runInteractive('file-tests/typeUnion.py', """formatAnimal(myCat)
out = runInteractive('test-data/typeUnion.py', """formatAnimal(myCat)
formatAnimal(myParrot)
formatAnimal(None)
""")
self.assertEqual("'Cat Pumpernickel'", out[0])
self.assertEqual("\"Parrot Mike says: Let's go to the punkrock show\"", out[1])
self.assertIn('given: None\nexpected: Union[Cat, Parrot]', out[2])
self.assertIn('given: None\nexpected: value of type Union[Cat, Parrot]', out[2])

class StudentSubmissionTests(unittest.TestCase):
def check(self, file, testFile, ecode, tycheck=True):
flags = ['--check']
if not tycheck:
flags.append('--no-typechecking')
cmd = f"python3 src/runYourProgram.py {' '.join(flags)} --test-file {testFile} {file} {LOG_REDIR}"
print(cmd)
res = shell.run(cmd, onError='ignore')
self.assertEqual(ecode, res.exitcode)

def test_goodSubmission(self):
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0)
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0,
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0)
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0,
tycheck=False)

def test_badSubmission(self):
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1, tycheck=False)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1, tycheck=False)

def test_submissionWithTypeErrors(self):
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 0, tycheck=False)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 1)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 0, tycheck=False)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 0, tycheck=False)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 1)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 0, tycheck=False)

class InteractiveTests(unittest.TestCase):

def test_scopeBugPeter(self):
out = runInteractive('file-tests/scope-bug-peter.py', 'local_test()\nprint(spam)')
out = runInteractive('test-data/scope-bug-peter.py', 'local_test()\nprint(spam)')
self.assertIn('IT WORKS', out)

def test_types1(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc(3)')
out = runInteractive('test-data/testTypesInteractive.py', 'inc(3)')
self.assertEqual(['4'], out)

def test_types2(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc("3")')[0]
expected = """given: '3'
expected: int
^^^
out = runInteractive('test-data/testTypesInteractive.py', 'inc("3")')[0]
expected = """untypy.error.UntypyTypeError
given: '3'
expected: value of type int

context: inc(x: int) -> int
^^^
declared at: /Users/swehr/devel/write-your-python-program/python/test-data/testTypesInteractive.py:1
1 | def inc(x: int) -> int:
2 | return x + 1

inside of inc(x: int) -> int
^^^
declared at:"""
self.assertIn(expected, stripTrailingWs(out))
caused by: <console>:1"""
self.assertEqual(expected, out)

def test_types3(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")')[1]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_types4(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf(3)')
self.assertEqual(['...', '3'], out)

def test_types5(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")',
tycheck=False)
self.assertEqual(['...', "'x'"], out)

def test_typesInImportedModule1(self):
out = run('file-tests/testTypes3.py', ecode=1)
self.assertIn('expected: int', out)
out = run('test-data/testTypes3.py', ecode=1)
self.assertIn('expected: value of type int', out)

def test_typesInImportedModule2(self):
out = run('file-tests/testTypes3.py', tycheck=False)
out = run('test-data/testTypes3.py', tycheck=False)
self.assertEqual('END', out)

class ReplTesterTests(unittest.TestCase):

def test_replTester(self):
d = shell.pwd()
cmd = f'python3 {d}/src/replTester.py {d}/test-data/repl-test-lib.py --repl {d}/test-data/repl-test-checks.py'
res = shell.run(cmd, captureStdout=True, onError='die', cwd='/tmp')
self.assertIn('All 1 tests succeded. Great!', res.stdout)
5 changes: 5 additions & 0 deletions python/run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PYTHONPATH="$SCRIPT_DIR"/site-lib/ python3 "$SCRIPT_DIR"/src/runYourProgram.py "$@"
49 changes: 36 additions & 13 deletions python/runFileTests.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ d=$(pwd)
siteDir=$(python3 -c 'import site; print(site.USER_SITE)')
t=$(mktemp)

echo
echo "Running file tests, siteDir=$siteDir ..."
echo "Writing logs to $t"
function check()
Expand All@@ -23,10 +22,10 @@ function check()
python3 $d/src/runYourProgram.py --check --install-mode assertInstall $d/"$1" >> "$t"
popd > /dev/null
}
check file-tests/fileWithImport.py
check file-tests/fileWithoutImport.py
check file-tests/fileWithBothImports.py
check file-tests/fileWithRecursiveTypes.py
check test-data/fileWithImport.py
check test-data/fileWithoutImport.py
check test-data/fileWithBothImports.py
check test-data/fileWithRecursiveTypes.py

# First argument: whether to do type checking or not
# Second argument: expected exit code. If given as X:Y, then X is the exit code with active
Expand All@@ -37,6 +36,7 @@ function checkWithOutputAux()
local tycheck="$1"
local expectedEcode=$2
local file="$3"
echo "Checking $file"
shift 3
tycheckOpt=""
suffixes="${PYENV_VERSION}"
Expand DownExpand Up@@ -101,11 +101,34 @@ function checkWithOutput()
checkWithOutputAux no "$@"
}

checkWithOutput 1 file-tests/testTraceback.py
checkWithOutput 1 file-tests/testTraceback2.py
checkWithOutput 1 file-tests/testTraceback3.py
checkWithOutput 0 file-tests/testArgs.py ARG_1 ARG_2
checkWithOutput 0 file-tests/printModuleName.py
checkWithOutput 0 file-tests/printModuleNameImport.py
checkWithOutput 1 file-tests/testTypes1.py
checkWithOutput 1:0 file-tests/testTypes2.py
checkWithOutput 1 test-data/testTraceback.py
checkWithOutput 1 test-data/testTraceback2.py
checkWithOutput 1 test-data/testTraceback3.py
checkWithOutput 0 test-data/testArgs.py ARG_1 ARG_2
checkWithOutput 0 test-data/printModuleName.py
checkWithOutput 0 test-data/printModuleNameImport.py
checkWithOutput 1 test-data/testTypes1.py
checkWithOutput 1:0 test-data/testTypes2.py
checkWithOutputAux yes 1 test-data/testTypesCollections1.py
checkWithOutputAux yes 1 test-data/testTypesCollections2.py
# checkWithOutputAux yes 1 test-data/testTypesCollections3.py See #5
# checkWithOutputAux yes 1 test-data/testTypesCollections4.py See #6
checkWithOutputAux yes 1 test-data/testTypesProtos1.py
# checkWithOutputAux yes 1 test-data/testTypesProtos2.py See #8
checkWithOutputAux yes 1 test-data/testTypesProtos3.py
# checkWithOutputAux yes 1 test-data/testTypesProtos4.py See #9
# checkWithOutputAux yes 1 test-data/testTypesSubclassing1.py See #10
# checkWithOutputAux yes 1 test-data/testTypesHigherOrderFuns.py See #7
# checkWithOutputAux yes 1 test-data/testTypesRecordInheritance.py See #11
checkWithOutputAux yes 0 test-data/testForwardRef1.py
# checkWithOutputAux yes 1 test-data/testForwardRef2.py See #14
checkWithOutputAux yes 0 test-data/testForwardRef3.py
# checkWithOutputAux yes 1 test-data/testForwardRef4.py See #14
# checkWithOutputAux yes 1 test-data/testTypesReturn.py See #15
checkWithOutputAux yes 1 test-data/testTypesSequence1.py
checkWithOutputAux yes 1 test-data/testTypesSequence2.py
checkWithOutputAux yes 1 test-data/testTypesTuple1.py
# checkWithOutputAux yes 1 test-data/wrong-caused-by.py See #17
# checkWithOutputAux yes 1 test-data/declared-aty.py See #18


Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
67f3e67
Merge pull request #4 from CodeSteak/untypy
skogsbaer Sep 21, 2021
7434862
update untypy
skogsbaer Sep 21, 2021
2459169
update untypy
skogsbaer Sep 21, 2021
b6e440b
do not import a test module from some other test module
skogsbaer Sep 21, 2021
ee7b63c
update untypy
skogsbaer Sep 21, 2021
467b4f7
fix execution of integration tests
skogsbaer Sep 21, 2021
2a2b484
unskip to tests that now succeed
skogsbaer Sep 21, 2021
a23a8d0
update README
skogsbaer Sep 21, 2021
bdb0d96
remove leftover from implicit wypp import
skogsbaer Sep 21, 2021
55e0df9
improved repl tester and renamed some files
skogsbaer Sep 21, 2021
6349976
symlink for using wypp without installing
skogsbaer Sep 21, 2021
f4bb18e
test for replTester (fails!)
skogsbaer Sep 21, 2021
150c7a5
fix for failing replTester test
skogsbaer Sep 21, 2021
5da45e9
update TODO
skogsbaer Sep 21, 2021
e9504ab
update untypy
skogsbaer Sep 22, 2021
8f9ec73
fix tests
skogsbaer Sep 22, 2021
e8e2b9d
update untypy
skogsbaer Sep 22, 2021
febdc01
some new tests
skogsbaer Sep 22, 2021
4ad786e
export type vars from wypp
skogsbaer Sep 22, 2021
6a3854b
add github issues to failing tests
skogsbaer Sep 22, 2021
f84f048
update untypy
skogsbaer Sep 22, 2021
7ac53ac
tests for forward refs
skogsbaer Sep 23, 2021
ba89fb1
refer to github issue
skogsbaer Sep 23, 2021
96b5fa4
do not re-export internal ForwardRef type
skogsbaer Sep 23, 2021
1ba6f54
improve formatting of exceptions
skogsbaer Sep 23, 2021
6da4d25
test for return type
skogsbaer Sep 23, 2021
5b66956
update untypy
skogsbaer Sep 23, 2021
a47f8b4
script for invoking runYourProgram.py
skogsbaer Sep 23, 2021
9f311a1
add .ignore file for vscode
skogsbaer Sep 23, 2021
d72343b
update untypy
skogsbaer Sep 23, 2021
55570ef
make run script more powerful
skogsbaer Sep 23, 2021
fbdfd01
test for sequences
skogsbaer Sep 23, 2021
9762370
update untypy
skogsbaer Sep 23, 2021
5d63a48
test for variadic tuples
skogsbaer Sep 23, 2021
14f5570
failing test for sequence
skogsbaer Sep 23, 2021
3091c20
update untypy
skogsbaer Sep 23, 2021
50340ac
test for Sequence
skogsbaer Sep 23, 2021
4b3963e
update untypy
skogsbaer Sep 23, 2021
5a78f79
new failing test
skogsbaer Sep 23, 2021
f488566
another failing test
skogsbaer Sep 23, 2021
939f11e
update untypy
skogsbaer Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion TODO.org
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
* untypy
** add tests with type annotations
*** for records
**** construction
**** write access
**** test for correct location
** understand why commit 150c7a5b209ddb264fd104feae42eba4905c2be7 is necessary to fix the replTester test
* other
** mode where all functions or methods without type signatures are reported as errors
** upload dist to pypi
** update README
*** python version
*** pip
*** records
*** import
2 changes: 2 additions & 0 deletions python/.ignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
site-lib/wypp
site-lib/untypy
1 change: 0 additions & 1 deletion python/file-tests/testArgs.out

This file was deleted.

7 changes: 0 additions & 7 deletions python/file-tests/testTraceback.err

This file was deleted.

5 changes: 0 additions & 5 deletions python/file-tests/testTraceback2.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes1.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes2.err

This file was deleted.

8 changes: 5 additions & 3 deletions python/integration-tests/shell.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,10 +322,12 @@ def hook(self):

def exit(self, code=0):
if code is None:
code = 0
myCode = 0
elif type(code) != int:
code = 1
self.exitCode = code
myCode = 1
else:
myCode = code
self.exitCode = myCode
self._origExit(code)

def exc_handler(self, exc_type, exc, *args):
Expand Down
113 changes: 61 additions & 52 deletions python/integration-tests/testIntegration.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,140 +32,149 @@ def stripTrailingWs(s):

LOG_FILE = shell.mkTempFile(prefix="wypp-tests", suffix=".log", deleteAtExit='ifSuccess')
print(f'Output of integration tests goes to {LOG_FILE}')
LOG_REDIR = f'> {LOG_FILE} 2>&1'
LOG_REDIR = f'>> {LOG_FILE} 2>&1'

class TypeTests(unittest.TestCase):
def test_enumOk(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber("red")')
out = runInteractive('test-data/typeEnums.py', 'colorToNumber("red")')
self.assertEqual(['0'], out)

def test_enumTypeError(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: Literal['red', 'yellow', 'green']", out)
out = runInteractive('test-data/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: value of type Literal['red', 'yellow', 'green']", out)

def test_recordOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'Person("stefan", 42)')
self.assertEqual(["Person(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'incAge(Person("stefan", 42))')
self.assertEqual(["Person(name='stefan', age=43)"], out2)

@unittest.skip
def test_recordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'Person("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_recordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'mutableIncAge(Person("stefan", 42))')[0]
self.assertIn('expected: MutablePerson', out)
self.assertIn('expected: value of type MutablePerson', out)

def test_recordMutableOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'MutablePerson("stefan", 42)')
self.assertEqual(["MutablePerson(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'p = MutablePerson("stefan", 42)\nmutableIncAge(p)\np')
self.assertEqual(['', '', "MutablePerson(name='stefan', age=43)"], out2)

@unittest.skip
def test_mutableRecordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'MutablePerson("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_mutableRecordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'incAge(MutablePerson("stefan", 42))')[0]
self.assertIn('expected: Person', out)
self.assertIn('expected: value of type Person', out)

@unittest.skip
def test_mutableRecordFail3(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'p = MutablePerson("stefan", 42)\np.age = 42.4')
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_union(self):
out = runInteractive('file-tests/typeUnion.py', """formatAnimal(myCat)
out = runInteractive('test-data/typeUnion.py', """formatAnimal(myCat)
formatAnimal(myParrot)
formatAnimal(None)
""")
self.assertEqual("'Cat Pumpernickel'", out[0])
self.assertEqual("\"Parrot Mike says: Let's go to the punkrock show\"", out[1])
self.assertIn('given: None\nexpected: Union[Cat, Parrot]', out[2])
self.assertIn('given: None\nexpected: value of type Union[Cat, Parrot]', out[2])

class StudentSubmissionTests(unittest.TestCase):
def check(self, file, testFile, ecode, tycheck=True):
flags = ['--check']
if not tycheck:
flags.append('--no-typechecking')
cmd = f"python3 src/runYourProgram.py {' '.join(flags)} --test-file {testFile} {file} {LOG_REDIR}"
print(cmd)
res = shell.run(cmd, onError='ignore')
self.assertEqual(ecode, res.exitcode)

def test_goodSubmission(self):
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0)
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0,
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0)
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0,
tycheck=False)

def test_badSubmission(self):
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1, tycheck=False)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1, tycheck=False)

def test_submissionWithTypeErrors(self):
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 0, tycheck=False)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 1)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 0, tycheck=False)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 0, tycheck=False)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 1)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 0, tycheck=False)

class InteractiveTests(unittest.TestCase):

def test_scopeBugPeter(self):
out = runInteractive('file-tests/scope-bug-peter.py', 'local_test()\nprint(spam)')
out = runInteractive('test-data/scope-bug-peter.py', 'local_test()\nprint(spam)')
self.assertIn('IT WORKS', out)

def test_types1(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc(3)')
out = runInteractive('test-data/testTypesInteractive.py', 'inc(3)')
self.assertEqual(['4'], out)

def test_types2(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc("3")')[0]
expected = """given: '3'
expected: int
^^^
out = runInteractive('test-data/testTypesInteractive.py', 'inc("3")')[0]
expected = """untypy.error.UntypyTypeError
given: '3'
expected: value of type int

context: inc(x: int) -> int
^^^
declared at: /Users/swehr/devel/write-your-python-program/python/test-data/testTypesInteractive.py:1
1 | def inc(x: int) -> int:
2 | return x + 1

inside of inc(x: int) -> int
^^^
declared at:"""
self.assertIn(expected, stripTrailingWs(out))
caused by: <console>:1"""
self.assertEqual(expected, out)

def test_types3(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")')[1]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_types4(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf(3)')
self.assertEqual(['...', '3'], out)

def test_types5(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")',
tycheck=False)
self.assertEqual(['...', "'x'"], out)

def test_typesInImportedModule1(self):
out = run('file-tests/testTypes3.py', ecode=1)
self.assertIn('expected: int', out)
out = run('test-data/testTypes3.py', ecode=1)
self.assertIn('expected: value of type int', out)

def test_typesInImportedModule2(self):
out = run('file-tests/testTypes3.py', tycheck=False)
out = run('test-data/testTypes3.py', tycheck=False)
self.assertEqual('END', out)

class ReplTesterTests(unittest.TestCase):

def test_replTester(self):
d = shell.pwd()
cmd = f'python3 {d}/src/replTester.py {d}/test-data/repl-test-lib.py --repl {d}/test-data/repl-test-checks.py'
res = shell.run(cmd, captureStdout=True, onError='die', cwd='/tmp')
self.assertIn('All 1 tests succeded. Great!', res.stdout)
5 changes: 5 additions & 0 deletions python/run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PYTHONPATH="$SCRIPT_DIR"/site-lib/ python3 "$SCRIPT_DIR"/src/runYourProgram.py "$@"
49 changes: 36 additions & 13 deletions python/runFileTests.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ d=$(pwd)
siteDir=$(python3 -c 'import site; print(site.USER_SITE)')
t=$(mktemp)

echo
echo "Running file tests, siteDir=$siteDir ..."
echo "Writing logs to $t"
function check()
Expand All@@ -23,10 +22,10 @@ function check()
python3 $d/src/runYourProgram.py --check --install-mode assertInstall $d/"$1" >> "$t"
popd > /dev/null
}
check file-tests/fileWithImport.py
check file-tests/fileWithoutImport.py
check file-tests/fileWithBothImports.py
check file-tests/fileWithRecursiveTypes.py
check test-data/fileWithImport.py
check test-data/fileWithoutImport.py
check test-data/fileWithBothImports.py
check test-data/fileWithRecursiveTypes.py

# First argument: whether to do type checking or not
# Second argument: expected exit code. If given as X:Y, then X is the exit code with active
Expand All@@ -37,6 +36,7 @@ function checkWithOutputAux()
local tycheck="$1"
local expectedEcode=$2
local file="$3"
echo "Checking $file"
shift 3
tycheckOpt=""
suffixes="${PYENV_VERSION}"
Expand DownExpand Up@@ -101,11 +101,34 @@ function checkWithOutput()
checkWithOutputAux no "$@"
}

checkWithOutput 1 file-tests/testTraceback.py
checkWithOutput 1 file-tests/testTraceback2.py
checkWithOutput 1 file-tests/testTraceback3.py
checkWithOutput 0 file-tests/testArgs.py ARG_1 ARG_2
checkWithOutput 0 file-tests/printModuleName.py
checkWithOutput 0 file-tests/printModuleNameImport.py
checkWithOutput 1 file-tests/testTypes1.py
checkWithOutput 1:0 file-tests/testTypes2.py
checkWithOutput 1 test-data/testTraceback.py
checkWithOutput 1 test-data/testTraceback2.py
checkWithOutput 1 test-data/testTraceback3.py
checkWithOutput 0 test-data/testArgs.py ARG_1 ARG_2
checkWithOutput 0 test-data/printModuleName.py
checkWithOutput 0 test-data/printModuleNameImport.py
checkWithOutput 1 test-data/testTypes1.py
checkWithOutput 1:0 test-data/testTypes2.py
checkWithOutputAux yes 1 test-data/testTypesCollections1.py
checkWithOutputAux yes 1 test-data/testTypesCollections2.py
# checkWithOutputAux yes 1 test-data/testTypesCollections3.py See #5
# checkWithOutputAux yes 1 test-data/testTypesCollections4.py See #6
checkWithOutputAux yes 1 test-data/testTypesProtos1.py
# checkWithOutputAux yes 1 test-data/testTypesProtos2.py See #8
checkWithOutputAux yes 1 test-data/testTypesProtos3.py
# checkWithOutputAux yes 1 test-data/testTypesProtos4.py See #9
# checkWithOutputAux yes 1 test-data/testTypesSubclassing1.py See #10
# checkWithOutputAux yes 1 test-data/testTypesHigherOrderFuns.py See #7
# checkWithOutputAux yes 1 test-data/testTypesRecordInheritance.py See #11
checkWithOutputAux yes 0 test-data/testForwardRef1.py
# checkWithOutputAux yes 1 test-data/testForwardRef2.py See #14
checkWithOutputAux yes 0 test-data/testForwardRef3.py
# checkWithOutputAux yes 1 test-data/testForwardRef4.py See #14
# checkWithOutputAux yes 1 test-data/testTypesReturn.py See #15
checkWithOutputAux yes 1 test-data/testTypesSequence1.py
checkWithOutputAux yes 1 test-data/testTypesSequence2.py
checkWithOutputAux yes 1 test-data/testTypesTuple1.py
# checkWithOutputAux yes 1 test-data/wrong-caused-by.py See #17
# checkWithOutputAux yes 1 test-data/declared-aty.py See #18


Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
67f3e67
Merge pull request #4 from CodeSteak/untypy
skogsbaer Sep 21, 2021
7434862
update untypy
skogsbaer Sep 21, 2021
2459169
update untypy
skogsbaer Sep 21, 2021
b6e440b
do not import a test module from some other test module
skogsbaer Sep 21, 2021
ee7b63c
update untypy
skogsbaer Sep 21, 2021
467b4f7
fix execution of integration tests
skogsbaer Sep 21, 2021
2a2b484
unskip to tests that now succeed
skogsbaer Sep 21, 2021
a23a8d0
update README
skogsbaer Sep 21, 2021
bdb0d96
remove leftover from implicit wypp import
skogsbaer Sep 21, 2021
55e0df9
improved repl tester and renamed some files
skogsbaer Sep 21, 2021
6349976
symlink for using wypp without installing
skogsbaer Sep 21, 2021
f4bb18e
test for replTester (fails!)
skogsbaer Sep 21, 2021
150c7a5
fix for failing replTester test
skogsbaer Sep 21, 2021
5da45e9
update TODO
skogsbaer Sep 21, 2021
e9504ab
update untypy
skogsbaer Sep 22, 2021
8f9ec73
fix tests
skogsbaer Sep 22, 2021
e8e2b9d
update untypy
skogsbaer Sep 22, 2021
febdc01
some new tests
skogsbaer Sep 22, 2021
4ad786e
export type vars from wypp
skogsbaer Sep 22, 2021
6a3854b
add github issues to failing tests
skogsbaer Sep 22, 2021
f84f048
update untypy
skogsbaer Sep 22, 2021
7ac53ac
tests for forward refs
skogsbaer Sep 23, 2021
ba89fb1
refer to github issue
skogsbaer Sep 23, 2021
96b5fa4
do not re-export internal ForwardRef type
skogsbaer Sep 23, 2021
1ba6f54
improve formatting of exceptions
skogsbaer Sep 23, 2021
6da4d25
test for return type
skogsbaer Sep 23, 2021
5b66956
update untypy
skogsbaer Sep 23, 2021
a47f8b4
script for invoking runYourProgram.py
skogsbaer Sep 23, 2021
9f311a1
add .ignore file for vscode
skogsbaer Sep 23, 2021
d72343b
update untypy
skogsbaer Sep 23, 2021
55570ef
make run script more powerful
skogsbaer Sep 23, 2021
fbdfd01
test for sequences
skogsbaer Sep 23, 2021
9762370
update untypy
skogsbaer Sep 23, 2021
5d63a48
test for variadic tuples
skogsbaer Sep 23, 2021
14f5570
failing test for sequence
skogsbaer Sep 23, 2021
3091c20
update untypy
skogsbaer Sep 23, 2021
50340ac
test for Sequence
skogsbaer Sep 23, 2021
4b3963e
update untypy
skogsbaer Sep 23, 2021
5a78f79
new failing test
skogsbaer Sep 23, 2021
f488566
another failing test
skogsbaer Sep 23, 2021
939f11e
update untypy
skogsbaer Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion TODO.org
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
* untypy
** add tests with type annotations
*** for records
**** construction
**** write access
**** test for correct location
** understand why commit 150c7a5b209ddb264fd104feae42eba4905c2be7 is necessary to fix the replTester test
* other
** mode where all functions or methods without type signatures are reported as errors
** upload dist to pypi
** update README
*** python version
*** pip
*** records
*** import
2 changes: 2 additions & 0 deletions python/.ignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
site-lib/wypp
site-lib/untypy
1 change: 0 additions & 1 deletion python/file-tests/testArgs.out

This file was deleted.

7 changes: 0 additions & 7 deletions python/file-tests/testTraceback.err

This file was deleted.

5 changes: 0 additions & 5 deletions python/file-tests/testTraceback2.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes1.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes2.err

This file was deleted.

8 changes: 5 additions & 3 deletions python/integration-tests/shell.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,10 +322,12 @@ def hook(self):

def exit(self, code=0):
if code is None:
code = 0
myCode = 0
elif type(code) != int:
code = 1
self.exitCode = code
myCode = 1
else:
myCode = code
self.exitCode = myCode
self._origExit(code)

def exc_handler(self, exc_type, exc, *args):
Expand Down
113 changes: 61 additions & 52 deletions python/integration-tests/testIntegration.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,140 +32,149 @@ def stripTrailingWs(s):

LOG_FILE = shell.mkTempFile(prefix="wypp-tests", suffix=".log", deleteAtExit='ifSuccess')
print(f'Output of integration tests goes to {LOG_FILE}')
LOG_REDIR = f'> {LOG_FILE} 2>&1'
LOG_REDIR = f'>> {LOG_FILE} 2>&1'

class TypeTests(unittest.TestCase):
def test_enumOk(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber("red")')
out = runInteractive('test-data/typeEnums.py', 'colorToNumber("red")')
self.assertEqual(['0'], out)

def test_enumTypeError(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: Literal['red', 'yellow', 'green']", out)
out = runInteractive('test-data/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: value of type Literal['red', 'yellow', 'green']", out)

def test_recordOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'Person("stefan", 42)')
self.assertEqual(["Person(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'incAge(Person("stefan", 42))')
self.assertEqual(["Person(name='stefan', age=43)"], out2)

@unittest.skip
def test_recordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'Person("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_recordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'mutableIncAge(Person("stefan", 42))')[0]
self.assertIn('expected: MutablePerson', out)
self.assertIn('expected: value of type MutablePerson', out)

def test_recordMutableOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'MutablePerson("stefan", 42)')
self.assertEqual(["MutablePerson(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'p = MutablePerson("stefan", 42)\nmutableIncAge(p)\np')
self.assertEqual(['', '', "MutablePerson(name='stefan', age=43)"], out2)

@unittest.skip
def test_mutableRecordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'MutablePerson("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_mutableRecordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'incAge(MutablePerson("stefan", 42))')[0]
self.assertIn('expected: Person', out)
self.assertIn('expected: value of type Person', out)

@unittest.skip
def test_mutableRecordFail3(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'p = MutablePerson("stefan", 42)\np.age = 42.4')
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_union(self):
out = runInteractive('file-tests/typeUnion.py', """formatAnimal(myCat)
out = runInteractive('test-data/typeUnion.py', """formatAnimal(myCat)
formatAnimal(myParrot)
formatAnimal(None)
""")
self.assertEqual("'Cat Pumpernickel'", out[0])
self.assertEqual("\"Parrot Mike says: Let's go to the punkrock show\"", out[1])
self.assertIn('given: None\nexpected: Union[Cat, Parrot]', out[2])
self.assertIn('given: None\nexpected: value of type Union[Cat, Parrot]', out[2])

class StudentSubmissionTests(unittest.TestCase):
def check(self, file, testFile, ecode, tycheck=True):
flags = ['--check']
if not tycheck:
flags.append('--no-typechecking')
cmd = f"python3 src/runYourProgram.py {' '.join(flags)} --test-file {testFile} {file} {LOG_REDIR}"
print(cmd)
res = shell.run(cmd, onError='ignore')
self.assertEqual(ecode, res.exitcode)

def test_goodSubmission(self):
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0)
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0,
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0)
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0,
tycheck=False)

def test_badSubmission(self):
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1, tycheck=False)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1, tycheck=False)

def test_submissionWithTypeErrors(self):
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 0, tycheck=False)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 1)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 0, tycheck=False)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 0, tycheck=False)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 1)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 0, tycheck=False)

class InteractiveTests(unittest.TestCase):

def test_scopeBugPeter(self):
out = runInteractive('file-tests/scope-bug-peter.py', 'local_test()\nprint(spam)')
out = runInteractive('test-data/scope-bug-peter.py', 'local_test()\nprint(spam)')
self.assertIn('IT WORKS', out)

def test_types1(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc(3)')
out = runInteractive('test-data/testTypesInteractive.py', 'inc(3)')
self.assertEqual(['4'], out)

def test_types2(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc("3")')[0]
expected = """given: '3'
expected: int
^^^
out = runInteractive('test-data/testTypesInteractive.py', 'inc("3")')[0]
expected = """untypy.error.UntypyTypeError
given: '3'
expected: value of type int

context: inc(x: int) -> int
^^^
declared at: /Users/swehr/devel/write-your-python-program/python/test-data/testTypesInteractive.py:1
1 | def inc(x: int) -> int:
2 | return x + 1

inside of inc(x: int) -> int
^^^
declared at:"""
self.assertIn(expected, stripTrailingWs(out))
caused by: <console>:1"""
self.assertEqual(expected, out)

def test_types3(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")')[1]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_types4(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf(3)')
self.assertEqual(['...', '3'], out)

def test_types5(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")',
tycheck=False)
self.assertEqual(['...', "'x'"], out)

def test_typesInImportedModule1(self):
out = run('file-tests/testTypes3.py', ecode=1)
self.assertIn('expected: int', out)
out = run('test-data/testTypes3.py', ecode=1)
self.assertIn('expected: value of type int', out)

def test_typesInImportedModule2(self):
out = run('file-tests/testTypes3.py', tycheck=False)
out = run('test-data/testTypes3.py', tycheck=False)
self.assertEqual('END', out)

class ReplTesterTests(unittest.TestCase):

def test_replTester(self):
d = shell.pwd()
cmd = f'python3 {d}/src/replTester.py {d}/test-data/repl-test-lib.py --repl {d}/test-data/repl-test-checks.py'
res = shell.run(cmd, captureStdout=True, onError='die', cwd='/tmp')
self.assertIn('All 1 tests succeded. Great!', res.stdout)
5 changes: 5 additions & 0 deletions python/run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PYTHONPATH="$SCRIPT_DIR"/site-lib/ python3 "$SCRIPT_DIR"/src/runYourProgram.py "$@"
49 changes: 36 additions & 13 deletions python/runFileTests.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ d=$(pwd)
siteDir=$(python3 -c 'import site; print(site.USER_SITE)')
t=$(mktemp)

echo
echo "Running file tests, siteDir=$siteDir ..."
echo "Writing logs to $t"
function check()
Expand All@@ -23,10 +22,10 @@ function check()
python3 $d/src/runYourProgram.py --check --install-mode assertInstall $d/"$1" >> "$t"
popd > /dev/null
}
check file-tests/fileWithImport.py
check file-tests/fileWithoutImport.py
check file-tests/fileWithBothImports.py
check file-tests/fileWithRecursiveTypes.py
check test-data/fileWithImport.py
check test-data/fileWithoutImport.py
check test-data/fileWithBothImports.py
check test-data/fileWithRecursiveTypes.py

# First argument: whether to do type checking or not
# Second argument: expected exit code. If given as X:Y, then X is the exit code with active
Expand All@@ -37,6 +36,7 @@ function checkWithOutputAux()
local tycheck="$1"
local expectedEcode=$2
local file="$3"
echo "Checking $file"
shift 3
tycheckOpt=""
suffixes="${PYENV_VERSION}"
Expand DownExpand Up@@ -101,11 +101,34 @@ function checkWithOutput()
checkWithOutputAux no "$@"
}

checkWithOutput 1 file-tests/testTraceback.py
checkWithOutput 1 file-tests/testTraceback2.py
checkWithOutput 1 file-tests/testTraceback3.py
checkWithOutput 0 file-tests/testArgs.py ARG_1 ARG_2
checkWithOutput 0 file-tests/printModuleName.py
checkWithOutput 0 file-tests/printModuleNameImport.py
checkWithOutput 1 file-tests/testTypes1.py
checkWithOutput 1:0 file-tests/testTypes2.py
checkWithOutput 1 test-data/testTraceback.py
checkWithOutput 1 test-data/testTraceback2.py
checkWithOutput 1 test-data/testTraceback3.py
checkWithOutput 0 test-data/testArgs.py ARG_1 ARG_2
checkWithOutput 0 test-data/printModuleName.py
checkWithOutput 0 test-data/printModuleNameImport.py
checkWithOutput 1 test-data/testTypes1.py
checkWithOutput 1:0 test-data/testTypes2.py
checkWithOutputAux yes 1 test-data/testTypesCollections1.py
checkWithOutputAux yes 1 test-data/testTypesCollections2.py
# checkWithOutputAux yes 1 test-data/testTypesCollections3.py See #5
# checkWithOutputAux yes 1 test-data/testTypesCollections4.py See #6
checkWithOutputAux yes 1 test-data/testTypesProtos1.py
# checkWithOutputAux yes 1 test-data/testTypesProtos2.py See #8
checkWithOutputAux yes 1 test-data/testTypesProtos3.py
# checkWithOutputAux yes 1 test-data/testTypesProtos4.py See #9
# checkWithOutputAux yes 1 test-data/testTypesSubclassing1.py See #10
# checkWithOutputAux yes 1 test-data/testTypesHigherOrderFuns.py See #7
# checkWithOutputAux yes 1 test-data/testTypesRecordInheritance.py See #11
checkWithOutputAux yes 0 test-data/testForwardRef1.py
# checkWithOutputAux yes 1 test-data/testForwardRef2.py See #14
checkWithOutputAux yes 0 test-data/testForwardRef3.py
# checkWithOutputAux yes 1 test-data/testForwardRef4.py See #14
# checkWithOutputAux yes 1 test-data/testTypesReturn.py See #15
checkWithOutputAux yes 1 test-data/testTypesSequence1.py
checkWithOutputAux yes 1 test-data/testTypesSequence2.py
checkWithOutputAux yes 1 test-data/testTypesTuple1.py
# checkWithOutputAux yes 1 test-data/wrong-caused-by.py See #17
# checkWithOutputAux yes 1 test-data/declared-aty.py See #18


Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
67f3e67
Merge pull request #4 from CodeSteak/untypy
skogsbaer Sep 21, 2021
7434862
update untypy
skogsbaer Sep 21, 2021
2459169
update untypy
skogsbaer Sep 21, 2021
b6e440b
do not import a test module from some other test module
skogsbaer Sep 21, 2021
ee7b63c
update untypy
skogsbaer Sep 21, 2021
467b4f7
fix execution of integration tests
skogsbaer Sep 21, 2021
2a2b484
unskip to tests that now succeed
skogsbaer Sep 21, 2021
a23a8d0
update README
skogsbaer Sep 21, 2021
bdb0d96
remove leftover from implicit wypp import
skogsbaer Sep 21, 2021
55e0df9
improved repl tester and renamed some files
skogsbaer Sep 21, 2021
6349976
symlink for using wypp without installing
skogsbaer Sep 21, 2021
f4bb18e
test for replTester (fails!)
skogsbaer Sep 21, 2021
150c7a5
fix for failing replTester test
skogsbaer Sep 21, 2021
5da45e9
update TODO
skogsbaer Sep 21, 2021
e9504ab
update untypy
skogsbaer Sep 22, 2021
8f9ec73
fix tests
skogsbaer Sep 22, 2021
e8e2b9d
update untypy
skogsbaer Sep 22, 2021
febdc01
some new tests
skogsbaer Sep 22, 2021
4ad786e
export type vars from wypp
skogsbaer Sep 22, 2021
6a3854b
add github issues to failing tests
skogsbaer Sep 22, 2021
f84f048
update untypy
skogsbaer Sep 22, 2021
7ac53ac
tests for forward refs
skogsbaer Sep 23, 2021
ba89fb1
refer to github issue
skogsbaer Sep 23, 2021
96b5fa4
do not re-export internal ForwardRef type
skogsbaer Sep 23, 2021
1ba6f54
improve formatting of exceptions
skogsbaer Sep 23, 2021
6da4d25
test for return type
skogsbaer Sep 23, 2021
5b66956
update untypy
skogsbaer Sep 23, 2021
a47f8b4
script for invoking runYourProgram.py
skogsbaer Sep 23, 2021
9f311a1
add .ignore file for vscode
skogsbaer Sep 23, 2021
d72343b
update untypy
skogsbaer Sep 23, 2021
55570ef
make run script more powerful
skogsbaer Sep 23, 2021
fbdfd01
test for sequences
skogsbaer Sep 23, 2021
9762370
update untypy
skogsbaer Sep 23, 2021
5d63a48
test for variadic tuples
skogsbaer Sep 23, 2021
14f5570
failing test for sequence
skogsbaer Sep 23, 2021
3091c20
update untypy
skogsbaer Sep 23, 2021
50340ac
test for Sequence
skogsbaer Sep 23, 2021
4b3963e
update untypy
skogsbaer Sep 23, 2021
5a78f79
new failing test
skogsbaer Sep 23, 2021
f488566
another failing test
skogsbaer Sep 23, 2021
939f11e
update untypy
skogsbaer Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion TODO.org
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
* untypy
** add tests with type annotations
*** for records
**** construction
**** write access
**** test for correct location
** understand why commit 150c7a5b209ddb264fd104feae42eba4905c2be7 is necessary to fix the replTester test
* other
** mode where all functions or methods without type signatures are reported as errors
** upload dist to pypi
** update README
*** python version
*** pip
*** records
*** import
2 changes: 2 additions & 0 deletions python/.ignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
site-lib/wypp
site-lib/untypy
1 change: 0 additions & 1 deletion python/file-tests/testArgs.out

This file was deleted.

7 changes: 0 additions & 7 deletions python/file-tests/testTraceback.err

This file was deleted.

5 changes: 0 additions & 5 deletions python/file-tests/testTraceback2.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes1.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes2.err

This file was deleted.

8 changes: 5 additions & 3 deletions python/integration-tests/shell.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,10 +322,12 @@ def hook(self):

def exit(self, code=0):
if code is None:
code = 0
myCode = 0
elif type(code) != int:
code = 1
self.exitCode = code
myCode = 1
else:
myCode = code
self.exitCode = myCode
self._origExit(code)

def exc_handler(self, exc_type, exc, *args):
Expand Down
113 changes: 61 additions & 52 deletions python/integration-tests/testIntegration.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,140 +32,149 @@ def stripTrailingWs(s):

LOG_FILE = shell.mkTempFile(prefix="wypp-tests", suffix=".log", deleteAtExit='ifSuccess')
print(f'Output of integration tests goes to {LOG_FILE}')
LOG_REDIR = f'> {LOG_FILE} 2>&1'
LOG_REDIR = f'>> {LOG_FILE} 2>&1'

class TypeTests(unittest.TestCase):
def test_enumOk(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber("red")')
out = runInteractive('test-data/typeEnums.py', 'colorToNumber("red")')
self.assertEqual(['0'], out)

def test_enumTypeError(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: Literal['red', 'yellow', 'green']", out)
out = runInteractive('test-data/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: value of type Literal['red', 'yellow', 'green']", out)

def test_recordOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'Person("stefan", 42)')
self.assertEqual(["Person(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'incAge(Person("stefan", 42))')
self.assertEqual(["Person(name='stefan', age=43)"], out2)

@unittest.skip
def test_recordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'Person("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_recordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'mutableIncAge(Person("stefan", 42))')[0]
self.assertIn('expected: MutablePerson', out)
self.assertIn('expected: value of type MutablePerson', out)

def test_recordMutableOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'MutablePerson("stefan", 42)')
self.assertEqual(["MutablePerson(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'p = MutablePerson("stefan", 42)\nmutableIncAge(p)\np')
self.assertEqual(['', '', "MutablePerson(name='stefan', age=43)"], out2)

@unittest.skip
def test_mutableRecordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'MutablePerson("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_mutableRecordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'incAge(MutablePerson("stefan", 42))')[0]
self.assertIn('expected: Person', out)
self.assertIn('expected: value of type Person', out)

@unittest.skip
def test_mutableRecordFail3(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'p = MutablePerson("stefan", 42)\np.age = 42.4')
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_union(self):
out = runInteractive('file-tests/typeUnion.py', """formatAnimal(myCat)
out = runInteractive('test-data/typeUnion.py', """formatAnimal(myCat)
formatAnimal(myParrot)
formatAnimal(None)
""")
self.assertEqual("'Cat Pumpernickel'", out[0])
self.assertEqual("\"Parrot Mike says: Let's go to the punkrock show\"", out[1])
self.assertIn('given: None\nexpected: Union[Cat, Parrot]', out[2])
self.assertIn('given: None\nexpected: value of type Union[Cat, Parrot]', out[2])

class StudentSubmissionTests(unittest.TestCase):
def check(self, file, testFile, ecode, tycheck=True):
flags = ['--check']
if not tycheck:
flags.append('--no-typechecking')
cmd = f"python3 src/runYourProgram.py {' '.join(flags)} --test-file {testFile} {file} {LOG_REDIR}"
print(cmd)
res = shell.run(cmd, onError='ignore')
self.assertEqual(ecode, res.exitcode)

def test_goodSubmission(self):
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0)
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0,
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0)
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0,
tycheck=False)

def test_badSubmission(self):
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1, tycheck=False)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1, tycheck=False)

def test_submissionWithTypeErrors(self):
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 0, tycheck=False)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 1)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 0, tycheck=False)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 0, tycheck=False)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 1)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 0, tycheck=False)

class InteractiveTests(unittest.TestCase):

def test_scopeBugPeter(self):
out = runInteractive('file-tests/scope-bug-peter.py', 'local_test()\nprint(spam)')
out = runInteractive('test-data/scope-bug-peter.py', 'local_test()\nprint(spam)')
self.assertIn('IT WORKS', out)

def test_types1(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc(3)')
out = runInteractive('test-data/testTypesInteractive.py', 'inc(3)')
self.assertEqual(['4'], out)

def test_types2(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc("3")')[0]
expected = """given: '3'
expected: int
^^^
out = runInteractive('test-data/testTypesInteractive.py', 'inc("3")')[0]
expected = """untypy.error.UntypyTypeError
given: '3'
expected: value of type int

context: inc(x: int) -> int
^^^
declared at: /Users/swehr/devel/write-your-python-program/python/test-data/testTypesInteractive.py:1
1 | def inc(x: int) -> int:
2 | return x + 1

inside of inc(x: int) -> int
^^^
declared at:"""
self.assertIn(expected, stripTrailingWs(out))
caused by: <console>:1"""
self.assertEqual(expected, out)

def test_types3(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")')[1]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_types4(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf(3)')
self.assertEqual(['...', '3'], out)

def test_types5(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")',
tycheck=False)
self.assertEqual(['...', "'x'"], out)

def test_typesInImportedModule1(self):
out = run('file-tests/testTypes3.py', ecode=1)
self.assertIn('expected: int', out)
out = run('test-data/testTypes3.py', ecode=1)
self.assertIn('expected: value of type int', out)

def test_typesInImportedModule2(self):
out = run('file-tests/testTypes3.py', tycheck=False)
out = run('test-data/testTypes3.py', tycheck=False)
self.assertEqual('END', out)

class ReplTesterTests(unittest.TestCase):

def test_replTester(self):
d = shell.pwd()
cmd = f'python3 {d}/src/replTester.py {d}/test-data/repl-test-lib.py --repl {d}/test-data/repl-test-checks.py'
res = shell.run(cmd, captureStdout=True, onError='die', cwd='/tmp')
self.assertIn('All 1 tests succeded. Great!', res.stdout)
5 changes: 5 additions & 0 deletions python/run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PYTHONPATH="$SCRIPT_DIR"/site-lib/ python3 "$SCRIPT_DIR"/src/runYourProgram.py "$@"
49 changes: 36 additions & 13 deletions python/runFileTests.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ d=$(pwd)
siteDir=$(python3 -c 'import site; print(site.USER_SITE)')
t=$(mktemp)

echo
echo "Running file tests, siteDir=$siteDir ..."
echo "Writing logs to $t"
function check()
Expand All@@ -23,10 +22,10 @@ function check()
python3 $d/src/runYourProgram.py --check --install-mode assertInstall $d/"$1" >> "$t"
popd > /dev/null
}
check file-tests/fileWithImport.py
check file-tests/fileWithoutImport.py
check file-tests/fileWithBothImports.py
check file-tests/fileWithRecursiveTypes.py
check test-data/fileWithImport.py
check test-data/fileWithoutImport.py
check test-data/fileWithBothImports.py
check test-data/fileWithRecursiveTypes.py

# First argument: whether to do type checking or not
# Second argument: expected exit code. If given as X:Y, then X is the exit code with active
Expand All@@ -37,6 +36,7 @@ function checkWithOutputAux()
local tycheck="$1"
local expectedEcode=$2
local file="$3"
echo "Checking $file"
shift 3
tycheckOpt=""
suffixes="${PYENV_VERSION}"
Expand DownExpand Up@@ -101,11 +101,34 @@ function checkWithOutput()
checkWithOutputAux no "$@"
}

checkWithOutput 1 file-tests/testTraceback.py
checkWithOutput 1 file-tests/testTraceback2.py
checkWithOutput 1 file-tests/testTraceback3.py
checkWithOutput 0 file-tests/testArgs.py ARG_1 ARG_2
checkWithOutput 0 file-tests/printModuleName.py
checkWithOutput 0 file-tests/printModuleNameImport.py
checkWithOutput 1 file-tests/testTypes1.py
checkWithOutput 1:0 file-tests/testTypes2.py
checkWithOutput 1 test-data/testTraceback.py
checkWithOutput 1 test-data/testTraceback2.py
checkWithOutput 1 test-data/testTraceback3.py
checkWithOutput 0 test-data/testArgs.py ARG_1 ARG_2
checkWithOutput 0 test-data/printModuleName.py
checkWithOutput 0 test-data/printModuleNameImport.py
checkWithOutput 1 test-data/testTypes1.py
checkWithOutput 1:0 test-data/testTypes2.py
checkWithOutputAux yes 1 test-data/testTypesCollections1.py
checkWithOutputAux yes 1 test-data/testTypesCollections2.py
# checkWithOutputAux yes 1 test-data/testTypesCollections3.py See #5
# checkWithOutputAux yes 1 test-data/testTypesCollections4.py See #6
checkWithOutputAux yes 1 test-data/testTypesProtos1.py
# checkWithOutputAux yes 1 test-data/testTypesProtos2.py See #8
checkWithOutputAux yes 1 test-data/testTypesProtos3.py
# checkWithOutputAux yes 1 test-data/testTypesProtos4.py See #9
# checkWithOutputAux yes 1 test-data/testTypesSubclassing1.py See #10
# checkWithOutputAux yes 1 test-data/testTypesHigherOrderFuns.py See #7
# checkWithOutputAux yes 1 test-data/testTypesRecordInheritance.py See #11
checkWithOutputAux yes 0 test-data/testForwardRef1.py
# checkWithOutputAux yes 1 test-data/testForwardRef2.py See #14
checkWithOutputAux yes 0 test-data/testForwardRef3.py
# checkWithOutputAux yes 1 test-data/testForwardRef4.py See #14
# checkWithOutputAux yes 1 test-data/testTypesReturn.py See #15
checkWithOutputAux yes 1 test-data/testTypesSequence1.py
checkWithOutputAux yes 1 test-data/testTypesSequence2.py
checkWithOutputAux yes 1 test-data/testTypesTuple1.py
# checkWithOutputAux yes 1 test-data/wrong-caused-by.py See #17
# checkWithOutputAux yes 1 test-data/declared-aty.py See #18


Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
67f3e67
Merge pull request #4 from CodeSteak/untypy
skogsbaer Sep 21, 2021
7434862
update untypy
skogsbaer Sep 21, 2021
2459169
update untypy
skogsbaer Sep 21, 2021
b6e440b
do not import a test module from some other test module
skogsbaer Sep 21, 2021
ee7b63c
update untypy
skogsbaer Sep 21, 2021
467b4f7
fix execution of integration tests
skogsbaer Sep 21, 2021
2a2b484
unskip to tests that now succeed
skogsbaer Sep 21, 2021
a23a8d0
update README
skogsbaer Sep 21, 2021
bdb0d96
remove leftover from implicit wypp import
skogsbaer Sep 21, 2021
55e0df9
improved repl tester and renamed some files
skogsbaer Sep 21, 2021
6349976
symlink for using wypp without installing
skogsbaer Sep 21, 2021
f4bb18e
test for replTester (fails!)
skogsbaer Sep 21, 2021
150c7a5
fix for failing replTester test
skogsbaer Sep 21, 2021
5da45e9
update TODO
skogsbaer Sep 21, 2021
e9504ab
update untypy
skogsbaer Sep 22, 2021
8f9ec73
fix tests
skogsbaer Sep 22, 2021
e8e2b9d
update untypy
skogsbaer Sep 22, 2021
febdc01
some new tests
skogsbaer Sep 22, 2021
4ad786e
export type vars from wypp
skogsbaer Sep 22, 2021
6a3854b
add github issues to failing tests
skogsbaer Sep 22, 2021
f84f048
update untypy
skogsbaer Sep 22, 2021
7ac53ac
tests for forward refs
skogsbaer Sep 23, 2021
ba89fb1
refer to github issue
skogsbaer Sep 23, 2021
96b5fa4
do not re-export internal ForwardRef type
skogsbaer Sep 23, 2021
1ba6f54
improve formatting of exceptions
skogsbaer Sep 23, 2021
6da4d25
test for return type
skogsbaer Sep 23, 2021
5b66956
update untypy
skogsbaer Sep 23, 2021
a47f8b4
script for invoking runYourProgram.py
skogsbaer Sep 23, 2021
9f311a1
add .ignore file for vscode
skogsbaer Sep 23, 2021
d72343b
update untypy
skogsbaer Sep 23, 2021
55570ef
make run script more powerful
skogsbaer Sep 23, 2021
fbdfd01
test for sequences
skogsbaer Sep 23, 2021
9762370
update untypy
skogsbaer Sep 23, 2021
5d63a48
test for variadic tuples
skogsbaer Sep 23, 2021
14f5570
failing test for sequence
skogsbaer Sep 23, 2021
3091c20
update untypy
skogsbaer Sep 23, 2021
50340ac
test for Sequence
skogsbaer Sep 23, 2021
4b3963e
update untypy
skogsbaer Sep 23, 2021
5a78f79
new failing test
skogsbaer Sep 23, 2021
f488566
another failing test
skogsbaer Sep 23, 2021
939f11e
update untypy
skogsbaer Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion TODO.org
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
* untypy
** add tests with type annotations
*** for records
**** construction
**** write access
**** test for correct location
** understand why commit 150c7a5b209ddb264fd104feae42eba4905c2be7 is necessary to fix the replTester test
* other
** mode where all functions or methods without type signatures are reported as errors
** upload dist to pypi
** update README
*** python version
*** pip
*** records
*** import
2 changes: 2 additions & 0 deletions python/.ignore
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
site-lib/wypp
site-lib/untypy
1 change: 0 additions & 1 deletion python/file-tests/testArgs.out

This file was deleted.

7 changes: 0 additions & 7 deletions python/file-tests/testTraceback.err

This file was deleted.

5 changes: 0 additions & 5 deletions python/file-tests/testTraceback2.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes1.err

This file was deleted.

17 changes: 0 additions & 17 deletions python/file-tests/testTypes2.err

This file was deleted.

8 changes: 5 additions & 3 deletions python/integration-tests/shell.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -322,10 +322,12 @@ def hook(self):

def exit(self, code=0):
if code is None:
code = 0
myCode = 0
elif type(code) != int:
code = 1
self.exitCode = code
myCode = 1
else:
myCode = code
self.exitCode = myCode
self._origExit(code)

def exc_handler(self, exc_type, exc, *args):
Expand Down
113 changes: 61 additions & 52 deletions python/integration-tests/testIntegration.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,140 +32,149 @@ def stripTrailingWs(s):

LOG_FILE = shell.mkTempFile(prefix="wypp-tests", suffix=".log", deleteAtExit='ifSuccess')
print(f'Output of integration tests goes to {LOG_FILE}')
LOG_REDIR = f'> {LOG_FILE} 2>&1'
LOG_REDIR = f'>> {LOG_FILE} 2>&1'

class TypeTests(unittest.TestCase):
def test_enumOk(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber("red")')
out = runInteractive('test-data/typeEnums.py', 'colorToNumber("red")')
self.assertEqual(['0'], out)

def test_enumTypeError(self):
out = runInteractive('file-tests/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: Literal['red', 'yellow', 'green']", out)
out = runInteractive('test-data/typeEnums.py', 'colorToNumber(1)')[0]
self.assertIn("expected: value of type Literal['red', 'yellow', 'green']", out)

def test_recordOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'Person("stefan", 42)')
self.assertEqual(["Person(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'incAge(Person("stefan", 42))')
self.assertEqual(["Person(name='stefan', age=43)"], out2)

@unittest.skip
def test_recordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'Person("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_recordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'mutableIncAge(Person("stefan", 42))')[0]
self.assertIn('expected: MutablePerson', out)
self.assertIn('expected: value of type MutablePerson', out)

def test_recordMutableOk(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out1 = runInteractive(rec, 'MutablePerson("stefan", 42)')
self.assertEqual(["MutablePerson(name='stefan', age=42)"], out1)
out2 = runInteractive(rec, 'p = MutablePerson("stefan", 42)\nmutableIncAge(p)\np')
self.assertEqual(['', '', "MutablePerson(name='stefan', age=43)"], out2)

@unittest.skip
def test_mutableRecordFail1(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'MutablePerson("stefan", 42.3)')[0]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_mutableRecordFail2(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'incAge(MutablePerson("stefan", 42))')[0]
self.assertIn('expected: Person', out)
self.assertIn('expected: value of type Person', out)

@unittest.skip
def test_mutableRecordFail3(self):
rec = 'file-tests/typeRecords.py'
rec = 'test-data/typeRecords.py'
out = runInteractive(rec, 'p = MutablePerson("stefan", 42)\np.age = 42.4')
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_union(self):
out = runInteractive('file-tests/typeUnion.py', """formatAnimal(myCat)
out = runInteractive('test-data/typeUnion.py', """formatAnimal(myCat)
formatAnimal(myParrot)
formatAnimal(None)
""")
self.assertEqual("'Cat Pumpernickel'", out[0])
self.assertEqual("\"Parrot Mike says: Let's go to the punkrock show\"", out[1])
self.assertIn('given: None\nexpected: Union[Cat, Parrot]', out[2])
self.assertIn('given: None\nexpected: value of type Union[Cat, Parrot]', out[2])

class StudentSubmissionTests(unittest.TestCase):
def check(self, file, testFile, ecode, tycheck=True):
flags = ['--check']
if not tycheck:
flags.append('--no-typechecking')
cmd = f"python3 src/runYourProgram.py {' '.join(flags)} --test-file {testFile} {file} {LOG_REDIR}"
print(cmd)
res = shell.run(cmd, onError='ignore')
self.assertEqual(ecode, res.exitcode)

def test_goodSubmission(self):
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0)
self.check("file-tests/student-submission.py", "file-tests/student-submission-tests.py", 0,
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0)
self.check("test-data/student-submission.py", "test-data/student-submission-tests.py", 0,
tycheck=False)

def test_badSubmission(self):
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-bad.py",
"file-tests/student-submission-tests.py", 1, tycheck=False)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-bad.py",
"test-data/student-submission-tests.py", 1, tycheck=False)

def test_submissionWithTypeErrors(self):
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 1)
self.check("file-tests/student-submission-tyerror.py",
"file-tests/student-submission-tests.py", 0, tycheck=False)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 1)
self.check("file-tests/student-submission.py",
"file-tests/student-submission-tests-tyerror.py", 0, tycheck=False)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 1)
self.check("test-data/student-submission-tyerror.py",
"test-data/student-submission-tests.py", 0, tycheck=False)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 1)
self.check("test-data/student-submission.py",
"test-data/student-submission-tests-tyerror.py", 0, tycheck=False)

class InteractiveTests(unittest.TestCase):

def test_scopeBugPeter(self):
out = runInteractive('file-tests/scope-bug-peter.py', 'local_test()\nprint(spam)')
out = runInteractive('test-data/scope-bug-peter.py', 'local_test()\nprint(spam)')
self.assertIn('IT WORKS', out)

def test_types1(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc(3)')
out = runInteractive('test-data/testTypesInteractive.py', 'inc(3)')
self.assertEqual(['4'], out)

def test_types2(self):
out = runInteractive('file-tests/testTypesInteractive.py', 'inc("3")')[0]
expected = """given: '3'
expected: int
^^^
out = runInteractive('test-data/testTypesInteractive.py', 'inc("3")')[0]
expected = """untypy.error.UntypyTypeError
given: '3'
expected: value of type int

context: inc(x: int) -> int
^^^
declared at: /Users/swehr/devel/write-your-python-program/python/test-data/testTypesInteractive.py:1
1 | def inc(x: int) -> int:
2 | return x + 1

inside of inc(x: int) -> int
^^^
declared at:"""
self.assertIn(expected, stripTrailingWs(out))
caused by: <console>:1"""
self.assertEqual(expected, out)

def test_types3(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")')[1]
self.assertIn('expected: int', out)
self.assertIn('expected: value of type int', out)

def test_types4(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf(3)')
self.assertEqual(['...', '3'], out)

def test_types5(self):
out = runInteractive('file-tests/testTypesInteractive.py',
out = runInteractive('test-data/testTypesInteractive.py',
'def f(x: int) -> int: return x\n\nf("x")',
tycheck=False)
self.assertEqual(['...', "'x'"], out)

def test_typesInImportedModule1(self):
out = run('file-tests/testTypes3.py', ecode=1)
self.assertIn('expected: int', out)
out = run('test-data/testTypes3.py', ecode=1)
self.assertIn('expected: value of type int', out)

def test_typesInImportedModule2(self):
out = run('file-tests/testTypes3.py', tycheck=False)
out = run('test-data/testTypes3.py', tycheck=False)
self.assertEqual('END', out)

class ReplTesterTests(unittest.TestCase):

def test_replTester(self):
d = shell.pwd()
cmd = f'python3 {d}/src/replTester.py {d}/test-data/repl-test-lib.py --repl {d}/test-data/repl-test-checks.py'
res = shell.run(cmd, captureStdout=True, onError='die', cwd='/tmp')
self.assertIn('All 1 tests succeded. Great!', res.stdout)
5 changes: 5 additions & 0 deletions python/run
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

PYTHONPATH="$SCRIPT_DIR"/site-lib/ python3 "$SCRIPT_DIR"/src/runYourProgram.py "$@"
49 changes: 36 additions & 13 deletions python/runFileTests.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ d=$(pwd)
siteDir=$(python3 -c 'import site; print(site.USER_SITE)')
t=$(mktemp)

echo
echo "Running file tests, siteDir=$siteDir ..."
echo "Writing logs to $t"
function check()
Expand All@@ -23,10 +22,10 @@ function check()
python3 $d/src/runYourProgram.py --check --install-mode assertInstall $d/"$1" >> "$t"
popd > /dev/null
}
check file-tests/fileWithImport.py
check file-tests/fileWithoutImport.py
check file-tests/fileWithBothImports.py
check file-tests/fileWithRecursiveTypes.py
check test-data/fileWithImport.py
check test-data/fileWithoutImport.py
check test-data/fileWithBothImports.py
check test-data/fileWithRecursiveTypes.py

# First argument: whether to do type checking or not
# Second argument: expected exit code. If given as X:Y, then X is the exit code with active
Expand All@@ -37,6 +36,7 @@ function checkWithOutputAux()
local tycheck="$1"
local expectedEcode=$2
local file="$3"
echo "Checking $file"
shift 3
tycheckOpt=""
suffixes="${PYENV_VERSION}"
Expand DownExpand Up@@ -101,11 +101,34 @@ function checkWithOutput()
checkWithOutputAux no "$@"
}

checkWithOutput 1 file-tests/testTraceback.py
checkWithOutput 1 file-tests/testTraceback2.py
checkWithOutput 1 file-tests/testTraceback3.py
checkWithOutput 0 file-tests/testArgs.py ARG_1 ARG_2
checkWithOutput 0 file-tests/printModuleName.py
checkWithOutput 0 file-tests/printModuleNameImport.py
checkWithOutput 1 file-tests/testTypes1.py
checkWithOutput 1:0 file-tests/testTypes2.py
checkWithOutput 1 test-data/testTraceback.py
checkWithOutput 1 test-data/testTraceback2.py
checkWithOutput 1 test-data/testTraceback3.py
checkWithOutput 0 test-data/testArgs.py ARG_1 ARG_2
checkWithOutput 0 test-data/printModuleName.py
checkWithOutput 0 test-data/printModuleNameImport.py
checkWithOutput 1 test-data/testTypes1.py
checkWithOutput 1:0 test-data/testTypes2.py
checkWithOutputAux yes 1 test-data/testTypesCollections1.py
checkWithOutputAux yes 1 test-data/testTypesCollections2.py
# checkWithOutputAux yes 1 test-data/testTypesCollections3.py See #5
# checkWithOutputAux yes 1 test-data/testTypesCollections4.py See #6
checkWithOutputAux yes 1 test-data/testTypesProtos1.py
# checkWithOutputAux yes 1 test-data/testTypesProtos2.py See #8
checkWithOutputAux yes 1 test-data/testTypesProtos3.py
# checkWithOutputAux yes 1 test-data/testTypesProtos4.py See #9
# checkWithOutputAux yes 1 test-data/testTypesSubclassing1.py See #10
# checkWithOutputAux yes 1 test-data/testTypesHigherOrderFuns.py See #7
# checkWithOutputAux yes 1 test-data/testTypesRecordInheritance.py See #11
checkWithOutputAux yes 0 test-data/testForwardRef1.py
# checkWithOutputAux yes 1 test-data/testForwardRef2.py See #14
checkWithOutputAux yes 0 test-data/testForwardRef3.py
# checkWithOutputAux yes 1 test-data/testForwardRef4.py See #14
# checkWithOutputAux yes 1 test-data/testTypesReturn.py See #15
checkWithOutputAux yes 1 test-data/testTypesSequence1.py
checkWithOutputAux yes 1 test-data/testTypesSequence2.py
checkWithOutputAux yes 1 test-data/testTypesTuple1.py
# checkWithOutputAux yes 1 test-data/wrong-caused-by.py See #17
# checkWithOutputAux yes 1 test-data/declared-aty.py See #18


Loading