The janus API for Prolog Calling
Python
Contents
- Preliminary Definitions
- The Main Predicates To Call Python
- Python Reflection Predicates
- Other
janusPredicates
This chapter describes each predicate in the
janus Prolog calling Python API. Examples are
provided for some of the predicates, many more examples
can be found in Janus Examples for
Prolog Calling Python .
Preliminary Definitions
We introduce some terminology and calling conventions through a short series of examples.
janus GoalTerms
Syntactically, a janus GoalTerm
is either an atom or a compound term. If it is a compound
term, any argument to a goal whose outer functor is
=/2 is treated as a Python keyword argument.
As in Python any keyword argument must occur after all
positional arguments.
If GoalTerm is an atom it corresponds to a attribute call; if it is a compound term it corresponds to function or method call.
janus
GoalTerm Example
py_func(jns_rdflib,rdflib_write_file(Triples,'out.ttl',format=turtle),Return).
calls the Python function
jns_rdflib.rdflib_write_file() to write
Triples, a list of triples in Prolog format,
to the file new_sample.ttl using the RDF
turtle (ttl) format. For the Python function
jns_rdf.rdflib_write_file(),
format is a keyword, and turtle
is an allowed value for that keyword.
Keyword arguments are allowed in
py_call/[2,3,4], py_func/[3,4],
py_dot/[3,4], and
py_iter/[2,3,4].
janus
GoalSequences
janus
GoalSequence: Introductory Example
Consider a file dog.py such as the
following (modified from the Python
documentation)
-------------- -------------- --------------
current_dog = ''
latest_trick = []
class Dog:
tricks = []
def __init__(self, name):
global current_dog
self.name = name
current_dog = name
def add_trick(self, trick):
global latest_trick
self.tricks.append(trick)
latest_trick = trick
return self.tricks
-------------- -------------- --------------
We can interact with this class as follows. Executing the either:
?- py_call(dog:'Dog'('Fido'), MyDog).
or
?- py_func(dog,'Dog'('Fido'), MyDog).
unifies Dog with a reference to the Python
object created by initializing an instance of the
Dog class via: dog.Dog('Fido').
Next, suppose we extend both goals.
?- py_call(dog:'Dog'('Fido'), MyDog),
py_call(MyDog:add_trick(roll_over),Tricks).
and
?- py_func(dog,'Dog'('Fido'), MyDog),
py_dot(MyDog,add_trick(roll_over),Tricks).
both goals not only create the dog MyDog
but add a trick to the repetoire of MyDog and
return the current tricks of MyDog. The
second goal shows in each case illustrates how to make a
method call to a Python object reference.
Suppose that there were no need to retain the dog
object in Prolog, but simply to update the global
variables of the module dog.py The above
conjunctive goal could be rewritten as:
?- py_call(dog:'Dog'('Fido'):add_trick(roll_over), Tricks).
Finally, consider checking one of the attributes of the
module dog. In this case the goals
?- py_call(dog:current_dog,Name)
and
?- py_dot(dog,current_dog,Name)
both unifiy Name with the
dog.current_dog and illustrate how to obtain
an attribute of a Python object reference.
janus
GoalSequence: Definition
Formally, a janus GoalSequence is
defined inductively as:
Target:GoalTerm where
Targetis either an atom corresponding to a Python Module name, or a Python object reference; andGoalTermis defined as in 1.1.GoalSequence:GoalTerm where TargetSequence is a GoalSequence such that
py_call(GoalSequence,Return)unifies
Returnwith an atom corresponding to a module name or a Python object reference.
The Pseudo-Module
builtins
In addition to using Python module names, Python
built-in functions can be called using the “pseudo-module”
builtins. For instance
py_func(builtins, float(’+1E6’),F).
produces the expected result:
F = 1000000.0
The pseudo-module builtins is allowed in
the first argument of py_call/[2,3,4],
py_func/[3,4], py_dot/[3,4], and
epy_iter/[2,3,4].
Python Errors
A python_error is a term of the form:
error(python_error(ErrorType,ErrorValue),OtherInformation)
where - ErrorType is the Python type name
for the exception
type - ErrorValue is a translation into
Prolog of the Python Object associated with the error
The Main Predicates to Call Python
Predicates py_func/3 py_func/4
- py_func(+Module, +Function,
?Return)
- py_func(+Module, +Function, ?Return,
+Options)
Ensures that the Python module Module is
loaded, and calls Module.Function unifying
the return of Function with
Return.
Function is a Goal Term (1.1), while
Module is an atom representing a Python
module. If Module has not already been
loaded, it will be automatically loaded during the call.
Python modules are searched for in the paths maintained in
Python’s sys.path list; these Python paths
can be queried from Prolog via py_lib_dir/1
and modified via py_add_lib_dir/1.
Prolog Options
py_object(true) This option returns most
Python data structures as object references, so that
attributes of those data structures can be queried if
needed. The only data not returned as object
references are
Objects of
booleantypeObjects of
nonetypeObjects of exactly the class
long,floatorstring. Objects that are proper subclasses of these types are returned as object references.
Error Cases
py_func/4is called withModule,FunctionorOptionsuninstantiatedinstantiation_error
Moduleis not a Prolog atom:type_error
Modulecannot be found in the current Python search paths or is otherwise unloadable:python_error
Functionis not a callable termtype_error
Functiondoes not correspond to a Python function inModuleor is otherwise uncallablepython_error
Optionscontains an improper element or combination of elementsdomain_error
Functioncontains a Prolog term that cannot be translated into Python:domain_error
Any other error thrown by Python during the call should
be caught and thrown as a Prolog
python_error
Predicates py_dot/3, py_dot/4
- py_dot(+Target, +MethAttr,
?Return)
- py_dot(+Target, +MethAttr, ?Return,
+Options)
Applies a method to Target or obtains an
attribute value for Target. More
specifically, Target is a either Python
object reference or an atom representing a Python module.
MethAttris a Goal Term (1.1) that can either
be a Prolog compound term or a Prolog atom:
If
MethAttris a Prolog compound term corresponding to a Python method forTarget, the method is called and its return unified withReturn.If
MethAttris a Prolog atom corresponding to the name of an attribute ofTarget, the attribute value (forTarget) is accessed and unified withReturn.
Options is as described for
py_func/[3,4] (2.1)
Error Cases
py_dot/4is called withTarget,MethAttrorOptionsuninstantiated:instantiation_error
Targetis not a Prolog atom or Python object referencetype_error
MethAttris not a callable term or atom.type_error
MethAttrdoes not correspond to a Python method or attribute forTargetpython_error
Optionscontains an improper element, or combination of elements.domain_error
MethAttrcontains a Prolog term that cannot be translated into Python:domain_error
Any other error thrown by Python during the call should
be caught and thrown as a Prolog
python_error.
Predicate py_setattr/3
- py_setattr(+Target, +Attr,
+Value)
If Target is a module or an object, this
command is equivalent to the Python
setattr(Target, Attr, Value)
or in Prolog
py_setattr(Target, Name, Value) :-
py_call(Target, Obj, [py_object(true)]),
py_call(setattr(Obj, Name, Value)).
Error Cases
py_setattr/3is called withTarget,AttrorValueuninstantiated:instantiation_error
Targetis not a Python object reference or Prolog atomtype_error
Nameis not an atom.type_error
Valuecontains a Prolog term that cannot be translated into Python:domain_error
Any other error thrown by Python during the call should
be caught and thrown as a Prolog
python_error.
Predicates py_iter/2, py_iter/3
- py_iter(+Iterator, ?Value)
- py_iter(+Iterator,
?Value,+Options)
In py_iter/[2,3] Iterator can
either be a reference to a Python iterator object or a
janus GoalSequene (1.2) that
produces a reference to a Python iterator object. In
either case, the first value of the iterator will be
returned by the goal and subsequence values returned via
backtracking (cf. Example <a href=“#jns-examp:lazy-ret”
data-reference-type=“ref” py_iter/[2,3] when
there are no values left for Iterator.
Options are as described in
py_func/[3,4]
Examples
The example below uses the built-in iterator
range():
?- py_iter(range(1,3), X). X = 1 ; X = 2.
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
Error Cases
py_iter/[2,3]is called withIteratornonground orOptionsuninstantiatedinstantiation_error
- The GoalSequence
Iteratorcontains a goalTarget:GoalTermwhereTargetis neither a Prolog atom nor a reference to a Python iterator object:type_error
Targetis an atom representing a Python module that cannot be found in the current Python search paths or is otherwise unloadable:python_error
GoalTermis neither a callable term nor an atomtype_error
Functiondoes not correspond to a Python function inModuleor is otherwise uncallablepython_error
GoalTermcontains a Prolog term that cannot be translated into Python:domain_error
Optionscontains an improper element, or combination of elementsdomain_error
Predicates py_call/1, py_call/2, py_call/3
- py_call(+GoalSequence)
- py_call(+GoalSequence,
?Return)
- py_call(+GoalSequence, ?Return,
+Options)
Execute GoalSequence in Python and and
unify the result with Return (in
py_call/[2,3]). GoalSequence is
a janus GoalSequence as described in
1.2. Options is as described for
py_func/[3,4]
Error Cases
py_call/[2,3,4]is called with a nongroundGoalSequeneorOptionsuninstantiatedinstantiation_error
GoalSequencecontains a goalTarget:GoalTermwhereTargetis neither a Prolog atom nor a reference to a Python object:type_error
Targetis an atom representing a Python module that cannot be found in the current Python search paths or is otherwise unloadable:python_error
GoalTermis neither a callable term nor an atomtype_error
Functiondoes not correspond to a Python function inModuleor is otherwise uncallablepython_error
GoalTermcontains a Prolog term that cannot be translated into Python:domain_error
Optionscontains an improper element, or combination of elementsdomain_error
Python Reflection Predicates
Predicate py_type/2
py_type(+ObjRef, ?Type)
True when theTypeunifies with the name of the type ofObjRefrepresented as a Prolog atom. This is the same astype(ObjRef).__name__
in Python.
Error Cases
-
py_type/2 is called with a nonground
ObjRef - instantiation_error -
py_type/2is called withTypeneither a variable nor an atom -type_error`
Predicate py_isinstance/2
- py_isinstance(+ObjRef, +Type)
True ifObjRefis an instance ofTypeor an instance of one of the sub types ofType. This is the same asisinstance(ObjRef)in Python.Typemust be instantiated either to a termModule:Typeor to an atom to refer to a built-in type.
Error Cases
- ObjRef
or Type is uninstantiaed at call -
instantiation_error - ObjRef is not a Python
object reference, or Type is not an atom -
type_error
Predicate py_module_exists/1
py_module_exists(+Module)
True if the atomModuleis a module loaded into Python or loadable into Python. The predicate calls the Pythonimportlib.util.find_spec(Module)
Error Cases
- Module
is uninstantiaed at call - instantiation_error - `Module
is not an atom - type_error
Other janus
predicates
Predicate py_is_object/1
- py_is_object(+ObjRef)
Succeeds ifObjRefis a Python object reference and fails otherwise. Different Prologs that implement Janus will have different representations of Python object references, so this predicate should be used to determine whether a term is a Python object reference.
Predicate py_free/1
- py_free(+ObjRef)
In general when janus bi-translates
between Python objects and Prolog terms it performs a
copy: this has the advantage that each system can perform
its own memory management independently of the other. The
exception is when a reference to a Python object is passed
to Prolog. In this case, Python must explicitly be told
that the Python object can be reclaimed, and this is done
through py_free/1.
Calling py_free(ObjRef) causes Python to
decrement the reference count of ObjRef. This
may not actually delete the object because the object may
have references inside Python.
On some implementations, reclaiming references from
Prolog to Python objects is done by the Prolog garbage
collector. For portability, py_free/1 must be
called exactly once on each object reference
obtained from Python. Further usage of the object
reference may cause undefined behavior.
Predicates py_pp/1, py_pp/2, py_pp/3
- py_pp(+Stream,
+Term,+Options)
- py_pp(+Stream, +Term)
- py_pp(+Term)
Pretty prints a janus Python term
Term to . The implementation and behavior of
these predicates are system-dependent.
Common Error Cases
Stream.TermorOptionsis not instantiated- instantiation_error
- Stream_or_alias is neither a variable, a stream term,
nor an alias; or
Optionscontains an improper elementdomain_error
Predicates
py_add_lib_dir/1, py_add_lib_dir/2
py_add_lib_dir(+Dir)
py_add_lib_dir(+Dir, +Where)
Add a directory to the Python module search path (
sys.path). In the second form,Whereis one offirstorlast.py_add_lib_dir/1adds the directory aslast. The propertysys:pathis not modified if it already containsDir.
Error Cases
DirorWhereis uninstantiated at call- instantiation error
DirorWhereare not instantiated to an atom- type error
Whereis notfirstorlast- domain_error
Predicate py_lib_dirs/1
- py_lib_dirs(?Path)
This convenience and compatibility predicate unifies
Path with a list of the current Python
library directories as obtained from
sys.path. There are no associated error
cases.
Predicate values/3
values(+Dict, +Path, ?Val)
Convenience and compatibility predicate to obtain a value from a (possibly nested)janusdictionary term . The goalvalues(D,key1,V)
is equivalent to the Python expression
D[key1] while
values(D,[key1,key2,key3],V)
is equivalent to the Python expression
D[key1][key2][key3]
There are no error conditions associated with this predicate.
Predicates items/2, key/2, keys/2
These convenience predicates provide a Prolog equivalent of some of Python’s dictionary access routines.
keys(+Dict, ?Keys)
True when
Keysis a list of keys that appear inDict.key(+Dict, ?Key)
True when
Keyis a key inDict. Backtracking enumerates all known keys.items(+Dict, ?Items)
True when
Itemsis a list ofKey:Valuemappings that appear inDict.

