Skip to content

Commit

Permalink
wip ruff
Browse files Browse the repository at this point in the history
  • Loading branch information
Napam committed Mar 13, 2024
1 parent a919a84 commit d37f42c
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 42 deletions.
29 changes: 14 additions & 15 deletions meny/casehandlers.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from abc import abstractclassmethod
from typing import Any, Dict, Iterable, List, Optional
from abc import abstractclassmethod, abstractmethod
from typing import Any, Sequence, List
import meny
from meny.exceptions import MenuError
from ast import literal_eval
from inspect import getfullargspec, unwrap
from types import FunctionType
from meny.infos import _error_info_case
from meny.exceptions import MenuError


def _handle_args(func: FunctionType, args: Iterable[str]) -> List:
def _handle_args(func: FunctionType, args: Sequence[str]) -> List:
"""
Handles list of strings that are the arguments using ast.literal_eval.
Expand All @@ -24,28 +23,26 @@ def _handle_args(func: FunctionType, args: Iterable[str]) -> List:
if len(args) > len(params):
raise MenuError(f"Got too many arguments, should be {len(params)}, but got {len(args)}")

typed_arglist = [None] * len(args)
typed_arglist: List[str | None] = [None] * len(args)
i = 0
arg = None
try:
for i, (param, arg) in enumerate(zip(params, args)):
if argsspec.annotations.get(param, None) == str:
typed_arglist[i] = arg
else:
typed_arglist[i] = literal_eval(arg)
except (ValueError, SyntaxError) as e:
raise MenuError(
f"Got arguments: {args}\n" f"But could not evaluate argument at position {i}:\n\t {arg}"
) from e
raise MenuError(f"Got arguments: {args}\n" f"But could not evaluate argument at position {i}:\n\t {arg}") from e
return typed_arglist


def _handle_casefunc(casefunc: FunctionType, args: List[str], menu: meny.Menu) -> Any:
program_args = menu.case_args.get(casefunc, ())
program_kwargs = menu.case_kwargs.get(casefunc, {})
program_args = (menu.case_args or {}).get(casefunc, ())
program_kwargs = (menu.case_kwargs or {}).get(casefunc, {})
if program_args or program_kwargs: # If programmatic arguments
if args:
raise MenuError(
"This function takes arguments progammatically" " and should not be given any arguments"
)
raise MenuError("This function takes arguments progammatically" " and should not be given any arguments")
return casefunc(*program_args, **program_kwargs)
elif args:
# Raises TypeError if wrong number of arguments
Expand All @@ -67,15 +64,17 @@ def __call__(cls, menu: meny.Menu, casefunc: FunctionType, args: List[str]) -> N
finally:
cls.afterCallReturn(menu, casefunc, args)

@abstractclassmethod
@classmethod
@abstractmethod
def onCall(cls, menu: meny.Menu, casefunc: FunctionType, args: List[str]) -> None:
"""
Responsibility:
Call casefunc
Do whatever else to enforce handler behavior (related to unittests)
"""

@abstractclassmethod
@classmethod
@abstractmethod
def afterCallReturn(cls, menu: meny.Menu, casefunc: FunctionType, args: List[str]) -> None:
"""
Responsibility:
Expand Down
16 changes: 10 additions & 6 deletions meny/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import string
import re
import json
import subprocess
import shutil
import platform
import signal
Expand All @@ -31,6 +30,8 @@ def load_module_from_path(path: Path):
sys.path.append(str(Path(path).parent))
loader = importlib.machinery.SourceFileLoader(f"__meny_module_{path.stem}", str(path))
spec = importlib.util.spec_from_loader(loader.name, loader)
if spec is None:
raise ImportError(f"Could not load {path}")
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
sys.path.pop()
Expand Down Expand Up @@ -58,14 +59,14 @@ def menu_from_python_code(filepath: Path, repeat: bool):
class MenyTemplate(string.Template):
default_arg = r"[\w ]*"
delimiter = "@"
pattern = fr"""
pattern = rf"""
@(?:
(?P<escaped>@) | # Escape sequence of two delimiters
(?P<named>\w+) | # delimiter and a Python identifier
{{(?P<braced>\w+=?{default_arg})}} | # delimiter and a braced identifier
(?P<invalid>) # Other ill-formed delimiter exprs
)
"""
""" # type: ignore


def get_casefunc(command: str, executable: str):
Expand Down Expand Up @@ -95,7 +96,6 @@ def get_casefunc(command: str, executable: str):
args = ", ".join(arg_components)

# Remove default argument from command string
template = MenyTemplate(re.sub(fr"@{{(\w+)={MenyTemplate.default_arg}}}", r"@{\1}", command))
if executable is not None:
executable = f"'{executable}'"

Expand Down Expand Up @@ -158,13 +158,17 @@ def cli():
sys.exit(1)

try:
signal.signal(signal.SIGINT, lambda *args, **kwargs: None)
signal.signal(signal.SIGINT, lambda *__args__, **__kwargs__: None)
if filepath.suffix == ".json":
if platform.system() == "Windows":
executable = shutil.which("powershell")
else:
executable = shutil.which("bash")
executable = Path(executable).as_posix() # Need this or will crash in windows due to backslash stuff

if not executable:
executable = "sh"

