Repository: sagemath/pari-jupyter (language: python)

Issue:
Test
It would be helpful to run tests for the pari_jupyter kernel using https://github.com/jupyter/jupyter_kernel_test
- [x] https://github.com/jupyter/jupyter_kernel_test/issues/70


Discussion / hints:

Fix patch:
diff --git a/README.rst b/README.rst
index 6add059..7786fed 100644
--- a/README.rst
+++ b/README.rst
@@ -29,3 +29,11 @@ Dependencies
 * `PARI <http://pari.math.u-bordeaux.fr/>`_ version 2.13 or later
 * `Readline <http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html>`_ (any version which works with PARI)
 * Optional: `Cython <http://cython.org/>`_ version 0.25 or later
+
+Running tests
+-------------
+
+There is a standalone python script in test/ that depends on `jupyter_kernel_test
+<https://github.com/jupyter/jupyter_kernel_test>`_ (see the file
+test/environment.yml for the precise dependency list that are run in the github
+action using conda).


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..42fa27b
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,33 @@
+name: Test
+
+on:
+  push:
+    branches:
+      - master
+  pull_request:
+    branches:
+      - master
+
+permissions: read-all
+
+jobs:
+  test:
+    runs-on: ubuntu-20.04
+    steps:
+      - uses: actions/checkout@v2
+        with: { submodules: recursive }
+      - uses: conda-incubator/setup-miniconda@v2
+        with: { mamba-version: "*", channels: "conda-forge", channel-priority: true }
+      - name: Install dependencies
+        shell: bash -l {0}
+        run: |
+          mamba env create -f test/environment.yml
+          conda list
+      - name: Install pari-jupyter
+        shell: bash -l {0}
+        run: pip install --verbose --no-index .
+      - name: Run test
+        shell: bash -l {0}
+        run: |
+          cd test
+          python test_pari_jupyter_kernel.py
diff --git a/test/environment.yml b/test/environment.yml
new file mode 100644
index 0000000..a1919b4
--- /dev/null
+++ b/test/environment.yml
@@ -0,0 +1,16 @@
+# This file lists the minimial dependencies needed to build and test
+# pari-jupyter. Create a conda environment with these dependencies
+# preinstalled with:
+# conda env create -f environment.yml
+name: pari-jupyter-test
+channels:
+  - conda-forge
+  - defaults
+dependencies:
+  - python=3.9 # NOTE: does not work with 3.10, see https://github.com/jupyter/jupyter_console/issues/245
+  - cython
+  - jupyter
+  - pip
+  - ipykernel
+  - pip:
+    - jupyter_kernel_test # NOTE: not recent enough in conda, see https://github.com/jupyter/jupyter_kernel_test/issues/70
diff --git a/test/test_pari_jupyter_kernel.py b/test/test_pari_jupyter_kernel.py
new file mode 100644
index 0000000..d39b8b2
--- /dev/null
+++ b/test/test_pari_jupyter_kernel.py
@@ -0,0 +1,102 @@
+"""
+Example use of jupyter_kernel_test, with tests for the default python3 kernel
+(IPyKernel). This includes all the currently available tests.
+"""
+
+import unittest
+import jupyter_kernel_test as jkt
+
+class PARIKernelTests(jkt.KernelTests):
+
+    # REQUIRED
+
+    # the kernel to be tested
+    # this is the normally the name of the directory containing the
+    # kernel.json file - you should be able to do
+    # `jupyter console --kernel KERNEL_NAME`
+    kernel_name = "pari_jupyter"
+
+    # Everything else is OPTIONAL
+
+    # the name of the language the kernel executes
+    # checked against language_info.name in kernel_info_reply
+    language_name = "gp"
+
+    # the normal file extension (including the leading dot) for this language
+    # checked against language_info.file_extension in kernel_info_reply
+    # file_extension = ".gp"
+
+    # code which should write the exact string `hello, world` to STDOUT
+    code_hello_world = "print(\"hello, world\")"
+
+    # samples for the autocompletion functionality
+    # for each dictionary, `text` is the input to try and complete, and
+    # `matches` the list of all complete matching strings which should be found
+    # completion_samples = [
+    #    {
+    #        'text': 'cot',
+    #        'matches': {'cotan', 'cotanh'},
+    #    },
+    # ]
+
+    # samples for testing code-completeness (used by console only)
+    # these samples should respectively be unambigiously complete statements
+    # (which should be executed on <enter>), incomplete statements or code
+    # which should be identified as invalid
+    # complete_code_samples = ['1', "print('hello, world')", "def f(x):\n  return x*2\n\n\n"]
+    # incomplete_code_samples = ["print('''hello", "def f(x):\n  x*2"]
+    # invalid_code_samples = ['import = 7q']
+
+    # code which should cause a help pager to be displayed (as of 4.1, this is
+    # displayed by the notebook only as inline text, so it's probably more
+    # useful for console clients)
+    code_page_something = "?cos"
+
+    # code which should generate a (user-level) error in the kernel, and send
+    # a traceback to the client
+    # code_generate_error = "raise"
+
+    # a statement or block of code which generates a result (which is shown
+    # as Out[n] instead of just something printed to stdout)
+    # running each `code` should cause `result` to be displayed (note that the
+    # result here will always be a string representation of whatever the actual
+    # result type is - be careful of string formatting)
+    code_execute_result = [
+        {'code': "1+2+3", 'result': "6"},
+    ]
+
+    # code which generates some sort of rich output
+    # for each `code` input a single rich display object with the specified
+    # `mime` type should be sent to the frontend
+    # note that this expects a `display_data` message rather than
+    # `execute_result`; this test might be a little too inflexible in some cases
+    # code_display_data = [
+    #    {'code': "from IPython.display import HTML, display; display(HTML('<b>test</b>'))",
+    #     'mime': "text/html"},
+    #    {'code': "from IPython.display import Math, display; display(Math('\\frac{1}{2}'))",
+    #     'mime': "text/latex"}
+    # ]
+
+    # test the support for searching/recalling history (used by console only)
+    # the history tests re-use the code blocks in `code_execute_result` above,
+    # so will not run if no test code is available
+    # `code_history_pattern` is a glob-style pattern which should match at least
+    # one code sample in `code_execute_result`
+    # `supported_history_operations` is a list of the `hist_access_type` options
+    # which should be tested; possible values are "tail", "range" and "search"
+    # code_history_pattern = "1?2*"
+    # supported_history_operations = ("tail", "search")
+
+    # test the support for object inspection
+    # the sample should be a name about which the kernel can give some help
+    # information (a built-in function is probably a good choice)
+    # only the default inspection level (equivalent to ipython "obj?")
+    # is currently tested
+    # code_inspect_sample = "zip"
+
+    # a code sample which should cause a `clear_output` message to be sent to
+    # the client
+    # code_clear_output = "from IPython.display import clear_output; clear_output()"
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)