Skip to content

Commit

Permalink
cli/run: updated error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
BitterB0NG0 committed Dec 19, 2024
1 parent 535c1a5 commit 7d5ace0
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 37 deletions.
7 changes: 4 additions & 3 deletions src/demo/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def main():
print('[DEMO] Input file not found.')
exit(1)

file = open('.' + ''.join(args['<inp>'].split('.')[:-1]) + '.outp', 'x')
file.write('MCNP Output! :)')
file.close()
path = ''.join(args['<inp>'].split('.')[:-1]) + '.outp'
with open(path, 'x') as file:
print(path)
file.write('MCNP Output! :)')
78 changes: 78 additions & 0 deletions src/pymcnp/cli/_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""
Contains classes representing errors for CLI.
"""

import enum
from typing import Final


class CliCode(enum.Enum):
"""
Represents ``CliError`` error codes.
Notes:
10X: Value, ``Run``.
"""

INVALID_INP = 100
INVALID_PATH = 101
INVALID_PREHOOK = 102
INVALID_POSTHOOK = 103
INVALID_COMMAND = 104


class CliError(Exception):
"""
Represents cli errors.
PyMCNP raises ``CliError`` while doing things with MCNP.
Attributes:
code: Error code.
info: Error string.
"""

def __init__(self, code: CliCode, info: str):
"""
Initializes ``CliError``
Parameters:
code: Error code.
info: Error string.
"""

self.code: Final[CliCode] = code
self.info: Final[str] = info

def __str__(self) -> str:
"""
Stringifies ``CliError``.
"""

head = ''
hint = ''

match self.code:
case CliCode.INVALID_INP:
head += 'Invalid ``Inp`` object.'
hint += ''
case CliCode.INVALID_PATH:
head += 'Invalid ``pathlib.Path`` object.'
hint += ''
case CliCode.INVALID_PREHOOK:
head += 'Invalid prehook executable.'
hint += 'Prehook executables need ``main`` functions.'
case CliCode.INVALID_POSTHOOK:
head += 'Invalid posthook executable.'
hint += 'Posthook executables need ``main`` functions.'
case CliCode.INVALID_COMMAND:
head += 'Invalid command.'
hint += 'Terminal command not found.'
case _:
head += "I'm working on it! :)"
hint += ''

if hint:
return f'\n\033[31;4;1mCliError[{self.code.name}]\033[0m: {head}\n|\n| {repr(self.info)}\n|\n| \033[35;4mHint\033[0m: {hint}\n|'
else:
return f'\n\033[31;4;1mCliError[{self.code.name}]\033[0m: {head}\n|\n| {repr(self.info)}\n|'
34 changes: 7 additions & 27 deletions src/pymcnp/cli/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,18 @@

import datetime


ERROR_INSUFFICENT_ARGS = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m Insufficent Arguments.'
ERROR_EXCESSIVE_ARGS = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m Excesive Arguments.'
ERROR_UNRECOGNIZED_ARGS = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m Unrecognized Arguments.'
ERROR_UNRECOGNIZED_OPTION = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m Unrecognized Option.'
ERROR_ALIAS_NOT_FOUND = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m INP Alias Not Found.'
ERROR_FILE_NOT_FOUND = '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m File Not Found.'


def ERROR_INP_VALUE(msg: str) -> str:
return '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m INP Syntax Error: ' + msg


def ERROR_INP_SYNTAX(msg: str) -> str:
return '\x1b[1mpymcnp: \x1b[31mERROR:\x1b[0m INP Value Error: ' + msg


INFO_RUNNING_CQEDITOR = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Launching CQ-Editor.'
INFO_RUNNING_MCNP = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Launching MCNP.'
INFO_BUILD_INP = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built INP.'
INFO_BUILD_CELL = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Cell.'
INFO_BUILD_SURFACE = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Surface.'
INFO_BUILD_DATUM = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Datum.'
INFO_BUILD_TITLE = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Title.'
INFO_BUILD_MESSAGE = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Message.'
INFO_BUILD_OTHER = '\x1b[1mpymcnp: \x1b[31m\x1b[34mINFO:\x1b[0m Built Other.'
import rich


def get_timestamp() -> str:
return datetime.datetime.today().strftime('%Y-%m-%d--%H-%M-%S')


def error(msg):
print(msg)
rich.print(msg)
exit(1)


def warning(msg):
rich.print(rich.panel.Panel(msg))
return
50 changes: 43 additions & 7 deletions src/pymcnp/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from docopt import docopt

from . import _io
from . import _errors
from .. import files
from .hooks import default

Expand Down Expand Up @@ -76,13 +77,39 @@ def __init__(
command: Terminal command.
prehook: Prehook module with ``main`` function.
posthook: Posthook module with ``main`` function.
Raises:
CliError: INVALID_INP.
CliError: INVALID_PATH.
CliError: INVALID_PREHOOK.
CliError: INVALID_POSTHOOK.
CliError: INVALID_COMMAND.
"""

if inps is None:
raise _errors.CliError(_errors.CliCode.INVALID_INP, str(inps))

for inp in inps:
if inp is None:
raise _errors.CliError(_errors.CliCode.INVALID_INP, str(inp))

if path is None:
raise _errors.CliError(_errors.CliCode.INVALID_PATH, str(path))

if prehook is None or not hasattr(prehook, 'main'):
raise _errors.CliError(_errors.CliCode.INVALID_PREHOOK, str(prehook))

if posthook is None or not hasattr(posthook, 'main'):
raise _errors.CliError(_errors.CliCode.INVALID_POSTHOOK, str(posthook))

if command is None:
raise _errors.CliError(_errors.CliCode.INVALID_COMMAND, str(command))

if shutil.which(command) is None:
raise ValueError
raise _errors.CliError(_errors.CliCode.INVALID_COMMAND, str(command))

if shutil.which('parallel') is None:
raise ValueError
raise _errors.CliError(_errors.CliCode.INVALID_COMMAND, 'parallel')

# Storing arguments.
self.command = command
Expand All @@ -108,17 +135,18 @@ def run(self, hosts: list[str] = []):

# Creating directories.
self.path_directory.mkdir()

for i, (inp, path_subdirectory) in enumerate(zip(self.inps, self.path_subdirectories)):
path_inp = path_subdirectory / 'inp.i'
path_script = path_subdirectory / 'script.py'
path_prehook = path_subdirectory / 'prehook.py'
path_posthook = path_subdirectory / 'posthook.py'

command = f'{self.command} {path_inp}'

path_subdirectory.mkdir()
inp.to_mcnp_file(path_inp)
path_script.write_text(
EXECUTABLE.format(path=self.path_directory, command=f'{self.command} {path_inp}')
)
path_script.write_text(EXECUTABLE.format(path=self.path_directory, command=command))
shutil.copy(pathlib.Path(self.prehook.__file__), path_prehook)
shutil.copy(pathlib.Path(self.posthook.__file__), path_posthook)

Expand Down Expand Up @@ -149,8 +177,16 @@ def main() -> None:
hosts = args['--hosts'] if args['--hosts'] else []
command = args['--command'] if args['--command'] else 'mcnp6'

inps = [files.inp.Inp.from_mcnp_file(inp) for inp in inps]
try:
inps = [files.inp.Inp.from_mcnp_file(inp) for inp in inps]
except files.utils.errors.McnpError as err:
_io.error(err.__str__())

path = pathlib.Path(os.getcwd())

run = Run(inps, path, command=command)
try:
run = Run(inps, path, command=command)
except _errors.CliError as err:
_io.error(err.__str__())

run.run(hosts)

0 comments on commit 7d5ace0

Please sign in to comment.