From 698cae16555a6c3b78b38dac04936d5fc8468e08 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:05:46 +0600 Subject: [PATCH 01/18] fixed: mypy --strict core/errors.py --- core/errors.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/core/errors.py b/core/errors.py index 9fc0949..51cf9fd 100755 --- a/core/errors.py +++ b/core/errors.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Self from dataclasses import dataclass from core.colortools import Log @@ -67,11 +67,11 @@ def as_string(self) -> str: result += "\n" + string_with_arrows(self.pos_start.ftxt, self.pos_start, self.pos_end) return result - def set_pos(self, pos_start=None, pos_end=None): + def set_pos(self, pos_start: Optional[Position] = None, pos_end: Optional[Position] = None) -> Self: """Says it's gonna set the position, but actually does NOTHING""" return self - def set_context(self, context=None): + def set_context(self, context: Optional[Context] = None) -> Self: """Says it's gonna set the context, but actually does NOTHING""" return self @@ -80,8 +80,8 @@ def __repr__(self) -> str: return f"{self.error_name}: {self.details}" return self.error_name - def copy(self): - return __class__(self.pos_start, self.pos_end, self.error_name, self.details) + def copy(self) -> Self: + return type(self)(self.pos_start, self.pos_end, self.error_name, self.details) class IllegalCharError(Error): @@ -108,9 +108,9 @@ def __init__(self, pos_start: Position, pos_end: Position, details: str = "") -> class RTError(Error): """Runtime Error class""" - context: Context + context: Optional[Context] - def __init__(self, pos_start: Position, pos_end: Position, details: Optional[str], context: Context) -> None: + def __init__(self, pos_start: Position, pos_end: Position, details: Optional[str], context: Optional[Context]) -> None: super().__init__(pos_start, pos_end, "RuntimeError", details) self.context = context @@ -136,12 +136,12 @@ def generate_radiation(self) -> str: result = ( f" File {Log.light_info(fn)}, line {Log.light_info(str(ln))}, in {Log.light_info(name)}\n" + result ) - pos = ctx.parent_entry_pos # type: ignore - ctx = ctx.parent # type: ignore + pos = ctx.parent_entry_pos # type: ignore + ctx = ctx.parent return Log.light_purple("Radiation (most recent call last):\n") + result - def set_context(self, context=None): + def set_context(self, context: Optional[Context] = None) -> Self: """Says it's gonna set the context, but actually does nothing""" return self @@ -169,6 +169,6 @@ def generate_radiation(self) -> str: class VError(RTError): """Value Error class""" - def __init__(self, pos_start, pos_end, details, context): - super().__init__(pos_start, pos_end, "ValueError", details) + def __init__(self, pos_start: Position, pos_end: Position, details: str, context: Context,): + super().__init__(pos_start, pos_end, "ValueError", context) self.context = context From 662953088b4675cfa7f21f18eac0ae015d5d1c89 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:05:59 +0600 Subject: [PATCH 02/18] fixed: mypy --strict core/parser.py --- core/parser.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/core/parser.py b/core/parser.py index 7c71fb4..6ca44e4 100755 --- a/core/parser.py +++ b/core/parser.py @@ -4,7 +4,7 @@ from core.tokens import * from core.nodes import * -from typing import TYPE_CHECKING, Optional, Generic, TypeVar, Callable +from typing import TYPE_CHECKING, Optional, Generic, TypeVar, Callable, TypeAlias from collections.abc import Sequence from dataclasses import dataclass, field @@ -38,7 +38,7 @@ def register_advancement(self) -> None: U = TypeVar("U") - def register(self, res): + def register(self, res: ParseResult[U]) -> Optional[U]: self.last_registered_advance_count = res.advance_count self.advance_count += res.advance_count if res.error: @@ -84,7 +84,7 @@ def __init__(self, tokens: list[Token]) -> None: self.update_current_tok() - def advance(self, res: ParseResult) -> Token: + def advance(self, res: ParseResult[T]) -> Token: self.tok_idx += 1 self.update_current_tok() res.register_advancement() @@ -153,7 +153,7 @@ def statements(self) -> ParseResult[Node]: return res.success(ArrayNode(list_statements, pos_start, self.current_tok.pos_end.copy())) - def statement(self) -> ParseResult[Optional[Node]] | ParseResult[Node]: + def statement(self) -> ParseResult[Node]: res = ParseResult[Node]() pos_start = self.current_tok.pos_start.copy() @@ -334,7 +334,7 @@ def assign_expr(self) -> ParseResult[Node]: self.advance(res) # handle class properties - extra_names = [] + extra_names: list[Token] = [] while self.current_tok.type == TT_DOT: if qualifier is not None: @@ -538,8 +538,8 @@ def call(self) -> ParseResult[Node]: if self.current_tok.type == TT_LPAREN: self.advance(res) - arg_nodes = [] - kwarg_nodes = {} + arg_nodes: list[Node] = [] + kwarg_nodes: dict[str, Node] = {} if self.current_tok.type == TT_RPAREN: self.advance(res) @@ -786,7 +786,7 @@ def assert_expr(self) -> ParseResult[Node]: def array_expr(self) -> ParseResult[Node]: res = ParseResult[Node]() - element_nodes = [] + element_nodes: list[Node] = [] pos_start = self.current_tok.pos_start.copy() if self.current_tok.type != TT_LSQUARE: @@ -961,7 +961,7 @@ def if_expr_b_or_c(self) -> ParseResult[tuple[list[Case], Optional[tuple[Node, b def if_expr_cases(self, case_keyword: str) -> ParseResult[tuple[list[Case], Optional[tuple[Node, bool]]]]: res = ParseResult[tuple[list[Case], Optional[tuple[Node, bool]]]]() - cases = [] + cases: list[tuple[Node, Node, bool]] = [] else_case = None if not self.current_tok.matches(TT_KEYWORD, case_keyword): @@ -1033,6 +1033,10 @@ def for_expr(self) -> ParseResult[Node]: self.advance(res) is_for_in = False + iterable_node = None + start_value = None + end_value = None + step_value = None if self.current_tok.type != TT_EQ and not self.current_tok.matches(TT_KEYWORD, "in"): return res.failure( @@ -1235,7 +1239,7 @@ def func_def(self) -> ParseResult[Node]: ) self.advance(res) - arg_name_toks = [] + arg_name_toks: list[Token] = [] defaults: list[Optional[Node]] = [] has_optionals = False is_va = False @@ -1409,7 +1413,7 @@ def switch_statement(self) -> ParseResult[Node]: self.skip_newlines() - cases = [] + cases: list[tuple[Node, Node]] = [] while self.current_tok.matches(TT_KEYWORD, "case"): self.advance(res) expr = res.register(self.expr()) @@ -1733,6 +1737,9 @@ def set_var(self, name: str, value: Value, qualifier: Optional[str] = None) -> R case "const": self.symbols[name] = value self.consts.add(name) + case _: + # Handle mypy checking only. No other reason. + pass return RTResult[None]().success(None) def set_static(self, name: str, value: Value, qualifier: Optional[str] = None) -> RTResult[None]: From 60599f9ff97b94f6042dad2c2bf2b1e77b16806e Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:06:32 +0600 Subject: [PATCH 03/18] refactor: ruff format --- core/errors.py | 8 +++++--- test.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/errors.py b/core/errors.py index 51cf9fd..4f66e4a 100755 --- a/core/errors.py +++ b/core/errors.py @@ -110,7 +110,9 @@ class RTError(Error): context: Optional[Context] - def __init__(self, pos_start: Position, pos_end: Position, details: Optional[str], context: Optional[Context]) -> None: + def __init__( + self, pos_start: Position, pos_end: Position, details: Optional[str], context: Optional[Context] + ) -> None: super().__init__(pos_start, pos_end, "RuntimeError", details) self.context = context @@ -136,7 +138,7 @@ def generate_radiation(self) -> str: result = ( f" File {Log.light_info(fn)}, line {Log.light_info(str(ln))}, in {Log.light_info(name)}\n" + result ) - pos = ctx.parent_entry_pos # type: ignore + pos = ctx.parent_entry_pos # type: ignore ctx = ctx.parent return Log.light_purple("Radiation (most recent call last):\n") + result @@ -169,6 +171,6 @@ def generate_radiation(self) -> str: class VError(RTError): """Value Error class""" - def __init__(self, pos_start: Position, pos_end: Position, details: str, context: Context,): + def __init__(self, pos_start: Position, pos_end: Position, details: str, context: Context): super().__init__(pos_start, pos_end, "ValueError", context) self.context = context diff --git a/test.py b/test.py index ff3f4b8..0c18ebe 100755 --- a/test.py +++ b/test.py @@ -85,7 +85,7 @@ def run_tests(directory: str = "tests") -> int: return 1 -def record_tests(directory: str ="tests") -> int: +def record_tests(directory: str = "tests") -> int: for test in os.listdir(directory): if not test.endswith(".rn"): continue From 9aba4c56f7112b1603ead44cb78a80c80960efe5 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:09:22 +0600 Subject: [PATCH 04/18] feat: added isort import sorting PEP-8 comfortable. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index c95b9d3..e94d09a 100755 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ help: .PHONY: format format: @ruff format . + @isort . .PHONY: lint lint: From ce2c6babf0957b56d8cd767230304247039c6a8e Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:10:35 +0600 Subject: [PATCH 05/18] refactor: isort import sorting updated. --- core/__init__.py | 2 +- core/builtin_classes/__init__.py | 2 +- core/builtin_classes/base_classes.py | 8 ++++---- core/builtin_classes/file_object.py | 11 ++++++----- core/builtin_classes/json_object.py | 13 +++++++------ core/builtin_classes/requests_object.py | 17 +++++++++-------- core/builtin_classes/string_object.py | 7 ++++--- core/builtin_funcs.py | 13 ++++++------- core/colortools.py | 1 + core/datatypes.py | 14 ++++++++------ core/errors.py | 5 +++-- core/interpreter.py | 13 ++++++------- core/lexer.py | 2 +- core/nodes.py | 5 +++-- core/parser.py | 11 ++++++----- core/tokens.py | 6 ++---- radon.py | 4 ++-- test.py | 10 +++++----- 18 files changed, 75 insertions(+), 69 deletions(-) diff --git a/core/__init__.py b/core/__init__.py index 816b504..8cd340e 100755 --- a/core/__init__.py +++ b/core/__init__.py @@ -5,7 +5,7 @@ Github: @Almas-Ali """ -from core.builtin_funcs import run, global_symbol_table, radonify +from core.builtin_funcs import global_symbol_table, radonify, run __all__ = ["run", "global_symbol_table", "radonify"] __version__ = "0.0.1" diff --git a/core/builtin_classes/__init__.py b/core/builtin_classes/__init__.py index 3a20932..cb868a8 100644 --- a/core/builtin_classes/__init__.py +++ b/core/builtin_classes/__init__.py @@ -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"] diff --git a/core/builtin_classes/base_classes.py b/core/builtin_classes/base_classes.py index 6f895f8..f11fa85 100644 --- a/core/builtin_classes/base_classes.py +++ b/core/builtin_classes/base_classes.py @@ -1,11 +1,11 @@ from __future__ import annotations -from core.errors import * +from typing import Any, Callable + +from core.builtin_funcs import BuiltInFunction, args from core.datatypes import * +from core.errors import * from core.parser import RTResult -from core.builtin_funcs import BuiltInFunction, args - -from typing import Callable, Any class BuiltInClass(BaseClass): diff --git a/core/builtin_classes/file_object.py b/core/builtin_classes/file_object.py index 5fe2512..1fc7838 100644 --- a/core/builtin_classes/file_object.py +++ b/core/builtin_classes/file_object.py @@ -1,10 +1,11 @@ -from core.errors import * +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 * +from core.errors 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 class FileObject(BuiltInObject): diff --git a/core/builtin_classes/json_object.py b/core/builtin_classes/json_object.py index 47f61f1..5a704ef 100644 --- a/core/builtin_classes/json_object.py +++ b/core/builtin_classes/json_object.py @@ -1,11 +1,12 @@ -from core.errors import * +import json + +from core.builtin_classes.base_classes import (BuiltInObject, check, method, + operator) +from core.builtin_funcs import args from core.datatypes import * +from core.datatypes import deradonify, radonify +from core.errors 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 class JSONObject(BuiltInObject): diff --git a/core/builtin_classes/requests_object.py b/core/builtin_classes/requests_object.py index 4c69566..2eab655 100644 --- a/core/builtin_classes/requests_object.py +++ b/core/builtin_classes/requests_object.py @@ -1,13 +1,14 @@ -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 * +from core.datatypes import deradonify, radonify +from core.errors import * +from core.parser import RTResult class RequestsObject(BuiltInObject): diff --git a/core/builtin_classes/string_object.py b/core/builtin_classes/string_object.py index f87c478..446cb62 100644 --- a/core/builtin_classes/string_object.py +++ b/core/builtin_classes/string_object.py @@ -1,8 +1,9 @@ -from core.errors import * +from core.builtin_classes.base_classes import (BuiltInObject, check, method, + operator) +from core.builtin_funcs import args from core.datatypes import * +from core.errors import * from core.parser import RTResult -from core.builtin_funcs import args -from core.builtin_classes.base_classes import BuiltInObject, operator, check, method class StringObject(BuiltInObject): diff --git a/core/builtin_funcs.py b/core/builtin_funcs.py index ec7b3d9..903a7cc 100755 --- a/core/builtin_funcs.py +++ b/core/builtin_funcs.py @@ -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, Optional, ParamSpec, Protocol, cast -from typing import Optional, Callable, Protocol, cast, Generic, ParamSpec +from core.datatypes import * +from core.errors import * +from core.lexer import * +from core.parser import Parser +from core.tokens import * P = ParamSpec("P") diff --git a/core/colortools.py b/core/colortools.py index a2376a8..add48f7 100644 --- a/core/colortools.py +++ b/core/colortools.py @@ -1,4 +1,5 @@ from __future__ import annotations + from enum import Enum diff --git a/core/datatypes.py b/core/datatypes.py index e3bbb26..caae6ac 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -1,13 +1,14 @@ from __future__ import annotations -from core.parser import RTResult, Context, SymbolTable -from core.tokens import Position -from core.errors import RTError, Error - import inspect from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Generator +from typing import Iterator as PyIterator +from typing import Optional, TypeAlias, TypeVar -from typing import TypeVar, Optional, TYPE_CHECKING, Generator, TypeAlias, Iterator as PyIterator +from core.errors import Error, RTError +from core.parser import Context, RTResult, SymbolTable +from core.tokens import Position if TYPE_CHECKING: from core.nodes import Node @@ -922,7 +923,8 @@ def _radonify(value: object) -> Value: case None: return Null.null() case _ if inspect.isfunction(value): - from core.builtin_funcs import BuiltInFunction, args # Lazy import + from core.builtin_funcs import (BuiltInFunction, # Lazy import + args) signature = inspect.signature(value) params = list(signature.parameters.keys()) diff --git a/core/errors.py b/core/errors.py index 4f66e4a..0dbf036 100755 --- a/core/errors.py +++ b/core/errors.py @@ -1,12 +1,13 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Optional, Self from dataclasses import dataclass +from typing import TYPE_CHECKING, Optional, Self + from core.colortools import Log if TYPE_CHECKING: - from core.tokens import Position from core.parser import Context + from core.tokens import Position ####################################### # ERRORS diff --git a/core/interpreter.py b/core/interpreter.py index 0ff645a..e176ffc 100755 --- a/core/interpreter.py +++ b/core/interpreter.py @@ -1,14 +1,13 @@ -from core.errors import * -from core.parser import * -from core.datatypes import * -from core.builtin_funcs import run, create_global_symbol_table -from core.colortools import Log - import os import sys - from typing import NoReturn +from core.builtin_funcs import create_global_symbol_table, run +from core.colortools import Log +from core.datatypes import * +from core.errors import * +from core.parser import * + class Interpreter: def assign( diff --git a/core/lexer.py b/core/lexer.py index 43bcac5..64d2d34 100755 --- a/core/lexer.py +++ b/core/lexer.py @@ -1,5 +1,5 @@ -from core.tokens import * from core.errors import * +from core.tokens import * class Lexer: diff --git a/core/nodes.py b/core/nodes.py index ebb37b3..eb74550 100755 --- a/core/nodes.py +++ b/core/nodes.py @@ -3,10 +3,11 @@ from __future__ import annotations from dataclasses import dataclass -from typing import TYPE_CHECKING, Protocol, Optional, TypeAlias, runtime_checkable +from typing import (TYPE_CHECKING, Optional, Protocol, TypeAlias, + runtime_checkable) if TYPE_CHECKING: - from core.tokens import Token, Position + from core.tokens import Position, Token @runtime_checkable diff --git a/core/parser.py b/core/parser.py index 6ca44e4..12f34c7 100755 --- a/core/parser.py +++ b/core/parser.py @@ -1,12 +1,13 @@ from __future__ import annotations -from core.errors import * -from core.tokens import * -from core.nodes import * - -from typing import TYPE_CHECKING, Optional, Generic, TypeVar, Callable, TypeAlias from collections.abc import Sequence from dataclasses import dataclass, field +from typing import (TYPE_CHECKING, Callable, Generic, Optional, TypeAlias, + TypeVar) + +from core.errors import * +from core.nodes import * +from core.tokens import * if TYPE_CHECKING: from core.datatypes import Value diff --git a/core/tokens.py b/core/tokens.py index b844923..d4dadee 100755 --- a/core/tokens.py +++ b/core/tokens.py @@ -1,11 +1,9 @@ from __future__ import annotations -import string import pathlib - -from typing import Optional, NewType, TypeAlias +import string from dataclasses import dataclass - +from typing import NewType, Optional, TypeAlias # STANDARD LIBRARIES BASE_DIR = pathlib.Path(__file__).parent.parent diff --git a/radon.py b/radon.py index d4f144a..c66cd9b 100755 --- a/radon.py +++ b/radon.py @@ -1,9 +1,9 @@ #!/usr/bin/python3.12 # By: Md. Almas Ali -import sys import os import platform +import sys from typing import IO try: @@ -19,8 +19,8 @@ import core as base_core from core.colortools import Log -from core.parser import Context from core.lexer import Position +from core.parser import Context documentation_link = "https://radon-project.github.io/docs/" diff --git a/test.py b/test.py index 0c18ebe..6f3f10d 100755 --- a/test.py +++ b/test.py @@ -1,12 +1,12 @@ #!/usr/bin/python3.12 -import sys +import json import os import subprocess -import json - -from typing import NamedTuple, IO -from difflib import unified_diff # Rule 34 of Python: If it exists, it's in the standard library +import sys +from difflib import \ + unified_diff # Rule 34 of Python: If it exists, it's in the standard library +from typing import IO, NamedTuple class Output(NamedTuple): From ac3d228ae6bbf537e24c8eecb830558f06e59452 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:11:58 +0600 Subject: [PATCH 06/18] refactor: ruff and isort formatted. --- Makefile | 2 +- core/builtin_classes/file_object.py | 3 +-- core/builtin_classes/json_object.py | 3 +-- core/builtin_classes/requests_object.py | 3 +-- core/builtin_classes/string_object.py | 3 +-- core/datatypes.py | 4 ++-- core/lexer.py | 2 ++ core/nodes.py | 3 +-- core/parser.py | 3 +-- test.py | 3 +-- 10 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index e94d09a..178886e 100755 --- a/Makefile +++ b/Makefile @@ -19,8 +19,8 @@ help: .PHONY: format format: - @ruff format . @isort . + @ruff format . .PHONY: lint lint: diff --git a/core/builtin_classes/file_object.py b/core/builtin_classes/file_object.py index 1fc7838..d15cb8a 100644 --- a/core/builtin_classes/file_object.py +++ b/core/builtin_classes/file_object.py @@ -1,7 +1,6 @@ from typing import IO -from core.builtin_classes.base_classes import (BuiltInObject, check, method, - operator) +from core.builtin_classes.base_classes import BuiltInObject, check, method, operator from core.builtin_funcs import args from core.datatypes import * from core.errors import * diff --git a/core/builtin_classes/json_object.py b/core/builtin_classes/json_object.py index 5a704ef..0e53aa6 100644 --- a/core/builtin_classes/json_object.py +++ b/core/builtin_classes/json_object.py @@ -1,7 +1,6 @@ import json -from core.builtin_classes.base_classes import (BuiltInObject, check, method, - operator) +from core.builtin_classes.base_classes import BuiltInObject, check, method, operator from core.builtin_funcs import args from core.datatypes import * from core.datatypes import deradonify, radonify diff --git a/core/builtin_classes/requests_object.py b/core/builtin_classes/requests_object.py index 2eab655..4cd9d42 100644 --- a/core/builtin_classes/requests_object.py +++ b/core/builtin_classes/requests_object.py @@ -2,8 +2,7 @@ import urllib.parse import urllib.request -from core.builtin_classes.base_classes import (BuiltInObject, check, method, - operator) +from core.builtin_classes.base_classes import BuiltInObject, check, method, operator from core.builtin_funcs import args from core.datatypes import * from core.datatypes import deradonify, radonify diff --git a/core/builtin_classes/string_object.py b/core/builtin_classes/string_object.py index 446cb62..1abbe3a 100644 --- a/core/builtin_classes/string_object.py +++ b/core/builtin_classes/string_object.py @@ -1,5 +1,4 @@ -from core.builtin_classes.base_classes import (BuiltInObject, check, method, - operator) +from core.builtin_classes.base_classes import BuiltInObject, check, method, operator from core.builtin_funcs import args from core.datatypes import * from core.errors import * diff --git a/core/datatypes.py b/core/datatypes.py index caae6ac..6efe3af 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -923,8 +923,8 @@ def _radonify(value: object) -> Value: case None: return Null.null() case _ if inspect.isfunction(value): - from core.builtin_funcs import (BuiltInFunction, # Lazy import - args) + from core.builtin_funcs import BuiltInFunction # Lazy import + from core.builtin_funcs import args signature = inspect.signature(value) params = list(signature.parameters.keys()) diff --git a/core/lexer.py b/core/lexer.py index 64d2d34..8a91605 100755 --- a/core/lexer.py +++ b/core/lexer.py @@ -1,3 +1,5 @@ +from typing import Optional + from core.errors import * from core.tokens import * diff --git a/core/nodes.py b/core/nodes.py index eb74550..9d0b761 100755 --- a/core/nodes.py +++ b/core/nodes.py @@ -3,8 +3,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import (TYPE_CHECKING, Optional, Protocol, TypeAlias, - runtime_checkable) +from typing import TYPE_CHECKING, Optional, Protocol, TypeAlias, runtime_checkable if TYPE_CHECKING: from core.tokens import Position, Token diff --git a/core/parser.py b/core/parser.py index 12f34c7..cbe0551 100755 --- a/core/parser.py +++ b/core/parser.py @@ -2,8 +2,7 @@ from collections.abc import Sequence from dataclasses import dataclass, field -from typing import (TYPE_CHECKING, Callable, Generic, Optional, TypeAlias, - TypeVar) +from typing import TYPE_CHECKING, Callable, Generic, Optional, TypeAlias, TypeVar from core.errors import * from core.nodes import * diff --git a/test.py b/test.py index 6f3f10d..a9fc885 100755 --- a/test.py +++ b/test.py @@ -4,8 +4,7 @@ import os import subprocess import sys -from difflib import \ - unified_diff # Rule 34 of Python: If it exists, it's in the standard library +from difflib import unified_diff # Rule 34 of Python: If it exists, it's in the standard library from typing import IO, NamedTuple From e0e673b5cf6668b4de81247cb61720e5e3bf3157 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:18:57 +0600 Subject: [PATCH 07/18] fixes: removed support for Number and String comparison in Radon. --- core/datatypes.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 6efe3af..5a8936d 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -229,16 +229,12 @@ def modded_by(self, other: Value) -> ResultTuple: def get_comparison_eq(self, other: Value) -> ResultTuple: if isinstance(other, Number): return Boolean(self.value == other.value).set_context(self.context), None - elif isinstance(other, String): - return Boolean(self.value == other.value).set_context(self.context), None else: return None, Value.illegal_operation(self, other) def get_comparison_ne(self, other: Value) -> ResultTuple: if isinstance(other, Number): return Boolean(self.value != other.value).set_context(self.context), None - elif isinstance(other, String): - return Boolean(self.value != other.value).set_context(self.context), None else: return None, Value.illegal_operation(self, other) From bdb455a4b80c0078e8c0e161828dc2269b498797 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:23:51 +0600 Subject: [PATCH 08/18] fixes: removed support for String and Array comparison with Boolean. --- core/datatypes.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 5a8936d..3f229a8 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -334,10 +334,6 @@ def get_comparison_eq(self, other: Value) -> ResultTuple: return Boolean(self.value == other.value).set_context(self.context), None elif isinstance(other, Number): return Boolean(self.value == other.value).set_context(self.context), None - elif isinstance(other, String): - return Boolean(self.value == other.value).set_context(self.context), None - elif isinstance(other, Array): - return Boolean(self.value == other.elements).set_context(self.context), None else: return None, Value.illegal_operation(self, other) @@ -346,10 +342,6 @@ def get_comparison_ne(self, other: Value) -> ResultTuple: return Boolean(self.value != other.value).set_context(self.context), None elif isinstance(other, Number): return Boolean(self.value != other.value).set_context(self.context), None - elif isinstance(other, String): - return Boolean(self.value != other.value).set_context(self.context), None - elif isinstance(other, Array): - return Boolean(self.value != other.elements).set_context(self.context), None else: return None, Value.illegal_operation(self, other) From ac822f615c7f7cd6f48337cc491e079ba9bd0ae9 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:27:43 +0600 Subject: [PATCH 09/18] fixes: reverted Number to String comparison; default selected. --- core/datatypes.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/datatypes.py b/core/datatypes.py index 3f229a8..60927ed 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -229,12 +229,16 @@ def modded_by(self, other: Value) -> ResultTuple: def get_comparison_eq(self, other: Value) -> ResultTuple: if isinstance(other, Number): return Boolean(self.value == other.value).set_context(self.context), None + elif isinstance(other, String): + return Boolean(False).set_context(self.context), None else: return None, Value.illegal_operation(self, other) def get_comparison_ne(self, other: Value) -> ResultTuple: if isinstance(other, Number): return Boolean(self.value != other.value).set_context(self.context), None + elif isinstance(other, String): + return Boolean(True).set_context(self.context), None else: return None, Value.illegal_operation(self, other) @@ -334,6 +338,10 @@ def get_comparison_eq(self, other: Value) -> ResultTuple: return Boolean(self.value == other.value).set_context(self.context), None elif isinstance(other, Number): return Boolean(self.value == other.value).set_context(self.context), None + elif isinstance(other, String): + return Boolean(self.value == other.value).set_context(self.context), None + elif isinstance(other, Array): + return Boolean(self.value == other.elements).set_context(self.context), None else: return None, Value.illegal_operation(self, other) @@ -342,6 +350,10 @@ def get_comparison_ne(self, other: Value) -> ResultTuple: return Boolean(self.value != other.value).set_context(self.context), None elif isinstance(other, Number): return Boolean(self.value != other.value).set_context(self.context), None + elif isinstance(other, String): + return Boolean(self.value != other.value).set_context(self.context), None + elif isinstance(other, Array): + return Boolean(self.value != other.elements).set_context(self.context), None else: return None, Value.illegal_operation(self, other) From f53b9831dca97da82ea00850b412eae66a419445 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:29:48 +0600 Subject: [PATCH 10/18] fixes: reverted Boolean to String and Array comparison; default selected. --- core/datatypes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 60927ed..6da931a 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -339,9 +339,9 @@ def get_comparison_eq(self, other: Value) -> ResultTuple: elif isinstance(other, Number): return Boolean(self.value == other.value).set_context(self.context), None elif isinstance(other, String): - return Boolean(self.value == other.value).set_context(self.context), None + return Boolean(False).set_context(self.context), None elif isinstance(other, Array): - return Boolean(self.value == other.elements).set_context(self.context), None + return Boolean(False).set_context(self.context), None else: return None, Value.illegal_operation(self, other) @@ -351,9 +351,9 @@ def get_comparison_ne(self, other: Value) -> ResultTuple: elif isinstance(other, Number): return Boolean(self.value != other.value).set_context(self.context), None elif isinstance(other, String): - return Boolean(self.value != other.value).set_context(self.context), None + return Boolean(True).set_context(self.context), None elif isinstance(other, Array): - return Boolean(self.value != other.elements).set_context(self.context), None + return Boolean(True).set_context(self.context), None else: return None, Value.illegal_operation(self, other) From afb5c9b1e3802d543316ac92844543eadf97c8e8 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Sun, 21 Jul 2024 20:31:40 +0600 Subject: [PATCH 11/18] fixes: String to Array and Number comparison fixed; default selected. --- core/datatypes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 6da931a..20f239b 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -422,9 +422,9 @@ def get_comparison_eq(self, other: Value) -> ResultTuple: if isinstance(other, String): return Boolean(self.value == other.value).set_context(self.context), None elif isinstance(other, Array): - return Boolean(self.value == other.elements).set_context(self.context), None + return Boolean(False).set_context(self.context), None elif isinstance(other, Number): - return Boolean(self.value == other.value).set_context(self.context), None + return Boolean(False).set_context(self.context), None else: return None, Value.illegal_operation(self, other) @@ -432,9 +432,9 @@ def get_comparison_ne(self, other: Value) -> ResultTuple: if isinstance(other, String): return Boolean(self.value != other.value).set_context(self.context), None elif isinstance(other, Array): - return Boolean(self.value != other.elements).set_context(self.context), None + return Boolean(True).set_context(self.context), None elif isinstance(other, Number): - return Boolean(self.value != other.value).set_context(self.context), None + return Boolean(True).set_context(self.context), None else: return None, Value.illegal_operation(self, other) From 22632226ca9db01da32cfa503eaf1e846fdc7b6e Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Mon, 22 Jul 2024 00:02:41 +0600 Subject: [PATCH 12/18] fixed: mypy --strict core/datatypes.py --- core/datatypes.py | 66 +++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/core/datatypes.py b/core/datatypes.py index 20f239b..62541af 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -2,7 +2,7 @@ import inspect from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Generator +from typing import TYPE_CHECKING, Any, Generator from typing import Iterator as PyIterator from typing import Optional, TypeAlias, TypeVar @@ -103,8 +103,8 @@ def set_index(self, index: Value, value: Value) -> ResultTuple: def execute(self, args: list[Value], kwargs: dict[str, Value]) -> RTResult[Value]: return RTResult[Value]().failure(self.illegal_operation()) - def contains(self, value: Value) -> ResultTuple: - return None, self.illegal_operation(value) + def contains(self, other: Value) -> ResultTuple: + return None, self.illegal_operation(other) def copy(self: Self) -> Self: raise Exception("No copy method defined") @@ -542,10 +542,10 @@ def __help_repr__(self) -> str: def __iter__(self) -> PyIterator[str]: return iter(self.value) - def __getitem__(self, index): + def __getitem__(self, index: int) -> str: return self.value[index] - def __len__(self): + def __len__(self) -> int: return len(self.value) @@ -688,10 +688,10 @@ def set_index(self, index: Value, value: Value) -> ResultTuple: ) return self, None - def contains(self, value: Value) -> ResultTuple: + def contains(self, other: Value) -> ResultTuple: ret: Boolean = Boolean.false() for val in self.elements: - cmp, err = val.get_comparison_eq(value) + cmp, err = val.get_comparison_eq(other) if err is not None: return None, err assert cmp is not None @@ -738,13 +738,13 @@ def __help_repr__(self) -> str: Example: [1,2,3,true,"Hello World!"] """ - def __iter__(self): + def __iter__(self) -> PyIterator[Value]: return iter(self.elements) - def __getitem__(self, index) -> Value: + def __getitem__(self, index: int) -> Value: return self.elements[index] - def __len__(self): + def __len__(self) -> int: return len(self.elements) @@ -790,10 +790,10 @@ def set_index(self, index: Value, value: Value) -> ResultTuple: return self, None - def contains(self, value: Value) -> ResultTuple: + def contains(self, other: Value) -> ResultTuple: ret = Boolean.false() for val in self.values.keys(): - cmp, err = value.get_comparison_eq(String(val)) + cmp, err = other.get_comparison_eq(String(val)) if err: return None, err assert cmp is not None @@ -913,9 +913,11 @@ def _radonify(value: object) -> Value: case False: return Boolean.false() case dict(): - return HashMap({k: radonify(v, pos_start, pos_end, context) for k, v in value.items()}) + _value1: dict[str, Value] = value + return HashMap({k: radonify(v, pos_start, pos_end, context) for k, v in _value1.items()}) case list(): - return Array([radonify(v, pos_start, pos_end, context) for v in value]) + _value2: list[Value] = value + return Array([radonify(v, pos_start, pos_end, context) for v in _value2]) case str(): return String(value) case int() | float(): @@ -930,8 +932,8 @@ def _radonify(value: object) -> Value: params = list(signature.parameters.keys()) @args(params) - def wrapper(ctx): - res = RTResult() + def wrapper(ctx: Context) -> RTResult[Value]: + res = RTResult[Value]() deradonified_params = (deradonify(ctx.symbol_table.get(param)) for param in params) @@ -948,7 +950,7 @@ def wrapper(ctx): return _radonify(value).set_pos(pos_start, pos_end).set_context(context) -def deradonify(value: Value) -> object: +def deradonify(value: Optional[Value]) -> str | dict[str, Any] | int | float | list[object] | object: match value: case PyObj(): return value.value @@ -961,11 +963,10 @@ def deradonify(value: Value) -> object: case Array(): return [deradonify(v) for v in value.elements] case BaseFunction(): - - def ret(*args, **kwargs): + def ret(*args: list[Value], **kwargs: dict[str, Value]) -> object: res = value.execute( [radonify(arg, value.pos_start, value.pos_end, value.context) for arg in args], - {k: radonify(arg) for k, arg in kwargs.items()}, + {k: radonify(arg, value.pos_start, value.pos_end, value.context) for k, arg in kwargs.items()}, ) if res.error: raise RuntimeError(f"Radon exception: {res.error.as_string()}") @@ -1006,7 +1007,7 @@ def pyapi(self, ns: HashMap) -> RTResult[Value]: """TODO: update docs""" try: - locals_dict = deradonify(ns) + locals_dict: dict[str, Any] = deradonify(ns) # type: ignore assert isinstance(locals_dict, dict) # Execute the code and store the output in locals_dict exec(self.code, {}, locals_dict) @@ -1018,7 +1019,7 @@ def pyapi(self, ns: HashMap) -> RTResult[Value]: ns.values[key] = value except Exception as e: - return RTResult().failure( + return RTResult[Value]().failure( RTError( self.pos_start, self.pos_end, @@ -1097,7 +1098,7 @@ def check_args( return res.success(None) - def populate_args(self, arg_names, args, kwargs, defaults, max_pos_args, exec_ctx): + def populate_args(self, arg_names: list[str], args: list[Value], kwargs: dict[str, Value], defaults: list[Optional[Value]], max_pos_args: int, exec_ctx: Context) -> None: for i, (arg_name, default) in enumerate(zip(arg_names, defaults)): if default is not None: exec_ctx.symbol_table.set(arg_name, default) @@ -1113,7 +1114,7 @@ def populate_args(self, arg_names, args, kwargs, defaults, max_pos_args, exec_ct populated += 1 if self.va_name is not None: - va_list = [] + va_list: list[Value] = [] for i in range(populated, len(args)): arg = args[i] arg.set_context(exec_ctx) @@ -1124,8 +1125,8 @@ def populate_args(self, arg_names, args, kwargs, defaults, max_pos_args, exec_ct kwarg.set_context(exec_ctx) exec_ctx.symbol_table.set(kw, kwarg) - def check_and_populate_args(self, arg_names, args, kwargs, defaults, max_pos_args, exec_ctx): - res = RTResult() + def check_and_populate_args(self, arg_names: list[str], args: list[Value], kwargs: dict[str, Value], defaults: list[Optional[Value]], max_pos_args: int, exec_ctx: Context) -> RTResult[None]: + res = RTResult[None]() res.register(self.check_args(arg_names, args, kwargs, defaults, max_pos_args)) if res.should_return(): return res @@ -1134,10 +1135,7 @@ def check_and_populate_args(self, arg_names, args, kwargs, defaults, max_pos_arg class BaseInstance(Value, ABC): - parent_class: BaseClass - symbol_table: SymbolTable - - def __init__(self, parent_class, symbol_table): + def __init__(self, parent_class: BaseClass, symbol_table: Optional[SymbolTable]): super().__init__() self.parent_class = parent_class self.symbol_table = SymbolTable(symbol_table) @@ -1203,8 +1201,8 @@ def execute(self, args: list[Value], kwargs: dict[str, Value]) -> RTResult[Value assert res is not None return RTResult[Value]().success(res) - def contains(self, value: Value) -> ResultTuple: - return self.operator("__contains__", value) + def contains(self, other: Value) -> ResultTuple: + return self.operator("__contains__", other) def is_true(self) -> bool: res, err = self.operator("__truthy__") @@ -1221,9 +1219,9 @@ class Instance(BaseInstance): def __init__(self, parent_class: Class) -> None: super().__init__(parent_class, None) - def __exec_len__(self): + def __exec_len__(self) -> Value | Null: try: - return self.operator("__len__")[0].value + return self.operator("__len__")[0].value # type: ignore except AttributeError: return Null.null() From a9ef18979d665c5cf155ede1f20d2fe58097c4bd Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Tue, 23 Jul 2024 01:58:49 +0600 Subject: [PATCH 13/18] fixed: mypy . --strict checking. --- core/__init__.py | 3 +- core/builtin_classes/base_classes.py | 41 +++++---- core/builtin_classes/file_object.py | 9 +- core/builtin_classes/json_object.py | 7 +- core/builtin_classes/requests_object.py | 7 +- core/builtin_classes/string_object.py | 6 +- core/builtin_funcs.py | 75 +++++++++------- core/datatypes.py | 27 ++++-- core/interpreter.py | 111 ++++++++++++++++++++---- core/lexer.py | 51 ++++++++++- core/parser.py | 90 ++++++++++++++++++- radon.py | 24 +++-- test.py | 5 +- 13 files changed, 357 insertions(+), 99 deletions(-) diff --git a/core/__init__.py b/core/__init__.py index 8cd340e..9228f14 100755 --- a/core/__init__.py +++ b/core/__init__.py @@ -5,7 +5,8 @@ Github: @Almas-Ali """ -from core.builtin_funcs import global_symbol_table, radonify, run +from core.builtin_funcs import global_symbol_table, run +from core.datatypes import radonify __all__ = ["run", "global_symbol_table", "radonify"] __version__ = "0.0.1" diff --git a/core/builtin_classes/base_classes.py b/core/builtin_classes/base_classes.py index f11fa85..5b58d2e 100644 --- a/core/builtin_classes/base_classes.py +++ b/core/builtin_classes/base_classes.py @@ -1,11 +1,11 @@ from __future__ import annotations -from typing import Any, Callable +from typing import Any, Callable, Optional, Sequence, TypeAlias, TypeVar from core.builtin_funcs import BuiltInFunction, args -from core.datatypes import * -from core.errors import * -from core.parser import RTResult +from core.datatypes import BaseClass, BaseFunction, BaseInstance, ResultTuple, Value +from core.errors import RTError +from core.parser import Context, RTResult, SymbolTable class BuiltInClass(BaseClass): @@ -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 @@ -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)) @@ -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 @@ -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}()" @@ -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" diff --git a/core/builtin_classes/file_object.py b/core/builtin_classes/file_object.py index d15cb8a..42c2a26 100644 --- a/core/builtin_classes/file_object.py +++ b/core/builtin_classes/file_object.py @@ -2,9 +2,10 @@ from core.builtin_classes.base_classes import BuiltInObject, check, method, operator from core.builtin_funcs import args -from core.datatypes import * -from core.errors import * -from core.parser import RTResult +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): @@ -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() diff --git a/core/builtin_classes/json_object.py b/core/builtin_classes/json_object.py index 0e53aa6..2240e26 100644 --- a/core/builtin_classes/json_object.py +++ b/core/builtin_classes/json_object.py @@ -2,10 +2,9 @@ from core.builtin_classes.base_classes import BuiltInObject, check, method, operator from core.builtin_funcs import args -from core.datatypes import * -from core.datatypes import deradonify, radonify -from core.errors import * -from core.parser import RTResult +from core.datatypes import Null, String, Value, deradonify, radonify +from core.errors import RTError +from core.parser import Context, RTResult class JSONObject(BuiltInObject): diff --git a/core/builtin_classes/requests_object.py b/core/builtin_classes/requests_object.py index 4cd9d42..e3693b9 100644 --- a/core/builtin_classes/requests_object.py +++ b/core/builtin_classes/requests_object.py @@ -4,10 +4,9 @@ from core.builtin_classes.base_classes import BuiltInObject, check, method, operator from core.builtin_funcs import args -from core.datatypes import * -from core.datatypes import deradonify, radonify -from core.errors import * -from core.parser import RTResult +from core.datatypes import HashMap, Null, String, Value, deradonify, radonify +from core.errors import RTError +from core.parser import Context, RTResult class RequestsObject(BuiltInObject): diff --git a/core/builtin_classes/string_object.py b/core/builtin_classes/string_object.py index 1abbe3a..ba2f384 100644 --- a/core/builtin_classes/string_object.py +++ b/core/builtin_classes/string_object.py @@ -1,8 +1,8 @@ from core.builtin_classes.base_classes import BuiltInObject, check, method, operator from core.builtin_funcs import args -from core.datatypes import * -from core.errors import * -from core.parser import RTResult +from core.datatypes import Array, Boolean, Null, Number, String, Value +from core.errors import RTError +from core.parser import Context, RTResult class StringObject(BuiltInObject): diff --git a/core/builtin_funcs.py b/core/builtin_funcs.py index 903a7cc..8e84e66 100755 --- a/core/builtin_funcs.py +++ b/core/builtin_funcs.py @@ -2,13 +2,13 @@ import os from sys import stdout -from typing import Callable, Generic, Optional, ParamSpec, Protocol, cast +from typing import Callable, Generic, NoReturn, Optional, ParamSpec, Protocol, Sequence, Union, cast -from core.datatypes import * -from core.errors import * -from core.lexer import * -from core.parser import Parser -from core.tokens import * +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") @@ -25,7 +25,7 @@ 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) @@ -33,15 +33,13 @@ def args( 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 @@ -80,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: @@ -104,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]: @@ -266,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) @@ -443,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") @@ -459,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( @@ -535,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 @@ -565,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 @@ -626,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 diff --git a/core/datatypes.py b/core/datatypes.py index 62541af..0da6107 100755 --- a/core/datatypes.py +++ b/core/datatypes.py @@ -550,8 +550,6 @@ def __len__(self) -> int: class Array(Value): - elements: list[Value] - def __init__(self, elements: list[Value]) -> None: super().__init__() self.elements = elements @@ -963,6 +961,7 @@ def deradonify(value: Optional[Value]) -> str | dict[str, Any] | int | float | l case Array(): return [deradonify(v) for v in value.elements] case BaseFunction(): + def ret(*args: list[Value], **kwargs: dict[str, Value]) -> object: res = value.execute( [radonify(arg, value.pos_start, value.pos_end, value.context) for arg in args], @@ -1007,7 +1006,7 @@ def pyapi(self, ns: HashMap) -> RTResult[Value]: """TODO: update docs""" try: - locals_dict: dict[str, Any] = deradonify(ns) # type: ignore + locals_dict: dict[str, Any] = deradonify(ns) # type: ignore assert isinstance(locals_dict, dict) # Execute the code and store the output in locals_dict exec(self.code, {}, locals_dict) @@ -1098,7 +1097,15 @@ def check_args( return res.success(None) - def populate_args(self, arg_names: list[str], args: list[Value], kwargs: dict[str, Value], defaults: list[Optional[Value]], max_pos_args: int, exec_ctx: Context) -> None: + def populate_args( + self, + arg_names: list[str], + args: list[Value], + kwargs: dict[str, Value], + defaults: list[Optional[Value]], + max_pos_args: int, + exec_ctx: Context, + ) -> None: for i, (arg_name, default) in enumerate(zip(arg_names, defaults)): if default is not None: exec_ctx.symbol_table.set(arg_name, default) @@ -1125,7 +1132,15 @@ def populate_args(self, arg_names: list[str], args: list[Value], kwargs: dict[st kwarg.set_context(exec_ctx) exec_ctx.symbol_table.set(kw, kwarg) - def check_and_populate_args(self, arg_names: list[str], args: list[Value], kwargs: dict[str, Value], defaults: list[Optional[Value]], max_pos_args: int, exec_ctx: Context) -> RTResult[None]: + def check_and_populate_args( + self, + arg_names: list[str], + args: list[Value], + kwargs: dict[str, Value], + defaults: list[Optional[Value]], + max_pos_args: int, + exec_ctx: Context, + ) -> RTResult[None]: res = RTResult[None]() res.register(self.check_args(arg_names, args, kwargs, defaults, max_pos_args)) if res.should_return(): @@ -1221,7 +1236,7 @@ def __init__(self, parent_class: Class) -> None: def __exec_len__(self) -> Value | Null: try: - return self.operator("__len__")[0].value # type: ignore + return self.operator("__len__")[0].value # type: ignore except AttributeError: return Null.null() diff --git a/core/interpreter.py b/core/interpreter.py index e176ffc..5a9565e 100755 --- a/core/interpreter.py +++ b/core/interpreter.py @@ -1,12 +1,82 @@ import os import sys -from typing import NoReturn +from typing import Callable, NoReturn, Optional from core.builtin_funcs import create_global_symbol_table, run from core.colortools import Log -from core.datatypes import * -from core.errors import * -from core.parser import * +from core.datatypes import ( + Array, + BaseClass, + BaseFunction, + BaseInstance, + Class, + Function, + HashMap, + Instance, + Module, + Null, + Number, + String, + Value, +) +from core.errors import Error, RTError, TryError +from core.nodes import ( + ArrayNode, + AssertNode, + AttrAccessNode, + BinOpNode, + BreakNode, + CallNode, + ClassNode, + ContinueNode, + DecNode, + FalloutNode, + FallthroughNode, + ForInNode, + ForNode, + FuncDefNode, + HashMapNode, + IfNode, + ImportNode, + IncNode, + IndexGetNode, + IndexSetNode, + Node, + NumberNode, + RaiseNode, + ReturnNode, + SliceGetNode, + StringNode, + SwitchNode, + TryNode, + UnaryOpNode, + UnitRaiseNode, + VarAccessNode, + VarAssignNode, + WhileNode, +) +from core.parser import Context, RTResult, SymbolTable +from core.tokens import ( + BASE_DIR, + STDLIBS, + TT_DIV, + TT_EE, + TT_GT, + TT_GTE, + TT_IDIV, + TT_KEYWORD, + TT_LT, + TT_LTE, + TT_MINUS, + TT_MOD, + TT_MUL, + TT_NE, + TT_PLUS, + TT_POW, + Position, + Token, + TokenValue, +) class Interpreter: @@ -31,6 +101,7 @@ def assign( if nd is None: return res.failure(RTError(pos_start, pos_end, f"'{var_name}' not defined", context)) + name: Optional[TokenValue] = None for index, name_tok in enumerate(extra_names): name = name_tok.value assert isinstance(name, str) @@ -61,7 +132,7 @@ def assign( def call_value(self, value_to_call: Value, node: CallNode, context: Context) -> RTResult[Value]: res = RTResult[Value]() - args = [] + args: list[Value] = [] for arg_node in node.arg_nodes: arg = res.register(self.visit(arg_node, context)) if res.should_return(): @@ -69,7 +140,7 @@ def call_value(self, value_to_call: Value, node: CallNode, context: Context) -> assert arg is not None args.append(arg) - kwargs = {} + kwargs: dict[str, Value] = {} for kw, kwarg_node in node.kwarg_nodes.items(): kwarg = res.register(self.visit(kwarg_node, context)) if res.should_return(): @@ -86,7 +157,7 @@ def call_value(self, value_to_call: Value, node: CallNode, context: Context) -> def visit(self, node: Node, context: Context) -> RTResult[Value]: method_name = f"visit_{type(node).__name__}" - method = getattr(self, method_name, self.no_visit_method) + method: Callable[[Node, Context], NoReturn] = getattr(self, method_name, self.no_visit_method) try: return method(node, context) except Exception as e: @@ -118,7 +189,7 @@ def visit_StringNode(self, node: StringNode, context: Context) -> RTResult[Value def visit_ArrayNode(self, node: ArrayNode, context: Context) -> RTResult[Value]: res = RTResult[Value]() - elements = [] + elements: list[Value] = [] for element_node in node.element_nodes: elt = res.register(self.visit(element_node, context)) @@ -219,10 +290,11 @@ def visit_ImportNode(self, node: ImportNode, context: Context) -> RTResult[Value file_extension = module_name.split("/")[-1].split(".")[-1] if file_extension != "rn": module_name += ".rn" - module_file = module_name.split("/")[-1] + # module_file = module_name.split("/")[-1] module_path = os.path.dirname(os.path.realpath(module_name)) - module_name = os.path.join(context.get_import_cwd(), module_file) + module_name = os.path.join(context.get_import_cwd(), module_name) + # module_name = os.path.join(module_path, module_file) else: # For STDLIB modules module_path = os.path.join(BASE_DIR, "stdlib") @@ -238,6 +310,7 @@ def visit_ImportNode(self, node: ImportNode, context: Context) -> RTResult[Value new_ctx = Context(module_name, context, node.pos_start) new_ctx.symbol_table = symbol_table new_ctx.import_cwd = module_path + # error: Error _, error, should_exit = run(module_name, script, context=new_ctx) if error: @@ -246,7 +319,7 @@ def visit_ImportNode(self, node: ImportNode, context: Context) -> RTResult[Value node.pos_start, node.pos_end, f'{Log.light_error("Failed to finish executing script")} {Log.light_info(module_name)}\n' - + error.as_string(), + + error.as_string(), # type: ignore exec_ctx, ) ) @@ -377,7 +450,7 @@ def visit_IfNode(self, node: IfNode, context: Context) -> RTResult[Value]: def visit_ForNode(self, node: ForNode, context: Context) -> RTResult[Value]: res = RTResult[Value]() - elements = [] + elements: list[Value] = [] start_value = res.register(self.visit(node.start_value_node, context)) if res.should_return(): @@ -422,11 +495,11 @@ def visit_ForNode(self, node: ForNode, context: Context) -> RTResult[Value]: if step_value.value >= 0: - def condition(): + def condition() -> bool: return i < end_value.value else: - def condition(): + def condition() -> bool: return i > end_value.value while condition(): @@ -456,7 +529,7 @@ def condition(): def visit_WhileNode(self, node: WhileNode, context: Context) -> RTResult[Value]: res = RTResult[Value]() - elements = [] + elements: list[Value] = [] while True: condition = res.register(self.visit(node.condition_node, context)) @@ -560,7 +633,7 @@ def visit_ContinueNode(self, node: ContinueNode, context: Context) -> RTResult[V def visit_BreakNode(self, node: BreakNode, context: Context) -> RTResult[Value]: return RTResult[Value]().success_break() - def visit_TryNode(self, node: TryNode, context): + def visit_TryNode(self, node: TryNode, context: Context) -> RTResult[Value]: res = RTResult[Value]() res.register(self.visit(node.try_block, context)) handled_error = res.error @@ -568,7 +641,7 @@ def visit_TryNode(self, node: TryNode, context): return res elif handled_error is not None: var_name = node.exc_iden.value - context.symbol_table.set(var_name, res.error) + context.symbol_table.set(str(var_name), res.error) # type: ignore res.error = None res.register(self.visit(node.catch_block, context)) @@ -595,7 +668,7 @@ def visit_ForInNode(self, node: ForInNode, context: Context) -> RTResult[Value]: assert iterable is not None it = iterable.iter() - elements = [] + elements: list[Value] = [] for it_res in it: element = res.register(it_res) @@ -699,7 +772,7 @@ def visit_IndexSetNode(self, node: IndexSetNode, context: Context) -> RTResult[V def visit_HashMapNode(self, node: HashMapNode, context: Context) -> RTResult[Value]: res = RTResult[Value]() - values = {} + values: dict[str, Value] = {} for key_node, value_node in node.pairs: key = res.register(self.visit(key_node, context)) diff --git a/core/lexer.py b/core/lexer.py index 8a91605..911804a 100755 --- a/core/lexer.py +++ b/core/lexer.py @@ -1,7 +1,54 @@ from typing import Optional -from core.errors import * -from core.tokens import * +from core.errors import Error, ExpectedCharError, IllegalCharError +from core.tokens import ( + DIGITS, + KEYWORDS, + TT_ARROW, + TT_COLON, + TT_COMMA, + TT_DE, + TT_DIV, + TT_DOT, + TT_EE, + TT_EOF, + TT_EQ, + TT_FLOAT, + TT_GT, + TT_GTE, + TT_IDE, + TT_IDENTIFIER, + TT_IDIV, + TT_INT, + TT_KEYWORD, + TT_LBRACE, + TT_LPAREN, + TT_LSQUARE, + TT_LT, + TT_LTE, + TT_MDE, + TT_ME, + TT_MINUS, + TT_MINUS_MINUS, + TT_MOD, + TT_MUL, + TT_NE, + TT_NEWLINE, + TT_PE, + TT_PLUS, + TT_PLUS_PLUS, + TT_POW, + TT_POWE, + TT_RBRACE, + TT_RPAREN, + TT_RSQUARE, + TT_SPREAD, + TT_STRING, + TT_TE, + VALID_IDENTIFIERS, + Position, + Token, +) class Lexer: diff --git a/core/parser.py b/core/parser.py index cbe0551..9d85ce0 100755 --- a/core/parser.py +++ b/core/parser.py @@ -4,9 +4,89 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, Callable, Generic, Optional, TypeAlias, TypeVar -from core.errors import * -from core.nodes import * -from core.tokens import * +from core.errors import Error, InvalidSyntaxError, RTError +from core.nodes import ( + ArrayNode, + AssertNode, + AttrAccessNode, + BinOpNode, + BreakNode, + CallNode, + Case, + ClassNode, + ContinueNode, + DecNode, + FalloutNode, + FallthroughNode, + ForInNode, + ForNode, + FuncDefNode, + HashMapNode, + IfNode, + ImportNode, + IncNode, + IndexGetNode, + IndexSetNode, + Node, + NumberNode, + RaiseNode, + ReturnNode, + SliceGetNode, + StringNode, + SwitchNode, + TryNode, + UnaryOpNode, + UnitRaiseNode, + VarAccessNode, + VarAssignNode, + WhileNode, +) +from core.tokens import ( + TT_ARROW, + TT_COLON, + TT_COMMA, + TT_DE, + TT_DIV, + TT_DOT, + TT_EE, + TT_EOF, + TT_EQ, + TT_FLOAT, + TT_GT, + TT_GTE, + TT_IDE, + TT_IDENTIFIER, + TT_IDIV, + TT_INT, + TT_KEYWORD, + TT_LBRACE, + TT_LPAREN, + TT_LSQUARE, + TT_LT, + TT_LTE, + TT_MDE, + TT_ME, + TT_MINUS, + TT_MINUS_MINUS, + TT_MOD, + TT_MUL, + TT_NE, + TT_NEWLINE, + TT_PE, + TT_PLUS, + TT_PLUS_PLUS, + TT_POW, + TT_POWE, + TT_RBRACE, + TT_RPAREN, + TT_RSQUARE, + TT_SPREAD, + TT_STRING, + TT_TE, + Position, + Token, + TokenType, +) if TYPE_CHECKING: from core.datatypes import Value @@ -1677,6 +1757,10 @@ def __repr__(self) -> str: f"exit={self.should_exit})" ) + # Just to fix mypy issue; Not sure about this implementation right now. + def __iter__(self): ... # type: ignore + def __getitem__(self): ... # type: ignore + class SymbolTable: symbols: dict[str, Value] diff --git a/radon.py b/radon.py index c66cd9b..9c04f0e 100755 --- a/radon.py +++ b/radon.py @@ -4,7 +4,10 @@ import os import platform import sys -from typing import IO +from typing import IO, Optional + +from core.datatypes import Value +from core.errors import Error, RTError try: import readline @@ -19,8 +22,8 @@ import core as base_core from core.colortools import Log -from core.lexer import Position from core.parser import Context +from core.tokens import Position documentation_link = "https://radon-project.github.io/docs/" @@ -56,15 +59,20 @@ def shell() -> None: if brace_count == 0: break - (result, error, should_exit) = base_core.run("", text) + result: list[Optional[Value]] + error: Error | RTError | None + should_exit: Optional[bool] + (result, error, should_exit) = base_core.run("", text, import_cwd=os.getcwd()) # type: ignore if error: print(error.as_string()) else: if result: if len(result) == 1: - result = result[0] - print(repr(result)) + # result = result[0] + print(repr(result[0])) + else: + print(repr(result)) if should_exit: break @@ -141,7 +149,9 @@ def main(argv: list[str]) -> None: print(Log.deep_error(f"[!] FileNotFound: {Log.deep_error(source_file, bold=True)}")) exit(1) - (result, error, should_exit) = base_core.run(source_file, source, import_cwd=head) + error: Error | RTError | None + should_exit: Optional[bool] + (_, error, should_exit) = base_core.run(source_file, source, import_cwd=head) # type: ignore if error: print(error.as_string()) @@ -151,7 +161,7 @@ def main(argv: list[str]) -> None: exit() elif command is not None: - (result, error, should_exit) = base_core.run("", command) + (_, error, should_exit) = base_core.run("", command) # type: ignore if error: print(error.as_string()) diff --git a/test.py b/test.py index a9fc885..43670aa 100755 --- a/test.py +++ b/test.py @@ -36,7 +36,10 @@ def run_test(test: str) -> Output: def run_tests(directory: str = "tests") -> int: mypy = subprocess.Popen( - ["mypy", "."], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=dict(**os.environ, MYPY_FORCE_COLOR="1") + ["mypy", ".", "--strict"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=dict(**os.environ, MYPY_FORCE_COLOR="1"), ) failed_tests: list[str] = [] From b438a013a510d05a72104ab2f72c90c93c79512d Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Tue, 23 Jul 2024 01:59:54 +0600 Subject: [PATCH 14/18] fixes: added isort quite mode enabled. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 178886e..f14cd30 100755 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ help: .PHONY: format format: - @isort . + @isort . --quiet @ruff format . .PHONY: lint From 0f18b724b144e4cecb43d674f5ca4b0c03ec2bf3 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Tue, 23 Jul 2024 02:00:43 +0600 Subject: [PATCH 15/18] docs: just to let you know current Python version we support. --- .python-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .python-version diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..dd6a220 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12.4 \ No newline at end of file From a3622c82e2edd9c8d04dab29c3a6ee484ea4e064 Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Tue, 23 Jul 2024 02:01:18 +0600 Subject: [PATCH 16/18] fixed: removed previous ruff ignore settings. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a5809c5..b3cdef5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,6 @@ flake8-quotes = {inline-quotes = 'single', multiline-quotes = 'double'} isort = { known-first-party = ['core'] } mccabe = { max-complexity = 10 } pydocstyle = { convention = 'google' } -ignore = ["F403", "F405"] [tool.ruff.format] quote-style = 'double' From 94f42df40cdbcc95b768fa9b78ec41eb6b5c0ddb Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Wed, 24 Jul 2024 23:56:04 +0600 Subject: [PATCH 17/18] fixed: github workflow python version to 3.12. --- .github/workflows/ci.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c4fda60..b03ba34 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -5,7 +5,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: python3 -m pip install mypy ruff - - run: python3 test.py full - - + - run: python3.12 -m pip install mypy ruff + - run: python3.12 test.py full From 0dff962777f16351424719e81bc72d8bb405ae6d Mon Sep 17 00:00:00 2001 From: "Md. Almas Ali" Date: Thu, 25 Jul 2024 00:03:01 +0600 Subject: [PATCH 18/18] fixed: github python action issue. --- .github/workflows/ci.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b03ba34..dd6f3eb 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,9 +1,13 @@ name: CI on: [push, pull_request] jobs: - everything: + radon-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: python3.12 -m pip install mypy ruff - - run: python3.12 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