1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
import json
import logging
import os
# noinspection PyCompatibility
from dataclasses import dataclass
from io import StringIO
from typing import Any, Dict, List, NewType, Optional, Tuple, Union
from mypy.main import main as mypy_main
import pytest
from dataclasses_json import DataClassJsonMixin, CatchAll
@dataclass
class User(DataClassJsonMixin):
id: str
name: str = "John"
ca: CatchAll = None
Filename = NewType('Filename', str)
LineNumber = NewType('LineNumber', int)
ErrorLevel = NewType('ErrorLevel', str)
ErrorMessage = NewType('ErrorMessage', str)
class TestAnnotations:
u: User = User('ax9ssFxH')
j: str = u.to_json()
u2: User = User.from_json(j)
u2a: User = User.from_json(j.encode())
jMany = [{"id": "115412", "name": "Peter"},
{"id": "atxXxGhg", "name": "Parker"}]
sch = User.schema()
users1: List[User] = sch.loads(json.dumps(jMany), many=True)
n: str = users1[1].name
users2: List[User] = sch.load(jMany, many=True) # type: ignore
u3: User = sch.load(jMany[1])
j2: Dict[str, Any] = sch.dump(u)
j3: List[Dict[str, Any]] = sch.dump([u2, u3], many=True)
j4: str = sch.dumps(u2)
j4_dict: Dict[str, Any] = json.loads(j4)
u4a: User = User.from_json(j4)
u4b: User = User.from_dict(j4_dict)
def filter_errors(self, errors: List[str]) -> List[str]:
real_errors: List[str] = list()
current_file = __file__
current_path = os.path.split(current_file)
for line in errors:
line = line.strip()
if (not line):
continue
fn, lno, lvl, msg = self.parse_trace_line(line)
if (fn is not None):
_path = os.path.split(fn)
if (_path[-1] != current_path[-1]):
continue
real_errors.append(line)
return real_errors
def parse_trace_line(self, line: str) -> \
Tuple[Optional[Filename], Optional[LineNumber], Optional[
ErrorLevel], ErrorMessage]:
# Define variables
file_name: Union[str, Filename, None]
line_no: Union[str, LineNumber, None]
level: Union[str, ErrorLevel, None]
msg: Union[str, ErrorMessage, None]
where, sep, msg = line.partition(': ')
if (sep):
file_name, sep, line_no = where.rpartition(':')
file_name = Filename(file_name)
if (sep):
line_no = LineNumber(int(line_no))
else:
line_no = None
level, sep, msg = msg.partition(': ')
if (sep):
level = ErrorLevel(level)
else:
msg = level
level = None
else:
# Otherwise we get 'Found 1 error in 1 file (checked 1 source file)' as an error
# due to a mypy error in a different file
file_name = Filename("") if line.startswith("Found") else None
line_no = None
level = None
msg = line
msg = ErrorMessage(msg)
return file_name, line_no, level, msg
@pytest.mark.skip(reason="mypy_main signature changed")
def test_type_hints(self):
text_io = StringIO('')
try:
# mypy.main uses sys.stdout for printing
# We override it to catch error messages
mypy_main(args=[__file__], stdout=text_io, stderr=text_io, clean_exit=True)
except SystemExit:
# mypy.main could return errors found inside other files.
# filter_errors() will filter out all errors outside this file.
errors = text_io.getvalue().splitlines()
errors = self.filter_errors(errors)
else:
errors = None
# To prevent large errors raise error out of try/except
if (errors):
logging.error('\n'.join(errors))
raise AssertionError("Type annotations check failed")
|