Provide bin scripts for both Windows and *nix

Summary: This update does away with the scripts in bin and changes
setup.py to use entry_points in cmdline.py for the scripts 'hy' and
'hyc'.

This fixes installing and running on Windows.

The tests are updated to run the 'hy' script produced by setup.py
and not from bin/hy. This is more correct and makes the tox tests
run on both Window and *nix.

For running hy or nosetests directly in the source tree, you do have
to run 'python setup.py develop' first. But since tox runs and builds
dists, all tox tests pass on all platforms.

Also, since there is no built-in readline on Windows, the setup.py
only on Windows requires 'pyreadline' as a replacement.

Switched from optparse to argparse in cmdline.py

Instead of trying to manually separate args meant for
hy from args meant for a hy script, this switches from
optparse to argparse for the CLI.

argparse automatically peels out args meant for hy and leaves
the rest, including the user hy script in options.args.

This fixes the issue @paultag found running "hy foo" where
foo is not a real file. Also added a test that makes sure
trying to run a non-existent script exits instead of dropping
the user into the REPL.

Added argparse as setup.py resource (and removed from tox.ini) as well as removed uses of deprecated setf
This commit is contained in:
Bob Tolbert 2013-06-29 15:56:58 -06:00
parent 9cf3ee4b43
commit df7bb1d29a
10 changed files with 225 additions and 43 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
*.pyc
*swp
*hy*egg*
*pyreadline*egg*
.tox
*pycache*
dist

View File

@ -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

View File

@ -14,4 +14,5 @@
* Thomas Ballinger <thomasballinger@gmail.com>
* Morten Linderud <mcfoxax@gmail.com>
* Guillermo Vayá <guivaya@gmail.com>
* Bob Tolbert <bob@tolbert.org>
* Ralph Möritz <ralph.moeritz@outlook.com>

8
bin/hy
View File

@ -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))

View File

@ -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))

View File

@ -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 <filename>"
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])

116
make.bat Normal file
View File

@ -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
)

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python
# Copyright (c) 2012 Paul Tagliamonte <paultag@debian.org>
# Copyright (c) 2012, 2013 Paul Tagliamonte <paultag@debian.org>
#
# 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',

18
tests/resources/argparse_ex.hy Executable file
View File

@ -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"))))

View File

@ -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: