
janus.pl -- Call Python from Prolog
This library implements calling Python from Prolog. It is available
directly from Prolog if the janus package is bundled, providing access
to an embedded Python instance. If SWI-Prolog is embedded into Python
using the Python package janus-swi, this library is provided either
from Prolog or from the Python package.
Normally, the Prolog user can simply start calling Python using py_call/2 or friends. In special cases it may be needed to initialize Python with options using py_initialize/3 and optionally the Python search path may be extended using py_add_lib_dir/1.
py_version is det- Print version info on the embedded Python installation based on
Python
sys.version. If a Python virtual environment (venv) is active, indicate this with the location of this environment found.
py_call(+Call) is det
py_call(+Call, -Return) is det
py_call(+Call, -Return, +Options) is det- Call Python and return the result of the called function. Call has
the shape `[Target][:Action]*`, where Target is either a Python
module name or a Python object reference. Each Action is either an
atom to get the denoted attribute from current Target or it is a
compound term where the first argument is the function or method
name and the arguments provide the parameters to the Python
function. On success, the returned Python object is translated to
Prolog. Action without a Target denotes a buit-in function.
Arguments to Python functions use the Python conventions. Both positional and keyword arguments are supported. Keyword arguments are written as
Name = Valueand must appear after the positional arguments.Below are some examples.
% call a built-in ?- py_call(print("Hello World!\n")). true. % call a built-in (alternative) ?- py_call(builtins:print("Hello World!\n")). true. % call function in a module ?- py_call(sys:getsizeof([1,2,3]), Size). Size = 80. % call function on an attribute of a module ?- py_call(sys:path:append("/home/bob/janus")). true % get attribute from a module ?- py_call(sys:path, Path) Path = ["dir1", "dir2", ...]Given a class in a file
dog.pysuch as the following example from the Python documentationclass Dog: tricks = [] def __init__(self, name): self.name = name def add_trick(self, trick): self.tricks.append(trick)We can interact with this class as below. Note that
$Docin the SWI-Prolog toplevel refers to the last toplevel binding for the variable Dog.?- py_call(dog:'Dog'("Fido"), Dog). Dog = <py_Dog>(0x7f095c9d02e0). ?- py_call($Dog:add_trick("roll_over")). Dog = <py_Dog>(0x7f095c9d02e0). ?- py_call($Dog:tricks, Tricks). Dog = <py_Dog>(0x7f095c9d02e0), Tricks = ["roll_over"]py_call/1 can also be used to set an attribute on a module or object using the syntax
py_call(Obj:Attr = Value). For example:?- py_call(dog:'Dog'("Fido"), Dog), py_call(Dog:owner = "Bob"), py_call(Doc:owner, Owner). Dog = <py_Dog>(0x7ffff7112170), Owner = "Bob".If the principal term of the first argument is not
Target:Func, The argument is evaluated as the initial target, i.e., it must be an object reference or a module. For example:?- py_call(dog:'Dog'("Fido"), Dog), py_call(Dog, X). Dog = X, X = <py_Dog>(0x7fa8cbd12050). ?- py_call(sys, S). S = <py_module>(0x7fa8cd582390).Options processed:
- py_string_as(+Type)
- If Type is
atom(default), translate a Python String into a Prolog atom. If Type isstring, translate into a Prolog string. Strings are more efficient if they are short lived. - py_object(Boolean)
- If
true(defaultfalse), translate the return as a Python object reference. Some objects are always translated to Prolog, regardless of this flag. These are the Python constantsNone,TrueandFalseas well as instances of the Python base classes long, float, string or tuple. Instances of sub classes of these base classes are controlled by this option.
py_iter(+Iterator, -Value) is nondet
py_iter(+Iterator, -Value, +Options) is nondet- True when Value is returned by the Python Iterator. Python iterators
may be used to implement non-deterministic foreign predicates. The
implementation uses these steps:
- Evaluate Iterator as py_call/2 evaluates its first argument,
except the
Obj:Attr = Valueconstruct is not accepted. - Call
__iter__on the result to get the iterator itself. - Get the
__next__function of the iterator. - Loop over the return values of the next function. If the Python return value unifies with Value, succeed with a choicepoint. Abort on Python or unification exceptions.
- Re-satisfaction continues at (4).
The example below uses the built-in iterator
range():?- py_iter(range(1,3), X). X = 1 ; X = 2.
Note that the implementation performs a look ahead, i.e., after successful unification it calls `__next__()` again. On failure the Prolog predicate succeeds deterministically. On success, the next candidate is stored.
Note that a Python generator is a Python _iterator. Therefore, given the Python generator expression below, we can use
py_iter(squares(1,5),X)to generate the squares on backtracking.def squares(start, stop): for i in range(start, stop): yield i * i - Evaluate Iterator as py_call/2 evaluates its first argument,
except the
py_run(+String, +Globals, +Locals, -Result, +Options) is det[private]- Interface to Py_CompileString() followed by PyEval_EvalCode().
Options:
- file_name(String)
- Errors are reported against this pseudo file name
- start(Token)
- One of
eval,file(default) orsingle.
py_is_object(@Term) is semidet- True when Term is a Python object reference. Fails silently if @Term is any other Prolog term.
py_free(+Obj) is det- Immediately free (decrement the reference count) for th Python
object Obj. Further reference to Obj using py_call/1,2 or py_free/1
raises an
existence_error. Note that by decrementing the reference count, we make the reference invalid from Prolog. This may not actually delete the object because the object may have references inside Python.Prolog references to Python objects are subject to atom garbage collection and thus normally do not need to be freed explicitly.
py_with_gil(:Goal) is semidet- Run Goal as
once(Goal)while holding the Phyton GIL (Global Interpreter Lock). Note that py_call/1,2 also locks the GIL. This predicate is only required if we wish to make multiple calls to Python while keeping the GIL. The GIL is a recursive lock and thus calling py_call/1,2 while holding the GIL does not deadlock.
py_func(+Module, +Function, -Return) is det
py_func(+Module, +Function, -Return, +Options) is det- XSB compatible wrappers for py_call/2. Note that the wrapper
supports more call patterns. Options
- sizecheck(+Boolean)
- Used by XSB for memory management. Ignored in SWI-Prolog.
- py_object(+Boolean)
- Passed to py_call/3.
py_dot(+Module, +ObjRef, +MethAttr, -Ret) is det
py_dot(+Module, +ObjRef, +MethAttr, -Ret, +Options) is det- XSB compatible wrappers for py_call/2.
values(+Dict, +Path, ?Val) is semidet- Get the value associated with Dict at Path. Path is either a single key or a list of keys.
keys(+Dict, ?Keys) is det- True when Keys is a list of keys that appear in Dict.
key(+Dict, ?Key) is nondet- True when Key is a key in Dict. Backtracking enumerates all known keys.
items(+Dict, ?Items) is det- True when Items is a list of Key:Value that appear in Dict.
py_shell- Start an interactive Python REPL loop using the embedded Python
interpreter. The interpreter first imports
janusas below.from janus import *
So, we can do
?- py_shell. ... >>> once("writeln(X)", {"X":"Hello world"}) Hello world {'truth': True}If possible, we enable command line editing using the GNU readline library.
When used in an environment where Prolog does not use the file handles 0,1,2 for the standard streams, e.g., in
swipl-win, Python's I/O is rebound to use Prolog's I/O. This includes Prolog's command line editor, resulting in a mixed history of Prolog and Pythin commands.
py_pp(+Term) is det
py_pp(+Term, +Options) is det
py_pp(+Stream, +Term, +Options) is det- Pretty prints the Prolog translation of a Python data structure in
Python syntax. This exploits
pformat()from the Python modulepprintto do the actual formatting. Options is translated into keyword arguments passed to pprint.pformat(). For example:?- py_pp(py{a:1, l:[1,2,3], size:1000000}, [underscore_numbers(true)]). {'a': 1, 'l': [1, 2, 3], 'size': 1_000_000}
py_obj_dir(+ObjRef, -List) is det
py_obj_dict(+ObjRef, -Dict) is det- Examine attributes of an object. The predicate py_obj_dir/2 fetches the names of all attributes, while py_obj_dict/2 gets a dict with all attributes and their values.
py_initialize(+Program, +Argv, +Options) is det- Initialize and configure the embedded Python system. If this
predicate is not called before any other call to Python such as
py_call/2, it is called lazily, passing the Prolog executable as
Program, the non-Prolog arguments as Argv and an empty Options
list.
Calling this predicate while the Python is already initialized is a no-op. This predicate is thread-safe, where the first thread initializes Python.
In addition to initializing the Python system, it
- Adds the directory holding
janus.pyto the Python module search path. - If Prolog I/O is not connected to the file handles 0,1,2, it rebinds Python I/O to use the Prolog I/O.
- Adds the directory holding
py_connect_io is det[private]- If SWI-Prolog console streams are bound to something non-standard, bind the Python console I/O to our streans.
py_lib_dirs(-Dirs) is det- True when Dirs is a list of directories searched for Python modules. The elements of Dirs are in Prolog canonical notation.
py_add_lib_dir(+Dir) is det
py_add_lib_dir(+Dir, +Where) is det- Add a directory to the Python module search path. In the second
form, Where is one of
firstorlast. py_add_lib_dir/1 adds the directory as last.Dir is in Prolog notation. The added directory is converted to an absolute path using the OS notation.
A flexible way to add the directory holding the current Prolog file to the Python search path is in the template below. The here/0 predicate can be replaced by any predicate defined in the file, either above or below the initializing/1 directive. A simple name like here/0 is good style when this code is part of a Prolog module.
here. :- initialization ( source_file(here, File), file_directory_name(File, Dir), py_add_lib_dir(Dir, first) ).
Re-exported predicates
The following predicates are exported from this file while their implementation is defined in imported modules or non-module files loaded by this module.
py_iter(+Iterator, -Value) is nondet
py_iter(+Iterator, -Value, +Options) is nondet- True when Value is returned by the Python Iterator. Python iterators
may be used to implement non-deterministic foreign predicates. The
implementation uses these steps:
- Evaluate Iterator as py_call/2 evaluates its first argument,
except the
Obj:Attr = Valueconstruct is not accepted. - Call
__iter__on the result to get the iterator itself. - Get the
__next__function of the iterator. - Loop over the return values of the next function. If the Python return value unifies with Value, succeed with a choicepoint. Abort on Python or unification exceptions.
- Re-satisfaction continues at (4).
The example below uses the built-in iterator
range():?- py_iter(range(1,3), X). X = 1 ; X = 2.
Note that the implementation performs a look ahead, i.e., after successful unification it calls `__next__()` again. On failure the Prolog predicate succeeds deterministically. On success, the next candidate is stored.
Note that a Python generator is a Python _iterator. Therefore, given the Python generator expression below, we can use
py_iter(squares(1,5),X)to generate the squares on backtracking.def squares(start, stop): for i in range(start, stop): yield i * i - Evaluate Iterator as py_call/2 evaluates its first argument,
except the
py_call(+Call) is det
py_call(+Call, -Return) is det
py_call(+Call, -Return, +Options) is det- Call Python and return the result of the called function. Call has
the shape `[Target][:Action]*`, where Target is either a Python
module name or a Python object reference. Each Action is either an
atom to get the denoted attribute from current Target or it is a
compound term where the first argument is the function or method
name and the arguments provide the parameters to the Python
function. On success, the returned Python object is translated to
Prolog. Action without a Target denotes a buit-in function.
Arguments to Python functions use the Python conventions. Both positional and keyword arguments are supported. Keyword arguments are written as
Name = Valueand must appear after the positional arguments.Below are some examples.
% call a built-in ?- py_call(print("Hello World!\n")). true. % call a built-in (alternative) ?- py_call(builtins:print("Hello World!\n")). true. % call function in a module ?- py_call(sys:getsizeof([1,2,3]), Size). Size = 80. % call function on an attribute of a module ?- py_call(sys:path:append("/home/bob/janus")). true % get attribute from a module ?- py_call(sys:path, Path) Path = ["dir1", "dir2", ...]Given a class in a file
dog.pysuch as the following example from the Python documentationclass Dog: tricks = [] def __init__(self, name): self.name = name def add_trick(self, trick): self.tricks.append(trick)We can interact with this class as below. Note that
$Docin the SWI-Prolog toplevel refers to the last toplevel binding for the variable Dog.?- py_call(dog:'Dog'("Fido"), Dog). Dog = <py_Dog>(0x7f095c9d02e0). ?- py_call($Dog:add_trick("roll_over")). Dog = <py_Dog>(0x7f095c9d02e0). ?- py_call($Dog:tricks, Tricks). Dog = <py_Dog>(0x7f095c9d02e0), Tricks = ["roll_over"]py_call/1 can also be used to set an attribute on a module or object using the syntax
py_call(Obj:Attr = Value). For example:?- py_call(dog:'Dog'("Fido"), Dog), py_call(Dog:owner = "Bob"), py_call(Doc:owner, Owner). Dog = <py_Dog>(0x7ffff7112170), Owner = "Bob".If the principal term of the first argument is not
Target:Func, The argument is evaluated as the initial target, i.e., it must be an object reference or a module. For example:?- py_call(dog:'Dog'("Fido"), Dog), py_call(Dog, X). Dog = X, X = <py_Dog>(0x7fa8cbd12050). ?- py_call(sys, S). S = <py_module>(0x7fa8cd582390).Options processed:
- py_string_as(+Type)
- If Type is
atom(default), translate a Python String into a Prolog atom. If Type isstring, translate into a Prolog string. Strings are more efficient if they are short lived. - py_object(Boolean)
- If
true(defaultfalse), translate the return as a Python object reference. Some objects are always translated to Prolog, regardless of this flag. These are the Python constantsNone,TrueandFalseas well as instances of the Python base classes long, float, string or tuple. Instances of sub classes of these base classes are controlled by this option.
py_call(+Call) is det
py_call(+Call, -Return) is det
py_call(+Call, -Return, +Options) is det- Call Python and return the result of the called function. Call has
the shape `[Target][:Action]*`, where Target is either a Python
module name or a Python object reference. Each Action is either an
atom to get the denoted attribute from current Target or it is a
compound term where the first argument is the function or method
name and the arguments provide the parameters to the Python
function. On success, the returned Python object is translated to
Prolog. Action without a Target denotes a buit-in function.
Arguments to Python functions use the Python conventions. Both positional and keyword arguments are supported. Keyword arguments are written as
Name = Valueand must appear after the positional arguments.Below are some examples.
% call a built-in ?- py_call(print("Hello World!\n")). true. % call a built-in (alternative) ?- py_call(builtins:print("Hello World!\n")). true. % call function in a module ?- py_call(sys:getsizeof([1,2,3]), Size). Size = 80. % call function on an attribute of a module ?- py_call(sys:path:append("/home/bob/janus")). true % get attribute from a module ?- py_call(sys:path, Path) Path = ["dir1", "dir2", ...]Given a class in a file
dog.pysuch as the following example from the Python documentationclass Dog: tricks = [] def __init__(self, name): self.name = name def add_trick(self, trick): self.tricks.append(trick)We can interact with this class as below. Note that
$Docin the SWI-Prolog toplevel refers to the last toplevel binding for the variable Dog.?- py_call(dog:'Dog'("Fido"), Dog). Dog = <py_Dog>(0x7f095c9d02e0). ?- py_call($Dog:add_trick("roll_over")). Dog = <py_Dog>(0x7f095c9d02e0). ?- py_call($Dog:tricks, Tricks). Dog = <py_Dog>(0x7f095c9d02e0), Tricks = ["roll_over"]py_call/1 can also be used to set an attribute on a module or object using the syntax
py_call(Obj:Attr = Value). For example:?- py_call(dog:'Dog'("Fido"), Dog), py_call(Dog:owner = "Bob"), py_call(Doc:owner, Owner). Dog = <py_Dog>(0x7ffff7112170), Owner = "Bob".If the principal term of the first argument is not
Target:Func, The argument is evaluated as the initial target, i.e., it must be an object reference or a module. For example:?- py_call(dog:'Dog'("Fido"), Dog), py_call(Dog, X). Dog = X, X = <py_Dog>(0x7fa8cbd12050). ?- py_call(sys, S). S = <py_module>(0x7fa8cd582390).Options processed:
- py_string_as(+Type)
- If Type is
atom(default), translate a Python String into a Prolog atom. If Type isstring, translate into a Prolog string. Strings are more efficient if they are short lived. - py_object(Boolean)
- If
true(defaultfalse), translate the return as a Python object reference. Some objects are always translated to Prolog, regardless of this flag. These are the Python constantsNone,TrueandFalseas well as instances of the Python base classes long, float, string or tuple. Instances of sub classes of these base classes are controlled by this option.
py_func(+Module, +Function, -Return) is det
py_func(+Module, +Function, -Return, +Options) is det- XSB compatible wrappers for py_call/2. Note that the wrapper
supports more call patterns. Options
- sizecheck(+Boolean)
- Used by XSB for memory management. Ignored in SWI-Prolog.
- py_object(+Boolean)
- Passed to py_call/3.
py_add_lib_dir(+Dir) is det
py_add_lib_dir(+Dir, +Where) is det- Add a directory to the Python module search path. In the second
form, Where is one of
firstorlast. py_add_lib_dir/1 adds the directory as last.Dir is in Prolog notation. The added directory is converted to an absolute path using the OS notation.
A flexible way to add the directory holding the current Prolog file to the Python search path is in the template below. The here/0 predicate can be replaced by any predicate defined in the file, either above or below the initializing/1 directive. A simple name like here/0 is good style when this code is part of a Prolog module.
here. :- initialization ( source_file(here, File), file_directory_name(File, Dir), py_add_lib_dir(Dir, first) ).
py_obj_dir(+ObjRef, -List) is det
py_obj_dict(+ObjRef, -Dict) is det- Examine attributes of an object. The predicate py_obj_dir/2 fetches the names of all attributes, while py_obj_dict/2 gets a dict with all attributes and their values.
py_dot(+Module, +ObjRef, +MethAttr, -Ret) is det
py_dot(+Module, +ObjRef, +MethAttr, -Ret, +Options) is det- XSB compatible wrappers for py_call/2.
py_pp(+Term) is det
py_pp(+Term, +Options) is det
py_pp(+Stream, +Term, +Options) is det- Pretty prints the Prolog translation of a Python data structure in
Python syntax. This exploits
pformat()from the Python modulepprintto do the actual formatting. Options is translated into keyword arguments passed to pprint.pformat(). For example:?- py_pp(py{a:1, l:[1,2,3], size:1000000}, [underscore_numbers(true)]). {'a': 1, 'l': [1, 2, 3], 'size': 1_000_000}
py_pp(+Term) is det
py_pp(+Term, +Options) is det
py_pp(+Stream, +Term, +Options) is det- Pretty prints the Prolog translation of a Python data structure in
Python syntax. This exploits
pformat()from the Python modulepprintto do the actual formatting. Options is translated into keyword arguments passed to pprint.pformat(). For example:?- py_pp(py{a:1, l:[1,2,3], size:1000000}, [underscore_numbers(true)]). {'a': 1, 'l': [1, 2, 3], 'size': 1_000_000}