wvpy.pysheet

View Source
# run with:
#    python -m wvpy.pysheet test.py
#    python -m wvpy.pysheet test.ipynb

import argparse
import os
import shutil
import sys
import traceback
from wvpy.jtools import convert_py_file_to_notebook, convert_notebook_file_to_py


def main() -> int:
    parser = argparse.ArgumentParser(description="Convert between .py and .ipynb or back (can have suffix, or guess suffix)")
    parser.add_argument('--quiet', action='store_true', help='delete input file')
    parser.add_argument('--delete', action='store_true', help='delete input file')
    parser.add_argument(
        'infile', 
        metavar='infile', 
        type=str, 
        nargs='+',
        help='name of input file(s)')
    args = parser.parse_args()
    # some pre-checks
    assert len(args.infile) > 0
    assert len(set(args.infile)) == len(args.infile)
    assert isinstance(args.quiet, bool)
    assert isinstance(args.delete, bool)
    # set up the work request
    base_names_seen = set()
    input_suffices_seen = set()
    tasks = []
    other_suffix = {'.py': '.ipynb', '.ipynb': '.py'}
    for input_file_name in args.infile:
        assert isinstance(input_file_name, str)
        assert len(input_file_name) > 0
        suffix_seen = 'error'  # placeholder/sentinel
        base_name = input_file_name
        if input_file_name.endswith('.py'):
            suffix_seen = '.py'
            base_name = input_file_name.removesuffix(suffix_seen)
        elif input_file_name.endswith('.ipynb'):
            suffix_seen = '.ipynb'
            base_name = input_file_name.removesuffix(suffix_seen)
        else:
            py_exists = os.path.exists(input_file_name + '.py')
            ipynb_exists = os.path.exists(input_file_name + '.ipynb')
            if py_exists == ipynb_exists:
                raise ValueError(f'{base_name}: if no suffix is specified, then exactly one of the .py or ipynb file forms must be present')
            if py_exists:
                suffix_seen = '.py'
            else:
                suffix_seen = '.ipynb'
            input_file_name = input_file_name + suffix_seen
        assert os.path.exists(input_file_name)
        assert suffix_seen in other_suffix.keys()  # expected suffix
        assert base_name not in base_names_seen  # each base file name only used once
        base_names_seen.add(base_name)
        input_suffices_seen.add(suffix_seen)
        if len(input_suffices_seen) != 1:    # only one direction of conversion in batch job
            raise ValueError(f"conversion job may only have one input suffix: {input_suffices_seen}")
        output_file_name = base_name + other_suffix[suffix_seen]
        tasks.append((input_file_name, output_file_name))
    # do the work
    for input_file_name, output_file_name in tasks:
        if not args.quiet:
            print(f'from "{input_file_name}" to "{output_file_name}"')
        # back up result target if present
        if os.path.exists(output_file_name):
            output_backup_file = f'{output_file_name}~'
            if not args.quiet:
                print(f'   copying previous output target "{output_file_name}" to "{output_backup_file}"')
            shutil.copy2(output_file_name, output_backup_file)
        # convert
        if input_file_name.endswith('.py'):
            if not args.quiet:
                print(f"   converting Python {input_file_name} to Jupyter notebook {output_file_name}")
            convert_py_file_to_notebook(
                py_file=input_file_name,
                ipynb_file=output_file_name,
            )
        elif input_file_name.endswith('.ipynb'):
            if not args.quiet:
                print(f'   converting Jupyter notebook "{input_file_name}" to Python "{output_file_name}"')
            convert_notebook_file_to_py(
                ipynb_file=input_file_name,
                py_file=output_file_name)
        else:
            raise ValueError("input file name must end with .py or .ipynb")
        # do any deletions
        if args.delete:
            input_backup_file = f'{input_file_name}~'
            if not args.quiet:
                print(f"   moving input {input_file_name} to {input_backup_file}")
            try:
                os.remove(input_backup_file)
            except FileNotFoundError:
                pass
            os.rename(input_file_name, input_backup_file)
        if not args.quiet:
            print()
    return 0


