Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f2bb783
Fixing the missed style unit for grids
lmbelo Nov 16, 2022
6e78f1c
Including the Python ByteArray type
lmbelo Dec 2, 2022
152f480
Creating an overloaded CreateWith method with kwds
lmbelo Dec 2, 2022
4c0765c
Creating Stream wrappers
lmbelo Dec 2, 2022
1a72e7a
Stream basic operations
lmbelo Dec 2, 2022
0268229
Exposing rtti methods at definition time
lmbelo Dec 5, 2022
df41a78
Enabling rtti method exposition at definition time
lmbelo Dec 5, 2022
20b5c99
Exposing methods, fields and properties at definition time
lmbelo Dec 7, 2022
bb31c7c
Expose members by default for Delphi 11 or higher
lmbelo Dec 9, 2022
7a52e60
Fixing a bug when destroying the rtti members array
lmbelo Dec 9, 2022
79f1fca
Exposing class declared members only
lmbelo Dec 9, 2022
289971b
Including support for class hierarchy
lmbelo Dec 9, 2022
206f1a5
Including the PythonDocs unit
lmbelo Dec 17, 2022
6500cda
Processing docs for wrapped class types
lmbelo Dec 17, 2022
7278a00
Removing a typo
lmbelo Dec 17, 2022
010661f
Source foramatting
lmbelo Dec 17, 2022
913f65e
Adding the PythonDoc reference to the Python project
lmbelo Dec 17, 2022
530c499
Setting the default docs directory
lmbelo Dec 17, 2022
73d3f38
Including fields and properties to the member prefix extractor
lmbelo Dec 17, 2022
7142f25
Helper methods to load docs
lmbelo Dec 18, 2022
84757e2
Working with classref
lmbelo Dec 18, 2022
04000bd
Including class and static methods supports
lmbelo Dec 18, 2022
b0ce703
Reading docs from a single xml file
lmbelo Jan 10, 2023
523e3d0
The docs compiler app
lmbelo Jan 10, 2023
e9221ff
Including the FMX doc xml files
lmbelo Jan 10, 2023
9e1f8bb
Including the VCL doc xml files
lmbelo Jan 10, 2023
74a891a
A method can't be class and static at the same time
lmbelo Jan 11, 2023
9b875a2
Only include the doc unit if we are exposing members
lmbelo Jan 11, 2023
aa8c0e0
Including the definition inc file in the doc unit
lmbelo Jan 11, 2023
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Stream basic operations
  • Loading branch information
lmbelo committed Dec 2, 2022
commit 1a72e7a79aff648f4df695bfd9d38185efeaa18f
281 changes: 257 additions & 24 deletions Source/WrapDelphiClasses.pas
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,23 @@ TPyDelphiStream = class(TPyDelphiObject)
private
function GetDelphiObject: TStream;
procedure SetDelphiObject(const Value: TStream);

function GetReadCount(const AArgs: PPyObject): integer; inline;
protected
function ReadBytes_Wrapper(const AArgs: PPyObject): PPyObject;
function ReadInt_Wrapper(const AArgs: PPyObject): PPyObject;
function ReadString_Wrapper(const AArgs: PPyObject): PPyObject;
function ReadFloat_Wrapper(const AArgs: PPyObject): PPyObject;

function WriteBytes_Wrapper(const AArgs: PPyObject): PPyObject;
function WriteInt_Wrapper(const AArgs: PPyObject): PPyObject;
function WriteString_Wrapper(const AArgs: PPyObject): PPyObject;
function WriteFloat_Wrapper(const AArgs: PPyObject): PPyObject;
public
constructor CreateWith(APythonType: TPythonType; args, kwds: PPyObject); override;
// Class methods
class function DelphiObjectClass : TClass; override;
class procedure SetupType(PythonType: TPythonType); override;
class procedure RegisterMethods( PythonType : TPythonType ); override;
// Properties
property DelphiObject: TStream read GetDelphiObject write SetDelphiObject;
end;
Expand Down Expand Up @@ -1895,12 +1907,6 @@ procedure TPyReader.SetName(Component: TComponent; var Name: string);

{ TPyDelphiStream }

constructor TPyDelphiStream.CreateWith(APythonType: TPythonType;
args, kwds: PPyObject);
begin
inherited;
end;

class function TPyDelphiStream.DelphiObjectClass: TClass;
begin
Result := TStream;
Expand All @@ -1925,6 +1931,192 @@ class procedure TPyDelphiStream.SetupType(PythonType: TPythonType);
PythonType.TypeFlags := PythonType.TypeFlags + [TPFlag.tpTypeSubclass]
end;

