Problem with unicode characters (e.g. →) in prolog file on swiplserver

I have some simple prolog file logic.pl introducing some operator with unicode characters:

:-op(803, xfy, →).

binary_connective(X  → Y, X, Y).

The problem now is, that my python query does not work on that operator:

from swiplserver import PrologMQI, PrologThread

with PrologMQI() as mqi:
    with mqi.create_thread() as prolog_thread:
    	prolog_thread.query(f"consult('logic.pl').")
    	prolog_thread.query_async("binary_connective(p  → q, X, Y).",
                                  find_all=False)
    	while True:
    		result = prolog_thread.query_async_result()
    		if result is None:
    			break
    		else:
    			print(result)

If I change → in – it gives me some working result.

Is their some way to solve this in swiplserver libary?

I also made some post on this site (Problem with unicode characters (e.g. →) in prolog file · Issue #14 · SWI-Prolog/packages-mqi · GitHub)

What is the error you see when you run the query from Python?

Also: Does it work if you run it from the top level (it should (almost) always work the same if you are using the MQI library)? I.e.:

?- consult('logic.pl').
true

?- binary_connective(p  → q, X, Y).
????

Edit: If I try putting your code, exactly as you have it above, in a logic.pl file and consulting it, I get the following error. I may have missed some magic unicode incantation though, I haven’t done anything with unicode and SWI Prolog before:

ERROR: logic.pl:1:17: Syntax error: illegal_character
ERROR: logic.pl:3:21: Syntax error: Operator expected
true.

Hello,
thank you for your response. I don’t get some error if I put the predicate directly into swipl with
SWI-Prolog version 8.2.4 for x86_64-linux.

My prolog file simply contains the following content

:-op(803, xfy, →).

binary_connective(X  → Y, X, Y).

My output in swipl is:

?- consult('logic.pl').
true.

?- binary_connective(p → q, X, Y).
X = p,
Y = q.

I also tested it on https://swish.swi-prolog.org/ and it worked exactly the same.

If I run the query from Python I don’t get some error. It seems the program stucks at some point in some endless loop.

How can I run the program from toplevel? Did you mean use:

from swiplserver import PrologServer, PrologThread

with PrologServer() as server:
    with server.create_thread() as prolog_thread:
        prolog_thread.query("consult('logic.pl').")
        result = prolog_thread.query("binary_connective(p → q, X, Y).")
        print(result)

This doesn’t work, cause of error
ImportError: cannot import name ‘PrologServer’ from ‘swiplserver’ (/home/~/.local/lib/python3.9/site-packages/swiplserver/init.py)

It seams the __init__.py looks like this:

from swiplserver.prologmqi import (
    PrologMQI,
    PrologThread,
    PrologError,
    PrologLaunchError,
    PrologQueryTimeoutError,
    PrologQueryCancelledError,
    PrologConnectionFailedError,
    PrologResultNotAvailableError,
    PrologNoQueryError,
    is_prolog_variable,
    is_prolog_list,
    is_prolog_functor,
    is_prolog_atom,
    create_posix_path,
    prolog_name,
    prolog_args,
    quote_prolog_identifier,
    json_to_prolog,
)

# make "from swiplserver import *" work
__all__ = [
    "PrologLaunchError",
    "PrologQueryTimeoutError",
    "PrologQueryCancelledError",
    "PrologConnectionFailedError",
    "PrologResultNotAvailableError",
    "PrologNoQueryError",
    "PrologError",
    "PrologMQI",
    "PrologThread",
    "create_posix_path",
    "is_prolog_functor",
    "is_prolog_list",
    "is_prolog_variable",
    "is_prolog_atom",
    "prolog_name",
    "prolog_args",
    "quote_prolog_identifier",
    "json_to_prolog",
]

I am able to replicate the hang you are hitting on my mac if I do the below. On my mac, at least, I need to set the Prolog encoding to utf8 in order to load the logic.pl file properly:

with PrologMQI() as mqi:
	with mqi.create_thread() as prolog_thread:
		prolog_thread.query(f"set_prolog_flag(encoding,utf8).")
		prolog_thread.query(f"consult('logic.pl').")
		unicode = "binary_connective(p → q, X, Y)."
		prolog_thread.query(unicode)

The problem is a bug in the swiplserver library that sends the wrong count of characters to Prolog. I was able to fix the hang with the below change to the prologmqip.py file that is part of the library. I need to do some more research to make sure this is a good overall fix but I think it should unblock you for the moment. I’ll post when I have the final fix.

    def _send(self, value):
        value = value.strip()
        value = value.rstrip("\n.")
        value += ".\n"
        _log.debug("PrologMQI send: %s", value)
        utf8Value = value.encode("utf-8")

        # Comment out this line:
        # msgHeader = f"{str(len(utf8Value))}.\n".encode("utf-8")

        # Replace with this line:
        msgHeader = f"{str(len(value))}.\n".encode("utf-8")

        self._socket.sendall(msgHeader)
        self._socket.sendall(utf8Value)

Thank you, with that replacement it seems to be correct for me too.

I have submitted a more comprehensive fix to both the server and the Python client, but the client fix is basically what I posted above, the submitted fix just works against the existing MQI interface and the new fixed one. It also includes a really simple protocol versioning “feature” to more robustly handle versioning issues going forward.

I’ll push the Python library 1.0.2 to pypi.org early next week.

Thanks! Updated the git submodule.

Thank you I have closed the GitHub issue.

Thanks! You can now pip install swiplserver and get the latest version (1.0.2) with the above fix in it.