if __name__ == '__main__':
    try:
        ret = main()
        sys.exit(ret)
    except AssertionError:
        _, _, tb = sys.exc_info()
        tb_info = traceback.extract_tb(tb)
        filename, line, func, text = tb_info[-1]
        print(f'Assertion failed {filename}:{line} (caller {func}) in statement {text}')
    except Exception as ex:
        print(ex)
    sys.exit(-1)
    
#   def main() -> int:
View Source
def main() -> int:
    parser = argparse.ArgumentParser(description="Convert between .py and .ipynb or back (can have suffix, or guess suffix)")
    parser.add_argument('--quiet', action='store_true', help='delete input file')
    parser.add_argument('--delete', action='store_true', help='delete input file')
    parser.add_argument(
        'infile', 
        metavar='infile', 
        type=str, 
        nargs='+',
        help='name of input file(s)')
    args = parser.parse_args()
    # some pre-checks
    assert len(args.infile) > 0
    assert len(set(args.infile)) == len(args.infile)
    assert isinstance(args.quiet, bool)
    assert isinstance(args.delete, bool)
    # set up the work request
    base_names_seen = set()
    input_suffices_seen = set()
    tasks = []
    other_suffix = {'.py': '.ipynb', '.ipynb': '.py'}
    for input_file_name in args.infile:
        assert isinstance(input_file_name, str)
        assert len(input_file_name) > 0
        suffix_seen = 'error'  # placeholder/sentinel
        base_name = input_file_name
        if input_file_name.endswith('.py'):
            suffix_seen = '.py'
            base_name = input_file_name.removesuffix(suffix_seen)
        elif input_file_name.endswith('.ipynb'):
            suffix_seen = '.ipynb'
            base_name = input_file_name.removesuffix(suffix_seen)
        else:
            py_exists = os.path.exists(input_file_name + '.py')
            ipynb_exists = os.path.exists(input_file_name + '.ipynb')
            if py_exists == ipynb_exists:
                raise ValueError(f'{base_name}: if no suffix is specified, then exactly one of the .py or ipynb file forms must be present')
            if py_exists:
                suffix_seen = '.py'
            else:
                suffix_seen = '.ipynb'
            input_file_name = input_file_name + suffix_seen
        assert os.path.exists(input_file_name)
        assert suffix_seen in other_suffix.keys()  # expected suffix
        assert base_name not in base_names_seen  # each base file name only used once
        base_names_seen.add(base_name)
        input_suffices_seen.add(suffix_seen)
        if len(input_suffices_seen) != 1:    # only one direction of conversion in batch job
            raise ValueError(f"conversion job may only have one input suffix: {input_suffices_seen}")
        output_file_name = base_name + other_suffix[suffix_seen]
        tasks.append((input_file_name, output_file_name))
    # do the work
    for input_file_name, output_file_name in tasks:
        if not args.quiet:
            print(f'from "{input_file_name}" to "{output_file_name}"')
        # back up result target if present
        if os.path.exists(output_file_name):
            output_backup_file = f'{output_file_name}~'
            if not args.quiet:
                print(f'   copying previous output target "{output_file_name}" to "{output_backup_file}"')
            shutil.copy2(output_file_name, output_backup_file)
        # convert
        if input_file_name.endswith('.py'):
            if not args.quiet:
                print(f"   converting Python {input_file_name} to Jupyter notebook {output_file_name}")
            convert_py_file_to_notebook(
                py_file=input_file_name,
                ipynb_file=output_file_name,
            )
        elif input_file_name.endswith('.ipynb'):
            if not args.quiet:
                print(f'   converting Jupyter notebook "{input_file_name}" to Python "{output_file_name}"')
            convert_notebook_file_to_py(
                ipynb_file=input_file_name,
                py_file=output_file_name)
        else:
            raise ValueError("input file name must end with .py or .ipynb")
        # do any deletions
        if args.delete:
            input_backup_file = f'{input_file_name}~'
            if not args.quiet:
                print(f"   moving input {input_file_name} to {input_backup_file}")
            try:
                os.remove(input_backup_file)
            except FileNotFoundError:
                pass
            os.rename(input_file_name, input_backup_file)
        if not args.quiet:
            print()
    return 0