Files
gnatcoll-bindings/python3/gnatcoll-scripts-python.adb
Nicolas Roche e259adfecb Fix issue with binding of the interpreter lifecycle functions
* Py_SetProgramName expect a *wchar_t
* Py_SetPythonhome expect a *wchar_t
* Py_Main except decoded arguments as  *wchar_t
* Expose function Py_DecodeLocale

Part of T518-013

Change-Id: I3ad1df239203ecf70e5de7dfe78aed202cd21666
2020-05-22 16:05:10 +00:00

4786 lines
137 KiB
Ada

------------------------------------------------------------------------------
-- G N A T C O L L --
-- --
-- Copyright (C) 2003-2020, AdaCore --
-- --
-- This library is free software; you can redistribute it and/or modify it --
-- under terms of the GNU General Public License as published by the Free --
-- Software Foundation; either version 3, or (at your option) any later --
-- version. This library is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
-- --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception, --
-- version 3.1, as published by the Free Software Foundation. --
-- --
-- You should have received a copy of the GNU General Public License and --
-- a copy of the GCC Runtime Library Exception along with this program; --
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
-- <http://www.gnu.org/licenses/>. --
-- --
------------------------------------------------------------------------------
with Ada.Characters.Handling; use Ada.Characters.Handling;
with Ada.Exceptions; use Ada.Exceptions;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Unchecked_Conversion;
with Ada.Unchecked_Deallocation;
with Interfaces.C.Strings; use Interfaces.C, Interfaces.C.Strings;
with GNAT.IO; use GNAT.IO;
with GNAT.Strings; use GNAT.Strings;
with GNATCOLL.Any_Types.Python;
with GNATCOLL.Python.Lifecycle;
with GNATCOLL.Scripts.Impl; use GNATCOLL.Scripts, GNATCOLL.Scripts.Impl;
with GNATCOLL.Traces; use GNATCOLL.Traces;
with System; use System;
with System.Storage_Elements; use System.Storage_Elements;
package body GNATCOLL.Scripts.Python is
package Lifecycle renames GNATCOLL.Python.Lifecycle;
Me : constant Trace_Handle := Create ("PYTHON");
Me_Error : constant Trace_Handle := Create ("PYTHON.ERROR", On);
Me_Stack : constant Trace_Handle := Create ("PYTHON.TB", Off);
Me_Log : constant Trace_Handle := Create ("SCRIPTS.LOG", Off);
Me_Crash : constant Trace_Handle := Create ("PYTHON.TRACECRASH", On);
Finalized : Boolean := True;
-- Whether Python has been finalized (or never initialized).
function Ada_Py_Builtin return Interfaces.C.Strings.chars_ptr;
pragma Import (C, Ada_Py_Builtin, "ada_py_builtin");
function Ada_Py_Builtins return Interfaces.C.Strings.chars_ptr;
pragma Import (C, Ada_Py_Builtins, "ada_py_builtins");
function Ada_Is_Python3 return Integer;
pragma Import (C, Ada_Is_Python3, "ada_is_python3");
Is_Python3 : constant Boolean := Ada_Is_Python3 = 1;
Builtin_Name : constant String := Value (Ada_Py_Builtin);
Builtins_Name : constant String := Value (Ada_Py_Builtins);
procedure Set_Item (Args : PyObject; T : Integer; Item : PyObject);
-- Change the T-th item in Args.
-- This increases the refcount of Item
procedure Name_Parameters
(Data : in out Python_Callback_Data; Params : Param_Array);
-- Internal version of Name_Parameters
type Property_User_Data_Record is record
Script : Python_Scripting;
Prop : Property_Descr_Access;
end record;
type Property_User_Data is access all Property_User_Data_Record;
function Convert is new Ada.Unchecked_Conversion
(System.Address, Property_User_Data);
function Convert is new Ada.Unchecked_Conversion
(Property_User_Data, System.Address);
-- Subprograms needed to support the user data passed to the Property
-- setters and getters
procedure Run_Callback
(Script : Python_Scripting;
Cmd : Module_Command_Function;
Command : String;
Data : in out Python_Callback_Data'Class;
Result : out PyObject);
-- Return Cmd and pass (Data, Command) parameters to it.
-- This properly handles returned value, exceptions and python errors.
-- This also freed the memory used by Data
------------------------
-- Python_Subprograms --
------------------------
type Python_Subprogram_Record is new Subprogram_Record with record
Script : Python_Scripting;
Subprogram : PyObject;
end record;
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return Boolean;
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return String;
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return Any_Type;
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return Class_Instance;
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean)
return GNAT.Strings.String_List;
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return List_Instance'Class;
overriding procedure Free (Subprogram : in out Python_Subprogram_Record);
overriding function Get_Name
(Subprogram : access Python_Subprogram_Record) return String;
overriding function Get_Script
(Subprogram : Python_Subprogram_Record) return Scripting_Language;
-- See doc from inherited subprograms
--------------------------
-- Python_Callback_Data --
--------------------------
procedure Prepare_Value_Key
(Data : in out Python_Callback_Data'Class;
Key : PyObject;
Append : Boolean);
-- Internal version of Set_Return_Value_Key
---------------------------
-- Python_Class_Instance --
---------------------------
type Python_Class_Instance_Record is new Class_Instance_Record with record
Data : PyObject;
end record;
type Python_Class_Instance is access all Python_Class_Instance_Record'Class;
overriding procedure Free (Self : in out Python_Class_Instance_Record);
overriding function Get_User_Data
(Inst : not null access Python_Class_Instance_Record)
return access User_Data_List;
overriding function Print_Refcount
(Instance : access Python_Class_Instance_Record) return String;
overriding function Is_Subclass
(Instance : access Python_Class_Instance_Record;
Base : String) return Boolean;
overriding procedure Set_Property
(Instance : access Python_Class_Instance_Record;
Name : String; Value : Integer);
overriding procedure Set_Property
(Instance : access Python_Class_Instance_Record;
Name : String; Value : Boolean);
overriding procedure Set_Property
(Instance : access Python_Class_Instance_Record;
Name : String; Value : Float);
overriding procedure Set_Property
(Instance : access Python_Class_Instance_Record;
Name : String; Value : String);
overriding function Get_Method
(Instance : access Python_Class_Instance_Record;
Name : String) return Subprogram_Type;
-- See doc from inherited subprogram
function Get_CI
(Script : Python_Scripting; Object : PyObject) return Class_Instance;
-- Wraps the python object into a Class_Instance.
-- The refcount of the object is increased by one, owned by Class_Instance.
------------------
-- Handler_Data --
------------------
type Handler_Data is record
Script : Python_Scripting;
Cmd : Command_Descr_Access;
end record;
type Handler_Data_Access is access Handler_Data;
-- Information stored with each python function to call the right Ada
-- subprogram.
function Command_Name (Data : Handler_Data) return String;
-- Return the qualified name of the command "command" or "class.command"
function Convert is new Ada.Unchecked_Conversion
(System.Address, Handler_Data_Access);
procedure Unchecked_Free is new Ada.Unchecked_Deallocation
(Handler_Data, Handler_Data_Access);
procedure Destroy_Handler_Data (Handler : System.Address);
pragma Convention (C, Destroy_Handler_Data);
-- Called when the python object associated with Handler is destroyed
-------------------------------
-- Class_Instance properties --
-------------------------------
type PyObject_Data_Record is record
Props : aliased User_Data_List;
end record;
type PyObject_Data is access all PyObject_Data_Record;
-- Data stored in each PyObject representing a class instance, as a
-- __gps_data property.
function Convert is new Ada.Unchecked_Conversion
(System.Address, PyObject_Data);
procedure Unchecked_Free is new Ada.Unchecked_Deallocation
(PyObject_Data_Record, PyObject_Data);
procedure On_PyObject_Data_Destroy (Data : System.Address);
pragma Convention (C, On_PyObject_Data_Destroy);
-- Called when the __gps_data property is destroyed.
----------------------
-- Interpreter_View --
----------------------
function First_Level (Self, Args, Kw : PyObject) return PyObject;
pragma Convention (C, First_Level);
-- First level handler for all functions exported to python. This function
-- is in charge of dispatching to the actual Ada subprogram.
procedure Setup_Return_Value (Data : in out Python_Callback_Data'Class);
-- Mark Data as containing a return value, and free the previous value if
-- there is any
function First_Level_Getter
(Obj : PyObject; Closure : System.Address) return PyObject;
pragma Convention (C, First_Level_Getter);
-- Handles getters for descriptor objects
function First_Level_Setter
(Obj, Value : PyObject; Closure : System.Address) return Integer;
pragma Convention (C, First_Level_Setter);
-- Handles setters for descriptor objects
procedure Trace_Dump (Name : String; Obj : PyObject);
pragma Unreferenced (Trace_Dump);
-- Print debug info for Obj
function Refcount_Msg
(Obj : PyObject) return Interfaces.C.Strings.chars_ptr;
pragma Import (C, Refcount_Msg, "ada_py_refcount_msg");
-- Print a debug message to trace the refcounting on Obj
function Run_Command
(Script : access Python_Scripting_Record'Class;
Command : String;
Console : Virtual_Console := null;
Show_Command : Boolean := False;
Hide_Output : Boolean := False;
Hide_Exceptions : Boolean := False;
Errors : access Boolean) return String;
-- Same as above, but also return the output of the command
procedure Python_Global_Command_Handler
(Data : in out Callback_Data'Class; Command : String);
-- Handles all commands pre-defined in this module
procedure Log_Python_Exception;
-- Log the current exception to a trace_handle
------------------------
-- Internals Nth_Arg --
------------------------
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Success : access Boolean) return String;
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Success : access Boolean) return Unbounded_String;
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Success : access Boolean) return Integer;
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Success : access Boolean) return Float;
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Success : access Boolean) return Boolean;
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Success : access Boolean) return Subprogram_Type;
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Class : Class_Type;
Allow_Null : Boolean; Success : access Boolean)
return Class_Instance;
-- These functions are called by the overridden Nth_Arg functions. They try
-- to return the parameter at the location N. If no parameter is found,
-- Success is false, true otherwise. It's the responsibility of the
-- enclosing Nth_Arg to either raise a No_Such_Parameter exception or to
-- return a default value.
-------------
-- Modules --
-------------
function Lookup_Module
(Self : not null access Python_Scripting_Record'Class;
Name : String) return PyObject;
-- Return the module object.
function Lookup_Object
(Self : not null access Python_Scripting_Record'Class;
Qualified_Name : String) return PyObject;
-- Lookup an object from its fully qualified name (module.module.name).
-- If there is no module specified, the object is looked for in the default
-- module, or the builtins.
------------------
-- Dictionaries --
------------------
type Python_Dictionary_Instance is new Dictionary_Instance with record
Script : Python_Scripting;
Dict : PyObject;
end record;
function Iterator
(Self : Python_Dictionary_Instance) return Dictionary_Iterator'Class;
-- Returns iterator for given dictionary
function Has_Key
(Self : Python_Dictionary_Instance; Key : String) return Boolean;
function Has_Key
(Self : Python_Dictionary_Instance; Key : Integer) return Boolean;
function Has_Key
(Self : Python_Dictionary_Instance; Key : Float) return Boolean;
function Has_Key
(Self : Python_Dictionary_Instance; Key : Boolean) return Boolean;
-- Returns True when dictionary has value for given key
function Value
(Self : Python_Dictionary_Instance; Key : String) return String;
function Value
(Self : Python_Dictionary_Instance; Key : Integer) return String;
function Value
(Self : Python_Dictionary_Instance; Key : Float) return String;
function Value
(Self : Python_Dictionary_Instance; Key : Boolean) return String;
function Value
(Self : Python_Dictionary_Instance; Key : String) return Integer;
function Value
(Self : Python_Dictionary_Instance; Key : Integer) return Integer;
function Value
(Self : Python_Dictionary_Instance; Key : Float) return Integer;
function Value
(Self : Python_Dictionary_Instance; Key : Boolean) return Integer;
function Value
(Self : Python_Dictionary_Instance; Key : String) return Float;
function Value
(Self : Python_Dictionary_Instance; Key : Integer) return Float;
function Value
(Self : Python_Dictionary_Instance; Key : Float) return Float;
function Value
(Self : Python_Dictionary_Instance; Key : Boolean) return Float;
function Value
(Self : Python_Dictionary_Instance; Key : String) return Boolean;
function Value
(Self : Python_Dictionary_Instance; Key : Integer) return Boolean;
function Value
(Self : Python_Dictionary_Instance; Key : Float) return Boolean;
function Value
(Self : Python_Dictionary_Instance; Key : Boolean) return Boolean;
-- Returns value of given key
type Python_Dictionary_Iterator is new Dictionary_Iterator with record
Script : Python_Scripting;
Dict : PyObject;
Position : Integer := 0;
Key : PyObject;
Value : PyObject;
end record;
function Next
(Self : not null access Python_Dictionary_Iterator) return Boolean;
-- Moves iterator to next pair in dictionary. Returns False when where is
-- no more pairs available.
function Key (Self : Python_Dictionary_Iterator) return String;
function Key (Self : Python_Dictionary_Iterator) return Integer;
function Key (Self : Python_Dictionary_Iterator) return Float;
function Key (Self : Python_Dictionary_Iterator) return Boolean;
-- Returns value of current pair in dictionary
function Value (Self : Python_Dictionary_Iterator) return String;
function Value (Self : Python_Dictionary_Iterator) return Integer;
function Value (Self : Python_Dictionary_Iterator) return Float;
function Value (Self : Python_Dictionary_Iterator) return Boolean;
-- Returns value of current pair in dictionary
function Conditional_To
(Condition : Boolean; Object : PyObject; Name : String) return String;
function Conditional_To
(Condition : Boolean; Object : PyObject; Name : String) return Integer;
function Conditional_To
(Condition : Boolean; Object : PyObject; Name : String) return Float;
function Conditional_To
(Condition : Boolean;
Script : Scripting_Language;
Object : PyObject) return Boolean;
-- Converts Python's value when Condition is true
function Internal_To (Object : PyObject; Name : String) return String;
function Internal_To (Object : PyObject; Name : String) return Integer;
function Internal_To (Object : PyObject; Name : String) return Float;
function Internal_To
(Script : Scripting_Language; Object : PyObject) return Boolean;
-- Converts Python's value
----------------
-- Tracebacks --
----------------
function Trace_Python_Code
(User_Arg : GNATCOLL.Python.PyObject;
Frame : GNATCOLL.Python.PyFrameObject;
Why : GNATCOLL.Python.Why_Trace_Func;
Object : GNATCOLL.Python.PyObject) return Integer
with Convention => C;
-- Trace callback routine
Last_Call_Frame : PyFrameObject := null;
-- Global variable to save frame object of the last call
function Error_Message_With_Stack return String;
-- Returns error message with Python stack when available
--------------------
-- Block_Commands --
--------------------
procedure Block_Commands
(Script : access Python_Scripting_Record; Block : Boolean) is
begin
Script.Blocked := Block;
end Block_Commands;
----------------
-- Trace_Dump --
----------------
procedure Trace_Dump (Name : String; Obj : PyObject) is
S : PyObject;
begin
if Obj = null then
Put_Line (Name & "=<null>");
else
-- Special handling here, since for a string PyObject_Str returns
-- the string itself, thus impacting the refcounting
S := PyObject_Str (Obj);
if S = Obj then
Py_DECREF (Obj); -- Preserve original refcount
end if;
Put_Line (Name & "="""
& PyString_AsString (S) & '"' & ASCII.LF
& " refcount=" & Value (Refcount_Msg (Obj)));
if S /= Obj then
Py_DECREF (S);
end if;
-- Other possible debug info:
-- repr = PyString_AsString (PyObject_Repr (Obj))
-- methods = PyString_AsString (PyObject_Str (PyObject_Dir (Obj)))
end if;
end Trace_Dump;
------------------
-- Command_Name --
------------------
function Command_Name (Data : Handler_Data) return String is
begin
if Data.Cmd.Class = No_Class then
return Data.Cmd.Command;
else
return Get_Name (Data.Cmd.Class) & "." & Data.Cmd.Command;
end if;
end Command_Name;
-------------
-- Destroy --
-------------
procedure Destroy (Script : access Python_Scripting_Record) is
begin
if not Finalized then
Trace (Me, "Finalizing python");
Finalized := True;
Set_Default_Console (Script, null);
Free (Script.Buffer);
Py_Finalize;
end if;
end Destroy;
----------------------------
-- Command_Line_Treatment --
----------------------------
overriding function Command_Line_Treatment
(Script : access Python_Scripting_Record) return Command_Line_Mode is
pragma Unreferenced (Script);
begin
return Raw_String;
end Command_Line_Treatment;
-------------------------------
-- Register_Python_Scripting --
-------------------------------
procedure Register_Python_Scripting
(Repo : access Scripts.Scripts_Repository_Record'Class;
Module : String;
Program_Name : String := "python";
Python_Home : String := "")
is
Script : Python_Scripting;
Ignored : Integer;
pragma Unreferenced (Ignored);
function Initialize_Py_And_Module
(Program, Module : String) return PyObject;
pragma Import (C, Initialize_Py_And_Module,
"ada_py_initialize_and_module");
Main_Module : PyObject;
begin
Script := new Python_Scripting_Record;
Script.Repo := Scripts_Repository (Repo);
Register_Scripting_Language (Repo, Script);
-- Set the program name and python home
if Python_Home /= "" then
Lifecycle.Py_SetPythonHome (Python_Home);
end if;
Script.Module := Initialize_Py_And_Module
(Program_Name & ASCII.NUL, Module & ASCII.NUL);
if Script.Module = null then
raise Program_Error with "Could not import module " & Module;
end if;
Finalized := False;
if Active (Me_Stack)
and then not PyRun_SimpleString ("import traceback")
then
raise Program_Error with "Could not import traceback.py";
end if;
Main_Module := PyImport_AddModule ("__main__");
if Main_Module = null then
raise Program_Error with "Could not import module __main__";
end if;
Script.Globals := PyModule_GetDict (Main_Module);
Script.Buffer := new String'("");
Script.Builtin := PyImport_ImportModule (Builtin_Name);
Script.Exception_Unexpected := PyErr_NewException
(Module & ".Unexpected_Exception", null, null);
Ignored := PyModule_AddObject
(Script.Module, "Unexpected_Exception" & ASCII.NUL,
Script.Exception_Unexpected);
Script.Exception_Misc := PyErr_NewException
(Module & ".Exception", null, null);
Ignored := PyModule_AddObject
(Script.Module, "Exception" & ASCII.NUL, Script.Exception_Misc);
Script.Exception_Missing_Args := PyErr_NewException
(Module & ".Missing_Arguments", null, null);
Ignored := PyModule_AddObject
(Script.Module, "Missing_Arguments" & ASCII.NUL,
Script.Exception_Missing_Args);
Script.Exception_Invalid_Arg := PyErr_NewException
(Module & ".Invalid_Argument", null, null);
Ignored := PyModule_AddObject
(Script.Module, "Invalid_Argument" & ASCII.NUL,
Script.Exception_Invalid_Arg);
-- PyGTK prints its error messages using sys.argv, which doesn't
-- exist in non-interactive mode. We therefore define it here
if not PyRun_SimpleString ("sys.argv=['" & Module & "']") then
Trace (Me_Error, "Could not initialize sys.argv");
end if;
-- This function is required for support of the Python menu (F120-025),
-- so that we can execute python commands in the context of the global
-- interpreter instead of the current context (for the menu, that would
-- be python_support.py, and thus would have no impact on the
-- interpreter itself)
Register_Command
(Repo,
Command => "exec_in_console",
Handler => Python_Global_Command_Handler'Access,
Minimum_Args => 1,
Maximum_Args => 1,
Language => Python_Name);
if Active (Me_Crash) then
PyEval_SetTrace (Trace_Python_Code'Access, null);
end if;
end Register_Python_Scripting;
-----------------------------------
-- Python_Global_Command_Handler --
-----------------------------------
procedure Python_Global_Command_Handler
(Data : in out Callback_Data'Class; Command : String)
is
Result : PyObject;
Errors : aliased Boolean;
begin
if Command = "exec_in_console" then
Result := Run_Command
(Python_Scripting (Get_Script (Data)),
Command => Nth_Arg (Data, 1),
Need_Output => False,
Show_Command => True,
Errors => Errors'Unchecked_Access);
Py_XDECREF (Result);
end if;
end Python_Global_Command_Handler;
--------------------------
-- Destroy_Handler_Data --
--------------------------
procedure Destroy_Handler_Data (Handler : System.Address) is
H : Handler_Data_Access := Convert (Handler);
begin
Unchecked_Free (H);
end Destroy_Handler_Data;
----------
-- Free --
----------
procedure Free (Data : in out Python_Callback_Data) is
begin
if Data.Args /= null then
Py_DECREF (Data.Args);
end if;
if Data.Kw /= null then
Py_DECREF (Data.Kw);
end if;
if Data.Return_Value /= null then
Py_DECREF (Data.Return_Value);
Data.Return_Value := null;
end if;
if Data.Return_Dict /= null then
Py_DECREF (Data.Return_Dict);
Data.Return_Dict := null;
end if;
end Free;
--------------
-- Set_Item --
--------------
procedure Set_Item (Args : PyObject; T : Integer; Item : PyObject) is
N : Integer;
pragma Unreferenced (N);
begin
-- Special case tuples, since they are immutable through
-- PyObject_SetItem
if PyTuple_Check (Args) then
PyTuple_SetItem (Args, T, Item); -- Doesn't modify refcount
Py_INCREF (Item);
-- Also special case lists, since we want to append if the index is
-- too big
elsif PyList_Check (Args) then
if T < PyList_Size (Args) then
PyObject_SetItem (Args, T, Item);
else
N := PyList_Append (Args, Item);
end if;
else
PyObject_SetItem (Args, T, Item);
end if;
end Set_Item;
-----------
-- Clone --
-----------
function Clone (Data : Python_Callback_Data) return Callback_Data'Class is
D : Python_Callback_Data := Data;
Item : PyObject;
Size : Integer;
begin
if D.Args /= null then
Size := PyObject_Size (D.Args);
D.Args := PyTuple_New (Size);
for T in 0 .. Size - 1 loop
Item := PyObject_GetItem (Data.Args, T);
Set_Item (D.Args, T, Item);
Py_DECREF (Item);
end loop;
end if;
if D.Kw /= null then
Py_INCREF (D.Kw);
end if;
D.Return_Value := null;
D.Return_Dict := null;
return D;
end Clone;
------------
-- Create --
------------
function Create
(Script : access Python_Scripting_Record;
Arguments_Count : Natural) return Callback_Data'Class
is
Callback : constant Python_Callback_Data :=
(Callback_Data with
Script => Python_Scripting (Script),
Args => PyTuple_New (Arguments_Count),
Kw => null,
Return_Value => null,
Return_Dict => null,
Has_Return_Value => False,
Return_As_List => False,
First_Arg_Is_Self => False);
begin
return Callback;
end Create;
-----------------
-- Set_Nth_Arg --
-----------------
procedure Set_Nth_Arg
(Data : in out Python_Callback_Data;
N : Positive; Value : PyObject) is
begin
Set_Item (Data.Args, N - 1, Value);
Py_DECREF (Value);
end Set_Nth_Arg;
-----------------
-- Set_Nth_Arg --
-----------------
procedure Set_Nth_Arg
(Data : in out Python_Callback_Data;
N : Positive; Value : Subprogram_Type)
is
Subp : constant PyObject :=
Python_Subprogram_Record (Value.all).Subprogram;
begin
Set_Item (Data.Args, N - 1, Subp);
Py_DECREF (Subp);
end Set_Nth_Arg;
-----------------
-- Set_Nth_Arg --
-----------------
procedure Set_Nth_Arg
(Data : in out Python_Callback_Data; N : Positive; Value : String)
is
Item : constant PyObject := PyString_FromString (Value);
begin
Set_Item (Data.Args, N - 1, Item);
Py_DECREF (Item);
end Set_Nth_Arg;
-----------------
-- Set_Nth_Arg --
-----------------
procedure Set_Nth_Arg
(Data : in out Python_Callback_Data; N : Positive; Value : Integer)
is
Item : constant PyObject := PyInt_FromLong (Interfaces.C.long (Value));
begin
Set_Item (Data.Args, N - 1, Item);
Py_DECREF (Item);
end Set_Nth_Arg;
-----------------
-- Set_Nth_Arg --
-----------------
procedure Set_Nth_Arg
(Data : in out Python_Callback_Data; N : Positive; Value : Float)
is
Item : constant PyObject := PyFloat_FromDouble
(Interfaces.C.double (Value));
begin
Set_Item (Data.Args, N - 1, Item);
Py_DECREF (Item);
end Set_Nth_Arg;
-----------------
-- Set_Nth_Arg --
-----------------
procedure Set_Nth_Arg
(Data : in out Python_Callback_Data; N : Positive; Value : Boolean)
is
Item : constant PyObject := PyInt_FromLong (Boolean'Pos (Value));
begin
Set_Item (Data.Args, N - 1, Item);
Py_DECREF (Item);
end Set_Nth_Arg;
-----------------
-- Set_Nth_Arg --
-----------------
procedure Set_Nth_Arg
(Data : in out Python_Callback_Data; N : Positive; Value : Class_Instance)
is
Inst : PyObject;
begin
if Value = No_Class_Instance then
Set_Item (Data.Args, N - 1, Py_None); -- Increments refcount
else
Inst := Python_Class_Instance (Get_CIR (Value)).Data;
Set_Item (Data.Args, N - 1, Inst); -- Increments refcount
end if;
end Set_Nth_Arg;
-----------------
-- Set_Nth_Arg --
-----------------
procedure Set_Nth_Arg
(Data : in out Python_Callback_Data; N : Positive; Value : List_Instance)
is
V : constant PyObject := Python_Callback_Data (Value).Args;
begin
Set_Item (Data.Args, N - 1, V); -- Increments refcount
end Set_Nth_Arg;
-----------------
-- First_Level --
-----------------
function First_Level (Self, Args, Kw : PyObject) return PyObject is
-- Args and Kw could both be null, as called from PyCFunction_Call
Handler : Handler_Data_Access;
Size : Integer := 0;
Callback : Python_Callback_Data;
First_Arg_Is_Self : Boolean;
Result : PyObject;
begin
Handler := Convert (PyCObject_AsVoidPtr (Self));
if Finalized
and then Handler.Cmd.Command /= Destructor_Method
then
PyErr_SetString (Handler.Script.Exception_Unexpected,
"Application was already finalized");
return null;
end if;
if Active (Me_Log) then
Trace (Me_Log, "First_Level: " & Handler.Cmd.Command);
end if;
if Active (Me_Stack) then
declare
Module : constant PyObject := PyImport_ImportModule ("traceback");
Newline, List, Join : PyObject;
begin
if Module /= null then
List := PyObject_CallMethod (Module, "format_stack");
if List /= null then
Newline := PyString_FromString ("");
Join := PyObject_CallMethod (Newline, "join", List);
Trace (Me_Stack, "Exec " & Command_Name (Handler.all)
& ASCII.LF & PyString_AsString (Join));
Py_DECREF (Newline);
Py_DECREF (List);
Py_DECREF (Join);
end if;
end if;
exception
when E : others =>
Trace (Me_Stack, E);
end;
end if;
if Args /= null then
Size := PyObject_Size (Args);
end if;
if Kw /= null then
declare
S : constant Integer := PyDict_Size (Kw);
begin
if S < 0 then
raise Program_Error with
"Incorrect dictionary when calling function "
& Handler.Cmd.Command;
end if;
Size := S + Size;
end;
end if;
First_Arg_Is_Self :=
Handler.Cmd.Class /= No_Class and then not Handler.Cmd.Static_Method;
if First_Arg_Is_Self then
Size := Size - 1; -- First param is always the instance
end if;
-- Special case for constructors:
-- when we were using old-style classes, New_Instance was not calling
-- __init__. With new-style classes, however, __init__ is already called
-- when we call the metatype(). In particular, this means that the
-- profile of New_Instance should allow passing custom parameters,
-- otherwise the call to __init__ fails.
-- So for now we simply allow a call to the constructor with no
-- parameter, which does nothing.
-- This is not very elegant, since from python's point of view, this
-- relies on the user calling New_Instance and immediately initializing
-- the Class_Instance as done in the Constructor_Method handler.
if Handler.Script.Ignore_Constructor
and then Handler.Cmd.Command = Constructor_Method
then
Py_INCREF (Py_None);
return Py_None;
end if;
-- Check number of arguments
if Handler.Cmd.Minimum_Args > Size
or else Size > Handler.Cmd.Maximum_Args
then
if Handler.Cmd.Minimum_Args > Size then
PyErr_SetString (Handler.Script.Exception_Missing_Args,
"Wrong number of parameters for "
& Handler.Cmd.Command
& ", expecting at least"
& Handler.Cmd.Minimum_Args'Img & ", received"
& Size'Img);
else
PyErr_SetString (Handler.Script.Exception_Missing_Args,
"Wrong number of parameters for "
& Handler.Cmd.Command
& ", expecting at most"
& Handler.Cmd.Maximum_Args'Img & ", received"
& Size'Img);
end if;
return null;
end if;
Callback.Args := Args;
Py_XINCREF (Callback.Args);
Callback.Kw := Kw;
Py_XINCREF (Callback.Kw);
Callback.Return_Value := null;
Callback.Return_Dict := null;
Callback.Script := Handler.Script;
Callback.First_Arg_Is_Self := First_Arg_Is_Self;
if Handler.Cmd.Params /= null then
Name_Parameters (Callback, Handler.Cmd.Params.all);
end if;
Run_Callback
(Handler.Script, Handler.Cmd.Handler, Handler.Cmd.Command, Callback,
Result);
return Result;
end First_Level;
------------------
-- Run_Callback --
------------------
procedure Run_Callback
(Script : Python_Scripting;
Cmd : Module_Command_Function;
Command : String;
Data : in out Python_Callback_Data'Class;
Result : out PyObject)
is
begin
-- Return_Value will be set to null in case of error
Data.Return_Value := Py_None;
Py_INCREF (Py_None);
Cmd.all (Data, Command);
if Data.Return_Dict /= null then
Result := Data.Return_Dict;
else
Result := Data.Return_Value; -- might be null for an exception
end if;
Py_XINCREF (Result);
Free (Data);
exception
when E : Invalid_Parameter =>
if not Data.Has_Return_Value
or else Data.Return_Value /= null
then
PyErr_SetString
(Script.Exception_Invalid_Arg, Exception_Message (E));
end if;
Free (Data);
Result := null;
when E : others =>
if not Data.Has_Return_Value
or else Data.Return_Value /= null
then
PyErr_SetString
(Script.Exception_Unexpected,
"unexpected internal exception " & Exception_Information (E));
end if;
Free (Data);
Result := null;
end Run_Callback;
------------------------
-- First_Level_Getter --
------------------------
function First_Level_Getter
(Obj : PyObject; Closure : System.Address) return PyObject
is
Prop : constant Property_User_Data := Convert (Closure);
Callback : Python_Callback_Data;
Args : PyObject;
Result : PyObject;
begin
if Active (Me_Log) then
Trace (Me_Log, "First_Level_Getter " & Prop.Prop.Name);
end if;
Args := PyTuple_New (1);
Py_INCREF (Obj);
PyTuple_SetItem (Args, 0, Obj); -- don't increase refcount of Obj
Callback :=
(Script => Prop.Script,
Args => Args, -- Now owned by Callback
Kw => null,
Return_Value => null,
Return_Dict => null,
Has_Return_Value => False,
Return_As_List => False,
First_Arg_Is_Self => False);
Run_Callback (Prop.Script, Prop.Prop.Getter, Prop.Prop.Name, Callback,
Result);
-- Run_Callback frees Callback, which decref Args
return Result;
end First_Level_Getter;
------------------------
-- First_Level_Setter --
------------------------
function First_Level_Setter
(Obj, Value : PyObject; Closure : System.Address) return Integer
is
Prop : constant Property_User_Data := Convert (Closure);
Callback : Python_Callback_Data;
Args : PyObject;
Result : PyObject;
begin
if Active (Me_Log) then
Trace (Me_Log, "First_Level_Setter " & Prop.Prop.Name);
end if;
Args := PyTuple_New (2);
Py_INCREF (Obj);
PyTuple_SetItem (Args, 0, Obj); -- don't increase refcount of Obj
Py_INCREF (Value);
PyTuple_SetItem (Args, 1, Value); -- don't increase refcount of Value
Callback :=
(Script => Prop.Script,
Args => Args, -- Now owned by Callback
Kw => null,
Return_Value => null,
Return_Dict => null,
Has_Return_Value => False,
Return_As_List => False,
First_Arg_Is_Self => False);
Run_Callback
(Prop.Script, Prop.Prop.Setter, Prop.Prop.Name, Callback, Result);
-- Run_Callback frees Callback, which decref Args
if Result = null then
return -1;
else
Py_DECREF (Result);
return 0;
end if;
end First_Level_Setter;
-----------------------
-- Register_Property --
-----------------------
overriding procedure Register_Property
(Script : access Python_Scripting_Record;
Prop : Property_Descr_Access)
is
Klass : PyObject;
Ignored : Boolean;
pragma Unreferenced (Ignored);
Setter : C_Setter := First_Level_Setter'Access;
Getter : C_Getter := First_Level_Getter'Access;
H : constant Property_User_Data := new Property_User_Data_Record'
(Script => Python_Scripting (Script),
Prop => Prop);
-- ??? Memory leak. We do not know when H is no longer needed
begin
if Prop.Setter = null then
Setter := null;
end if;
if Prop.Getter = null then
Getter := null;
end if;
Klass := Lookup_Object (Script, Prop.Class.Qualified_Name.all);
Ignored := PyDescr_NewGetSet
(Typ => Klass,
Name => Prop.Name,
Setter => Setter,
Getter => Getter,
Closure => Convert (H));
end Register_Property;
----------------------
-- Register_Command --
----------------------
overriding procedure Register_Command
(Script : access Python_Scripting_Record;
Cmd : Command_Descr_Access)
is
H : constant Handler_Data_Access := new Handler_Data'
(Cmd => Cmd,
Script => Python_Scripting (Script));
User_Data : constant PyObject := PyCObject_FromVoidPtr
(H.all'Address, Destroy_Handler_Data'Access);
Klass : PyObject;
Def : PyMethodDef;
begin
if Cmd.Class = No_Class then
Add_Function
(Module => Script.Module,
Func => Create_Method_Def (Cmd.Command, First_Level'Access),
Self => User_Data);
else
if Cmd.Command = Constructor_Method then
Def := Create_Method_Def ("__init__", First_Level'Access);
elsif Cmd.Command = Addition_Method then
Def := Create_Method_Def ("__add__", First_Level'Access);
elsif Cmd.Command = Substraction_Method then
Def := Create_Method_Def ("__sub__", First_Level'Access);
elsif Cmd.Command = Comparison_Method then
Def := Create_Method_Def ("__cmp__", First_Level'Access);
elsif Cmd.Command = Equal_Method then
Def := Create_Method_Def ("__eq__", First_Level'Access);
elsif Cmd.Command = Destructor_Method then
Def := Create_Method_Def ("__del__", First_Level'Access);
else
Def := Create_Method_Def (Cmd.Command, First_Level'Access);
end if;
Klass := Lookup_Object
(Script, Cmd.Class.Qualified_Name.all);
if Klass = null then
Trace (Me_Error, "Class not found "
& Cmd.Class.Qualified_Name.all);
elsif Cmd.Static_Method then
Add_Static_Method
(Class => Klass, Func => Def, Self => User_Data,
Module => Script.Module);
else
Add_Method (Class => Klass, Func => Def, Self => User_Data,
Module => Script.Module);
end if;
end if;
end Register_Command;
-------------------
-- Lookup_Module --
-------------------
function Lookup_Module
(Self : not null access Python_Scripting_Record'Class;
Name : String) return PyObject
is
M, Tmp : PyObject := null;
First : Natural;
begin
if Name = "@" then
return Self.Module;
end if;
First := Name'First;
for N in Name'First .. Name'Last + 1 loop
if N > Name'Last or else Name (N) = '.' then
if Name (First .. N - 1) = "@" then
M := Self.Module;
else
if Name (Name'First .. Name'First + 1) = "@." then
Tmp := PyImport_AddModule
(PyModule_Getname (Self.Module)
& '.' & Name (Name'First + 2 .. N - 1));
else
Tmp := PyImport_AddModule (Name (Name'First .. N - 1));
end if;
if M /= null then
PyDict_SetItemString
(PyModule_GetDict (Tmp),
"__module__",
PyObject_GetAttrString (M, "__name__"));
Py_INCREF (Tmp);
if PyModule_AddObject
(M, Name (First .. N - 1), Tmp) /= 0
then
Trace (Me_Error, "Could not register submodule "
& Name (Name'First .. N - 1));
return null;
end if;
end if;
M := Tmp;
end if;
First := N + 1;
end if;
end loop;
return M;
end Lookup_Module;
-------------------
-- Lookup_Object --
-------------------
function Lookup_Object
(Self : not null access Python_Scripting_Record'Class;
Qualified_Name : String) return PyObject
is
M : PyObject;
begin
for N in reverse Qualified_Name'Range loop
if Qualified_Name (N) = '.' then
M := Lookup_Module
(Self, Qualified_Name (Qualified_Name'First .. N - 1));
return Lookup_Object
(M, Qualified_Name (N + 1 .. Qualified_Name'Last));
end if;
end loop;
M := Lookup_Object (Self.Module, Qualified_Name);
if M = null then
M := Lookup_Object (Self.Builtin, Qualified_Name);
end if;
return M;
end Lookup_Object;
--------------------
-- Register_Class --
--------------------
overriding procedure Register_Class
(Script : access Python_Scripting_Record;
Name : String;
Base : Class_Type := No_Class;
Module : Module_Type := Default_Module)
is
Dict : constant PyDictObject := PyDict_New;
Class : PyObject;
Ignored : Integer;
Bases : PyObject := null;
S : Interfaces.C.Strings.chars_ptr;
pragma Unreferenced (Ignored);
M : constant PyObject :=
Lookup_Module (Script, To_String (Module.Name));
begin
PyDict_SetItemString
(Dict, "__module__", PyObject_GetAttrString (M, "__name__"));
if Base /= No_Class then
Bases := Create_Tuple
((1 => Lookup_Object (Script, Base.Qualified_Name.all)));
end if;
Class := Type_New
(Name => Name,
Bases => Bases,
Dict => Dict);
if Class = null then
PyErr_Print;
raise Program_Error
with "Could not register class " & Name;
end if;
S := New_String (Name);
Ignored := PyModule_AddObject (M, S, Class);
Free (S);
end Register_Class;
---------------
-- Interrupt --
---------------
function Interrupt
(Script : access Python_Scripting_Record) return Boolean is
begin
if Script.In_Process then
PyErr_SetInterrupt;
return True;
else
return False;
end if;
end Interrupt;
--------------
-- Complete --
--------------
procedure Complete
(Script : access Python_Scripting_Record;
Input : String;
Completions : out String_Lists.List)
is
Start : Natural := Input'First - 1;
Last : Natural := Input'Last + 1;
Obj, Item : PyObject;
Errors : aliased Boolean;
begin
Completions := String_Lists.Empty_List;
for N in reverse Input'Range loop
if Input (N) = ' ' or else Input (N) = ASCII.HT then
Start := N;
exit;
elsif Input (N) = '.' and then Last > Input'Last then
Last := N;
end if;
end loop;
if Start < Input'Last then
Obj := Run_Command
(Script,
Builtins_Name
& ".dir(" & Input (Start + 1 .. Last - 1) & ")",
Need_Output => True,
Hide_Output => True,
Hide_Exceptions => True,
Errors => Errors'Unchecked_Access);
if Obj /= null then
for Index in 0 .. PyList_Size (Obj) - 1 loop
Item := PyList_GetItem (Obj, Index);
declare
S : constant String := PyString_AsString (Item);
begin
if S'First + Input'Last - Last - 1 <= S'Last
and then
(Last >= Input'Last
or else Input (Last + 1 .. Input'Last)
= S (S'First .. S'First + Input'Last - Last - 1))
then
String_Lists.Append
(Completions,
Input (Input'First .. Last - 1) & '.' & S);
end if;
end;
end loop;
Py_DECREF (Obj);
end if;
end if;
end Complete;
----------------
-- Get_Prompt --
----------------
overriding function Get_Prompt
(Script : access Python_Scripting_Record) return String
is
Ps : PyObject;
begin
if Script.Use_Secondary_Prompt then
Ps := PySys_GetObject ("ps2");
if Ps = null then
return "... ";
end if;
else
Ps := PySys_GetObject ("ps1");
if Ps = null then
return ">>> ";
end if;
end if;
return PyString_AsString (Ps);
end Get_Prompt;
--------------------
-- Display_Prompt --
--------------------
procedure Display_Prompt
(Script : access Python_Scripting_Record;
Console : Virtual_Console := null) is
begin
Insert_Prompt
(Script, Console, Get_Prompt (Scripting_Language (Script)));
end Display_Prompt;
-----------------
-- Run_Command --
-----------------
function Run_Command
(Script : access Python_Scripting_Record'Class;
Command : String;
Console : Virtual_Console := null;
Show_Command : Boolean := False;
Hide_Output : Boolean := False;
Hide_Exceptions : Boolean := False;
Errors : access Boolean) return String
is
Result : PyObject;
Str : PyObject;
begin
Result := Run_Command
(Script, Command,
Console => Console,
Need_Output => True,
Show_Command => Show_Command,
Hide_Output => Hide_Output,
Hide_Exceptions => Hide_Exceptions,
Errors => Errors);
if Result /= null and then not Errors.all then
Str := PyObject_Str (Result);
if Str = null then
Py_DECREF (Result);
return "Error calling __repr__ on the result of the script";
end if;
declare
S : constant String := PyString_AsString (Str);
begin
Py_DECREF (Result);
Py_DECREF (Str);
if Active (Me_Log) then
Trace (Me_Log, "output is: " & S);
end if;
return S;
end;
else
Py_XDECREF (Result);
return "";
end if;
end Run_Command;
--------------------------
-- Log_Python_Exception --
--------------------------
procedure Log_Python_Exception is
Typ, Occurrence, Traceback, S : PyObject;
begin
if Active (Me_Error) then
PyErr_Fetch (Typ, Occurrence, Traceback);
PyErr_NormalizeException (Typ, Occurrence, Traceback);
S := PyObject_Repr (Occurrence);
if S /= null then
Trace (Me_Error, "Exception " & PyString_AsString (S));
Py_DECREF (S);
end if;
PyErr_Restore (Typ, Occurrence, Traceback);
end if;
end Log_Python_Exception;
-----------------
-- Run_Command --
-----------------
function Run_Command
(Script : access Python_Scripting_Record'Class;
Command : String;
Need_Output : Boolean;
Console : Virtual_Console := null;
Show_Command : Boolean := False;
Hide_Output : Boolean := False;
Hide_Exceptions : Boolean := False;
Errors : access Boolean) return PyObject
is
Result : PyObject := null;
Code : PyCodeObject;
Indented_Input : constant Boolean := Command'Length > 0
and then (Command (Command'First) = ASCII.HT
or else Command (Command'First) = ' ');
Cmd : constant String := Script.Buffer.all & Command & ASCII.LF;
Typ, Occurrence, Traceback, S : PyObject;
Default_Console_Refed : Boolean := False;
Default_Console : constant Virtual_Console :=
Get_Default_Console (Script);
State : Interpreter_State;
begin
if Active (Me_Log) then
Trace (Me_Log, "command: " & Script.Buffer.all & Command);
end if;
Errors.all := False;
if Finalized or else Cmd = "" & ASCII.LF then
if not Hide_Output then
Display_Prompt (Script);
end if;
return null;
end if;
if Show_Command and not Hide_Output then
Insert_Text (Script, Console, Command & ASCII.LF);
end if;
-- The following code will not work correctly in multitasking mode if
-- each thread is redirecting to a different console. One might argue
-- this is up to the user to fix.
if Console /= null then
if Default_Console /= null then
Default_Console_Refed := True;
Ref (Default_Console);
end if;
Set_Default_Console (Script, Console);
end if;
-- If we want to have sys.displayhook called, we should use
-- <stdin> as the filename, otherwise <string> will ensure this is not
-- an interactive session.
-- For interactive code, python generates addition opcode PRINT_EXPR
-- which will call displayhook.
--
-- We cannot use Py_Eval_Input, although it would properly return the
-- result of evaluating the expression, but it would not support multi
-- line input, in particular function defintion.
-- So we need to use Py_Single_Input, but then the result of evaluating
-- the code is always None.
if Need_Output then
State := Py_Eval_Input;
else
State := Py_Single_Input;
end if;
if Hide_Output then
Code := Py_CompileString (Cmd, "<string>", State);
else
Code := Py_CompileString (Cmd, "<stdin>", State);
end if;
-- If code compiled just fine
if Code /= null and then not Indented_Input then
Script.Use_Secondary_Prompt := False;
Free (Script.Buffer);
Script.Buffer := new String'("");
if Get_Default_Console (Script) /= null then
Grab_Events (Get_Default_Console (Script), True);
-- No exception handler needed because PyEval_EvalCode cannot
-- raise an exception.
Result := PyEval_EvalCode (Code, Script.Globals, Script.Globals);
Grab_Events (Get_Default_Console (Script), False);
else
Result := PyEval_EvalCode (Code, Script.Globals, Script.Globals);
end if;
Py_XDECREF (PyObject (Code));
if Result = null then
if Active (Me_Error) then
PyErr_Fetch (Typ, Occurrence, Traceback);
PyErr_NormalizeException (Typ, Occurrence, Traceback);
S := PyObject_Repr (Occurrence);
if S /= null then
Trace (Me_Error, "Exception " & PyString_AsString (S));
Py_DECREF (S);
else
Trace
(Me_Error, "Python raised an exception with no __repr__");
end if;
-- Do not DECREF Typ, Occurrence or Traceback after this
PyErr_Restore (Typ, Occurrence, Traceback);
end if;
if not Hide_Exceptions then
PyErr_Print;
else
PyErr_Clear;
end if;
Errors.all := True;
end if;
-- Do we have compilation error because input was incomplete ?
elsif not Hide_Output then
Script.Use_Secondary_Prompt := Indented_Input;
if not Script.Use_Secondary_Prompt then
if PyErr_Occurred /= null then
PyErr_Fetch (Typ, Occurrence, Traceback);
PyErr_NormalizeException (Typ, Occurrence, Traceback);
if PyTuple_Check (Occurrence) then
-- Old style exceptions
S := PyTuple_GetItem (Occurrence, 0);
else
-- New style: occurrence is an instance
-- S is null if the exception is not a syntax_error
S := PyObject_GetAttrString (Occurrence, "msg");
end if;
PyErr_Restore (Typ, Occurrence, Traceback);
if S = null then
Script.Use_Secondary_Prompt := False;
else
declare
Msg : constant String := PyString_AsString (S);
begin
Py_DECREF (S);
-- Second message appears when typing:
-- >>> if 1:
-- ... pass
-- ... else:
if Msg = "unexpected EOF while parsing" then
Script.Use_Secondary_Prompt := Command'Length > 0
and then Command (Command'Last) = ':';
elsif Msg = "expected an indented block" then
Script.Use_Secondary_Prompt := Command'Length /= 0
and then Command (Command'Last) /= ASCII.LF;
else
Log_Python_Exception;
end if;
end;
end if;
if not Script.Use_Secondary_Prompt then
PyErr_Print;
Errors.all := True;
else
PyErr_Clear;
end if;
end if;
else
PyErr_Clear;
end if;
Free (Script.Buffer);
if Script.Use_Secondary_Prompt then
Script.Buffer := new String'(Cmd);
else
Script.Buffer := new String'("");
end if;
else
if Active (Me_Error) then
PyErr_Fetch (Typ, Occurrence, Traceback);
PyErr_NormalizeException (Typ, Occurrence, Traceback);
S := PyObject_Repr (Occurrence);
if S /= null then
Trace (Me_Error, "Exception " & PyString_AsString (S));
Py_DECREF (S);
end if;
PyErr_Restore (Typ, Occurrence, Traceback);
end if;
PyErr_Print;
end if;
if not Hide_Output then
Display_Prompt (Script);
end if;
if Console /= null then
Set_Default_Console (Script, Default_Console);
if Default_Console_Refed then
Unref (Default_Console);
end if;
end if;
return Result;
exception
when E : others =>
Trace (Me_Error, E);
Errors.all := True;
if Default_Console_Refed then
Unref (Default_Console);
end if;
return Result;
end Run_Command;
---------------------
-- Execute_Command --
---------------------
procedure Execute_Command
(Script : access Python_Scripting_Record;
CL : Arg_List;
Console : Virtual_Console := null;
Hide_Output : Boolean := False;
Show_Command : Boolean := True;
Errors : out Boolean)
is
E : aliased Boolean;
Result : PyObject;
begin
if Script.Blocked then
Errors := True;
Insert_Error (Script, Console, "A command is already executing");
else
Result := Run_Command
(Script, Get_Command (CL),
Console => Console,
Need_Output => False,
Hide_Output => Hide_Output,
Show_Command => Show_Command,
Errors => E'Unchecked_Access);
Py_XDECREF (Result);
Errors := E;
end if;
end Execute_Command;
---------------------
-- Execute_Command --
---------------------
function Execute_Command
(Script : access Python_Scripting_Record;
CL : Arg_List;
Console : Virtual_Console := null;
Hide_Output : Boolean := False;
Show_Command : Boolean := True;
Errors : access Boolean) return String
is
pragma Unreferenced (Show_Command);
begin
if Script.Blocked then
Errors.all := True;
Insert_Error (Script, Console, "A command is already executing");
return "";
else
return Run_Command
(Script, Get_Command (CL),
Console => Console,
Hide_Output => Hide_Output,
Errors => Errors);
end if;
end Execute_Command;
---------------------
-- Execute_Command --
---------------------
function Execute_Command
(Script : access Python_Scripting_Record;
CL : Arg_List;
Console : Virtual_Console := null;
Hide_Output : Boolean := False;
Errors : access Boolean) return Boolean
is
Obj : PyObject;
Result : Boolean;
begin
if Script.Blocked then
Errors.all := True;
Insert_Error (Script, Console, "A command is already executing");
return False;
else
Obj := Run_Command
(Script, Get_Command (CL),
Need_Output => True,
Console => Console,
Hide_Output => Hide_Output,
Errors => Errors);
Result := Obj /= null
and then ((PyInt_Check (Obj) and then PyInt_AsLong (Obj) = 1)
or else (PyBool_Check (Obj) and then PyBool_Is_True (Obj))
or else
(PyString_Check (Obj)
and then PyString_AsString (Obj) = "true")
or else
(PyUnicode_Check (Obj)
and then Unicode_AsString (Obj) = "true"));
Py_XDECREF (Obj);
return Result;
end if;
end Execute_Command;
---------------------
-- Execute_Command --
---------------------
function Execute_Command
(Script : access Python_Scripting_Record;
Command : String;
Args : Callback_Data'Class) return Boolean
is
Obj : PyObject;
Errors : aliased Boolean;
begin
if Script.Blocked then
return False;
else
Obj := Run_Command
(Script,
Command => Command,
Need_Output => True,
Console => null,
Errors => Errors'Unchecked_Access);
if Obj /= null and then PyFunction_Check (Obj) then
return Execute_Command (Script, Obj, Args, Errors'Access);
else
return False;
end if;
end if;
end Execute_Command;
---------------------
-- Execute_Command --
---------------------
function Execute_Command
(Script : access Python_Scripting_Record'Class;
Command : PyObject;
Args : Callback_Data'Class;
Error : access Boolean) return PyObject
is
Obj : PyObject;
Old, Args2, Item : PyObject;
Size : Integer;
begin
Error.all := False;
if Command = null then
Trace (Me_Error, "Trying to execute 'null'");
return null;
end if;
if Active (Me_Log) then
Obj := PyObject_Repr (Command);
if Obj /= null then
Trace (Me_Log, "Execute " & PyString_AsString (Obj));
Py_DECREF (Obj);
end if;
end if;
if Script.Blocked then
Error.all := True;
Trace (Me_Error, "A python command is already executing");
return null;
end if;
-- If we are calling a bound method whose self is the same as the
-- first parameter in Args, we remove the first parameter to avoid
-- a duplicate. This allows registering callbacks as:
-- class MyClass(object):
-- def my_callback(self, arg1):
-- pass
-- def __init__(self):
-- register_callback(self, self.my_callback)
-- register_callback(self, MyClass.my_callback)
-- If Ada calls the registered callback by passing the instance as
-- the first parameter in the Callback_Data, both the calls above
-- have the same effect when we remove the duplication. Otherwise,
-- the first one will result in an error since my_callback will be
-- called with three arguments (self, self, arg1).
-- Note that the second call does not provide dynamic dispatching when
-- MyClass is subclassed and my_callback overridden.
Old := Python_Callback_Data (Args).Args;
Size := PyTuple_Size (Old);
if PyMethod_Check (Command)
and then PyMethod_Self (Command) /= null
and then Size > 0
and then PyMethod_Self (Command) = PyTuple_GetItem (Old, 0)
then
if Size = 1 then
Args2 := Py_None;
Py_INCREF (Args2);
else
Args2 := PyTuple_New (Size => Size - 1);
for T in 1 .. Size - 1 loop -- Remove arg 0
Item := PyTuple_GetItem (Old, T); -- same refcount
Py_INCREF (Item);
PyTuple_SetItem (Args2, T - 1, Item); -- same refcount
end loop;
end if;
else
Args2 := Old;
Py_INCREF (Args2);
end if;
Obj := PyObject_Call (Command, Args2, Python_Callback_Data (Args).Kw);
Py_DECREF (Args2);
if Obj = null then
Error.all := True;
Trace (Me_Error, "Calling object raised an exception");
Log_Python_Exception;
PyErr_Print;
end if;
return Obj;
exception
when E : others =>
Trace (Me_Error, E, Error_Message_With_Stack);
raise;
end Execute_Command;
---------------------
-- Execute_Command --
---------------------
function Execute_Command
(Script : access Python_Scripting_Record'Class;
Command : PyObject;
Args : Callback_Data'Class;
Error : access Boolean) return String
is
Obj : constant PyObject :=
Execute_Command (Script, Command, Args, Error);
begin
if Obj /= null
and then PyString_Check (Obj)
then
declare
Str : constant String := PyString_AsString (Obj);
begin
Py_DECREF (Obj);
return Str;
end;
elsif Obj /= null
and then PyUnicode_Check (Obj)
then
declare
Str : constant String := Unicode_AsString (Obj, "utf-8");
begin
Py_DECREF (Obj);
return Str;
end;
else
if Obj /= null then
Py_DECREF (Obj);
else
Error.all := True;
end if;
return "";
end if;
end Execute_Command;
---------------------
-- Execute_Command --
---------------------
function Execute_Command
(Script : access Python_Scripting_Record'Class;
Command : PyObject;
Args : Callback_Data'Class;
Error : access Boolean) return Any_Type
is
Obj : constant PyObject :=
Execute_Command (Script, Command, Args, Error);
begin
if Obj /= null then
declare
Any : constant Any_Type :=
GNATCOLL.Any_Types.Python.From_PyObject (Obj);
begin
Py_DECREF (Obj);
return Any;
end;
else
return Empty_Any_Type;
end if;
end Execute_Command;
---------------------
-- Execute_Command --
---------------------
function Execute_Command
(Script : access Python_Scripting_Record'Class;
Command : PyObject;
Args : Callback_Data'Class;
Error : access Boolean) return Boolean
is
Obj : constant PyObject :=
Execute_Command (Script, Command, Args, Error);
Result : Boolean;
begin
if Obj = null then
return False;
else
Result := ((PyInt_Check (Obj) and then PyInt_AsLong (Obj) = 1)
or else (PyBool_Check (Obj) and then PyBool_Is_True (Obj))
or else
(PyString_Check (Obj)
and then PyString_AsString (Obj) = "true")
or else
(PyUnicode_Check (Obj)
and then Unicode_AsString (Obj) = "true"));
Py_DECREF (Obj);
return Result;
end if;
end Execute_Command;
------------------
-- Execute_File --
------------------
procedure Execute_File
(Script : access Python_Scripting_Record;
Filename : String;
Console : Virtual_Console := null;
Hide_Output : Boolean := False;
Show_Command : Boolean := True;
Errors : out Boolean) is
begin
Script.Current_File := To_Unbounded_String (Filename);
-- Before executing a Python script, add its directory to sys.path.
-- This is to mimic the behavior of the command-line shell, and
-- allow the loaded script to "import" scripts in the same directory.
declare
D : constant String := +Create (+Filename).Dir_Name;
-- Use Virtual_File as a reliable way to get the directory
L : Natural := D'Last;
begin
-- Strip the ending '\' if any.
if D /= ""
and then D (L) = '\'
then
L := L - 1;
end if;
Execute_Command
(Script,
Create ("import sys;sys.path.insert(0, r'"
& D (D'First .. L) & "')"),
Console => null, Hide_Output => True,
Show_Command => False, Errors => Errors);
end;
-- The call to compile is only necessary to get an error message
-- pointing back to Filename
if Is_Python3 then
Execute_Command
(Script, Create ("exec(compile(open(r'" & Filename
& "').read(),r'" & Filename & "','exec'))"),
Console, Hide_Output, Show_Command, Errors);
else
Execute_Command
(Script, Create ("execfile(r'" & Filename & "')"),
Console, Hide_Output, Show_Command, Errors);
end if;
Script.Current_File := Null_Unbounded_String;
end Execute_File;
--------------
-- Get_Name --
--------------
function Get_Name (Script : access Python_Scripting_Record) return String is
pragma Unreferenced (Script);
begin
return Python_Name;
end Get_Name;
----------------
-- Get_Script --
----------------
function Get_Script (Data : Python_Callback_Data)
return Scripting_Language
is
begin
return Scripting_Language (Data.Script);
end Get_Script;
--------------------
-- Get_Repository --
--------------------
function Get_Repository (Script : access Python_Scripting_Record)
return Scripts_Repository is
begin
return Script.Repo;
end Get_Repository;
--------------------
-- Current_Script --
--------------------
function Current_Script
(Script : access Python_Scripting_Record) return String
is
begin
if Script.Current_File = Null_Unbounded_String then
return "<python script>";
else
return To_String (Script.Current_File);
end if;
end Current_Script;
-------------------------
-- Number_Of_Arguments --
-------------------------
function Number_Of_Arguments (Data : Python_Callback_Data) return Natural is
begin
if Data.Kw /= null then
return PyDict_Size (Data.Kw) + PyObject_Size (Data.Args);
else
return PyObject_Size (Data.Args);
end if;
end Number_Of_Arguments;
---------------------
-- Name_Parameters --
---------------------
procedure Name_Parameters
(Data : in out Python_Callback_Data; Params : Param_Array)
is
First : Integer := 0;
Old_Args : constant PyObject := Data.Args;
Item : PyObject;
Nargs : Natural := 0; -- Number of entries in Data.Args
Nkeywords : Integer; -- Number of unhandled entries in Data.Kw
begin
if Data.Kw = null then
return;
end if;
Nkeywords := PyDict_Size (Data.Kw);
if Data.Args /= null then
Nargs := PyObject_Size (Data.Args);
end if;
-- Modify Data.Args in place, so we need to resize it appropriately.
-- Then, through a single loop, we fill it.
if Data.First_Arg_Is_Self then
First := 1;
end if;
Data.Args := PyTuple_New (Params'Length + First);
if First > 0 then
-- Copy "self"
if Old_Args /= null then
Item := PyObject_GetItem (Old_Args, 0);
Py_DECREF (Item);
else
Item := PyDict_GetItemString (Data.Kw, "self");
if Item = null then
First := 0; -- Unbound method ?
end if;
end if;
if Item /= null then
PyTuple_SetItem (Data.Args, 0, Item);
Py_INCREF (Item);
end if;
end if;
for N in Params'Range loop
-- Do we have a corresponding keyword parameter ?
Item := PyDict_GetItemString (Data.Kw, Params (N).Name.all);
if Item /= null then
Nkeywords := Nkeywords - 1;
if N - Params'First + First < Nargs then
Set_Error_Msg
(Data, "Parameter cannot be both positional ("
& Image (N - Params'First + 1 + First, 0) & Nargs'Img
& Params'First'Img
& ") and named: " & Params (N).Name.all);
Py_DECREF (Old_Args);
raise Invalid_Parameter;
end if;
Py_INCREF (Item);
elsif N - Params'First + First < Nargs then
Item := PyObject_GetItem (Old_Args, N - Params'First + First);
else
Item := Py_None;
Py_INCREF (Item);
end if;
PyTuple_SetItem (Data.Args, N - Params'First + First, Item);
end loop;
Py_DECREF (Old_Args);
-- Are there unused keyword arguments ?
if Nkeywords > 0 then
declare
Pos : Integer := 0;
Key, Value : PyObject;
begin
loop
PyDict_Next (Data.Kw, Pos, Key, Value);
exit when Pos = 1;
declare
K : constant String := PyString_AsString (Key);
Found : Boolean := False;
begin
for N in Params'Range loop
if Params (N).Name.all = K then
Found := True;
exit;
end if;
end loop;
if not Found then
Set_Error_Msg (Data, "Invalid keyword parameter: " & K);
raise Invalid_Parameter
with "Invalid keyword parameter " & K;
end if;
end;
end loop;
end;
end if;
-- Get rid of the old arguments
Py_DECREF (Data.Kw);
Data.Kw := null;
end Name_Parameters;
---------------------
-- Name_Parameters --
---------------------
procedure Name_Parameters
(Data : in out Python_Callback_Data; Names : Cst_Argument_List)
is
function Convert is new Ada.Unchecked_Conversion
(Cst_String_Access, GNAT.Strings.String_Access);
Params : Param_Array (Names'Range);
begin
for N in Names'Range loop
-- The conversion here is safe: Name_Parameters does not modify the
-- string, nor does it try to free it
Params (N) := (Name => Convert (Names (N)),
Optional => True);
end loop;
Name_Parameters (Data, Params);
end Name_Parameters;
---------------
-- Get_Param --
---------------
function Get_Param
(Data : Python_Callback_Data'Class; N : Positive)
return PyObject
is
Obj : PyObject := null;
begin
if Data.Args /= null and then N <= PyObject_Size (Data.Args) then
Obj := PyObject_GetItem (Data.Args, N - 1);
end if;
if Obj = null and then Data.Kw /= null then
-- We haven't called Name_Parameters
PyErr_SetString
(Data.Script.Exception_Misc, "Keyword parameters not supported");
raise Invalid_Parameter;
end if;
if Obj = null or else Obj = Py_None then
raise No_Such_Parameter with N'Img;
end if;
Py_DECREF (Obj); -- Return a borrowed reference
return Obj;
end Get_Param;
---------------
-- Get_Param --
---------------
procedure Get_Param
(Data : Python_Callback_Data'Class;
N : Positive;
Result : out PyObject;
Success : out Boolean)
is
begin
Result := null;
if Data.Args /= null and then N <= PyObject_Size (Data.Args) then
Result := PyObject_GetItem (Data.Args, N - 1);
Py_DECREF (Result); -- We want to return a borrowed reference
end if;
if Result = null and then Data.Kw /= null then
-- We haven't called Name_Parameters
PyErr_SetString
(Data.Script.Exception_Misc, "Keyword parameters not supported");
raise Invalid_Parameter;
end if;
Success := Result /= null and then Result /= Py_None;
end Get_Param;
-------------
-- Nth_Arg --
-------------
overriding function Nth_Arg
(Data : Python_Callback_Data; N : Positive)
return List_Instance'Class
is
Item : PyObject;
Success : Boolean;
List : Python_Callback_Data;
Iter : PyObject;
begin
List.Script := Data.Script;
List.First_Arg_Is_Self := False;
Get_Param (Data, N, Item, Success);
if not Success then
List.Args := PyTuple_New (0); -- An empty list
else
Iter := PyObject_GetIter (Item);
if Iter = null then
raise Invalid_Parameter
with "Parameter" & Integer'Image (N) & " should be iterable";
end if;
if PyDict_Check (Item) then
raise Invalid_Parameter
with "Parameter" & Integer'Image (N)
& " should not be dictionary";
end if;
if PyAnySet_Check (Item) then
raise Invalid_Parameter
with "Parameter" & Integer'Image (N) & " should not be set";
end if;
Py_DECREF (Iter);
List.Args := Item; -- Item is a borrowed reference ?
Py_INCREF (Item); -- so we just increase the refcount
end if;
return List;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
overriding function Nth_Arg
(Data : Python_Callback_Data; N : Positive)
return Dictionary_Instance'Class
is
Item : PyObject;
Success : Boolean;
Dictionary : Python_Dictionary_Instance;
begin
Dictionary.Script := Data.Script;
Get_Param (Data, N, Item, Success);
if not Success then
Dictionary.Dict := PyDict_New; -- An empty dictionary
else
if not PyDict_Check (Item) then
Raise_Exception
(Invalid_Parameter'Identity,
"Parameter" & Integer'Image (N) & " should be dictionary");
end if;
Dictionary.Dict := Item; -- Item is a borrowed reference ?
Py_INCREF (Item); -- so we just increase the refcount
end if;
return Dictionary;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Success : access Boolean)
return String
is
Item : PyObject;
begin
Get_Param (Data, N, Item, Success.all);
if not Success.all then
return "";
end if;
if PyString_Check (Item) then
return PyString_AsString (Item);
elsif PyUnicode_Check (Item) then
return Unicode_AsString (Item, "utf-8");
else
raise Invalid_Parameter
with "Parameter" & Integer'Image (N)
& " should be a string or unicode";
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Success : access Boolean)
return Unbounded_String
is
Item : PyObject;
begin
Get_Param (Data, N, Item, Success.all);
if not Success.all then
return Null_Unbounded_String;
end if;
return To_Unbounded_String (String'(Nth_Arg (Data, N, Success)));
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Success : access Boolean)
return Integer
is
Item : PyObject;
begin
Get_Param
(Data, N, Item, Success.all);
if not Success.all then
return 0;
end if;
if not PyInt_Check (Item) then
raise Invalid_Parameter
with "Parameter" & Integer'Image (N) & " should be an integer";
else
return Integer (PyInt_AsLong (Item));
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Success : access Boolean)
return Float
is
Item : PyObject;
begin
Get_Param
(Data, N, Item, Success.all);
if not Success.all then
return 0.0;
end if;
if not PyFloat_Check (Item) then
if PyInt_Check (Item) then
return Float (PyInt_AsLong (Item));
else
raise Invalid_Parameter
with "Parameter" & Integer'Image (N) & " should be a float";
end if;
else
return Float (PyFloat_AsDouble (Item));
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Success : access Boolean) return Boolean
is
Item : PyObject;
begin
Get_Param (Data, N, Item, Success.all);
if not Success.all then
return False;
end if;
-- For backward compatibility, accept these as "False" values.
-- Don't check for unicode here, which was never supported anyway.
if PyString_Check (Item)
and then (To_Lower (PyString_AsString (Item)) = "false"
or else PyString_AsString (Item) = "0")
then
Insert_Text
(Get_Script (Data), null,
"Warning: using string 'false' instead of"
& " boolean False is obsolescent");
return False;
else
-- Use standard python behavior
return PyObject_IsTrue (Item);
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Success : access Boolean) return Subprogram_Type
is
Item : PyObject;
begin
Get_Param (Data, N, Item, Success.all);
if not Success.all then
return null;
end if;
if Item /= null
and then (PyFunction_Check (Item) or else PyMethod_Check (Item))
then
Py_INCREF (Item);
return new Python_Subprogram_Record'
(Subprogram_Record with
Script => Python_Scripting (Get_Script (Data)),
Subprogram => Item);
else
raise Invalid_Parameter;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Class : Class_Type;
Allow_Null : Boolean; Success : access Boolean)
return Class_Instance
is
Item : PyObject;
C : PyObject;
Item_Class : PyObject;
begin
if Class /= Any_Class then
C := Lookup_Object (Data.Script, Class.Qualified_Name.all);
end if;
Get_Param (Data, N, Item, Success.all); -- Item is a borrowed reference
if not Success.all then
return No_Class_Instance;
end if;
if Class /= Any_Class
and then not PyObject_IsInstance (Item, C)
then
raise Invalid_Parameter
with "Parameter" & Integer'Image (N) & " should be an instance of "
& Get_Name (Class);
end if;
Item_Class := PyObject_GetAttrString (Item, "__class__");
-- Item_Class must be DECREF'd
if Item_Class = null then
raise Invalid_Parameter
with "Parameter" & Integer'Image (N) & " should be an instance of "
& Get_Name (Class) & " but has no __class__";
end if;
Py_DECREF (Item_Class);
return Get_CI (Python_Scripting (Get_Script (Data)), Item);
exception
when No_Such_Parameter =>
if Allow_Null then
return No_Class_Instance;
else
raise;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive) return String
is
Success : aliased Boolean;
Result : constant String := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
raise No_Such_Parameter with N'Img;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive) return Unbounded_String
is
Success : aliased Boolean;
Result : constant Unbounded_String := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
raise No_Such_Parameter with N'Img;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive) return Integer
is
Success : aliased Boolean;
Result : constant Integer := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
raise No_Such_Parameter with N'Img;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive) return Float
is
Success : aliased Boolean;
Result : constant Float := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
raise No_Such_Parameter with N'Img;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive) return Boolean
is
Success : aliased Boolean;
Result : constant Boolean := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
raise No_Such_Parameter with N'Img;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive) return Subprogram_Type
is
Success : aliased Boolean;
Result : constant Subprogram_Type := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
raise No_Such_Parameter with N'Img;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Class : Class_Type;
Allow_Null : Boolean := False)
return Class_Instance
is
Success : aliased Boolean;
Result : constant Class_Instance :=
Nth_Arg (Data, N, Class, Allow_Null, Success'Access);
begin
if not Success then
if Allow_Null then
return No_Class_Instance;
else
raise No_Such_Parameter with N'Img;
end if;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Default : String)
return String
is
Success : aliased Boolean;
Result : constant String := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
return Default;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Default : Integer)
return Integer
is
Success : aliased Boolean;
Result : constant Integer := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
return Default;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data; N : Positive; Default : Boolean)
return Boolean
is
Success : aliased Boolean;
Result : constant Boolean := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
return Default;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Class : Class_Type := Any_Class;
Default : Class_Instance;
Allow_Null : Boolean := False) return Class_Instance
is
Success : aliased Boolean;
Result : constant Class_Instance :=
Nth_Arg (Data, N, Class, Allow_Null, Success'Access);
begin
if not Success then
return Default;
else
return Result;
end if;
end Nth_Arg;
-------------
-- Nth_Arg --
-------------
function Nth_Arg
(Data : Python_Callback_Data;
N : Positive;
Default : Subprogram_Type) return Subprogram_Type
is
Success : aliased Boolean;
Result : constant Subprogram_Type := Nth_Arg (Data, N, Success'Access);
begin
if not Success then
return Default;
else
return Result;
end if;
end Nth_Arg;
-------------------
-- Get_User_Data --
-------------------
overriding function Get_User_Data
(Inst : not null access Python_Class_Instance_Record)
return access User_Data_List
is
Item : constant PyObject :=
PyObject_GetAttrString (Inst.Data, "__gps_data");
Data : PyObject;
Tmp : PyObject_Data;
Tmp_Addr : System.Address;
begin
if Item = null then
PyErr_Clear; -- error about "no such attribute"
Tmp := new PyObject_Data_Record;
Data := PyCObject_FromVoidPtr
(Tmp.all'Address, On_PyObject_Data_Destroy'Access);
if PyObject_GenericSetAttrString (Inst.Data, "__gps_data", Data) /=
0
then
Trace (Me, "Error creating __gps_data");
PyErr_Clear;
Py_DECREF (Data);
Unchecked_Free (Tmp);
return null;
end if;
Py_DECREF (Data);
return Tmp.Props'Access;
else
Tmp_Addr := PyCObject_AsVoidPtr (Item);
Tmp := Convert (Tmp_Addr);
Py_DECREF (Item);
return Tmp.Props'Access;
end if;
end Get_User_Data;
------------------------------
-- On_PyObject_Data_Destroy --
------------------------------
procedure On_PyObject_Data_Destroy (Data : System.Address) is
D : PyObject_Data := Convert (Data);
begin
Free_User_Data_List (D.Props);
Unchecked_Free (D);
end On_PyObject_Data_Destroy;
---------------------------------
-- Unregister_Python_Scripting --
---------------------------------
procedure Unregister_Python_Scripting
(Repo : access Scripts.Scripts_Repository_Record'Class)
is
Script : constant Scripting_Language := Lookup_Scripting_Language
(Repo, Python_Name);
begin
if Script /= null then
Destroy (Script);
end if;
end Unregister_Python_Scripting;
------------
-- Get_CI --
------------
function Get_CI
(Script : Python_Scripting; Object : PyObject) return Class_Instance
is
CI : Python_Class_Instance;
begin
PyErr_Clear;
-- If there was no instance, avoid a python exception later
CI := new Python_Class_Instance_Record;
CI.Script := Script;
CI.Data := Object; -- adopts the object
Py_INCREF (Object);
-- the class_instance needs to own one ref (decref'ed in Free)
return R : Class_Instance do
CI_Pointers.Set (R.Ref, CI);
end return;
end Get_CI;
----------
-- Free --
----------
overriding procedure Free (Self : in out Python_Class_Instance_Record) is
begin
if not Finalized then
Py_XDECREF (Self.Data);
end if;
end Free;
------------------
-- Get_PyObject --
------------------
function Get_PyObject (Instance : Class_Instance) return PyObject is
begin
return Python_Class_Instance (Get_CIR (Instance)).Data;
end Get_PyObject;
-----------------
-- Is_Subclass --
-----------------
function Is_Subclass
(Instance : access Python_Class_Instance_Record;
Base : String) return Boolean
is
C, B : PyObject;
begin
if Instance.Data = null then
raise Program_Error;
end if;
C := PyObject_GetAttrString (Instance.Data, "__class__");
B := Lookup_Object (Python_Scripting (Instance.Script), Base);
return Py_IsSubclass (C, Base => B);
end Is_Subclass;
------------------------
-- Setup_Return_Value --
------------------------
procedure Setup_Return_Value (Data : in out Python_Callback_Data'Class) is
begin
Py_XDECREF (Data.Return_Value);
Data.Has_Return_Value := True;
Data.Return_As_List := False;
Data.Return_Value := null;
end Setup_Return_Value;
-------------------
-- Set_Error_Msg --
-------------------
procedure Set_Error_Msg
(Data : in out Python_Callback_Data; Msg : String) is
begin
Setup_Return_Value (Data);
if Msg /= "" then
PyErr_SetString (Data.Script.Exception_Misc, Msg);
end if;
end Set_Error_Msg;
-----------------------
-- Prepare_Value_Key --
-----------------------
procedure Prepare_Value_Key
(Data : in out Python_Callback_Data'Class;
Key : PyObject;
Append : Boolean)
is
Obj, List : PyObject;
Tmp : Integer;
pragma Unreferenced (Tmp);
Created_List : Boolean := False;
begin
if Data.Return_Dict = null then
Data.Return_Dict := PyDict_New;
end if;
if Append then
Obj := PyDict_GetItem (Data.Return_Dict, Key);
if Obj /= null then
if PyList_Check (Obj) then
List := Obj;
else
List := PyList_New;
Tmp := PyList_Append (List, Obj);
Created_List := True;
end if;
Tmp := PyList_Append (List, Data.Return_Value);
else
List := Data.Return_Value;
end if;
else
List := Data.Return_Value;
end if;
Tmp := PyDict_SetItem (Data.Return_Dict, Key, List);
if Created_List then
Py_DECREF (List);
-- The only reference is now owned by the dictionary
end if;
-- Return_Value was either added to the value or directly to the
-- dictionary. In both cases, its refcount was increased by one.
Py_DECREF (Data.Return_Value);
Data.Return_Value := Py_None;
Py_INCREF (Data.Return_Value);
Data.Return_As_List := False;
end Prepare_Value_Key;
--------------------------
-- Set_Return_Value_Key --
--------------------------
procedure Set_Return_Value_Key
(Data : in out Python_Callback_Data;
Key : Integer;
Append : Boolean := False)
is
K : constant PyObject := PyInt_FromLong (long (Key));
begin
Prepare_Value_Key (Data, K, Append);
Py_DECREF (K);
end Set_Return_Value_Key;
--------------------------
-- Set_Return_Value_Key --
--------------------------
procedure Set_Return_Value_Key
(Data : in out Python_Callback_Data;
Key : String;
Append : Boolean := False)
is
K : constant PyObject := PyString_FromString (Key);
begin
Prepare_Value_Key (Data, K, Append);
Py_DECREF (K);
end Set_Return_Value_Key;
--------------------------
-- Set_Return_Value_Key --
--------------------------
procedure Set_Return_Value_Key
(Data : in out Python_Callback_Data;
Key : Class_Instance;
Append : Boolean := False)
is
K : constant PyObject := Python_Class_Instance (Get_CIR (Key)).Data;
begin
Prepare_Value_Key (Data, K, Append);
-- Do not decrease the reference counting here (even though the key has
-- now one more reference owned by Data.Return_Dict), since a
-- Class_Instance is refcounted as well, and will automatically decrease
-- the reference counting when no longer in use
-- Py_DECREF (K);
end Set_Return_Value_Key;
------------------------------
-- Set_Return_Value_As_List --
------------------------------
procedure Set_Return_Value_As_List
(Data : in out Python_Callback_Data;
Size : Natural := 0;
Class : Class_Type := No_Class)
is
pragma Unreferenced (Size);
begin
Setup_Return_Value (Data);
Data.Return_As_List := True;
Data.Has_Return_Value := True;
if Class = No_Class then
Data.Return_Value := PyList_New;
else
declare
C : constant Class_Instance := New_Instance (Data.Script, Class);
begin
if C = No_Class_Instance then
raise Program_Error;
end if;
Data.Return_Value := Python_Class_Instance (Get_CIR (C)).Data;
Py_INCREF (Data.Return_Value);
end;
end if;
end Set_Return_Value_As_List;
----------------------
-- Set_Return_Value --
----------------------
procedure Set_Return_Value
(Data : in out Python_Callback_Data; Value : PyObject)
is
Num : Integer;
pragma Unreferenced (Num);
begin
if Data.Return_As_List then
Num := PyList_Append (Data.Return_Value, Value);
else
Setup_Return_Value (Data);
Data.Return_Value := Value;
Py_INCREF (Value);
end if;
end Set_Return_Value;
----------------------
-- Set_Return_Value --
----------------------
procedure Set_Return_Value
(Data : in out Python_Callback_Data; Value : Integer)
is
Val : constant PyObject := PyInt_FromLong (long (Value));
begin
Set_Return_Value (Data, Val);
Py_DECREF (Val);
end Set_Return_Value;
------------------------------
-- Set_Address_Return_Value --
------------------------------
overriding procedure Set_Address_Return_Value
(Data : in out Python_Callback_Data; Value : System.Address)
is
Val : constant PyObject :=
PyInt_FromSize_t (size_t (To_Integer (Value)));
begin
Set_Return_Value (Data, Val);
Py_DECREF (Val);
end Set_Address_Return_Value;
----------------------
-- Set_Return_Value --
----------------------
procedure Set_Return_Value
(Data : in out Python_Callback_Data; Value : Float)
is
Val : constant PyObject := PyFloat_FromDouble (double (Value));
begin
Set_Return_Value (Data, Val);
Py_DECREF (Val);
end Set_Return_Value;
----------------------
-- Set_Return_Value --
----------------------
procedure Set_Return_Value
(Data : in out Python_Callback_Data; Value : String)
is
Val : constant PyObject := PyString_FromString (Value);
begin
Set_Return_Value (Data, Val);
Py_DECREF (Val);
end Set_Return_Value;
----------------------
-- Set_Return_Value --
----------------------
procedure Set_Return_Value
(Data : in out Python_Callback_Data; Value : Boolean)
is
Val : constant PyObject := PyBool_FromBoolean (Value);
begin
Set_Return_Value (Data, Val);
Py_DECREF (Val);
end Set_Return_Value;
----------------------
-- Set_Return_Value --
----------------------
procedure Set_Return_Value
(Data : in out Python_Callback_Data; Value : Class_Instance)
is
V : constant Python_Class_Instance :=
Python_Class_Instance (Get_CIR (Value));
Obj : PyObject;
Num : Integer;
pragma Unreferenced (Num);
begin
if V /= null then
Obj := V.Data;
if Active (Me) then
Assert (Me, V.Data /= null, "A Class_Instance has no PyObject");
end if;
else
Obj := Py_None;
end if;
if Data.Return_As_List then
Num := PyList_Append (Data.Return_Value, Obj); -- Increase refcount
-- Py_DECREF (Obj); -- The reference to Object is adopted by the result
else
Setup_Return_Value (Data);
Data.Return_Value := Obj;
Py_INCREF (Obj);
end if;
end Set_Return_Value;
----------------------
-- Set_Return_Value --
----------------------
procedure Set_Return_Value
(Data : in out Python_Callback_Data; Value : List_Instance)
is
V : constant PyObject := Python_Callback_Data (Value).Args;
Num : Integer;
pragma Unreferenced (Num);
begin
if Data.Return_As_List then
Num := PyList_Append (Data.Return_Value, V); -- Increase refcount
else
Py_INCREF (V);
Setup_Return_Value (Data);
Data.Return_Value := V;
end if;
end Set_Return_Value;
--------------
-- New_List --
--------------
overriding function New_List
(Script : access Python_Scripting_Record;
Class : Class_Type := No_Class)
return List_Instance'Class
is
List : Python_Callback_Data;
begin
List.Script := Python_Scripting (Script);
List.First_Arg_Is_Self := False;
if Class = No_Class then
List.Args := PyList_New;
else
declare
C : constant Class_Instance := New_Instance (Script, Class);
begin
if C = No_Class_Instance then
raise Program_Error;
end if;
List.Args := Python_Class_Instance (Get_CIR (C)).Data;
Py_INCREF (List.Args);
end;
end if;
return List;
end New_List;
------------------
-- New_Instance --
------------------
function New_Instance
(Script : access Python_Scripting_Record;
Class : Class_Type) return Class_Instance
is
Klass : constant PyObject :=
Lookup_Object (Script, Class.Qualified_Name.all);
Inst : Class_Instance;
Obj : PyObject;
Args : PyObject;
begin
if Klass = null then
return No_Class_Instance;
end if;
-- Creating a new instance is equivalent to calling its metaclass. This
-- is true for both new-style classes and old-style classes (for which
-- the tp_call slot is set to PyInstance_New.
-- Here, we are in fact calling Class.__new__ (cls, *args, **kwargs).
-- After allocating memory, this in turns automatically tp_init in the
-- type definition, which in the case of GNATCOLL cases is often set to
-- slot_tp_init. The latter in turn calls __init__
--
-- ??? This API does not permit passing extra parameters to the call
Args := PyTuple_New (0);
Script.Ignore_Constructor := True;
Obj := PyObject_Call
(Object => Klass,
Args => Args,
Kw => null); -- NOT: Py_None, which is not a valid dictionary
Script.Ignore_Constructor := False;
Py_DECREF (Args);
if Obj = null then
if Active (Me) then
Trace (Me, "Could not create instance");
PyErr_Print; -- debugging only
end if;
return No_Class_Instance;
end if;
if Active (Me) then
Assert
(Me, Get_Refcount (Obj) = 1,
"Object's refcount should be 1, got "
& Get_Refcount (Obj)'Img,
Raise_Exception => False);
end if;
Inst := Get_CI (Python_Scripting (Script), Obj); -- increases refcount
Py_DECREF (Obj);
-- The PyObject should have a single reference in the end, owned by
-- the class instance itself.
if Active (Me) then
Assert
(Me,
Get_Refcount (Python_Class_Instance (Get_CIR (Inst)).Data) = 1,
"New_Instance should own a single refcount of PyObject, got "
& Print_Refcount (Get_CIR (Inst)),
Raise_Exception => False);
end if;
return Inst;
exception
when others =>
Script.Ignore_Constructor := False;
raise;
end New_Instance;
----------------
-- Get_Method --
----------------
overriding function Get_Method
(Instance : access Python_Class_Instance_Record;
Name : String) return Subprogram_Type
is
Inst : constant PyObject := Instance.Data;
Subp : constant PyObject :=
PyObject_GetAttrString (Inst, Name => Name);
begin
if Subp = null then
-- Clear the raised python exception
PyErr_Clear;
return null;
else
return new Python_Subprogram_Record'
(Script => Python_Scripting (Instance.Script),
Subprogram => Subp);
end if;
end Get_Method;
--------------------
-- Print_Refcount --
--------------------
function Print_Refcount
(Instance : access Python_Class_Instance_Record) return String is
begin
if Instance.Data /= null then
return Print_Refcount (Class_Instance_Record (Instance.all)'Access)
& " Py=" & Value (Refcount_Msg (Instance.Data));
else
return Print_Refcount (Class_Instance_Record (Instance.all)'Access)
& " Py=<None>";
end if;
end Print_Refcount;
-------------
-- Execute --
-------------
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return Boolean is
begin
return Execute_Command
(Script => Subprogram.Script,
Command => Subprogram.Subprogram,
Args => Args,
Error => Error);
end Execute;
-------------
-- Execute --
-------------
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return String is
begin
return Execute_Command
(Script => Subprogram.Script,
Command => Subprogram.Subprogram,
Args => Args,
Error => Error);
end Execute;
-------------
-- Execute --
-------------
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return Class_Instance
is
Obj : PyObject;
begin
Obj := Execute_Command
(Script => Subprogram.Script,
Command => Subprogram.Subprogram,
Args => Args,
Error => Error);
if Obj = null then
return No_Class_Instance;
else
return Get_CI (Subprogram.Script, Obj);
end if;
end Execute;
-------------
-- Execute --
-------------
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return List_Instance'Class
is
Obj : PyObject;
List : Python_Callback_Data;
begin
Obj := Execute_Command
(Script => Subprogram.Script,
Command => Subprogram.Subprogram,
Args => Args,
Error => Error);
List.Script := Subprogram.Script;
List.First_Arg_Is_Self := False;
List.Args := Obj; -- now owns the reference to Obj
return List;
end Execute;
-------------
-- Execute --
-------------
overriding function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return Any_Type
is
begin
return Execute_Command
(Script => Subprogram.Script,
Command => Subprogram.Subprogram,
Args => Args,
Error => Error);
end Execute;
-------------
-- Execute --
-------------
function Execute
(Subprogram : access Python_Subprogram_Record;
Args : Callback_Data'Class;
Error : not null access Boolean) return GNAT.Strings.String_List
is
Obj : constant PyObject := Execute_Command
(Script => Subprogram.Script,
Command => Subprogram.Subprogram,
Args => Args,
Error => Error);
begin
if Obj = null then
return (1 .. 0 => null);
elsif Obj = Py_None then
Py_DECREF (Obj);
return (1 .. 0 => null);
elsif PyString_Check (Obj) then
declare
Str : constant String := PyString_AsString (Obj);
begin
Py_DECREF (Obj);
return (1 .. 1 => new String'(Str));
end;
elsif PyUnicode_Check (Obj) then
declare
Str : constant String := Unicode_AsString (Obj);
begin
Py_DECREF (Obj);
return (1 .. 1 => new String'(Str));
end;
elsif PyList_Check (Obj) then
declare
Result : GNAT.Strings.String_List (1 .. PyList_Size (Obj));
Item : PyObject;
begin
for J in 0 .. PyList_Size (Obj) - 1 loop
Item := PyList_GetItem (Obj, J);
if PyString_Check (Item) then
Result (J + 1) := new String'(PyString_AsString (Item));
elsif PyUnicode_Check (Item) then
Result (J + 1) := new String'(Unicode_AsString (Item));
end if;
end loop;
Py_DECREF (Obj);
return Result;
end;
end if;
Py_DECREF (Obj);
return (1 .. 0 => null);
end Execute;
----------
-- Free --
----------
procedure Free (Subprogram : in out Python_Subprogram_Record) is
begin
if not Finalized then
Py_DECREF (Subprogram.Subprogram);
end if;
end Free;
--------------
-- Get_Name --
--------------
function Get_Name
(Subprogram : access Python_Subprogram_Record) return String
is
S : constant PyObject := PyObject_Str (Subprogram.Subprogram);
Name : constant String := PyString_AsString (S);
begin
Py_DECREF (S);
return Name;
end Get_Name;
----------------
-- Get_Script --
----------------
function Get_Script
(Subprogram : Python_Subprogram_Record) return Scripting_Language
is
begin
return Scripting_Language (Subprogram.Script);
end Get_Script;
-------------------------
-- Set_Default_Console --
-------------------------
procedure Set_Default_Console
(Script : access Python_Scripting_Record;
Console : Virtual_Console)
is
Inst : Class_Instance;
Cons : PyObject := Py_None;
Errors : aliased Boolean;
begin
Set_Default_Console
(Scripting_Language_Record (Script.all)'Access, Console);
if Console /= null
and then Get_Console_Class (Get_Repository (Script)) /= No_Class
then
Inst := Get_Instance (Script, Console);
if Inst = No_Class_Instance then
Inst := New_Instance
(Script, Get_Console_Class (Get_Repository (Script)));
Set_Data (Inst, Console => Console);
end if;
Cons := Python_Class_Instance (Get_CIR (Inst)).Data;
PyDict_SetItemString
(PyModule_GetDict (PyImport_ImportModule ("sys")), "stdout", Cons);
PyDict_SetItemString
(PyModule_GetDict (PyImport_ImportModule ("sys")), "stderr", Cons);
PyDict_SetItemString
(PyModule_GetDict (PyImport_ImportModule ("sys")), "stdin", Cons);
else
Cons := Run_Command
(Script,
"sys.stdout, sys.stdin, sys.stderr = "
& "sys.__stdout__, sys.__stdin__, sys.__stderr__",
Hide_Output => True,
Need_Output => False,
Errors => Errors'Access);
Py_XDECREF (Cons);
end if;
end Set_Default_Console;
------------------
-- Set_Property --
------------------
overriding procedure Set_Property
(Instance : access Python_Class_Instance_Record;
Name : String; Value : Integer)
is
Val : PyObject;
Result : Integer;
pragma Unreferenced (Result);
begin
Val := PyInt_FromLong (long (Value));
Result := PyObject_GenericSetAttrString (Instance.Data, Name, Val);
Py_DECREF (Val);
end Set_Property;
overriding procedure Set_Property
(Instance : access Python_Class_Instance_Record;
Name : String; Value : Float)
is
Val : PyObject;
Result : Integer;
pragma Unreferenced (Result);
begin
Val := PyFloat_FromDouble (double (Value));
Result := PyObject_GenericSetAttrString (Instance.Data, Name, Val);
Py_DECREF (Val);
end Set_Property;
overriding procedure Set_Property
(Instance : access Python_Class_Instance_Record;
Name : String; Value : Boolean)
is
Val : PyObject;
Result : Integer;
pragma Unreferenced (Result);
begin
Val := PyBool_FromBoolean (Value);
Result := PyObject_GenericSetAttrString (Instance.Data, Name, Val);
Py_DECREF (Val);
end Set_Property;
overriding procedure Set_Property
(Instance : access Python_Class_Instance_Record;
Name : String; Value : String)
is
Val : PyObject;
Result : Integer;
pragma Unreferenced (Result);
begin
Val := PyString_FromString (Value);
Result := PyObject_GenericSetAttrString (Instance.Data, Name, Val);
Py_DECREF (Val);
end Set_Property;
--------------------
-- Load_Directory --
--------------------
overriding procedure Load_Directory
(Script : access Python_Scripting_Record;
Directory : GNATCOLL.VFS.Virtual_File;
To_Load : Script_Loader := Load_All'Access)
is
Files : File_Array_Access;
Path : constant String := +Directory.Full_Name (True);
Last : Integer := Path'Last;
Errors : Boolean;
begin
if not Directory.Is_Directory then
return;
end if;
Trace (Me, "Load python files from " & Path);
-- Add the directory to the default python search path.
-- Python requires no trailing dir separator (at least on Windows)
if Is_Directory_Separator (Path (Last)) then
Last := Last - 1;
end if;
Execute_Command
(Script,
Create ("sys.path=[r'" & Path (Path'First .. Last) & "']+sys.path"),
Show_Command => False,
Hide_Output => True,
Errors => Errors);
-- ??? Should also check for python modules (ie subdirectories that
-- contain a __init__.py file
Files := Directory.Read_Dir;
-- Sort the files, to make the load order more stable than the
-- filesystem order.
Sort (Files.all);
for J in Files'Range loop
if Equal (Files (J).File_Extension, ".py") then
if To_Load (Files (J)) then
Trace (Me, "Load " & Files (J).Display_Full_Name);
Execute_Command
(Script,
Create ("import " & (+Base_Name (Files (J), ".py"))),
Show_Command => False,
Hide_Output => True,
Errors => Errors);
end if;
elsif Is_Regular_File (Create_From_Dir (Files (J), "__init__.py"))
and then To_Load (Files (J))
then
Trace (Me, "Load " & (+Base_Dir_Name (Files (J))) & "/");
Execute_Command
(Script,
Create ("import " & (+Base_Dir_Name (Files (J)))),
Show_Command => False,
Hide_Output => True,
Errors => Errors);
end if;
end loop;
Unchecked_Free (Files);
end Load_Directory;
------------------------
-- Execute_Expression --
------------------------
overriding procedure Execute_Expression
(Result : in out Python_Callback_Data;
Expression : String;
Hide_Output : Boolean := True)
is
Script : constant Python_Scripting :=
Python_Scripting (Get_Script (Result));
Res : PyObject;
Errors : aliased Boolean;
begin
if Script.Blocked then
Set_Error_Msg (Result, "A command is already executing");
else
Res := Run_Command
(Script,
Command => Expression,
Hide_Output => Hide_Output,
Hide_Exceptions => Hide_Output,
Need_Output => True,
Errors => Errors'Access);
Setup_Return_Value (Result);
if Errors then
Py_XDECREF (Res);
PyErr_Clear;
raise Error_In_Command with "Error in '" & Expression & "()'";
else
Result.Return_Value := Res; -- Adopts a reference
end if;
end if;
end Execute_Expression;
---------------------
-- Execute_Command --
---------------------
overriding procedure Execute_Command
(Args : in out Python_Callback_Data;
Command : String;
Hide_Output : Boolean := True)
is
Script : constant Python_Scripting :=
Python_Scripting (Get_Script (Args));
Func : PyObject;
Errors : aliased Boolean;
Result : PyObject;
begin
if Script.Blocked then
Set_Error_Msg (Args, "A command is already executing");
else
-- Fetch a handle on the function to execute. What we want to execute
-- is:
-- func = module.function_name
-- func(args)
Func := Run_Command
(Script,
Command => Command,
Hide_Output => Hide_Output,
Need_Output => True,
Errors => Errors'Access);
if Func /= null and then PyCallable_Check (Func) then
Setup_Return_Value (Args);
Result := Execute_Command (Script, Func, Args, Errors'Access);
if Errors then
Py_XDECREF (Result);
PyErr_Clear;
raise Error_In_Command with "Error in '" & Command & "()'";
else
Args.Return_Value := Result; -- Adopts a reference
end if;
else
raise Error_In_Command with Command & " is not a function";
end if;
end if;
end Execute_Command;
------------------
-- Return_Value --
------------------
overriding function Return_Value
(Data : Python_Callback_Data) return String is
begin
if Data.Return_Value = null then
raise Invalid_Parameter
with "Returned value is null (a python exception ?)";
elsif PyString_Check (Data.Return_Value) then
return PyString_AsString (Data.Return_Value);
elsif PyUnicode_Check (Data.Return_Value) then
return Unicode_AsString (Data.Return_Value);
else
raise Invalid_Parameter with "Returned value is not a string";
end if;
end Return_Value;
------------------
-- Return_Value --
------------------
overriding function Return_Value
(Data : Python_Callback_Data) return Integer is
begin
if not PyInt_Check (Data.Return_Value) then
raise Invalid_Parameter with "Returned value is not an integer";
else
return Integer (PyInt_AsLong (Data.Return_Value));
end if;
end Return_Value;
------------------
-- Return_Value --
------------------
overriding function Return_Value
(Data : Python_Callback_Data) return Float is
begin
if not PyFloat_Check (Data.Return_Value) then
raise Invalid_Parameter with "Returned value is not a float";
else
return Float (PyFloat_AsDouble (Data.Return_Value));
end if;
end Return_Value;
------------------
-- Return_Value --
------------------
overriding function Return_Value
(Data : Python_Callback_Data) return Boolean is
begin
return PyObject_IsTrue (Data.Return_Value);
end Return_Value;
------------------
-- Return_Value --
------------------
overriding function Return_Value
(Data : Python_Callback_Data) return Class_Instance
is
begin
if Data.Return_Value = Py_None then
return No_Class_Instance;
else
return Get_CI
(Python_Scripting (Get_Script (Data)), Data.Return_Value);
end if;
end Return_Value;
------------------
-- Return_Value --
------------------
overriding function Return_Value
(Data : Python_Callback_Data) return List_Instance'Class
is
List : Python_Callback_Data;
Iter : PyObject;
begin
List.Script := Data.Script;
List.First_Arg_Is_Self := False;
Iter := PyObject_GetIter (Data.Return_Value);
if Iter = null then
raise Invalid_Parameter with "Return value is not an iterable";
end if;
Py_DECREF (Iter);
List.Args := Data.Return_Value;
Py_INCREF (List.Args);
return List;
end Return_Value;
--------------
-- Iterator --
--------------
function Iterator
(Self : Python_Dictionary_Instance) return Dictionary_Iterator'Class is
begin
return
Python_Dictionary_Iterator'
(Script => Self.Script,
Dict => Self.Dict,
Position => 0,
Key => null,
Value => null);
end Iterator;
----------
-- Next --
----------
function Next
(Self : not null access Python_Dictionary_Iterator) return Boolean is
begin
if Self.Position /= -1 then
PyDict_Next (Self.Dict, Self.Position, Self.Key, Self.Value);
end if;
return Self.Position /= -1;
end Next;
-------------
-- Has_Key --
-------------
function Has_Key
(Self : Python_Dictionary_Instance; Key : String) return Boolean
is
K : constant PyObject := PyString_FromString (Key);
begin
return Result : constant Boolean := PyDict_Contains (Self.Dict, K) do
Py_DECREF (K);
end return;
end Has_Key;
-------------
-- Has_Key --
-------------
function Has_Key
(Self : Python_Dictionary_Instance; Key : Integer) return Boolean
is
K : constant PyObject := PyInt_FromLong (Interfaces.C.long (Key));
begin
return Result : constant Boolean := PyDict_Contains (Self.Dict, K) do
Py_DECREF (K);
end return;
end Has_Key;
-------------
-- Has_Key --
-------------
function Has_Key
(Self : Python_Dictionary_Instance; Key : Float) return Boolean
is
K : constant PyObject := PyFloat_FromDouble (Interfaces.C.double (Key));
begin
return Result : constant Boolean := PyDict_Contains (Self.Dict, K) do
Py_DECREF (K);
end return;
end Has_Key;
-------------
-- Has_Key --
-------------
function Has_Key
(Self : Python_Dictionary_Instance; Key : Boolean) return Boolean
is
K : constant PyObject := PyBool_FromBoolean (Key);
begin
return Result : constant Boolean := PyDict_Contains (Self.Dict, K) do
Py_DECREF (K);
end return;
end Has_Key;
--------------------
-- Conditional_To --
--------------------
function Conditional_To
(Condition : Boolean; Object : PyObject; Name : String) return String is
begin
if not Condition
or else Object = null
or else Object = Py_None
then
return "";
end if;
if PyString_Check (Object) then
return PyString_AsString (Object);
elsif PyUnicode_Check (Object) then
return Unicode_AsString (Object, "utf-8");
else
raise Invalid_Parameter
with Name & " should be a string or unicode";
end if;
end Conditional_To;
--------------------
-- Conditional_To --
--------------------
function Conditional_To
(Condition : Boolean; Object : PyObject; Name : String) return Integer is
begin
if not Condition
or else Object = null
or else Object = Py_None
then
return 0;
end if;
if PyInt_Check (Object) then
return Integer (PyInt_AsLong (Object));
else
raise Invalid_Parameter with Name & " should be an integer";
end if;
end Conditional_To;
--------------------
-- Conditional_To --
--------------------
function Conditional_To
(Condition : Boolean; Object : PyObject; Name : String) return Float is
begin
if not Condition
or else Object = null
or else Object = Py_None
then
return 0.0;
end if;
if not PyFloat_Check (Object) then
if PyInt_Check (Object) then
return Float (PyInt_AsLong (Object));
else
raise Invalid_Parameter with Name & " should be a float";
end if;
else
return Float (PyFloat_AsDouble (Object));
end if;
end Conditional_To;
--------------------
-- Conditional_To --
--------------------
function Conditional_To
(Condition : Boolean;
Script : Scripting_Language;
Object : PyObject) return Boolean is
begin
if not Condition
or else Object = null
or else Object = Py_None
then
return False;
end if;
-- For backward compatibility, accept these as "False" values.
-- Don't check for unicode here, which was never supported anyway.
if PyString_Check (Object)
and then (To_Lower (PyString_AsString (Object)) = "false"
or else PyString_AsString (Object) = "0")
then
Insert_Text
(Script,
null,
"Warning: using string 'false' instead of"
& " boolean False is obsolescent");
return False;
else
-- Use standard python behavior
return PyObject_IsTrue (Object);
end if;
end Conditional_To;
-----------------
-- Internal_To --
-----------------
function Internal_To (Object : PyObject; Name : String) return String is
begin
return Conditional_To (True, Object, Name);
end Internal_To;
-----------------
-- Internal_To --
-----------------
function Internal_To (Object : PyObject; Name : String) return Integer is
begin
return Conditional_To (True, Object, Name);
end Internal_To;
-----------------
-- Internal_To --
-----------------
function Internal_To (Object : PyObject; Name : String) return Float is
begin
return Conditional_To (True, Object, Name);
end Internal_To;
-----------------
-- Internal_To --
-----------------
function Internal_To
(Script : Scripting_Language; Object : PyObject) return Boolean is
begin
return Conditional_To (True, Script, Object);
end Internal_To;
---------
-- Key --
---------
function Key (Self : Python_Dictionary_Iterator) return String is
begin
return Conditional_To (Self.Position /= -1, Self.Key, "Key");
end Key;
---------
-- Key --
---------
function Key (Self : Python_Dictionary_Iterator) return Integer is
begin
return Conditional_To (Self.Position /= -1, Self.Key, "Key");
end Key;
---------
-- Key --
---------
function Key (Self : Python_Dictionary_Iterator) return Float is
begin
return Conditional_To (Self.Position /= -1, Self.Key, "Key");
end Key;
---------
-- Key --
---------
function Key (Self : Python_Dictionary_Iterator) return Boolean is
begin
return
Conditional_To
(Self.Position /= -1, Scripting_Language (Self.Script), Self.Key);
end Key;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : String) return String
is
K : constant PyObject := PyUnicode_FromString (Key);
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Integer) return String
is
K : constant PyObject := PyInt_FromLong (Interfaces.C.long (Key));
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Float) return String
is
K : constant PyObject := PyFloat_FromDouble (Interfaces.C.double (Key));
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Boolean) return String
is
K : constant PyObject := PyBool_FromBoolean (Key);
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : String) return Integer
is
K : constant PyObject := PyUnicode_FromString (Key);
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Integer) return Integer
is
K : constant PyObject := PyInt_FromLong (Interfaces.C.long (Key));
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Float) return Integer
is
K : constant PyObject := PyFloat_FromDouble (Interfaces.C.double (Key));
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Boolean) return Integer
is
K : constant PyObject := PyBool_FromBoolean (Key);
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : String) return Float
is
K : constant PyObject := PyUnicode_FromString (Key);
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Integer) return Float
is
K : constant PyObject := PyInt_FromLong (Interfaces.C.long (Key));
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Float) return Float
is
K : constant PyObject := PyFloat_FromDouble (Interfaces.C.double (Key));
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Boolean) return Float
is
K : constant PyObject := PyBool_FromBoolean (Key);
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (V, "Value");
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : String) return Boolean
is
K : constant PyObject := PyUnicode_FromString (Key);
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (Scripting_Language (Self.Script), V);
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Integer) return Boolean
is
K : constant PyObject := PyInt_FromLong (Interfaces.C.long (Key));
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (Scripting_Language (Self.Script), V);
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Float) return Boolean
is
K : constant PyObject := PyFloat_FromDouble (Interfaces.C.double (Key));
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (Scripting_Language (Self.Script), V);
end Value;
-----------
-- Value --
-----------
function Value
(Self : Python_Dictionary_Instance; Key : Boolean) return Boolean
is
K : constant PyObject := PyBool_FromBoolean (Key);
V : constant PyObject := PyDict_GetItem (Self.Dict, K);
begin
Py_DECREF (K);
return Internal_To (Scripting_Language (Self.Script), V);
end Value;
-----------
-- Value --
-----------
function Value (Self : Python_Dictionary_Iterator) return String is
begin
return Conditional_To (Self.Position /= -1, Self.Value, "Value");
end Value;
-----------
-- Value --
-----------
function Value (Self : Python_Dictionary_Iterator) return Integer is
begin
return Conditional_To (Self.Position /= -1, Self.Value, "Value");
end Value;
-----------
-- Value --
-----------
function Value (Self : Python_Dictionary_Iterator) return Float is
begin
return Conditional_To (Self.Position /= -1, Self.Value, "Value");
end Value;
-----------
-- Value --
-----------
function Value (Self : Python_Dictionary_Iterator) return Boolean is
begin
return
Conditional_To
(Self.Position /= -1, Scripting_Language (Self.Script), Self.Value);
end Value;
-------------------------
-- Begin_Allow_Threads --
-------------------------
function Begin_Allow_Threads return PyThreadState is
-- Import only if the function exists in python, otherwise
-- we can undefined symbols error at link time.
function PyEval_SaveThread return PyThreadState;
pragma Import (C, PyEval_SaveThread, "ada_PyEval_SaveThread");
begin
return PyEval_SaveThread;
end Begin_Allow_Threads;
-------------------------
-- Begin_Allow_Threads --
-------------------------
procedure Begin_Allow_Threads is
State : PyThreadState;
pragma Unreferenced (State);
begin
State := Begin_Allow_Threads;
end Begin_Allow_Threads;
-----------------------
-- End_Allow_Threads --
-----------------------
procedure End_Allow_Threads (State : PyThreadState) is
procedure PyEval_RestoreThread (State : PyThreadState);
pragma Import (C, PyEval_RestoreThread, "ada_PyEval_RestoreThread");
begin
PyEval_RestoreThread (State);
end End_Allow_Threads;
---------------------------
-- Get_This_Thread_State --
---------------------------
function Get_This_Thread_State return PyThreadState is
function PyGILState_GetThisThreadState return PyThreadState;
pragma Import
(C, PyGILState_GetThisThreadState,
"ada_PyGILState_GetThisThreadState");
begin
return PyGILState_GetThisThreadState;
end Get_This_Thread_State;
-------------------------
-- Ensure_Thread_State --
-------------------------
procedure Ensure_Thread_State is
function PyGILState_Ensure return Integer;
pragma Import (C, PyGILState_Ensure, "ada_PyGILState_Ensure");
Ignored : Integer;
pragma Unreferenced (Ignored);
begin
Ignored := PyGILState_Ensure;
end Ensure_Thread_State;
--------------------------------
-- Initialize_Threads_Support --
--------------------------------
procedure Initialize_Threads_Support is
procedure PyEval_InitThreads;
pragma Import (C, PyEval_InitThreads, "ada_PyEval_InitThreads");
begin
PyEval_InitThreads;
end Initialize_Threads_Support;
----------------------
-- Python_Backtrace --
----------------------
function Python_Backtrace return String is
F : PyFrameObject := Last_Call_Frame;
Aux : Ada.Strings.Unbounded.Unbounded_String;
begin
if F /= null then
while F /= null loop
declare
Image : String :=
Integer'Image (PyFrame_GetLineNumber (F));
begin
Image (Image'First) := ':';
Append
(Aux,
" "
& PyString_AsString
(PyCode_Get_Filename (PyFrame_Get_Code (F)))
& Image
& ASCII.LF);
end;
F := PyFrame_Get_Back (F);
end loop;
end if;
return To_String (Aux);
end Python_Backtrace;
------------------------------
-- Error_Message_With_Stack --
------------------------------
function Error_Message_With_Stack return String is
Aux : Ada.Strings.Unbounded.Unbounded_String;
begin
if Last_Call_Frame /= null then
Append
(Aux, "Unexpected exception: Python execution stack" & ASCII.LF);
Append (Aux, Python_Backtrace);
return To_String (Aux);
else
return "Unexpected exception: ";
end if;
end Error_Message_With_Stack;
-----------------------
-- Trace_Python_Code --
-----------------------
function Trace_Python_Code
(User_Arg : GNATCOLL.Python.PyObject;
Frame : GNATCOLL.Python.PyFrameObject;
Why : GNATCOLL.Python.Why_Trace_Func;
Object : GNATCOLL.Python.PyObject) return Integer
is
pragma Unreferenced (User_Arg);
pragma Unreferenced (Object);
begin
if Why in PyTrace_Call | PyTrace_C_Call then
if Last_Call_Frame /= null then
Py_DECREF (PyObject (Last_Call_Frame));
end if;
Last_Call_Frame := Frame;
Py_INCREF (PyObject (Last_Call_Frame));
end if;
return 0;
end Trace_Python_Code;
end GNATCOLL.Scripts.Python;