Skip to content

Commit

Permalink
Merge pull request #2388 from Kodiologist/pyodide
Browse files Browse the repository at this point in the history
Test on Pyodide
  • Loading branch information
Kodiologist committed Jan 22, 2023
2 parents 8d3d31a + 62b7e29 commit 70f549b
Show file tree
Hide file tree
Showing 17 changed files with 94 additions and 30 deletions.
41 changes: 34 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
matrix:
name-prefix: ['']
os: [ubuntu-latest]
python: [3.7, 3.8, 3.9, '3.10', 3.11, pypy-3.9]
python: [3.7, 3.8, 3.9, '3.10', 3.11, pypy-3.9, pyodide]
include:
# To keep the overall number of runs low, we test Windows
# only on the latest CPython.
Expand All @@ -21,6 +21,7 @@ jobs:
name: ${{ format('{0}{1}', matrix.name-prefix, matrix.python) }}
runs-on: ${{ matrix.os }}
env:
EMSCRIPTEN_VERSION: 3.1.27
TERM: xterm-256color
# This is needed to avoid a terminfo-related crash when
# testing PyPy.
Expand All @@ -29,11 +30,37 @@ jobs:
steps:
- run: git config --global core.autocrlf false
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- if: ${{ matrix.python != 'pyodide' }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- run: pip install . && rm -r hy
# We want to be sure we're testing the installed version,
# instead of running from the source tree.
- run: pip install pytest
- run: pytest
- if: ${{ matrix.python == 'pyodide' }}
uses: actions/setup-node@v3
- if: ${{ matrix.python == 'pyodide' }}
uses: mymindstorm/setup-emsdk@v11
with:
version: ${{ env.EMSCRIPTEN_VERSION }}
actions-cache-folder: emsdk-cache
- name: Install
shell: bash
run: |
if [[ ${{ matrix.python }} = pyodide ]] ; then
npm install pyodide
pip install 'pip >= 22.3.1'
# Older pips may fail to install `pyodide-build`.
pip install pyodide-build
pyodide venv .venv-pyodide
source .venv-pyodide/bin/activate
fi
pip install .
rm -r hy
# We want to be sure we're testing the installed version,
# instead of running from the source tree.
pip install pytest
- name: Test
shell: bash
run: |
if [[ ${{ matrix.python }} = pyodide ]] ; then
source .venv-pyodide/bin/activate
fi
python -m pytest tests
1 change: 1 addition & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Bug Fixes

New Features
------------------------------
* Pyodide is now officially supported.
* `.`, `..`, etc. are now usable as ordinary symbols (with the
remaining special rule that `...` compiles to `Ellipsis`)
* On Pythons ≥ 3.7, Hy modules can now be imported from ZIP
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ To install the latest release of Hy, just use the command `pip3 install
--user hy`. Then you can start an interactive read-eval-print loop (REPL) with
the command `hy`, or run a Hy program with `hy myprogram.hy`.

Hy is tested on all released and currently maintained versions of CPython (on
Linux and Windows), and on recent versions of PyPy and Pyodide.

* [Try Hy with a web console](https://hylang.github.io/hy-interpreter)
* [Why Hy?](http://docs.hylang.org/en/stable/whyhy.html)
* [Tutorial](http://docs.hylang.org/en/stable/tutorial.html)
Expand Down
3 changes: 3 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ To install the latest release of Hy, just use the command ``pip3 install
--user hy``. Then you can start an interactive read-eval-print loop (REPL) with
the command ``hy``, or run a Hy program with ``hy myprogram.hy``.

Hy is tested on all released and currently maintained versions of CPython (on
Linux and Windows), and on recent versions of PyPy and Pyodide.

.. toctree::
:maxdepth: 3

Expand Down
1 change: 1 addition & 0 deletions hy/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
PY3_10 = sys.version_info >= (3, 10)
PY3_11 = sys.version_info >= (3, 11)
PYPY = platform.python_implementation() == "PyPy"
PYODIDE = platform.system() == "Emscripten"


if not PY3_9:
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ def run(self):
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: PyPy",
"Environment :: WebAssembly :: Emscripten",
"Topic :: Software Development :: Code Generators",
"Topic :: Software Development :: Compilers",
"Topic :: Software Development :: Libraries",
Expand Down
7 changes: 4 additions & 3 deletions tests/native_tests/comprehensions.hy
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
(import
types
asyncio
pytest)
pytest
tests.resources [async-test])


(defn test-comprehension-types []
Expand Down Expand Up @@ -385,7 +386,7 @@
(assert (= x 3)))


(defn test-for-async []
(defn [async-test] test-for-async []
(defn/a numbers []
(for [i [1 2]]
(yield i)))
Expand All @@ -398,7 +399,7 @@
(assert (= x 3))))))


(defn test-for-async-else []
(defn [async-test] test-for-async-else []
(defn/a numbers []
(for [i [1 2]]
(yield i)))
Expand Down
5 changes: 3 additions & 2 deletions tests/native_tests/decorators.hy
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(import
asyncio)
asyncio
tests.resources [async-test])


(defn test-decorated-1line-function []
Expand Down Expand Up @@ -52,7 +53,7 @@
(assert (= l ["dec" "arg" "foo" "foo fn" "bar body" 1])))


(defn test-decorated-defn/a []
(defn [async-test] test-decorated-defn/a []
(defn decorator [func] (fn/a [] (/ (await (func)) 2)))

(defn/a [decorator] coro-test []
Expand Down
7 changes: 4 additions & 3 deletions tests/native_tests/functions.hy
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
(import
asyncio
typing [List]
pytest)
pytest
tests.resources [async-test])


(defn test-fn []
Expand All @@ -24,7 +25,7 @@
(assert (= (fn-test) None)))


(defn test-fn/a []
(defn [async-test] test-fn/a []
(assert (= (asyncio.run ((fn/a [] (await (asyncio.sleep 0)) [1 2 3])))
[1 2 3])))

Expand Down Expand Up @@ -132,7 +133,7 @@
(setv x [#* spam] y 1)))


(defn test-defn/a []
(defn [async-test] test-defn/a []
(defn/a coro-test []
(await (asyncio.sleep 0))
[1 2 3])
Expand Down
6 changes: 4 additions & 2 deletions tests/native_tests/import.hy
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
os.path [exists isdir isfile]
sys :as systest
sys
pytest)
pytest
hy._compat [PYODIDE])


(defn test-imported-bits []
Expand Down Expand Up @@ -202,7 +203,8 @@ in expansions."

;; Now that bytecode is present, reload the module, clear the `require`d
;; macros and tags, and rerun the tests.
(assert (os.path.isfile pyc-file))
(when (not PYODIDE)
(assert (os.path.isfile pyc-file)))

;; Reload the module and clear the local macro context.
(.clear sys.path_importer_cache)
Expand Down
1 change: 0 additions & 1 deletion tests/native_tests/model_patterns.hy
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,4 @@
for n from 1 to 3
for p in [k n (* 10 n)]
do (.append l p) (-= k 1))
(print l)
(assert (= l [2 1 10 -1 2 20 -4 3 30])))
2 changes: 1 addition & 1 deletion tests/native_tests/setv.hy
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
(an (setv x (for [i (range 3)] i (+ i 1))))
(an (setv x (assert True)))

(an (setv x (with [(open "README.md" "r")] 3)))
(an (setv x (with [(open "tests/resources/text.txt" "r")] 3)))
(assert (= x 3))
(an (setv x (try (/ 1 2) (except [ZeroDivisionError] "E1"))))
(assert (= x .5))
Expand Down
18 changes: 9 additions & 9 deletions tests/native_tests/with.hy
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
(import
asyncio
pytest
tests.resources [AsyncWithTest])
tests.resources [async-test AsyncWithTest])

(defn test-context []
(with [fd (open "README.md" "r")] (assert fd))
(with [(open "README.md" "r")] (do)))
(with [fd (open "tests/resources/text.txt" "r")] (assert fd))
(with [(open "tests/resources/text.txt" "r")] (do)))

(defn test-with-return []
(defn read-file [filename]
(with [fd (open filename "r")] (.read fd)))
(assert (!= 0 (len (read-file "README.md")))))
(with [fd (open filename "r" :encoding "UTF-8")] (.read fd)))
(assert (= (read-file "tests/resources/text.txt") "TAARGÜS TAARGÜS\n")))

(defclass WithTest [object]
(defn __init__ [self val]
Expand Down Expand Up @@ -50,21 +50,21 @@
(assert (= t2 2))
(assert (= t3 3))))

(defn test-single-with/a []
(defn [async-test] test-single-with/a []
(asyncio.run
((fn/a []
(with/a [t (AsyncWithTest 1)]
(assert (= t 1)))))))

(defn test-two-with/a []
(defn [async-test] test-two-with/a []
(asyncio.run
((fn/a []
(with/a [t1 (AsyncWithTest 1)
t2 (AsyncWithTest 2)]
(assert (= t1 1))
(assert (= t2 2)))))))

(defn test-thrice-with/a []
(defn [async-test] test-thrice-with/a []
(asyncio.run
((fn/a []
(with/a [t1 (AsyncWithTest 1)
Expand All @@ -74,7 +74,7 @@
(assert (= t2 2))
(assert (= t3 3)))))))

(defn test-quince-with/a []
(defn [async-test] test-quince-with/a []
(asyncio.run
((fn/a []
(with/a [t1 (AsyncWithTest 1)
Expand Down
10 changes: 10 additions & 0 deletions tests/resources/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import pytest

from hy._compat import PYODIDE

in_init = "chippy"


Expand All @@ -9,6 +13,12 @@ def function_with_a_dash():
pass


can_test_async = not PYODIDE
async_test = pytest.mark.skipif(
not can_test_async, reason="`asyncio.run` not implemented"
)


class AsyncWithTest:
def __init__(self, val):
self.val = val
Expand Down
1 change: 1 addition & 0 deletions tests/resources/text.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TAARGÜS TAARGÜS
7 changes: 6 additions & 1 deletion tests/test_bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@

import pytest

from hy._compat import PY3_9, PYPY
from hy._compat import PY3_9, PYODIDE, PYPY

if PYODIDE:
pytest.skip(
'`subprocess.Popen` not implemented on Pyodide',
allow_module_level = True)


def pyr(s=""):
Expand Down
9 changes: 8 additions & 1 deletion tests/test_hy2py.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
import itertools
import math
import os
import platform

import pytest

import hy.importer
from hy import mangle
from hy._compat import PYODIDE
from tests.resources import can_test_async


def test_direct_import():
Expand All @@ -13,6 +18,7 @@ def test_direct_import():
assert_stuff(tests.resources.pydemo)


@pytest.mark.skipif(PYODIDE, reason="subprocess.check_call not implemented on Pyodide")
def test_hy2py_import():
import contextlib
import os
Expand Down Expand Up @@ -148,7 +154,8 @@ class C:
assert m.pys_accum == [0, 1, 2, 3, 4]
assert m.py_accum == "01234"

assert asyncio.run(m.coro()) == list("abcdef")
if can_test_async:
assert asyncio.run(m.coro()) == list("abcdef")

assert m.cheese == [1, 1]
assert m.mac_results == ["x", "x"]
Expand Down

0 comments on commit 70f549b

Please sign in to comment.