From 6ff2f6f3f920fb251026713bf1ce972e66cbf7ed Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Thu, 16 Nov 2023 11:52:28 -0500 Subject: [PATCH 1/5] In Python, delete the temporary file by default --- src/python/code/gnoll/__init__.py | 79 +++++++++++++++++-------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/src/python/code/gnoll/__init__.py b/src/python/code/gnoll/__init__.py index 99ae23ccb..a8f4cdcc0 100644 --- a/src/python/code/gnoll/__init__.py +++ b/src/python/code/gnoll/__init__.py @@ -48,20 +48,18 @@ def roll(s, mock=None, mock_const=3, breakdown=False, - builtins=False): + builtins=False, + keep_temp_file=False): """Parse some dice notation with GNOLL. @param s the string to parse @param verbose whether to enable verbosity (primarily for debug) @param mock override the internal random number generator (for testing). @param mock_const the seed value for overriding with mocks @param breakdown get the details of each dice rolled, not just the final result + @param keep_temp_file don't delete the temporary file @param force_dll_reload destroy the dll/shared object and reload (inadvisable) @return return code, final result, dice breakdown (None if disabled) """ - temp = tempfile.NamedTemporaryFile(prefix="gnoll_roll_", - suffix=".die", - delete=False) - def make_native_type(v): """ Change a string to a more appropriate type if possible. @@ -87,36 +85,47 @@ def extract_from_dice_file(lines, seperator): v = [list(map(make_native_type, x)) for x in v] return v - die_file = temp.name - os.remove(die_file) - - out_file = str(die_file).encode("ascii") - if verbose: - print("Rolling: ", s) - print("Output in:", out_file) - - s = s.encode("ascii") - - return_code = libc.roll_full_options( - s, - out_file, - verbose, # enable_verbose - breakdown, # enable_introspect - mock is not None, # enable_mock - builtins, # enable_builtins - mock, - mock_const, - ) - if return_code != 0: - raise_gnoll_error(return_code) - - with open(out_file, encoding="utf-8") as f: - lines = f.readlines() - - dice_breakdown = extract_from_dice_file(lines, ",") - result = extract_from_dice_file(lines, ";") - - return int(return_code), result, dice_breakdown + try: + temp = tempfile.NamedTemporaryFile(prefix="gnoll_roll_", + suffix=".die", + delete=False) + temp.close() + + die_file = temp.name + + out_file = str(die_file).encode("ascii") + if verbose: + print("Rolling: ", s) + print("Output in:", out_file) + + s = s.encode("ascii") + + return_code = libc.roll_full_options( + s, + out_file, + verbose, # enable_verbose + breakdown, # enable_introspect + mock is not None, # enable_mock + builtins, # enable_builtins + mock, + mock_const, + ) + if return_code != 0: + raise_gnoll_error(return_code) + + with open(out_file, encoding="utf-8") as f: + lines = f.readlines() + + dice_breakdown = extract_from_dice_file(lines, ",") + result = extract_from_dice_file(lines, ";") + + return int(return_code), result, dice_breakdown + + finally: + if not keep_temp_file: + if verbose: + print("Deleting:", out_file) + os.remove(die_file) if __name__ == "__main__": From f6934bba66674db84dfbb98fa4be729e476b4517 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Thu, 16 Nov 2023 12:07:03 -0500 Subject: [PATCH 2/5] Add a Python command-line interface --- README.md | 9 ++++++ src/python/code/gnoll/__main__.py | 48 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/python/code/gnoll/__main__.py diff --git a/README.md b/README.md index e3e3583db..98f96fbab 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,15 @@ roll("1d20") # (return code, final result, dice breakdown (if enabled)) ``` +Or, use the command-line interface (see `--help`): +```sh +$ python3 -m gnoll 2d4 +6 +$ function gnoll() { python3 -m gnoll --breakdown "$@" ; } +$ gnoll 3d6 + 10 +[5, 5, 4] --> 24 +``` + ### 🛠️ Installing From Source #### Basic Requirements ```bash diff --git a/src/python/code/gnoll/__main__.py b/src/python/code/gnoll/__main__.py new file mode 100644 index 000000000..00027f46e --- /dev/null +++ b/src/python/code/gnoll/__main__.py @@ -0,0 +1,48 @@ +'''Roll some dice with GNOLL.''' + +import sys, argparse, gnoll + +def parse_cmdline_args(args): + p = argparse.ArgumentParser( + description = __doc__, + usage = 'python3 -m gnoll [options] EXPR', + add_help = False) + + p.add_argument('EXPR', nargs = '+', + help = 'a dice expression to evaluate ' + '(multiple arguments will be joined with spaces)') + + g = p.add_argument_group('main options') + g.add_argument('-h', '--help', action = 'help', + help = 'show this help message and exit') + g.add_argument('-b', '--breakdown', action = 'store_true', + help = 'show a breakdown into individual dice') + g.add_argument('--no-builtins', action = 'store_true', + help = 'disable built-in macros') + + g = p.add_argument_group('debugging options') + g.add_argument('-v', '--verbose', action = 'store_true', + help = 'enable verbosity') + g.add_argument('--keep-temp-file', action = 'store_true', + help = "don't delete the created temporary file") + g.add_argument('--mock', metavar = 'TYPE', type = int, + help = 'mocking type') + g.add_argument('--mock-const', metavar = 'N', type = int, default = 3, + help = 'mocking constant') + + a = p.parse_args(args) + a.EXPR = ' '.join(a.EXPR) + return a + +def main(EXPR, no_builtins, **kwargs): + _, [[result]], breakdown = gnoll.roll( + EXPR, + builtins = not no_builtins, + **kwargs) + if breakdown: + print(breakdown[0], '-->', result) + else: + print(result) + +if __name__ == '__main__': + main(**vars(parse_cmdline_args(sys.argv[1:]))) From 884b22c0fc713ac6152ab1c9a1fef2dbd99ee237 Mon Sep 17 00:00:00 2001 From: Ian Hunter Date: Fri, 17 Nov 2023 11:43:09 +0000 Subject: [PATCH 3/5] Apply style fixes Signed-off-by: Ian Hunter --- src/python/code/gnoll/__init__.py | 3 +- src/python/code/gnoll/__main__.py | 62 ++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/python/code/gnoll/__init__.py b/src/python/code/gnoll/__init__.py index a8f4cdcc0..16afc4f91 100644 --- a/src/python/code/gnoll/__init__.py +++ b/src/python/code/gnoll/__init__.py @@ -124,7 +124,8 @@ def extract_from_dice_file(lines, seperator): finally: if not keep_temp_file: if verbose: - print("Deleting:", out_file) + print("Deleting:", out_file) + os.remove(die_file) diff --git a/src/python/code/gnoll/__main__.py b/src/python/code/gnoll/__main__.py index 00027f46e..84fbec94b 100644 --- a/src/python/code/gnoll/__main__.py +++ b/src/python/code/gnoll/__main__.py @@ -1,40 +1,57 @@ -'''Roll some dice with GNOLL.''' +"""Roll some dice with GNOLL.""" + +import sys +import argparse +import gnoll -import sys, argparse, gnoll def parse_cmdline_args(args): + """Extract values from the commandline + @param args - the arguments from the commandline (excluding the python3 call) + """ p = argparse.ArgumentParser( - description = __doc__, - usage = 'python3 -m gnoll [options] EXPR', - add_help = False) + description=__doc__, + usage='python3 -m gnoll [options] EXPR', + add_help=False) + - p.add_argument('EXPR', nargs = '+', - help = 'a dice expression to evaluate ' - '(multiple arguments will be joined with spaces)') + p.add_argument( + 'EXPR', + nargs='+', + help='a dice expression to evaluate (multiple arguments will be joined with spaces)' + ) g = p.add_argument_group('main options') - g.add_argument('-h', '--help', action = 'help', - help = 'show this help message and exit') - g.add_argument('-b', '--breakdown', action = 'store_true', - help = 'show a breakdown into individual dice') - g.add_argument('--no-builtins', action = 'store_true', - help = 'disable built-in macros') + g.add_argument('-h', '--help', action='help', + help='show this help message and exit') + g.add_argument('-b', '--breakdown', action='store_true', + help='show a breakdown into individual dice') + g.add_argument('--no-builtins', action='store_true', + help='disable built-in macros') g = p.add_argument_group('debugging options') - g.add_argument('-v', '--verbose', action = 'store_true', - help = 'enable verbosity') - g.add_argument('--keep-temp-file', action = 'store_true', - help = "don't delete the created temporary file") - g.add_argument('--mock', metavar = 'TYPE', type = int, - help = 'mocking type') - g.add_argument('--mock-const', metavar = 'N', type = int, default = 3, - help = 'mocking constant') + g.add_argument('-v', '--verbose', action='store_true', + help='enable verbosity') + g.add_argument('--keep-temp-file', action='store_true', + help="don't delete the created temporary file") + g.add_argument('--mock', metavar='TYPE', type=int, + help='mocking type') + g.add_argument('--mock-const', metavar='N', type=int, default=3, + help='mocking constant') + a = p.parse_args(args) a.EXPR = ' '.join(a.EXPR) return a + def main(EXPR, no_builtins, **kwargs): + """ + The entry point for gnoll when called via `python -m gnoll` + @param EXPR - the expression + @param no_builtins - a flag to disable builtins + @param **kwargs - other key word arguments to be passed to gnoll.roll + """ _, [[result]], breakdown = gnoll.roll( EXPR, builtins = not no_builtins, @@ -44,5 +61,6 @@ def main(EXPR, no_builtins, **kwargs): else: print(result) + if __name__ == '__main__': main(**vars(parse_cmdline_args(sys.argv[1:]))) From 5875f39fca7459ee961a84aed09ba763e6688ced Mon Sep 17 00:00:00 2001 From: Ian Hunter Date: Fri, 17 Nov 2023 11:51:38 +0000 Subject: [PATCH 4/5] more style fixes --- src/python/code/gnoll/__main__.py | 64 ++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/src/python/code/gnoll/__main__.py b/src/python/code/gnoll/__main__.py index 84fbec94b..1182ef084 100644 --- a/src/python/code/gnoll/__main__.py +++ b/src/python/code/gnoll/__main__.py @@ -14,31 +14,57 @@ def parse_cmdline_args(args): usage='python3 -m gnoll [options] EXPR', add_help=False) - p.add_argument( - 'EXPR', + 'EXPR', nargs='+', - help='a dice expression to evaluate (multiple arguments will be joined with spaces)' + help='a dice expression to evaluate' + '(multiple arguments will be joined with spaces)' ) g = p.add_argument_group('main options') - g.add_argument('-h', '--help', action='help', - help='show this help message and exit') - g.add_argument('-b', '--breakdown', action='store_true', - help='show a breakdown into individual dice') - g.add_argument('--no-builtins', action='store_true', - help='disable built-in macros') + g.add_argument( + '-h', + '--help', + action='help', + help='show this help message and exit' + ) + g.add_argument( + '-b', + '--breakdown', + action='store_true', + help='show a breakdown into individual dice' + ) + g.add_argument( + '--no-builtins', + action='store_true', + help='disable built-in macros' + ) g = p.add_argument_group('debugging options') - g.add_argument('-v', '--verbose', action='store_true', - help='enable verbosity') - g.add_argument('--keep-temp-file', action='store_true', - help="don't delete the created temporary file") - g.add_argument('--mock', metavar='TYPE', type=int, - help='mocking type') - g.add_argument('--mock-const', metavar='N', type=int, default=3, - help='mocking constant') - + g.add_argument( + '-v', + '--verbose', + action='store_true', + help='enable verbosity' + ) + g.add_argument( + '--keep-temp-file', + action='store_true', + help="don't delete the created temporary file" + ) + g.add_argument( + '--mock', + metavar='TYPE', + type=int, + help='mocking type' + ) + g.add_argument( + '--mock-const', + metavar='N', + type=int, + default=3, + help='mocking constant' + ) a = p.parse_args(args) a.EXPR = ' '.join(a.EXPR) @@ -54,7 +80,7 @@ def main(EXPR, no_builtins, **kwargs): """ _, [[result]], breakdown = gnoll.roll( EXPR, - builtins = not no_builtins, + builtins=not no_builtins, **kwargs) if breakdown: print(breakdown[0], '-->', result) From b5f9d3559856a25c16e573eab2b04318fdda5bf6 Mon Sep 17 00:00:00 2001 From: Ian Hunter Date: Fri, 17 Nov 2023 11:56:41 +0000 Subject: [PATCH 5/5] fix trailing whitespace --- src/python/code/gnoll/__main__.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/python/code/gnoll/__main__.py b/src/python/code/gnoll/__main__.py index 1182ef084..3f3e83e4a 100644 --- a/src/python/code/gnoll/__main__.py +++ b/src/python/code/gnoll/__main__.py @@ -18,13 +18,13 @@ def parse_cmdline_args(args): 'EXPR', nargs='+', help='a dice expression to evaluate' - '(multiple arguments will be joined with spaces)' + '(multiple arguments will be joined with spaces)' ) g = p.add_argument_group('main options') g.add_argument( - '-h', - '--help', + '-h', + '--help', action='help', help='show this help message and exit' ) @@ -42,26 +42,26 @@ def parse_cmdline_args(args): g = p.add_argument_group('debugging options') g.add_argument( - '-v', - '--verbose', + '-v', + '--verbose', action='store_true', help='enable verbosity' ) g.add_argument( - '--keep-temp-file', + '--keep-temp-file', action='store_true', help="don't delete the created temporary file" ) g.add_argument( - '--mock', - metavar='TYPE', + '--mock', + metavar='TYPE', type=int, help='mocking type' ) g.add_argument( - '--mock-const', - metavar='N', - type=int, + '--mock-const', + metavar='N', + type=int, default=3, help='mocking constant' )