executable = Path(executable).as_posix() # Need this or will crash in windows due to backslash stuff
returnDict = menu_from_json(filepath, args.repeat, args.executable or executable)
else:
returnDict = menu_from_python_code(filepath, args.repeat)
Expand Down
29 changes: 13 additions & 16 deletions meny/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@
Contains the command line interface (CLI) class, along its factory function:
menu()
"""

from importlib.util import find_spec
from time import sleep
from types import FunctionType, ModuleType
from typing import Any, Callable, Dict, Iterable, List, Optional, Union
from typing import Any, Callable, Dict, Iterable, List, Optional, Union, Sequence

from meny import config as cng
from meny import strings
from meny.funcmap import construct_funcmap
from meny.utils import (
_assert_supported,
_extract_and_preprocess_functions,
_get_module_cases,
extract_and_preprocess_functions,
get_module_cases,
input_splitter,
clear_screen,
)
Expand All @@ -21,7 +23,7 @@
import os


def raise_interrupt(*args, **kwargs) -> None:
def raise_interrupt(*__args__, **__kwargs__) -> None:
"""
Raises keyboard interrupt
"""
Expand Down Expand Up @@ -130,12 +132,8 @@ def __init__(

if frontend == "auto":
self._frontend = _menu_simple
try:
import curses

if find_spec("curses"):
self._frontend = _menu_curses
except ImportError:
pass

elif frontend == "fancy":
self._frontend = _menu_curses
Expand Down Expand Up @@ -236,13 +234,12 @@ def run(self) -> Dict:
Menu._depth -= 1
if Menu._depth == 0:
Menu._return_mode = None
self._case_handler = None

return Menu._return or {}


def build_menu(
cases: Union[Iterable[FunctionType], Dict[str, FunctionType], ModuleType],
cases: Union[Sequence[FunctionType], Dict[str, FunctionType], ModuleType],
title: Optional[str] = None,
*,
case_args: Optional[Dict[FunctionType, tuple]] = None,
Expand All @@ -260,9 +257,9 @@ def build_menu(
Returns Menu object
"""
if isinstance(cases, ModuleType):
cases_to_send = _get_module_cases(cases)
cases_to_send = get_module_cases(cases)
elif isinstance(cases, dict):
cases_to_send = _extract_and_preprocess_functions(cases)
cases_to_send = extract_and_preprocess_functions(cases)
# If this menu is the first menu initialized, and is given the locally
# defined functions, then must filter the functions that are defined
# in __main__
Expand All @@ -271,13 +268,13 @@ def build_menu(
if moduleName == "__main__":
cases_to_send = [case for case in cases_to_send if case.__module__ == "__main__"]

elif isinstance(cases, Iterable):
elif isinstance(cases, Sequence):
# Looks kinda stupid, but it reuses the code, which is nice
cases_to_send = _extract_and_preprocess_functions({case.__name__: case for case in cases})
cases_to_send = extract_and_preprocess_functions({case.__name__: case for case in cases})
else:
raise TypeError(f"Invalid type for cases, got: {type(cases)}")

cases_to_send: Iterable[FunctionType]
cases_to_send: Sequence[FunctionType]

cases_to_send = filter(lambda case: cng._CASE_IGNORE not in vars(case), cases_to_send)

Expand Down
8 changes: 4 additions & 4 deletions meny/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

RE_ANSI = re.compile(r"\x1b\[[;\d]*[A-Za-z]") # Taken from tqdm source code, matches escape codes

RE_INPUT = re.compile("[\w.-]+|\[.*?\]|\{.*?\}|\(.*?\)|\".*?\"|'.*?'")
RE_INPUT = re.compile(r"[\w.-]+|\[.*?\]|\{.*?\}|\(.*?\)|\".*?\"|'.*?'")


def _assert_supported(arg: Any, paramname: str, supported: Container):
Expand All @@ -27,7 +27,7 @@ def _assert_supported(arg: Any, paramname: str, supported: Container):
AssertionError: Got unsupported argument for parameter "animal". Available options are: ('dog', 'rabbit')
"""
assert arg in supported, (
f'Got unsupported argument "'
'Got unsupported argument "'
+ strings.YELLOW
+ str(arg)
+ strings.END
Expand Down Expand Up @@ -74,7 +74,7 @@ def clear_screen() -> None:
os.system(_CLEAR_COMMAND)


def _extract_and_preprocess_functions(dict_: Dict[str, FunctionType]) -> List[FunctionType]:
def extract_and_preprocess_functions(dict_: Dict[str, FunctionType]) -> List[FunctionType]:
"""
Parameters
-------------
Expand Down Expand Up @@ -105,7 +105,7 @@ def input_splitter(argstring: str) -> List[str]:
return RE_INPUT.findall(argstring)


def _get_module_cases(module: ModuleType) -> List[FunctionType]:
def get_module_cases(module: ModuleType) -> List[FunctionType]:
"""Get all functions defined in module"""
def inModule(f):
moduleOfF = getmodule(f)
Expand Down
2 changes: 1 addition & 1 deletion tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def func2():
def func3():
pass

cases = meny.utils._extract_and_preprocess_functions(locals())
cases = meny.utils.extract_and_preprocess_functions(locals())
self.assertListEqual(cases, [linear, quadratic, cubic, func1, func2, func3])

def test_input_splitter(self):
Expand Down

0 comments on commit d37f42c

Please sign in to comment.