Repository: hylang/hy

Issue:
`hyc` doesn't require an argument
Compiling from stdin results in a weird error which seems like hyc is trying to read the file from the disk.

```
% cat > tmp.hy
(import os sys)

% hy tmp.hy

% hyc tmp.hy
Compiling tmp.hy

% hyc - < tmp.hy
[Errno 2] No such file or directory: '(import os sys)'

% hyc < tmp.hy  
[Errno 2] No such file or directory: '(import os sys)'
```

Discussion:

Patch:
diff --git a/NEWS.rst b/NEWS.rst
index 39fb71f6..d4d8f62b 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -10,6 +10,12 @@ Bug Fixes
 * Fixed a bug with `python -O` where assertions were still partly
   evaluated.
 
+Misc. Improvements
+------------------------------
+* `hyc` now requires a command-line argument.
+* `hyc` prints each path it writes bytecode to, and its messages now
+  go to standard error instead of standard output.
+
 0.24.0 (released 2022-06-23)
 ==============================
 
diff --git a/docs/cli.rst b/docs/cli.rst
index 9ed1ab84..e1e34cfb 100644
--- a/docs/cli.rst
+++ b/docs/cli.rst
@@ -59,56 +59,24 @@ Command Line Options
    Print the Hy version number and exit.
 
 
-.. _hyc:
-
-hyc
----
-
-Command Line Options
-^^^^^^^^^^^^^^^^^^^^
-
-.. cmdoption:: file[, fileN]
-
-   Compile Hy code to Python bytecode. For example, save the
-   following code as ``hyname.hy``:
-
-   .. code-block:: hy
-
-      (defn hy-hy [name]
-        (print (+ "Hy " name "!")))
-
-      (hy-hy "Afroman")
-
-   Then run:
-
-   .. code-block:: bash
-
-      $ hyc hyname.hy
-      $ python hyname.pyc
-      Hy Afroman!
-
-
 .. _hy2py:
 
 hy2py
 -----
 
-.. versionadded:: 0.10.1
+``hy2py`` is a program to convert Hy source code into Python source code. Use ``hy2py --help`` for usage instructions. It can take its input from standard input or from a filename provided as a command-line argument. The result is written to standard output.
 
-Command Line Options
-^^^^^^^^^^^^^^^^^^^^
+    .. warning::
+       ``hy2py`` can execute arbitrary code. Don't give it untrusted input.
 
-.. cmdoption:: -s
-               --with-source
 
-   Show the parsed source structure.
 
-.. cmdoption:: -a
-               --with-ast
+.. _hyc:
 
-   Show the generated AST.
+hyc
+---
 
-.. cmdoption:: -np
-               --without-python
+``hyc`` is a program to compile files of Hy code into Python bytecode. Use ``hyc --help`` for usage instructions. The generated bytecode files are named and placed according to the usual scheme of your Python executable, as indicated by :py:func:`importlib.util.cache_from_source`.
 
-   Do not show the Python code generated from the AST.
+    .. warning::
+       ``hyc`` can execute arbitrary code. Don't give it untrusted input.
diff --git a/docs/tutorial.rst b/docs/tutorial.rst
index 9294abf9..03f25c76 100644
--- a/docs/tutorial.rst
+++ b/docs/tutorial.rst
@@ -74,7 +74,7 @@ and return code to be executed at run-time.
 Comments start with a ``;`` character and continue till the end of the line. A
 comment is functionally equivalent to whitespace. ::
 
-    (print (** 2 64))   ; Max 64-bit unsigned integer value
+    (setv password "susan")   ; My daughter's name
 
 Although ``#`` isn't a comment character in Hy, a Hy program can begin with a
 `shebang line <https://en.wikipedia.org/wiki/Shebang_(Unix)>`_, which Hy itself
diff --git a/hy/cmdline.py b/hy/cmdline.py
index 446bb1c1..76f905c4 100644
--- a/hy/cmdline.py
+++ b/hy/cmdline.py
@@ -721,44 +721,27 @@ def hy_main():
 
 def hyc_main():
     parser = argparse.ArgumentParser(prog="hyc")
-    parser.add_argument(
-        "files",
-        metavar="FILE",
-        nargs="*",
-        help=("File(s) to compile (use STDIN if only" ' "-" or nothing is provided)'),
-    )
+    parser.add_argument("files", metavar="FILE", nargs="+", help="File(s) to compile")
     parser.add_argument("-v", action="version", version=VERSION)
 
     options = parser.parse_args(sys.argv[1:])
 
     rv = 0
-    if len(options.files) == 0 or (len(options.files) == 1 and options.files[0] == "-"):
-        while True:
-            filename = sys.stdin.readline()
-            if not filename:
-                break
-            filename = filename.rstrip("\n")
-            set_path(filename)
-            try:
-                py_compile.compile(filename, doraise=True)
-            except py_compile.PyCompileError as error:
-                rv = 1
-                sys.stderr.write("%s\n" % error.msg)
-            except OSError as error:
-                rv = 1
-                sys.stderr.write("%s\n" % error)
-            sys.path.pop(0)
-    else:
-        for filename in options.files:
-            set_path(filename)
-            try:
-                print("Compiling %s" % filename)
-                py_compile.compile(filename, doraise=True)
-            except py_compile.PyCompileError as error:
-                # return value to indicate at least one failure
-                rv = 1
-                sys.stderr.write("%s\n" % error.msg)
-            sys.path.pop(0)
+    for filename in options.files:
+        set_path(filename)
+        try:
+            print(
+                "Compiling {!r} --> {!r}".format(
+                    filename, importlib.util.cache_from_source(filename)
+                ),
+                file=sys.stderr,
+            )
+            py_compile.compile(filename, doraise=True)
+        except py_compile.PyCompileError as error:
+            # return value to indicate at least one failure
+            rv = 1
+            print(error.msg, file=sys.stderr)
+        sys.path.pop(0)
     return rv
 
 


Test patch:
diff --git a/tests/test_bin.py b/tests/test_bin.py
index 64b8adfa..45bae911 100644
--- a/tests/test_bin.py
+++ b/tests/test_bin.py
@@ -341,18 +341,12 @@ def test_file_with_args():
 
 
 def test_hyc():
-    _, err = run_cmd("hyc", expect=0)
-    assert err == ""
-
-    _, err = run_cmd("hyc -", expect=0)
-    assert err == ""
-
     output, _ = run_cmd("hyc -h")
     assert "usage" in output
 
     path = "tests/resources/argparse_ex.hy"
-    output, _ = run_cmd("hyc " + path)
-    assert "Compiling" in output
+    _, err = run_cmd("hyc " + path)
+    assert "Compiling" in err
     assert os.path.exists(cache_from_source(path))
     rm(cache_from_source(path))