From e5bb153b0c8e0dd81fda63d52c013dc94f56142a Mon Sep 17 00:00:00 2001 From: Luis Mondesi Date: Wed, 8 Oct 2025 11:30:51 -0400 Subject: [PATCH] fix: better template --- share/vim/skeleton.py | 141 +++++++++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 30 deletions(-) diff --git a/share/vim/skeleton.py b/share/vim/skeleton.py index 6b829acb..0efcf06f 100644 --- a/share/vim/skeleton.py +++ b/share/vim/skeleton.py @@ -1,38 +1,119 @@ #!/usr/bin/env python3 - -''' -$Revision: 1.0.0 $ -$Date: 2018-08-01 22:35 EDT $ +""" +$Revision: 1.1.0 $ +$Date: 2025-10-08 22:35 EDT $ my_name < email@example.com > -DESCRIPTION: Python 2.7 and above ... -USAGE: skeleton --help -LICENSE: ___ - -Example: python skeleton.py 1 2 --required foo --sum --move paper +DESCRIPTION: + Demo skeleton showing ensure-style thread cleanup: + submit N items, always wait for completion, collect results & errors. -''' +USAGE: + skeleton.py 1 2 --required foo --sum --move paper --workers 8 --fail-prob 0.3 +""" import argparse import sys +import time +import random +import traceback +from concurrent.futures import ThreadPoolExecutor, as_completed + +def parse_args(argv=None): + p = argparse.ArgumentParser(description='description for skeleton program to ...') + p.add_argument('integers', metavar='N', type=int, nargs='+', + help='an integer for the accumulator') + p.add_argument('--sum', dest='accumulate', action='store_const', + const=sum, default=max, + help='sum the integers (default: find the max)') + p.add_argument('--move', choices=['rock', 'paper', 'scissors']) + p.add_argument('--required', required=True) + p.add_argument('--workers', type=int, default=None, + help='max worker threads (default: library chooses)') + p.add_argument('--fail-prob', type=float, default=0.30, + help='probability a task raises (0.0–1.0)') + p.add_argument('--seed', type=int, default=None, help='random seed for reproducibility') + p.add_argument('-v', '--verbose', action='store_true', help='verbose output') + return p.parse_args(argv) + +# --- workload --------------------------------------------------------------- + +def handle(item, fail_prob=0.3): + """Simulate work; sometimes fail.""" + time.sleep(random.uniform(0.05, 0.25)) + if random.random() < fail_prob: + raise RuntimeError(f"boom on {item}") + return f"processed {item}" + +# --- orchestration with ensure-style cleanup -------------------------------- + +def process_all(items, max_workers=None, fail_prob=0.3, verbose=False): + results, errors = [], [] + executor = ThreadPoolExecutor(max_workers=max_workers) + futures = {executor.submit(handle, it, fail_prob): it for it in items} + + try: + for fut in as_completed(futures): + item = futures[fut] + try: + out = fut.result() + results.append(out) + if verbose: + print(f"[ok] {out}") + except Exception as e: + tb = traceback.format_exc() + errors.append((item, e, tb)) + if verbose: + print(f"[err] item={item} err={e}\n{tb}") + finally: + # ensure-style: always join threads and tear down + executor.shutdown(wait=True) + + return results, errors + +# --- main ------------------------------------------------------------------- + +def main(argv=None): + args = parse_args(argv) + if args.seed is not None: + random.seed(args.seed) + + try: + sum_of_items = args.accumulate(args.integers) + items = list(range(sum_of_items)) + results, errors = process_all( + items, + max_workers=args.workers, + fail_prob=args.fail_prob, + verbose=args.verbose + ) + + print("Results:") + for r in results: + print(" ", r) + + print("\nErrors:") + for item, exc, tb in errors: + print(f" item={item} err={exc}") + if args.verbose: + print(tb) + + # Example: do something with --move just to use it + if args.move: + print(f"\nYou played: {args.move}") + + return 0 if not errors else 1 + + except KeyboardInterrupt: + # Still safe: executor is shut down in finally block + print("\nInterrupted by user.", file=sys.stderr) + return 130 + except Exception as e: + # Print a brief message and detailed traceback + print(f"ERROR: {e}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + return 1 + +if __name__ == "__main__": + sys.exit(main()) -parser = argparse.ArgumentParser(description='description for skeleton program to ...') - # ... usage='skeleton [options]') -parser.add_argument('integers', metavar='N', type=int, nargs='+', - help='an integer for the accumulator') -parser.add_argument('--sum', dest='accumulate', action='store_const', - const=sum, default=max, - help='sum the integers (default: find the max)') - -parser.add_argument('--move', choices=['rock', 'paper', 'scissors']) -parser.add_argument('--required', required=True) - -try: - args = parser.parse_args() - print(args.accumulate(args.integers)) -#except BaseException as e: -except Exception as e: - print("ERROR: typical error %s\n" % str(e)) - #print(sys.exc_type) - print(sys.exc_info) - #print(sys.exc_traceback)