diff --git a/src/demo/main.py b/src/demo/main.py index 6566352..ef554c7 100644 --- a/src/demo/main.py +++ b/src/demo/main.py @@ -1,25 +1,19 @@ -import sys - -import docopt - - -DEMO_DOCOPT = """ +""" Usage: demo """ +import docopt + def main(): - args = docopt.docopt(DEMO_DOCOPT) + args = docopt.docopt(__doc__) try: open(args['']) - print(f"[DEMO] Args: {' '.join(sys.argv)}") except FileNotFoundError: - print('[DEMO] Input file not found.') exit(1) path = ''.join(args[''].split('.')[:-1]) + '.outp' with open(path, 'x') as file: - print(path) file.write('MCNP Output! :)') diff --git a/src/pymcnp/cli/_errors.py b/src/pymcnp/cli/_errors.py index 81fa9e6..65c69e2 100644 --- a/src/pymcnp/cli/_errors.py +++ b/src/pymcnp/cli/_errors.py @@ -11,14 +11,15 @@ class CliCode(enum.Enum): Represents ``CliError`` error codes. Notes: - 10X: Value, ``Run``. + 10X: System. + 11X: Value, ``Run``. """ - INVALID_INP = 100 - INVALID_PATH = 101 - INVALID_PREHOOK = 102 - INVALID_POSTHOOK = 103 - INVALID_COMMAND = 104 + INVALID_INP = 110 + INVALID_PATH = 111 + INVALID_PREHOOK = 112 + INVALID_POSTHOOK = 113 + INVALID_COMMAND = 114 class CliError(Exception): @@ -73,6 +74,6 @@ def __str__(self) -> str: 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|' + return f'[red][bold]McnpError[{self.code.name}]:[/][/] {head}\n\n``{self.info[:]}``\n\n[magenta][bold]Hint:[/bold][/magenta] {hint}' else: - return f'\n\033[31;4;1mCliError[{self.code.name}]\033[0m: {head}\n|\n| {repr(self.info)}\n|' + return f'[red][bold]McnpError[{self.code.name}]:[/][/] {head}\n\n``{self.info[:]}``' diff --git a/src/pymcnp/cli/_io.py b/src/pymcnp/cli/_io.py index a1b4f88..b0a6f6b 100644 --- a/src/pymcnp/cli/_io.py +++ b/src/pymcnp/cli/_io.py @@ -5,6 +5,7 @@ import datetime import rich +import rich.panel def get_timestamp() -> str: @@ -12,10 +13,23 @@ def get_timestamp() -> str: def error(msg): - rich.print(msg) + rich.print(rich.panel.Panel(msg)) exit(1) -def warning(msg): +def print(msg): rich.print(rich.panel.Panel(msg)) - return + + +def done(): + rich.print(rich.panel.Panel('[deep_sky_blue1][bold]Info:[/][/] Done!')) + + +def warning(): + rich.print( + rich.panel.Panel( + '[bold][gold3]Warning:[/][/] PyMCNP is just getting started! ' + 'Please, double check the output to make sure everything works. ' + 'If you find errors, please, report them on [link=https://github.com/FSIBT/PyMCNP/issues]GitHub[/link].' + ) + ) diff --git a/src/pymcnp/cli/check.py b/src/pymcnp/cli/check.py index a44895d..bbd9a53 100644 --- a/src/pymcnp/cli/check.py +++ b/src/pymcnp/cli/check.py @@ -1,20 +1,18 @@ """ Usage: - pymcnp check [options] + pymcnp check [options] Options: -f --fix Reformat input file. - -o file --output=file Write to file instead of overwriting the input file. """ -from pathlib import Path -import sys +import pathlib +import difflib from docopt import docopt -from rich import print -from rich.panel import Panel -import pymcnp +from . import _io +from .. import files def main() -> None: @@ -24,42 +22,27 @@ def main() -> None: ``pymcnp check`` checks INP file syntax. """ - args = docopt(__doc__) - - input_file = Path(args['']) - - print( - Panel( - '[orange3]Warning[/] PyMCNP is just getting started.' - 'Please double check the output to make sure everyhing is working as expected' - 'If you find an error, please report it at https://github.com/FSIBT/PyMCNP/issues' - ) - ) + _io.warning() - if not input_file.is_file(): - print(f'[red]ERROR[/] Input file {input_file} does not exists.') - sys.exit(1) + # Processing CLI arguments. + args = docopt(__doc__) + file = pathlib.Path(args['']) + # Reading INP file. try: - data = pymcnp.read_input(input_file) - except: # noqa - print('[red]ERROR[/] Cannot read input file.') - print( - ' We would appreciate if you can report this ' - '(and if possible share the input file) at https://github.com/FSIBT/PyMCNP/issues' - 'Thanks! -- your PyMCNP team' - ) - sys.exit(2) - + inp = files.inp.Inp.from_mcnp_file(file) + except files.utils.errors.McnpError as err: + _io.error(err.__str__()) + except FileNotFoundError: + _io.error(f'[red][bold]IoError:[/][/] ``{file}`` not found.') + + # Running ``diff``! + with open(file, 'r') as file: + diff = difflib.unified_diff(file.readlines(), inp.to_mcnp().split('\n')) + _io.print('\n'.join(line.rstrip('\n') for line in diff)) + + # Handling ``--fix``. if args['--fix']: - output = args['--output'] - if output is None: - print(data.to_mcnp()) - else: - output = Path(output) - if output.is_file(): - print('[orange3]Warning[/] Overwriting existing file.') - data.to_mcnp_file(output) - print(':thumbs_up: Rewrote input file.') - else: - print(f':thumbs_up: Input file {input_file} can be parsed.') + inp.to_mcnp_file(file) + + _io.done() diff --git a/src/pymcnp/cli/convert.py b/src/pymcnp/cli/convert.py index 79be888..1b001c5 100644 --- a/src/pymcnp/cli/convert.py +++ b/src/pymcnp/cli/convert.py @@ -20,9 +20,9 @@ from docopt import docopt from rich import print -from rich.panel import Panel import pymcnp +from . import _io def main() -> None: @@ -32,19 +32,13 @@ def main() -> None: ``pymcnp convert`` converts MCNP output files to pandas dataframes. """ + _io.warning() + args = docopt(__doc__) N = args['--number'] file_in = Path(args['']) - print( - Panel( - '[orange3]Warning[/] PyMCNP is just getting started.' - 'Please double check the output to make sure everyhing is working as expected' - 'If you find an error, please report it at https://github.com/FSIBT/PyMCNP/issues' - ) - ) - if not file_in.is_file(): print(f'[red]Error[/] Cannot access file {file_in}') sys.exit(1) @@ -69,3 +63,5 @@ def main() -> None: print(f'Saving tally {N} as parquet to ', file_out) case _: print('Currently cannot handle this file type') + + _io.done() diff --git a/src/pymcnp/cli/hooks/__init__.py b/src/pymcnp/cli/hooks/__init__.py new file mode 100644 index 0000000..738d953 --- /dev/null +++ b/src/pymcnp/cli/hooks/__init__.py @@ -0,0 +1,9 @@ +from . import nps +from . import clean +from . import empty + +__all__ = [ + 'nps', + 'clean', + 'empty', +] diff --git a/src/pymcnp/cli/hooks/clean.py b/src/pymcnp/cli/hooks/clean.py index 1526f40..b038247 100644 --- a/src/pymcnp/cli/hooks/clean.py +++ b/src/pymcnp/cli/hooks/clean.py @@ -1,3 +1,4 @@ +import shutil import pathlib @@ -5,9 +6,6 @@ def main(path): path = pathlib.Path(path) for file_or_dir in path.rglob('*'): - if file_or_dir.is_file(): - file_or_dir.unlink() - else: - file_or_dir.rmdir() + shutil.rmtree(file_or_dir) path.rmdir() diff --git a/src/pymcnp/cli/hooks/default.py b/src/pymcnp/cli/hooks/empty.py similarity index 100% rename from src/pymcnp/cli/hooks/default.py rename to src/pymcnp/cli/hooks/empty.py diff --git a/src/pymcnp/cli/plot.py b/src/pymcnp/cli/plot.py index dc4c766..d5f7fac 100644 --- a/src/pymcnp/cli/plot.py +++ b/src/pymcnp/cli/plot.py @@ -13,9 +13,9 @@ from docopt import docopt from matplotlib import pyplot as plt from rich import print -from rich.panel import Panel import pymcnp +from . import _io def main() -> None: @@ -25,19 +25,13 @@ def main() -> None: ``pymcnp plot`` plots MCNP output data. """ + _io.warning() + args = docopt(__doc__) N = args['--number'] file_in = Path(args['']) - print( - Panel( - '[orange3]Warning[/] PyMCNP is just getting started.' - 'Please double check the output to make sure everyhing is working as expected' - 'If you find an error, please report it at https://github.com/FSIBT/PyMCNP/issues' - ) - ) - if not file_in.is_file(): print(f'[red]Error[/] Cannot access file {file_in}') sys.exit(1) @@ -78,3 +72,5 @@ def main() -> None: plt.savefig(output_filename) else: plt.show() + + _io.done() diff --git a/src/pymcnp/cli/run.py b/src/pymcnp/cli/run.py index 0b59a59..66eb3e9 100644 --- a/src/pymcnp/cli/run.py +++ b/src/pymcnp/cli/run.py @@ -16,9 +16,9 @@ from docopt import docopt from . import _io +from . import hooks from . import _errors from .. import files -from .hooks import default EXECUTABLE = """ @@ -57,15 +57,17 @@ class Run: path_subdirectories: List of paths to run directories. """ - PREHOOK_PASS = default - POSTHOOK_PASS = default + PREHOOK_EMPTY = hooks.empty + POSTHOOK_EMPTY = hooks.empty + PREHOOK_NPS = hooks.nps + POSTHOOK_CLEAN = hooks.clean def __init__( self, inps: list[files.inp.Inp], path: pathlib.Path, - prehook: ModuleType = PREHOOK_PASS, - posthook: ModuleType = POSTHOOK_PASS, + prehook: ModuleType = PREHOOK_EMPTY, + posthook: ModuleType = POSTHOOK_EMPTY, command: str = 'mcnp6', ): """ @@ -127,7 +129,7 @@ def __init__( def run(self, hosts: list[str] = []): """ - Runs MCNP INP files. + Runs MCNP INP pymcnp. Parameters: hosts: List of hostnames on which to execute. @@ -168,25 +170,35 @@ def main() -> None: """ Executes the ``pymcnp run`` command. - ``pymcnp run`` runs INP files. + ``pymcnp run`` runs INP pymcnp. """ - args = docopt(__doc__) + _io.warning() + # Processing CLI arguments. + args = docopt(__doc__) inps = args[''] hosts = args['--hosts'] if args['--hosts'] else [] command = args['--command'] if args['--command'] else 'mcnp6' + # Reading INP files. try: inps = [files.inp.Inp.from_mcnp_file(inp) for inp in inps] except files.utils.errors.McnpError as err: _io.error(err.__str__()) + except FileNotFoundError: + _io.error(f'[red][bold]IoError:[/][/] {inps} File not found.') - path = pathlib.Path(os.getcwd()) - + # Running! try: - run = Run(inps, path, command=command) + Run( + inps, + pathlib.Path(os.getcwd()), + prehook=Run.PREHOOK_EMPTY, + posthook=Run.POSTHOOK_CLEAN, + command=command, + ).run(hosts) except _errors.CliError as err: _io.error(err.__str__()) - run.run(hosts) + _io.done() diff --git a/src/pymcnp/cli/visualize.py b/src/pymcnp/cli/visualize.py index 2ab0f15..7f57bdc 100644 --- a/src/pymcnp/cli/visualize.py +++ b/src/pymcnp/cli/visualize.py @@ -5,6 +5,9 @@ from docopt import docopt +from . import _io +from .. import files + def main() -> None: """ @@ -13,5 +16,22 @@ def main() -> None: ``pymcnp visualize`` visualizes INP files using PyVISTA. """ + _io.warning() + + # Processing CLI arguments. args = docopt(__doc__) - print(args) + inp = args[''] + + # Reading INP file(s). + try: + inp = files.inp.Inp.from_mcnp_file(inp) + except files.utils.errors.McnpError as err: + _io.error(err.__str__()) + except FileNotFoundError: + _io.error(f'[red][bold]IoError:[/][/] ``{inp}`` not found.') + + # Visualizing! + data = inp.to_pyvista() + data.plot() + + _io.done() diff --git a/src/pymcnp/files/utils/errors.py b/src/pymcnp/files/utils/errors.py index 39dff0d..393f0c9 100644 --- a/src/pymcnp/files/utils/errors.py +++ b/src/pymcnp/files/utils/errors.py @@ -257,6 +257,6 @@ def __str__(self) -> str: hint += '' if hint: - return f'\n\033[31;4;1mMcnpError[{self.code.name}]\033[0m: {head}\n|\n| {repr(self.info)}\n|\n| \033[35;4mHint\033[0m: {hint}\n|' + return f'[red][bold]McnpError[{self.code.name}]:[/][/] {head}\n\n``{self.info[:]}``\n\n[bold][magenta]Hint:[/][/] {hint}' else: - return f'\n\033[31;4;1mMcnpError[{self.code.name}]\033[0m: {head}\n|\n| {repr(self.info)}\n|' + return f'[red][bold]McnpError[{self.code.name}]:[/][/] {head}\n\n``{self.info[:]}``'