class procedure TPyDelphiStream.RegisterMethods(PythonType: TPythonType);
begin
inherited;
PythonType.AddMethod('ReadBytes', @TPyDelphiStream.ReadBytes_Wrapper,
'TPyDelphiStream.ReadBytes()' + #10 + 'Read content as bytearray.');
PythonType.AddMethod('ReadInt', @TPyDelphiStream.ReadInt_Wrapper,
'TPyDelphiStream.ReadInt()' + #10 + 'Read content as integer.');
PythonType.AddMethod('ReadString', @TPyDelphiStream.ReadString_Wrapper,
'TPyDelphiStream.ReadString()' + #10 + 'Read content as string.');
PythonType.AddMethod('ReadFloat', @TPyDelphiStream.ReadFloat_Wrapper,
'TPyDelphiStream.ReadFloat()' + #10 + 'Read content as float.');

PythonType.AddMethod('WriteBytes', @TPyDelphiStream.WriteBytes_Wrapper,
'TPyDelphiStream.WriteBytes()' + #10 + 'Write content as bytearray.');
PythonType.AddMethod('WriteInt', @TPyDelphiStream.WriteInt_Wrapper,
'TPyDelphiStream.WriteInt()' + #10 + 'Write content as integer.');
PythonType.AddMethod('WriteString', @TPyDelphiStream.WriteString_Wrapper,
'TPyDelphiStream.WriteString()' + #10 + 'Write content as string.');
PythonType.AddMethod('WriteFloat', @TPyDelphiStream.WriteFloat_Wrapper,
'TPyDelphiStream.WriteFloat()' + #10 + 'Write content as float.');
end;

function TPyDelphiStream.GetReadCount(const AArgs: PPyObject): integer;
begin
if GetPythonEngine().PyArg_ParseTuple(AArgs, 'i:Create', @Result) = 0 then
Result := 0;
end;

function TPyDelphiStream.ReadBytes_Wrapper(const AArgs: PPyObject): PPyObject;
var
LCount: Integer;
LValue: TBytes;
LItem: PPyObject;
LBytes: PPyObject;
LByte: byte;
begin
Adjust(@Self);
//Returns multiple results
with GetPythonEngine() do begin
Result := PyList_New(0);
LCount := GetReadCount(AArgs);
if (LCount > 0) then begin
//The read result
SetLength(LValue, LCount);
LItem := PyLong_FromLong(DelphiObject.Read(LValue, LCount));
PyList_Append(Result, LItem);
Py_XDecRef(LItem);
//Create a list of bytes, then convert it to bytearray
LBytes := PyList_New(0);
for LByte in LValue do begin
LItem := PyLong_FromLong(LByte);
PyList_Append(LBytes, LItem);
Py_XDecRef(LItem);
end;
//The content
LItem := PyByteArray_FromObject(LBytes);
Py_XDecRef(LBytes);
PyList_Append(Result, LItem);
Py_XDecRef(LItem);
end;
end;
end;

function TPyDelphiStream.ReadFloat_Wrapper(const AArgs: PPyObject): PPyObject;
var
LValue: single;
LItem: PPyObject;
begin
Adjust(@Self);
//Returns multiple results
with GetPythonEngine() do begin
Result := PyList_New(0);
//The read result
LItem := PyLong_FromLong(DelphiObject.Read(LValue, SizeOf(single)));
PyList_Append(Result, LItem);
Py_XDecRef(LItem);
//The content
LItem := PyFloat_FromDouble(LValue);
PyList_Append(Result, LItem);
Py_XDecRef(LItem);
end;
end;

function TPyDelphiStream.ReadInt_Wrapper(const AArgs: PPyObject): PPyObject;
var
LValue: integer;
LItem: PPyObject;
begin
Adjust(@Self);
//Returns multiple results
with GetPythonEngine() do begin
Result := PyList_New(0);
//The read result
LItem := PyLong_FromLong(DelphiObject.Read(LValue, SizeOf(Integer)));
PyList_Append(Result, LItem);
Py_XDecRef(LItem);
//The content
LItem := PyLong_FromLong(LValue);
PyList_Append(Result, LItem);
Py_XDecRef(LItem);
end;
end;

function TPyDelphiStream.ReadString_Wrapper(const AArgs: PPyObject): PPyObject;
var
LCount: Integer;
LValue: string;
LItem: PPyObject;
begin
Adjust(@Self);
//Returns multiple results
with GetPythonEngine() do begin
Result := PyList_New(0);
LCount := GetReadCount(AArgs);
if (LCount > 0) then begin
//The read result
SetLength(LValue, LCount);
LItem := PyLong_FromLong(DelphiObject.Read(Pointer(LValue)^, LCount * SizeOf(Char)));
PyList_Append(Result, LItem);
Py_XDecRef(LItem);
//The content
LItem := PyUnicodeFromString(LValue);
PyList_Append(Result, LItem);
Py_XDecRef(LItem);
end;
end;
end;

function TPyDelphiStream.WriteBytes_Wrapper(const AArgs: PPyObject): PPyObject;
var
LValue: PPyObject;
LCount: integer;
LBuffer: TBytes;
begin
Adjust(@Self);
Result := nil;
with GetPythonEngine() do begin
if PyArg_ParseTuple(AArgs, 'Yi:Create', @LValue, @LCount) <> 0 then
if PyByteArray_Check(LValue) then begin
LBuffer := TEncoding.Default.GetBytes(String(PyByteArray_AsString(LValue)));
Result := PyLong_FromLong(DelphiObject.Write(LBuffer, LCount));
end;
end;
end;

function TPyDelphiStream.WriteFloat_Wrapper(const AArgs: PPyObject): PPyObject;
var
LValue: single;
begin
Adjust(@Self);
Result := nil;
with GetPythonEngine() do begin
if PyArg_ParseTuple(AArgs, 'f:Create', @LValue) <> 0 then
Result := PyLong_FromLong(DelphiObject.Write(LValue, SizeOf(Single)));
end;
end;

function TPyDelphiStream.WriteInt_Wrapper(const AArgs: PPyObject): PPyObject;
var
LValue: integer;
begin
Adjust(@Self);
Result := nil;
with GetPythonEngine() do begin
if PyArg_ParseTuple(AArgs, 'i:Create', @LValue) <> 0 then
Result := PyLong_FromLong(DelphiObject.Write(LValue, SizeOf(Integer)));
end;
end;

function TPyDelphiStream.WriteString_Wrapper(
const AArgs: PPyObject): PPyObject;
var
LValue: PAnsiChar;
LCount: integer;
LStr: string;
begin
Adjust(@Self);
Result := nil;
with GetPythonEngine() do begin
if PyArg_ParseTuple(AArgs, 'si:Create', @LValue, @LCount) <> 0 then begin
LStr := String(LValue);
Result := PyLong_FromLong(DelphiObject.Write(Pointer(LStr)^, LCount * SizeOf(Char)));
end;
end;
end;

{ TPyDelphiHandleStream }

constructor TPyDelphiHandleStream.CreateWith(APythonType: TPythonType;
Expand All @@ -1936,6 +2128,9 @@ THandleStreamClass = class of THandleStream;
LHandle: THandle;
begin
inherited;
//Clear unsuccessful overloaded constructor error
APythonType.Engine.PyErr_Clear();

LParamCount := APythonType.Engine.PyTuple_Size(args);
if (LParamCount = 1) then
{$IFDEF CPUX64}
Expand Down Expand Up @@ -1974,6 +2169,8 @@ TFileStreamClass = class of TFileStream;
LFileName: PAnsiChar;
begin
inherited;
//Clear unsuccessful overloaded constructor error
APythonType.Engine.PyErr_Clear();

if (APythonType.PyObjectClass <> TPyDelphiFileStream) then
Exit;
Expand All @@ -1986,6 +2183,10 @@ TFileStreamClass = class of TFileStream;
if APythonType.Engine.PyArg_ParseTuple(args, 'sHI:Create', @LFileName, @LMode, @LRights) <> 0 then
DelphiObject := TFileStreamClass(DelphiObjectClass).Create(String(LFileName), LMode, LRights);
end;

//Maybe it was created on the next attempt...
if Assigned(DelphiObject) then
APythonType.Engine.PyErr_Clear();
end;

class function TPyDelphiFileStream.DelphiObjectClass: TClass;
Expand Down Expand Up @@ -2020,6 +2221,9 @@ TBufferedFileStreamClass = class of TBufferedFileStream;
LBufferSize: integer;
begin
inherited; //We MUST use the overloaded constructor
//Clear unsuccessful overloaded constructor error
APythonType.Engine.PyErr_Clear();

//We need kwargs here due to constructor overloads with default value (BufferSize)
LBufferSize := 32768;
LArgCount := APythonType.Engine.PyTuple_Size(args);
Expand All @@ -2030,6 +2234,10 @@ TBufferedFileStreamClass = class of TBufferedFileStream;
if (APythonType.Engine.PyArg_ParseTupleAndKeywords(args, kwds, 'sHI|i:Create', @LKwArgs2[0], @LFileName, @LMode, @LRights, @LBufferSize) <> 0) then
DelphiObject := TBufferedFileStreamClass(DelphiObjectClass).Create(String(LFileName), LMode, LRights, LBufferSize);
end;

//Maybe it was created on the next attempt...
if Assigned(DelphiObject) then
APythonType.Engine.PyErr_Clear();
end;

class function TPyDelphiBufferedFileStream.DelphiObjectClass: TClass;
Expand Down Expand Up @@ -2093,18 +2301,27 @@ TBytesStreamClass = class of TBytesStream;
LBytes: PPyObject;
begin
inherited;
//Clear unsuccessful overloaded constructor error
APythonType.Engine.PyErr_Clear();

if (APythonType.Engine.PyTuple_Size(args) = 1) then
if APythonType.Engine.PyArg_ParseTuple(args, 'Y:Create', @LBytes) <> 0 then begin
if APythonType.Engine.PyByteArray_Check(LBytes) then begin
DelphiObject := TBytesStreamClass(DelphiObjectClass).Create(TEncoding.Default.GetBytes(
String(APythonType.Engine.PyByteArray_AsString(LBytes))));
DelphiObject := TBytesStreamClass(DelphiObjectClass).Create(
TEncoding.Default.GetBytes(
String(APythonType.Engine.PyByteArray_AsString(LBytes))));
end;
end else if APythonType.Engine.PyArg_ParseTuple(args, 'S:Create', @LBytes) <> 0 then begin
if APythonType.Engine.PyBytes_Check(LBytes) then begin
DelphiObject := TBytesStreamClass(DelphiObjectClass).Create(TEncoding.Default.GetBytes(
String(APythonType.Engine.PyBytes_AsString(LBytes))));
DelphiObject := TBytesStreamClass(DelphiObjectClass).Create(
TEncoding.Default.GetBytes(
String(APythonType.Engine.PyBytes_AsString(LBytes))));
end;
end;

//Maybe it was created on the next attempt...
if Assigned(DelphiObject) then
APythonType.Engine.PyErr_Clear();
end;

class function TPyDelphiByteStream.DelphiObjectClass: TClass;
Expand Down Expand Up @@ -2132,6 +2349,9 @@ TStringStreamClass = class of TStringStream;
LDataString: PAnsiChar;
begin
inherited;
//Clear unsuccessful overloaded constructor error
APythonType.Engine.PyErr_Clear();

if (APythonType.Engine.PyTuple_Size(args) = 1) then
if APythonType.Engine.PyArg_ParseTuple(args, 's:Create', @LDataString) <> 0 then
DelphiObject := TStringStreamClass(DelphiObjectClass).Create(String(LDataString));
Expand Down Expand Up @@ -2165,19 +2385,32 @@ TResourceStreamClass = class of TResourceStream;
LResType: PAnsiChar;
begin
inherited;
{$IFDEF CPUX64}
if APythonType.Engine.PyArg_ParseTuple(args, 'Kss:Create', @LHandle, @LResName, @LResType) <> 0 then
{$ELSE}
if APythonType.Engine.PyArg_ParseTuple(args, 'Iss:Create', @LHandle, @LResName, @LResType) <> 0 then
{$ENDIF}
DelphiObject := TResourceStreamClass(DelphiObjectClass).Create(LHandle, String(LResName), PWideChar(String(LResType)))
else
{$IFDEF CPUX64}
if APythonType.Engine.PyArg_ParseTuple(args, 'Kis:Create', @LHandle, @LResId, @LResType) <> 0 then
{$ELSE}
if APythonType.Engine.PyArg_ParseTuple(args, 'Iis:Create', @LHandle, @LResId, @LResType)) <> 0 then
{$ENDIF}
DelphiObject := TResourceStreamClass(DelphiObjectClass).CreateFromID(LHandle, LResId, PWideChar(String(LResType)))
//Clear unsuccessful overloaded constructor error
APythonType.Engine.PyErr_Clear();

try
{$IFDEF CPUX64}
if APythonType.Engine.PyArg_ParseTuple(args, 'Kss:Create', @LHandle, @LResName, @LResType) <> 0 then
{$ELSE}
if APythonType.Engine.PyArg_ParseTuple(args, 'Iss:Create', @LHandle, @LResName, @LResType) <> 0 then
{$ENDIF}
DelphiObject := TResourceStreamClass(DelphiObjectClass).Create(LHandle, String(LResName), PWideChar(String(LResType)))
else
{$IFDEF CPUX64}
if APythonType.Engine.PyArg_ParseTuple(args, 'Kis:Create', @LHandle, @LResId, @LResType) <> 0 then
{$ELSE}
if APythonType.Engine.PyArg_ParseTuple(args, 'Iis:Create', @LHandle, @LResId, @LResType)) <> 0 then
{$ENDIF}
DelphiObject := TResourceStreamClass(DelphiObjectClass).CreateFromID(LHandle, LResId, PWideChar(String(LResType)));
except
on E: Exception do
with GetPythonEngine do
PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(AnsiString(E.Message)));
end;

//Maybe it was created on the next attempt...
if Assigned(DelphiObject) then
APythonType.Engine.PyErr_Clear();
end;

class function TPyDelphiResourceStream.DelphiObjectClass: TClass;
Expand Down