Package: prolog-kernel
Herculog - A Jupyter Kernel for PrologAJupyterkernel for Prolog based on theIPython kernel.By default,SICStus PrologandSWI-Prolog(which is the actualdefault) 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 forextending the kernel for further Prolog implementationsor running code with a different version of an implementation. For further information about this, seeConfiguration.Also see theJupyterLab Prolog CodeMirror Extensionforsyntax highlightingof 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.ExamplesThe directorynotebookscontains some example Juypter notebooks. Note that all of them can be viewed withnbviewerwithout having to install the kernel.For instance, the notebooks innotebooks/feature_introductioncan be accessed via:using_jupyter_notebooks_with_swi_prolog.ipynbusing_jupyter_notebooks_with_sicstus_prolog.ipynbThese notebooks serve as anintroduction to the featuresof the kernel for SWI and SICStus Prolog. They also point out some peculiarities of the implementations.The notebook innotebooks/slideswas created for aslideshowgiving a rough overview of the kernel's features and its implementation.The directorynotebooks/nbgrader_exampleprovides an example of acourse directoryfor thenbgrader extension.Additionally, the filejupyter_server_tests.pldefines somePL-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.InstallationRequirementsAt leastPython3.5Tested with Python 3.8.10Jupyterinstallation with JupyterLab and/or Juypter NotebookTested withjupyter_core: 4.10.0jupyterlab: 3.2.9notebook: 6.4.8AProloginstallation for the configured implementationIn order to use the default configuration, SWI-Prolog is needed and needs to be on the PATHTested with version 8.4.3 of SWI-Prolog and SICStus 4.5.1For Windows, installinggraphvizwith pip does not sufficeInstead, it can be installed fromhereand added to the PATH (a reboot is required afterwards)The installation was tested with Ubuntu 20.04 and Windows 10.InstallThe kernel is provided as a Python package on thePython Package Indexand can be installed withpip:Download the kernel:python -m pip install prolog_kernelInstall the kernel specification directory:python -m prolog_kernel.installThere are the following options which can be seen when runningpython -m prolog_kernel.install --help--user: install to the per-user kernel registry (default if not root and no prefix is specified)--sys-prefix: install to Python's sys.prefix (e.g. virtualenv/conda env)--prefix PREFIX: install to the given prefix: PREFIX/share/jupyter/kernels/ (e.g. virtualenv/conda env)Uninstallpip uninstall prolog_kerneljupyter kernelspec remove prolog_kernelConfigurationThe kernel can be configured by defining a Python config file namedprolog_kernel_config.py. The kernel will look for this file in the Jupyter config path (can be retrieved withjupyter --paths) and the current working directory. Anexampleof such a configuration file with an explanation of the options and their default values commented out can be foundhere.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:jupyter_logging: If set toTrue, the logging level is set to DEBUG by the kernel so thatPython debugging messagesare logged.Note that this way, logging debugging messages can only be enabled after reading a configuration file. Therefore, for instance, the user cannot be informed that no configuration file was loaded if none was defined at one of the expected locations.In order to switch on debugging messages by default, the development installation described in the GitHub repository can be followed and the logging level set toDEBUGin the filekernel.py(which contains a corresponding comment).However, note that this causes messages to be printed in the Jupyter console applications, which interferes with the other output.server_logging: If set toTrue, aProlog server log fileis created.The name of the file consists of the implementation ID preceded by.prolog_server_log_.implementation_id: The ID of theProlog implementationwith which the server is started.In order to use the default SWI- or SICStus Prolog implementation, the IDswiorsicstusis expected respectively.implementation_data: TheProlog implementation-specific datawhich is needed to run the server for code execution.This is required to be a dictionary containing at least an entry for the configuredimplementation_id.Each entry needs to define values forfailure_response: The output which is displayed if a queryfailssuccess_response: The output which is displayed if a querysucceeds without any variable bindingserror_prefix: The prefix that is output forerror messagesinformational_prefix: The prefix that is output forinformational messagesprogram_arguments:Command line argumentswith which the Prolog server can be startedFor SICStus and SWI-Prolog, the default Prolog server provided by the kernel can be used by configuring the string"default".In that case, the following arguments are used (where the file path is extended to be absolute):SWI-Prolog:["swipl", "-l", "prolog_server/jupyter_server.pl", "-t", "jupyter_server_start"]SICStus Prolog:["sicstus", "-l", "prolog_server/jupyter_server.pl", "--goal", "jupyter_server_start;halt.", "--nologo"]Additionally, akernel_implementation_pathcan be provided, which needs to be anabsolute path to a Python file:The corresponding module is required to define a subclass ofPrologKernelBaseImplementationnamedPrologKernelImplementation. This can be used to override some of the kernel's basic behavior (seeOverriding the Kernel Implementation).In addition to configuring the Prolog implementation to be used, the Prolog server implements the predicatejupyter:set_prolog_impl(+PrologImplementationID)tochange the Prolog implementation on the fly. In order for this to work, the configuredimplementation_datadictionary needs to contain data for more than one Prolog implementation.Troubleshooting:In case of SICStus Prolog, if the givenprogram_argumentsare 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 isnot able to log any exceptionand 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 ImplementationThe actual kernel code determining the handling of requests is not implemented by the kernel class itself. Instead, there is the fileprolog_kernel_base_implementation.pywhich defines the classPrologKernelBaseImplementation. 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, aPrologKernelBaseImplementationmethod is called. Bycreating a subclassof this and defining the path to it askernel_implementation_path, theactual implementation code can be replaced.If no such path is defined, the path itself or the defined class is invalid, adefault implementationis used instead. In case of SICStus and SWI-Prolog, the filesswi_kernel_implementation.pyandsicstus_kernel_implementation.pyare used. Otherwise, the base implementation from the fileprolog_kernel_base_implementation.pyis loaded.DevelopmentDevelopment Installgit clone https://github.com/anbre/prolog-jupyter-kernel.gitChange to the root directory of the repositorypip install .Install the kernel specification directory:python -m prolog_kernel.installFor available installation options, seeInstallUpload to PyPIThis kernel is available as a Python package on thePython Package Index. A new version of the package can be published in the following way:Install the requirements build and twine:pip install build twineIncrease the version inpyproject.tomlCreate the distribution files:python -m buildUpload the package to PyPI:twine upload dist/*For further information, see thePackaging Python Projects Tutorial.DebuggingUsually, 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, theProlog 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, ifserver_loggingis configured,messages can be written to a log fileby callinglog/1orlog/2from the modulejupyter_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 byjupyter_query_handling:delete_output_file. If an error occurs during the actual execution, the file cannot be deleted and thus, theoutput 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 codecan be enabled by configuringjupyter_logging. For instance, the client logs the responses received from the server.