Skip to content

Commit

Permalink
Fix type hints for type checker
Browse files Browse the repository at this point in the history
  • Loading branch information
niknetniko committed Aug 7, 2023
1 parent 555f2bd commit e4cf4e3
Show file tree
Hide file tree
Showing 61 changed files with 782 additions and 620 deletions.
10 changes: 6 additions & 4 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@
typing-inspect
pyyaml
pygments
python-i18n
# For Pycharm
setuptools
python-i18n
];
python-env = python.withPackages(ps: (core-packages ps) ++ [
ps.pylint
ps.pytest
ps.pytest-mock
ps.pytest-cov
# For Pycharm
ps.setuptools
ps.isort
ps.black
]);
core-deps = [
(python.withPackages(ps: (core-packages ps) ++ [ps.pylint]))
Expand Down Expand Up @@ -115,7 +117,7 @@
default = tested;
tested = pkgs.devshell.mkShell {
name = "TESTed";
packages = [python-env] ++ haskell-deps ++ node-deps ++ bash-deps ++ c-deps ++ java-deps ++ kotlin-deps ++ csharp-deps;
packages = [python-env pkgs.nodePackages.pyright] ++ haskell-deps ++ node-deps ++ bash-deps ++ c-deps ++ java-deps ++ kotlin-deps ++ csharp-deps;
devshell.startup.link.text = ''
mkdir -p "$PRJ_DATA_DIR/current"
ln -sfn "${python-env}/${python-env.sitePackages}" "$PRJ_DATA_DIR/current/python-packages"
Expand Down
84 changes: 0 additions & 84 deletions flake.old.nix

This file was deleted.

8 changes: 4 additions & 4 deletions tested/datatypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@

NumericTypes = Union[BasicNumericTypes, AdvancedNumericTypes]
StringTypes = Union[BasicStringTypes, AdvancedStringTypes]
BooleanTypes = Union[BasicBooleanTypes]
BooleanTypes = BasicBooleanTypes
NothingTypes = Union[BasicNothingTypes, AdvancedNothingTypes]
SequenceTypes = Union[BasicSequenceTypes, AdvancedSequenceTypes]
ObjectTypes = Union[BasicObjectTypes]
ObjectTypes = BasicObjectTypes

SimpleTypes = Union[NumericTypes, StringTypes, BooleanTypes, NothingTypes]
ComplexTypes = Union[SequenceTypes, ObjectTypes]
Expand All @@ -56,10 +56,10 @@ def resolve_to_basic(type_: AllTypes) -> BasicTypes:
"""
Resolve a type to its basic type. Basic types are returned unchanged.
"""
if isinstance(type_, get_args(BasicTypes)):
if isinstance(type_, BasicTypes):
return type_

assert isinstance(type_, get_args(AdvancedTypes))
assert isinstance(type_, AdvancedTypes)
return type_.base_type


Expand Down
14 changes: 7 additions & 7 deletions tested/description_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,14 @@ def create_description_instance_from_template(
judge_directory = Path(__file__).parent.parent
global_config = GlobalConfig(
dodona=DodonaConfig(
resources="",
source="",
resources="", # type: ignore
source="", # type: ignore
time_limit=0,
memory_limit=0,
natural_language=natural_language,
programming_language=programming_language,
workdir="",
judge=str(judge_directory),
workdir="", # type: ignore
judge=judge_directory,
test_suite="suite.yaml",
),
context_separator_secret="",
Expand Down Expand Up @@ -185,7 +185,7 @@ def get_variable(var_name: str, is_global: bool = True):
if is_html:
namespace = html.escape(namespace)

return template.render(
return template.render( # type: ignore
function=partial(description_generator.get_function_name, is_html=is_html),
property=partial(description_generator.get_property_name, is_html=is_html),
variable=get_variable,
Expand Down Expand Up @@ -224,9 +224,9 @@ def create_description_instance(
if not language_exists(programming_language):
raise ValueError(f"Language {programming_language} doesn't exists")

template = prepare_template(template, is_html)
template = prepare_template(template, is_html) # type: ignore
return create_description_instance_from_template(
template, programming_language, natural_language, namespace, is_html
template, programming_language, natural_language, namespace, is_html # type: ignore
)


Expand Down
8 changes: 5 additions & 3 deletions tested/dodona.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import dataclasses
import json
from enum import StrEnum, auto, unique
from typing import IO, Literal, Optional, Type, Union
from typing import IO, Literal, Optional, Union

from pydantic import BaseModel
from pydantic.dataclasses import dataclass
Expand Down Expand Up @@ -138,7 +138,7 @@ class AnnotateCode:

row: Index
text: str
externalUrl: str = None
externalUrl: Optional[str] = None
column: Optional[Index] = None
type: Optional[Severity] = None
rows: Optional[Index] = None
Expand Down Expand Up @@ -227,7 +227,9 @@ class CloseJudgment:
}


def close_for(type_: str) -> Type[Update]:
def close_for(
type_: str,
) -> type[CloseJudgment | CloseTab | CloseContext | CloseTestcase | CloseTest]:
return _mapping[type_]


Expand Down
33 changes: 26 additions & 7 deletions tested/dsl/ast_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
- Collection and datastructure literals
- Negation operator
- Function calls
- Keyword arguments (ie. named arguments)
- Properties (ie. attributes)
- Keyword arguments (i.e. named arguments)
- Properties (i.e. attributes)
"""

import ast
import dataclasses
from typing import Optional
from typing import Literal, Optional, cast, overload

from pydantic import ValidationError

Expand Down Expand Up @@ -70,9 +70,11 @@ def _is_and_get_allowed_empty(node: ast.Call) -> Optional[Value]:
"""
assert isinstance(node.func, ast.Name)
if node.func.id in AdvancedSequenceTypes.__members__.values():
assert isinstance(node.func.id, AdvancedSequenceTypes)
# noinspection PyTypeChecker
return SequenceType(type=node.func.id, data=[])
elif node.func.id in BasicSequenceTypes.__members__.values():
assert isinstance(node.func.id, BasicSequenceTypes)
# noinspection PyTypeChecker
return SequenceType(type=node.func.id, data=[])
elif node.func.id in BasicObjectTypes.__members__.values():
Expand All @@ -96,6 +98,7 @@ def _is_type_cast(node: ast.expr) -> bool:
def _convert_ann_assignment(node: ast.AnnAssign) -> Assignment:
if not isinstance(node.target, ast.Name):
raise InvalidDslError("You can only assign to simple variables")
assert node.value
value = _convert_expression(node.value, False)
if isinstance(node.annotation, ast.Name):
type_ = node.annotation.id
Expand All @@ -109,6 +112,7 @@ def _convert_ann_assignment(node: ast.AnnAssign) -> Assignment:
if not is_our_type:
type_ = VariableType(data=type_)

assert isinstance(type_, VariableType | AllTypes)
return Assignment(variable=node.target.id, expression=value, type=type_)


Expand All @@ -125,7 +129,7 @@ def _convert_assignment(node: ast.Assign) -> Assignment:

# Support a few obvious ones, such as constructor calls or literal values.
type_ = None
if isinstance(value, get_args(Value)):
if isinstance(value, Value):
type_ = value.type
elif isinstance(value, FunctionCall) and value.type == FunctionType.CONSTRUCTOR:
type_ = VariableType(data=value.name)
Expand All @@ -135,6 +139,7 @@ def _convert_assignment(node: ast.Assign) -> Assignment:
f"Could not deduce the type of variable {variable.id}: add a type annotation."
)

assert isinstance(type_, AllTypes | VariableType)
return Assignment(variable=variable.id, expression=value, type=type_)


Expand Down Expand Up @@ -162,7 +167,8 @@ def _convert_call(node: ast.Call) -> FunctionCall:
for keyword in node.keywords:
arguments.append(
NamedArgument(
name=keyword.arg, value=_convert_expression(keyword.value, False)
name=cast(str, keyword.arg),
value=_convert_expression(keyword.value, False),
)
)

Expand All @@ -184,6 +190,7 @@ def _convert_constant(node: ast.Constant) -> Value:
def _convert_expression(node: ast.expr, is_return: bool) -> Expression:
if _is_type_cast(node):
assert isinstance(node, ast.Call)
assert isinstance(node.func, ast.Name)

# "Casts" of sequence types can also be used a constructor for an empty sequence.
# For example, "set()", "map()", ...
Expand All @@ -210,7 +217,7 @@ def _convert_expression(node: ast.expr, is_return: bool) -> Expression:
subexpression = node.args[0]
value = _convert_expression(subexpression, is_return)

if not isinstance(value, get_args(Value)):
if not isinstance(value, Value):
raise InvalidDslError(
"The argument of a cast function must resolve to a value."
)
Expand Down Expand Up @@ -254,7 +261,8 @@ def _convert_expression(node: ast.expr, is_return: bool) -> Expression:
elif isinstance(node, ast.Dict):
elements = [
ObjectKeyValuePair(
_convert_expression(k, is_return), _convert_expression(v, is_return)
key=_convert_expression(cast(ast.expr, k), is_return),
value=_convert_expression(v, is_return),
)
for k, v in zip(node.keys, node.values)
]
Expand All @@ -269,6 +277,7 @@ def _convert_expression(node: ast.expr, is_return: bool) -> Expression:
value = _convert_constant(node.operand)
if not isinstance(value, NumberType):
raise InvalidDslError("'-' is only supported on literal numbers")
assert isinstance(value.data, int | float)
return NumberType(type=value.type, data=-value.data)
else:
raise InvalidDslError(f"Unsupported expression type: {type(node)}")
Expand Down Expand Up @@ -303,6 +312,16 @@ def _translate_to_ast(node: ast.Interactive, is_return: bool) -> Statement:
return _convert_statement(statement_or_expression)


@overload
def parse_string(code: str, is_return: Literal[True]) -> Value:
...


@overload
def parse_string(code: str, is_return: Literal[False] = False) -> Statement:
...


def parse_string(code: str, is_return=False) -> Statement:
"""
Parse a string with Python code into our AST.
Expand Down
Loading

0 comments on commit e4cf4e3

Please sign in to comment.