Home

Awesome

Herculog - A Jupyter Kernel for Prolog

A Jupyter kernel for Prolog based on the IPython kernel.

By default, SICStus Prolog and SWI-Prolog (which is the actual default) are supported. The kernel is implemented in a way that basically all functionality except the loading of configuration files can easily be overridden. This is especially useful for extending the kernel for further Prolog implementations or running code with a different version of an implementation. For further information about this, see Configuration.

Also see the JupyterLab Prolog CodeMirror Extension for syntax highlighting of Prolog code in JupyterLab.

Note: The project is still under development. Even though major changes are unlikely, the possibility cannot be excluded. Furthermore, no liability is accepted for correctness and completeness.

Examples

The directory notebooks contains some example Juypter notebooks. Note that all of them can be viewed with nbviewer without having to install the kernel.

For instance, the notebooks in notebooks/feature_introduction can be accessed via:

These notebooks serve as an introduction to the features of the kernel for SWI and SICStus Prolog. They also point out some peculiarities of the implementations.

The notebook in notebooks/slides was created for a slideshow giving a rough overview of the kernel's features and its implementation.

The directory notebooks/nbgrader_example provides an example of a course directory for the nbgrader extension.

The kernel has been used to prepare some notebooks for teaching logic programming.

Additionally, the file jupyter_server_tests.pl defines some PL-Unit tests. They provide further examples of what kind of code the Prolog server (and therefore the kernel) can handle and what the expected behavior is.

Installation

Requirements

The following configurations have been tested:

Install

The kernel is provided as a Python package on the Python Package Index and can be installed with pip:

  1. Download the kernel:<br/> python -m pip install prolog_kernel
  2. Install the kernelspec:
    • python -m prolog_kernel.install
    • There are the following options which can be seen when running python -m prolog_kernel.install --help
      • --user: install to the per-user kernel registry instead of sys.prefix (use if you get permission errors during installation)
      • --prefix PREFIX: install to the given prefix: PREFIX/share/jupyter/kernels/

Uninstall

  1. pip uninstall prolog_kernel
  2. jupyter kernelspec remove prolog_kernel

Configuration

The kernel can be configured by defining a Python config file named prolog_kernel_config.py. The kernel will look for this file in the Jupyter config path (can be retrieved with jupyter --paths) and the current working directory. An example of such a configuration file with an explanation of the options and their default values commented out can be found here.

Note: If a config file exists in the current working directory, it overrides values from other configuration files.

In general, the kernel can be configured to use a different Prolog server (which is responsible for code execution) or kernel implementation. Furthermore, it can be configured to use another Prolog implementation altogether which might not be supported by default. The following options can be configured:

In addition to configuring the Prolog implementation to be used, the Prolog server implements the predicate jupyter:set_prolog_impl(+PrologImplementationID) to change the Prolog implementation on the fly. In order for this to work, the configured implementation_data dictionary needs to contain data for more than one Prolog implementation.

Troubleshooting: In case of SICStus Prolog, if the given program_arguments are invalid (e.g. if the Prolog code file does not exist), the kernel waits for a response from the server which it will never receive. In that state it is not able to log any exception and instead, nothing happens. To facilitate finding the cause of the error, before trying to start the Prolog server, the arguments and the directory from which they are tried to be executed are logged.

Overriding the Kernel Implementation

The actual kernel code determining the handling of requests is not implemented by the kernel class itself. Instead, there is the file prolog_kernel_base_implementation.py which defines the class PrologKernelBaseImplementation. When the kernel is started, a (sub)object of this class is created. It handles the starting of and communication with the Prolog server. For all requests (execution, shutdown, completion, inspection) the kernel receives, a PrologKernelBaseImplementation method is called. By creating a subclass of this and defining the path to it as kernel_implementation_path, the actual implementation code can be replaced.

If no such path is defined, the path itself or the defined class is invalid, a default implementation is used instead. In case of SICStus and SWI-Prolog, the files swi_kernel_implementation.py and sicstus_kernel_implementation.py are used. Otherwise, the base implementation from the file prolog_kernel_base_implementation.py is loaded.

Development

Development Install

  1. git clone https://github.com/anbre/prolog-jupyter-kernel.git
  2. Change to the root directory of the repository
  3. pip install .
  4. Install the kernelspec:
    • python -m prolog_kernel.install
    • For available installation options, see Install

Local Changes

In general, in order for local code adjustments to take effect, the kernel needs to be reinstalled. When installing the local project in editable mode with pip install -e . (e.g. by running make), restarting the kernel suffices.

Adjustments of the Prolog server code are loaded when the server is restarted. Thus, when changing Prolog code only, instead of restarting the whole kernel, it can be interrupted, which causes the Prolog server to be restarted.

Upload to PyPI

This kernel is available as a Python package on the Python Package Index. A new version of the package can be published in the following way:

  1. Install the requirements build and twine: <br/> pip install build twine
  2. Increase the version in pyproject.toml
  3. Create the distribution files: <br/> python -m build
  4. Upload the package to PyPI: <br/> twine upload dist/*

For further information, see the Packaging Python Projects Tutorial.

Debugging

Usually, if the execution of a goal causes an exception, the corresponding Prolog error message is computed and displayed in the Jupyter frontend. However, in case something goes wrong unexpectedly or the query does not terminate, the Prolog server might not be able to send a response to the client. In that case, the user can only see that the execution does not terminate without any information about the error or output that might have been produced. However, it is possible to write logging messages and access any potential output, which might facilitate finding the cause of the error.

Debugging the server code is not possible in the usual way by tracing invocations. Furthermore, all messages exchanged with the client are written to the standard streams. Therefore, printing helpful debugging messages does not work either. Instead, if server_logging is configured, messages can be written to a log file by calling log/1 or log/2 from the module jupyter_logging. By default, only the responses sent to the client are logged.

When a query is executed, all its output is written to a file named .server_output, which is deleted afterwards by jupyter_query_handling:delete_output_file. If an error occurs during the actual execution, the file cannot be deleted and thus, the output of the goal can be accessed. Otherwise, the deletion might be prevented.

Furthermore, the server might send a response which the client cannot handle. In that case, logging for the Python code can be enabled by configuring jupyter_logging. For instance, the client logs the responses received from the server.

Credits

The Prolog Jupyter kernel was developed by Anne Brecklinghaus in her Master's thesis at the University of Düsseldorf under the supervision of Michael Leuschel and Philipp Körner. Michael Leuschel is using the notebooks in his lectures and is adding features and making improvements along the way.