initial commit

This commit is contained in:
Bacruru Sakaguchi
2025-09-12 17:10:13 +07:00
commit 9e5e214944
57 changed files with 1538 additions and 0 deletions

85
shell/Handlers/ABS.py Normal file
View File

@@ -0,0 +1,85 @@
from pathlib import Path
from modelspace.Repository import Repository
global_repo = Repository(str(Path('..') / 'repo'))
class ExecutionError(RuntimeError): pass
class Handler:
syntax_error = SyntaxError
execution_error = ExecutionError
def __init__(self):
self.forwarding_table: dict[str, Handler] = {}
self.handle_table: dict = {}
self.succeed = False
pass
@staticmethod
def _check_arg(keys: dict, arg: str):
if not keys.get(arg, None): raise TypeError('Unfilled argument:', arg)
def handle(self, command: list[str], pos = 0):
self.succeed = False
if len(command) <= pos: raise self.syntax_error
verb = command[pos].lower()
if verb in self.forwarding_table:
self.forwarding_table[verb].handle(command, pos + 1)
if self.forwarding_table[verb].succeed:
self.succeed = True
return
elif verb in self.handle_table:
self.handle_table[verb](command, pos + 1)
if self.succeed:
return
@staticmethod
def parse_arguments(args_list: list[str], expected_args: list[str], key_mode=False) -> tuple[dict[str, str | None], list[str]]:
"""
Парсит список аргументов согласно ожидаемым именам.
Args:
args_list: список аргументов для обработки
expected_args: список ожидаемых имен аргументов
Returns:
Кортеж из двух элементов:
- Словарь с ключами из expected_args и значениями аргументов (или None)
- Список необработанных аргументов
"""
# Инициализируем результат значениями None для всех ожидаемых аргументов
result: dict[str, str | None] = {arg: None for arg in expected_args}
# Извлекаем именованные аргументы (в формате "имя:значение")
remaining_args = []
for arg in args_list:
if ':' in arg:
key, value = arg.split(':', 1)
if key in expected_args:
result[key] = value
else:
# Если имя аргумента не ожидается, добавляем в оставшиеся
remaining_args.append(arg)
else:
remaining_args.append(arg)
# Заполняем оставшиеся аргументы по порядку
arg_index = 0
if not key_mode:
for arg_name in expected_args:
if result[arg_name] is None and arg_index < len(remaining_args):
result[arg_name] = remaining_args[arg_index]
arg_index += 1
# Все оставшиеся аргументы добавляем в unsorted
unsorted = remaining_args[arg_index:]
return result, unsorted

View File

@@ -0,0 +1,27 @@
from shell.Handlers.ABS import Handler
from shell.Handlers.PythonappHandler import PythonappHandler
from shell.Handlers.ModelSpaceHandler import ModelSpaceHandler
class GlobalHandler(Handler):
def __init__(self):
super().__init__()
self.forwarding_table: dict[str, Handler] = {
'pythonapp': PythonappHandler(),
'modelspace': ModelSpaceHandler(),
}
self.handle_table: dict = {
'tell': self._tell
}
def _tell(self, command: list[str], pos = 0):
command_str = ''
for word in command[pos:]: command_str += word + ' '
print(command_str)
self.succeed = True
def _exit(self, command: list[str], pos = 0):
raise KeyboardInterrupt

View File

@@ -0,0 +1,18 @@
from shell.Handlers.ABS import Handler, global_repo
class ModelSpaceHandler(Handler):
def __init__(self):
super().__init__()
self.forwarding_table: dict[str, Handler] = {
}
self.handle_table: dict = {
'create_inter': self._create_inter
}
pass
def _create_inter(self, command: list[str], pos=0):
global_repo.add_model_package_interactive()
self.succeed = True

View File

@@ -0,0 +1,88 @@
from shell.Handlers.ABS import Handler
from pythonapp.Instance.Instance import Instance
class PythonappHandler(Handler):
def __init__(self):
super().__init__()
self.forwarding_table: dict[str, Handler] = {
'package': PackageHandler(self)
}
self.handle_table: dict = {
'create': self._create,
'load': self._load,
'show': self._show,
'activate': self._activate,
}
self._loaded_instances: dict[str, Instance] = {}
self._active_instance: Instance | None = None
def _load(self, command: list[str], pos = 0):
keys, args = self.parse_arguments(command[pos:], ['path', 'name'])
self._check_arg(keys, 'path')
if not keys['name']: keys['name'] = 'app'
i = Instance(path=str(keys['path']))
if not i.config.created: raise self.execution_error("ACTIVATE INSTANCE: instance not exists")
self._loaded_instances[keys['name']] = i
self._active_instance = i
print(f"instance {keys['path']} loaded and activated. identified by {keys['name']}")
def _activate(self, command: list[str], pos = 0):
keys, args = self.parse_arguments(command[pos:], ['name'])
self._check_arg(keys, 'name')
i = self._loaded_instances.get(command[1], None)
if i:
self._active_instance = i
else:
raise ValueError(f"pyapp {keys['name']} not loaded")
def _show(self, command: list[str], pos = 0):
print("Environment type:", self._active_instance.config.env_type)
# TODO Add new config info (app section)
def _create(self, command: list[str], pos = 0):
keys, args = self.parse_arguments(command[pos:], ['env', 'path', 'python'])
self.succeed = True
pass
@property
def active_instance(self):
return self._active_instance
class PackageHandler(Handler):
def __init__(self,parent: PythonappHandler):
super().__init__()
self.forwarding_table: dict[str, Handler] = {}
self.handle_table: dict = {
'install': self._install,
'exclude': self._exclude
}
self.parent = parent
def _install(self, command: list[str], pos = 0):
if not self.parent.active_instance: raise self.execution_error("I don't have active instance yet!")
keys, args = self.parse_arguments(command[pos:], ['pin', 'index', 'extra'], key_mode=True)
if keys['pin']: pin = True
else: pin = False
self.parent.active_instance.install_packages(pkgs=args, repo=keys.get('index', None), extra=keys.get('extra', None), pin=pin)
def _exclude(self, command: list[str], pos = 0):
if not self.parent.active_instance: raise self.execution_error("I don't have active instance yet!")
pkgs = command[pos:]
self.parent.active_instance.exclude_packages(pkgs)
self.succeed = True

View File

Binary file not shown.

Binary file not shown.