diff --git a/.gitignore b/.gitignore index 39a6fc8..e46a222 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.pyc *swp *hy*egg* +*pyreadline*egg* .tox *pycache* dist diff --git a/.travis.yml b/.travis.yml index 1b8ef6e..124afc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ python: # command to install dependencies install: - pip install -r requirements.txt --use-mirrors - - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install importlib unittest2 astor --use-mirrors; fi + - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install argparse importlib unittest2 astor --use-mirrors; fi - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install astor --use-mirrors; fi - if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then pip install astor --use-mirrors; fi - python setup.py -q install diff --git a/AUTHORS b/AUTHORS index 3630a44..eb253ba 100644 --- a/AUTHORS +++ b/AUTHORS @@ -14,4 +14,5 @@ * Thomas Ballinger * Morten Linderud * Guillermo Vayá +* Bob Tolbert * Ralph Möritz diff --git a/bin/hy b/bin/hy deleted file mode 100755 index 14cf5e0..0000000 --- a/bin/hy +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python - -import sys -from hy.cmdline import cmdline_handler - - -if __name__ == '__main__': - sys.exit(cmdline_handler("hy", sys.argv)) diff --git a/bin/hyc b/bin/hyc deleted file mode 100755 index c371b4b..0000000 --- a/bin/hyc +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env hy - -(import sys) -(import [hy.importer [write-hy-as-pyc]]) - -(write-hy-as-pyc (get sys.argv 1)) diff --git a/hy/cmdline.py b/hy/cmdline.py index 4eca900..48b5d8c 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -24,7 +24,7 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -import optparse +import argparse import code import ast import sys @@ -198,26 +198,40 @@ def run_icommand(source): return run_repl(hr) -USAGE = "usage: %prog [-h | -i cmd | -c cmd | file | -]" -VERSION = "%prog " + hy.__version__ +USAGE = "%(prog)s [-h | -i cmd | -c cmd | file | -] [arg] ..." +VERSION = "%(prog)s " + hy.__version__ EPILOG = """ file program read from script - program read from stdin + [arg] ... arguments passed to program in sys.argv[1:] """ def cmdline_handler(scriptname, argv): - parser = optparse.OptionParser(usage=USAGE, version=VERSION) - parser.add_option( - "-c", dest="command", metavar="COMMAND", - help="program passed in as string") - parser.add_option( - "-i", dest="icommand", metavar="ICOMMAND", - help="program passed in as string, then stay in repl") + parser = argparse.ArgumentParser( + prog="hy", + usage=USAGE, + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=EPILOG) + parser.add_argument("-c", dest="command", + help="program passed in as a string") + parser.add_argument( + "-i", dest="icommand", + help="program passed in as a string, then stay in REPL") - # Hylarious way of adding non-option options to help text - parser.format_epilog = lambda self: EPILOG + parser.add_argument("-v", action="version", version=VERSION) - (options, args) = parser.parse_args() + # this will contain the script/program name and any arguments for it. + parser.add_argument('args', nargs=argparse.REMAINDER, + help=argparse.SUPPRESS) + + # stash the hy exectuable in case we need it later + # mimics Python sys.executable + hy.executable = argv[0] + + options = parser.parse_args(argv[1:]) + + # reset sys.argv like Python + sys.argv = options.args if options.command: # User did "hy -c ..." @@ -227,14 +241,25 @@ def cmdline_handler(scriptname, argv): # User did "hy -i ..." return run_icommand(options.icommand) - if args: - if args[0] == "-": + if options.args: + if options.args[0] == "-": # Read the program from stdin return run_command(sys.stdin.read()) else: # User did "hy " - return run_file(args[0]) + return run_file(options.args[0]) # User did NOTHING! return run_repl() + + +# entry point for cmd line script "hy" +def hy_main(): + sys.exit(cmdline_handler("hy", sys.argv)) + + +# entry point for cmd line script "hyc" +def hyc_main(): + from hy.importer import write_hy_as_pyc + write_hy_as_pyc(sys.argv[1]) diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..ccf6138 --- /dev/null +++ b/make.bat @@ -0,0 +1,116 @@ +@ECHO OFF + +REM Make batch file for Hy development + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo. No default step. Use setup.py + echo. + echo. Other targets: + echo. + echo. - docs + echo. - full + echo. + echo. - dev "test & flake" + echo. - flake + echo. - test + echo. - diff + echo. - tox + echo. - d + echo. - r + echo. + goto end +) + +if "%1" == "docs" ( +:docs + echo.docs not yet supported under Windows +goto :EOF +) + +if "%1" == "upload" ( +:upload + python setup.py sdist upload +goto :EOF +) + +if "%1" == "clear" ( +:clear + cls +goto :EOF +) + +if "%1" == "d" ( +:d + call :clear + call :dev +goto :EOF +) + +if "%1" == "test" ( +:test + call :venv + nosetests -sv +goto :EOF +) + +if "%1" == "venv" ( +:venv + echo.%VIRTUAL_ENV% | findstr /C:"hy" 1>nul + if errorlevel 1 ( + echo.You're not in a Hy virtualenv. FOR SHAME + ) ELSE ( + echo.We're properly in a virtualenv. Going ahead. + ) +goto :EOF +) + +if "%1" == "flake" ( +:flake + echo.flake8 hy + flake8 hy +goto :EOF +) + +if "%1" == "dev" ( +:dev + call :test + call :flake +goto :EOF +) + +if "%1" == "tox" ( +:tox + call :venv + tox -e "py26,py27,py32,py33,flake8" +goto :EOF +) + +if "%1" == "d" ( +:d + call :clear + call :dev +goto :EOF +) + +if "%i" == "diff" ( +:diff + git diff --color +goto :EOF +) + +if "%1" == "r" ( +:r + call :d + call :tox + call :diff +goto :EOF +) + +if "%1" == full ( + call :docs + call :d + call :tox +) \ No newline at end of file diff --git a/setup.py b/setup.py index c3bb159..8b6ba62 100755 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 Paul Tagliamonte +# Copyright (c) 2012, 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -23,12 +23,15 @@ from hy import __appname__, __version__ from setuptools import setup import os +import sys long_description = """Hy is a Python <--> Lisp layer. It helps make things work nicer, and lets Python and the Hy lisp variant play nice together. """ install_requires = [] +if sys.version_info[0] == 2: + install_requires.append('argparse>=1.2.1') if os.name == 'nt': install_requires.append('pyreadline==2.0') @@ -36,10 +39,12 @@ setup( name=__appname__, version=__version__, install_requires=install_requires, - scripts=[ - "bin/hy", - "bin/hyc", - ], + entry_points={ + 'console_scripts': [ + 'hy = hy.cmdline:hy_main', + 'hyc = hy.cmdline:hyc_main' + ] + }, packages=[ 'hy', 'hy.lex', diff --git a/tests/resources/argparse_ex.hy b/tests/resources/argparse_ex.hy new file mode 100755 index 0000000..9b2500f --- /dev/null +++ b/tests/resources/argparse_ex.hy @@ -0,0 +1,18 @@ +#!/usr/bin/env hy + +(import sys) +(import argparse) + +(setv parser (argparse.ArgumentParser)) + +(.add_argument parser "-i") +(.add_argument parser "-c") + +(setv args (.parse_args parser)) + +;; using (cond) allows -i to take precedence over -c + +(cond (args.i + (print (str args.i))) + (args.c + (print (str "got c")))) diff --git a/tests/test_bin.py b/tests/test_bin.py index 4cdfb58..3a4849c 100644 --- a/tests/test_bin.py +++ b/tests/test_bin.py @@ -25,13 +25,18 @@ import subprocess import sys -def run_cmd(cmd): +def run_cmd(cmd, stdin_data=None): p = subprocess.Popen(cmd, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) stdout = "" stderr = "" + if stdin_data is not None: + p.stdin.write(stdin_data.encode('ASCII')) + p.stdin.flush() + p.stdin.close() # Read stdout and stderr otherwise if the PIPE buffer is full, we might # wait for ever… while p.poll() is None: @@ -41,28 +46,28 @@ def run_cmd(cmd): def test_bin_hy(): - ret = run_cmd("echo | bin/hy") + ret = run_cmd("hy", "") assert ret[0] == 0 def test_bin_hy_stdin(): - ret = run_cmd("echo \"(koan)\" | bin/hy") + ret = run_cmd("hy", '(koan)') assert ret[0] == 0 assert "monk" in ret[1] def test_bin_hy_cmd(): - ret = run_cmd("bin/hy -c \"(koan)\"") + ret = run_cmd("hy -c \"(koan)\"") assert ret[0] == 0 assert "monk" in ret[1] - ret = run_cmd("bin/hy -c \"(koan\"") + ret = run_cmd("hy -c \"(koan\"") assert ret[0] == 1 assert "LexException" in ret[1] def test_bin_hy_icmd(): - ret = run_cmd("echo \"(ideas)\" | bin/hy -i \"(koan)\"") + ret = run_cmd("hy -i \"(koan)\"", "(ideas)") assert ret[0] == 0 output = ret[1] @@ -71,16 +76,41 @@ def test_bin_hy_icmd(): def test_bin_hy_file(): - ret = run_cmd("bin/hy eg/nonfree/halting-problem/halting.hy") + ret = run_cmd("hy eg/nonfree/halting-problem/halting.hy") assert ret[0] == 0 assert "27" in ret[1] +def test_bin_hy_missing_file(): + ret = run_cmd("hy foobarbaz") + assert ret[0] == 1 + assert "No such file" in ret[2] + + +def test_bin_hy_file_with_args(): + ret = run_cmd("hy tests/resources/argparse_ex.hy -h") + assert ret[0] == 0 + assert "usage" in ret[1] + ret = run_cmd("hy tests/resources/argparse_ex.hy -c bar") + assert ret[0] == 0 + assert "got c" in ret[1] + ret = run_cmd("hy tests/resources/argparse_ex.hy -i foo") + assert ret[0] == 0 + assert "foo" in ret[1] + ret = run_cmd("hy tests/resources/argparse_ex.hy -i foo -c bar") + assert ret[0] == 0 + assert "foo" in ret[1] + + def test_hy2py(): # XXX Astor doesn't seem to support Python3 :( if sys.version_info[0] == 3: return + # and running this script this way doesn't work on Windows + if os.name == "nt": + return + i = 0 for dirpath, dirnames, filenames in os.walk("tests/native_tests"): for f in filenames: