Skip to content

Commit

Permalink
Merge pull request #170 from radon-project/mypy-strict-fixing-2
Browse files Browse the repository at this point in the history
Mypy strict fixing 2
  • Loading branch information
Almas-Ali authored Jul 24, 2024
2 parents b69126f + 0dff962 commit 8cbc4e4
Show file tree
Hide file tree
Showing 22 changed files with 470 additions and 201 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
name: CI
on: [push, pull_request]
jobs:
everything:
radon-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: python3 -m pip install mypy ruff
- run: python3 test.py full


- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: python -m pip install mypy ruff
- run: python test.py full
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12.4
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ help:

.PHONY: format
format:
@isort . --quiet
@ruff format .

.PHONY: lint
Expand Down
3 changes: 2 additions & 1 deletion core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
Github: @Almas-Ali
"""

from core.builtin_funcs import run, global_symbol_table, radonify
from core.builtin_funcs import global_symbol_table, run
from core.datatypes import radonify

__all__ = ["run", "global_symbol_table", "radonify"]
__version__ = "0.0.1"
2 changes: 1 addition & 1 deletion core/builtin_classes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from core.builtin_classes.base_classes import BuiltInClass
from core.builtin_classes.file_object import FileObject
from core.builtin_classes.string_object import StringObject
from core.builtin_classes.json_object import JSONObject
from core.builtin_classes.requests_object import RequestsObject
from core.builtin_classes.string_object import StringObject

__all__ = ["BuiltInClass", "FileObject", "StringObject", "JSONObject", "RequestsObject"]
43 changes: 26 additions & 17 deletions core/builtin_classes/base_classes.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from __future__ import annotations

from core.errors import *
from core.datatypes import *
from core.parser import RTResult
from core.builtin_funcs import BuiltInFunction, args
from typing import Any, Callable, Optional, Sequence, TypeAlias, TypeVar

from typing import Callable, Any
from core.builtin_funcs import BuiltInFunction, args
from core.datatypes import BaseClass, BaseFunction, BaseInstance, ResultTuple, Value
from core.errors import RTError
from core.parser import Context, RTResult, SymbolTable


class BuiltInClass(BaseClass):
Expand Down Expand Up @@ -43,8 +43,6 @@ def __repr__(self) -> str:


class BuiltInInstance(BaseInstance):
obj: BuiltInObject

def __init__(self, parent_class: BuiltInClass, obj: BuiltInObject) -> None:
super().__init__(parent_class, parent_class.instance_class.__symbol_table__)
self.obj = obj
Expand All @@ -57,7 +55,7 @@ def bind_method(self, method: BaseFunction) -> RTResult[BaseFunction]:
@args(method.func.arg_names, method.func.defaults)
def new_func(ctx: Context) -> RTResult[Value]:
assert method.func is not None
return method.func(self.obj, ctx)
return method.func(self.obj, ctx) # type: ignore

return RTResult[BaseFunction]().success(BuiltInFunction(method.name, new_func))

Expand Down Expand Up @@ -108,10 +106,12 @@ def __init__(self, parent_class: BuiltInClass) -> None:


# Decorators for methods and operators
C = TypeVar("C", bound=Callable)
C = TypeVar("C", bound=Callable) # type: ignore


def operator(dunder: str) -> Callable[[C], C]:
"""Convert to operator."""

def _deco(f: C) -> C:
f.__operator__ = dunder # type: ignore
return f
Expand All @@ -120,20 +120,29 @@ def _deco(f: C) -> C:


def method(f: C) -> C:
"""Convert to method."""
f.__is_method__ = True # type: ignore
return f


# Decorator to check argument types
def check(
types: list[type[Value]], defaults: Optional[list[Optional[Value]]] = None
) -> Any: # return type == "idk figure it out"
MethodType: TypeAlias = (
Callable[[Any], RTResult[Value]]
| Callable[[Any, Any], RTResult[Value]]
| Callable[[Any, Any, Any], RTResult[Value]]
)
DecoReturn: TypeAlias = Callable[[BuiltInInstance, Sequence[str]], RTResult[Value]]
CheckReturn: TypeAlias = Callable[[MethodType], DecoReturn]


def check(types: Sequence[type[Value]], defaults: Optional[Sequence[Optional[Value]]] = None) -> CheckReturn:
"""Decorator to check argument types"""

if defaults is None:
defaults = [None] * len(types)

def _deco(f):
def wrapper(self, args):
res = RTResult()
def _deco(f: MethodType) -> DecoReturn:
def wrapper(self: BuiltInInstance, args: Sequence[str]) -> RTResult[Value]:
res = RTResult[Value]()
func_name = f.__name__
class_name = self.parent_class.name
full_func_name = f"{class_name}.{func_name}()"
Expand All @@ -160,7 +169,7 @@ def wrapper(self, args):
)

# Populate defaults
real_args = []
real_args: list[Value | str] = []
for i, typ in enumerate(types):
arg = defaults[i] if i >= len(args) else args[i]
assert arg is not None, "We should have already errored"
Expand Down
15 changes: 8 additions & 7 deletions core/builtin_classes/file_object.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from core.errors import *
from core.datatypes import *
from core.parser import RTResult
from core.builtin_funcs import args
from core.builtin_classes.base_classes import BuiltInObject, operator, check, method

from typing import IO

from core.builtin_classes.base_classes import BuiltInObject, check, method, operator
from core.builtin_funcs import args
from core.datatypes import Array, Boolean, Null, Number, String, Value
from core.errors import RTError
from core.parser import Context, RTResult
from core.tokens import Position


class FileObject(BuiltInObject):
file: IO[str]
Expand Down Expand Up @@ -47,7 +48,7 @@ def read(self, ctx: Context) -> RTResult[Value]:

@args([])
@method
def readline(self, ctx: Context):
def readline(self, ctx: Context) -> RTResult[Value]:
res = RTResult[Value]()
try:
value = self.file.readline()
Expand Down
13 changes: 6 additions & 7 deletions core/builtin_classes/json_object.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from core.errors import *
from core.datatypes import *
from core.parser import RTResult
from core.builtin_funcs import args
from core.builtin_classes.base_classes import BuiltInObject, operator, check, method
from core.datatypes import radonify, deradonify

import json

from core.builtin_classes.base_classes import BuiltInObject, check, method, operator
from core.builtin_funcs import args
from core.datatypes import Null, String, Value, deradonify, radonify
from core.errors import RTError
from core.parser import Context, RTResult


class JSONObject(BuiltInObject):
@operator("__constructor__")
Expand Down
15 changes: 7 additions & 8 deletions core/builtin_classes/requests_object.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from core.errors import *
from core.datatypes import *
from core.parser import RTResult
from core.builtin_funcs import args
from core.builtin_classes.base_classes import BuiltInObject, operator, check, method
from core.datatypes import radonify, deradonify

import json
import urllib.request
import urllib.parse
import urllib.request

from core.builtin_classes.base_classes import BuiltInObject, check, method, operator
from core.builtin_funcs import args
from core.datatypes import HashMap, Null, String, Value, deradonify, radonify
from core.errors import RTError
from core.parser import Context, RTResult


class RequestsObject(BuiltInObject):
Expand Down
8 changes: 4 additions & 4 deletions core/builtin_classes/string_object.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from core.errors import *
from core.datatypes import *
from core.parser import RTResult
from core.builtin_classes.base_classes import BuiltInObject, check, method, operator
from core.builtin_funcs import args
from core.builtin_classes.base_classes import BuiltInObject, operator, check, method
from core.datatypes import Array, Boolean, Null, Number, String, Value
from core.errors import RTError
from core.parser import Context, RTResult


class StringObject(BuiltInObject):
Expand Down
76 changes: 46 additions & 30 deletions core/builtin_funcs.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from __future__ import annotations

from core.errors import *
from core.tokens import *
from core.datatypes import *
from core.parser import Parser
from core.lexer import *

import os
from sys import stdout
from typing import Callable, Generic, NoReturn, Optional, ParamSpec, Protocol, Sequence, Union, cast

from typing import Optional, Callable, Protocol, cast, Generic, ParamSpec
from core.datatypes import Array, BaseFunction, Boolean, HashMap, Null, Number, PyAPI, String, Type, Value
from core.errors import Error, InvalidSyntaxError, RTError
from core.lexer import Lexer
from core.parser import Context, Parser, RTResult, SymbolTable
from core.tokens import BASE_DIR, STDLIBS, Position

P = ParamSpec("P")

Expand All @@ -26,23 +25,21 @@ def defaults(self) -> list[Optional[Value]]: ...

# Decorator for built-in functions
def args(
arg_names: list[str], defaults: Optional[list[Optional[Value]]] = None
arg_names: list[str], defaults: Optional[Sequence[Optional[Value]]] = None
) -> Callable[[Callable[P, RTResult[Value]]], RadonCompatibleFunction[P]]:
if defaults is None:
defaults = [None] * len(arg_names)

def _args(f: Callable[P, RTResult[Value]]) -> RadonCompatibleFunction[P]:
f.arg_names = arg_names # type: ignore
f.defaults = defaults # type: ignore
return cast(RadonCompatibleFunction, f)
return cast(RadonCompatibleFunction[P], f)

return _args


class BuiltInFunction(BaseFunction):
func: Optional[RadonCompatibleFunction]

def __init__(self, name: str, func: Optional[RadonCompatibleFunction] = None):
def __init__(self, name: str, func: Optional[RadonCompatibleFunction[P]] = None):
super().__init__(name, None)
self.func = func
self.va_name = None
Expand Down Expand Up @@ -81,7 +78,7 @@ def execute(self, args: list[Value], kwargs: dict[str, Value]) -> RTResult[Value
return res.success(return_value)

@args([])
def no_execute_method(self, context: Context):
def no_execute_method(self, context: Context) -> NoReturn:
raise Exception(f"No execute_{self.name} method defined")

def copy(self) -> BuiltInFunction:
Expand All @@ -105,23 +102,38 @@ def execute_print_ret(self, exec_ctx: Context) -> RTResult[Value]:

@args(["value"])
def execute_len(self, exec_ctx: Context) -> RTResult[Value]:
val = exec_ctx.symbol_table.get("value")
val: Optional[Value] = exec_ctx.symbol_table.get("value")
try:
if val is not None and val.__class__ is not Value:
if hasattr(val, "__len__"):
ret = int(val.__len__())
# ret = int(val.__len__())
ret = int(getattr(val, "__len__")())
elif hasattr(val, "__exec_len__"):
ret = int(val.__exec_len__())
# ret = int(val.__exec_len__())
ret = int(getattr(val, "__exec_len__")())
else:
raise TypeError()
return RTResult[Value]().success(Number(ret))
raise TypeError()
except TypeError:
return RTResult[Value]().failure(
Error(
self.pos_start, self.pos_end, "TypeError", f'Object of type "{val.__class__.__name__}" has no len()'
try:
return RTResult[Value]().failure(
Error(
self.pos_start,
self.pos_end,
"TypeError",
f'Object of type "{val.parent_class.name}" has no len()', # type: ignore
)
)
except AttributeError:
return RTResult[Value]().failure(
Error(
self.pos_start,
self.pos_end,
"TypeError",
f'Object of type "{val.__class__.__name__}" has no len()',
)
)
)

@args(["value"])
def execute_input(self, exec_ctx: Context) -> RTResult[Value]:
Expand Down Expand Up @@ -267,8 +279,7 @@ def execute_arr_chunk(self, exec_ctx: Context) -> RTResult[Value]:
val = int(value.value)

try:
# _list = Array(array.elements[start.value:end.value])
_list = Array([array[i : i + val] for i in range(0, len(array), val)])
_list = Array([Array(array[i : i + val]) for i in range(0, len(array), val)]) # type: ignore
except IndexError:
return RTResult[Value]().failure(
RTError(self.pos_start, self.pos_end, "Could't not complete chunk", exec_ctx)
Expand Down Expand Up @@ -444,11 +455,10 @@ def execute_require(self, exec_ctx: Context) -> RTResult[Value]:
module_file = module.split("/")[-1]
module_path = os.path.dirname(os.path.realpath(module))

global CURRENT_DIR
if CURRENT_DIR is None:
CURRENT_DIR = module_path
# if CURRENT_DIR is None:
# CURRENT_DIR = module_path

module = os.path.join(CURRENT_DIR, module_file)
module = os.path.join(module_path, module_file)
else:
# For STDLIB modules
module = os.path.join(BASE_DIR, "stdlib", f"{module}.rn")
Expand All @@ -460,7 +470,8 @@ def execute_require(self, exec_ctx: Context) -> RTResult[Value]:
RTError(self.pos_start, self.pos_end, f'Failed to load script "{module}"\n' + str(e), exec_ctx)
)

_, error, should_exit = run(module, script)
error: Error | RTError | None
_, error, should_exit = run(module, script) # type: ignore

if error:
return RTResult[Value]().failure(
Expand Down Expand Up @@ -536,7 +547,12 @@ def run(
return_result: bool = False,
hide_paths: bool = False,
import_cwd: Optional[str] = None,
):
) -> Union[
tuple[None, Error, bool],
tuple[None, InvalidSyntaxError, bool],
tuple[None, RTResult[Value], None],
tuple[Optional[Value], Optional[RTError | Error], bool],
]:
from core.interpreter import Interpreter # Lazy import

# Generate tokens
Expand Down Expand Up @@ -566,7 +582,7 @@ def run(
result = interpreter.visit(ast.node, context)

if return_result:
return result
return result # type: ignore
return result.value, result.error, result.should_exit


Expand Down Expand Up @@ -627,7 +643,7 @@ def create_global_symbol_table() -> SymbolTable:
ret.set("File", bic.BuiltInClass("File", bic.FileObject))
ret.set("String", bic.BuiltInClass("String", bic.StringObject))
ret.set("Json", bic.BuiltInClass("Json", bic.JSONObject))
ret.set("Requests", bic.BuiltInClass("Json", bic.RequestsObject))
ret.set("Requests", bic.BuiltInClass("Requests", bic.RequestsObject))
return ret


Expand Down
Loading

0 comments on commit 8cbc4e4

Please sign in to comment.