You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@denfromufa I'm not going very far in pythonnet. currently, I have used these methods,
PythonEngine.PythonPath: to embed CPython into .NET as a independ module
Initialize
Py.GIL method:
PyScope class: I use it instead of RunSimpleString, Exec and Eval
PythonEngine.AcquireLock and PythonEngine.ReleaseLock: used in C# callback funtion passed to CPython
PyIter class: to analyse the OrderedDict object return from CPython
dynamic type: used for visiting Python object, field and method.
KeywordArguments class: but did not use Py.kw method
In the future, I will dig deep, such as using threading and asynchronous callback, and share my experience here.
Before writing the docs, I think we need to do some work on the embedding API design.
For the embedding API design, I hold the same view as @filmor,
All functions that operate on pointers directly should be internal. one of the reasons is security.
According to this principle, some functions and properties can be removed from the current API list, such as the Handle property of PyObject, the BeginAllowThreads method, the EndAllowThreads.
In order to remove these APIs related to the IntPtr, some new APIs need to be designed and provided. Use the PythonEngine.AcquireLock and PythonEngine.ReleaseLock as example, these two methods should be removed according to this principle. Their problems include, programe will crash if the ReleaseLock is called redundantly, and CPython will be blocked if forge to call the ReleaseLock method. The Py.GIL class can be extended to cover their usage, such as the PyScope.GIL class in the PyScope proposal.
Following are my other proposals for the embedding API design,
Merge the PythonEngine class and Py class. PythonEngine called the methods in Py such as Throw, Py called the PythonEngine in PythonEngine, I don‘t know the principle of where to put a method, Py or PythonEngine.
The KeywordArguments class can be moved out from Py class, the Py.kw method can be put into the KeywordArguments class as a static convert method, and other convert methods can also be putted into the KeywordArguments as overloading methods. For example, I used a convert method to transform C# Dictionary into KeywordArguments.
It seems there is no way to flatten a list and pass it to a python function. A new TupleArguments class similar to KeywordArguments can do this.
The GILState class can be moved out from Py class, and should be extended as shown above.
A class wrapping threading may be needed. (explore later)
For the docs of embedding CPython, @vmuriart said the easier approach is writing a few more example based on the unittests, supplementary approach is providing a doc according to topics. Topics come from the list of issues users encontered. For example, following is what I have currently,
how to embed CPython into .NET as a independ module. I developed a python module to extract and pack the moduled into a zip file.
Pass .NET object as attribute of CPython object. For example,
how to redirect sys.stdout and sys.stdin
Call python function
how to call a python function of signature "def func(arg1, *arg2, **kwargs)"
Transform CPython object (custom and build-in) into .NET Object. For example,
how to convert a CPython OrderedDict object into C# Dictionary
Callback
how to pass CPython object to the callback function defined in .NET (I encontered a bug here)
double[] x = { 1.0, 2.0, 3.0, 4.0 };
double[] y = { 1.0, 2.0, 1.0, 2.0 };
this.pyplot.plot(x, y);
public void Set(string name, dynamic content)
{
using (Py.GIL())
{
System.Type ValueType = content.GetType();
// Arrays are always converted to python lists
if (ValueType.IsArray)
{
if (!NumpyLoaded)
{
throw new PythonException("numpy must be loaded for array conversion.");
}
// BlockCopy possibly multidimensional array of arbitrary type to onedimensional byte array
System.Type ElementType = ValueType.GetElementType();
int nbytes = content.Length * Marshal.SizeOf(ElementType);
byte[] data = new byte[nbytes];
System.Buffer.BlockCopy(content, 0, data, 0, nbytes);
// <=== HERE IS THE EFFOR===> Create an python tuple with the dimensions of the input array
PyObject[] lengths = new PyObject[content.Rank];
for (int i = 0; i < content.Rank; i++)
lengths[i] = new PyInt(content.GetLength(i));
PyTuple shape = new PyTuple(lengths);
// Create an empty numpy array in correct shape and datatype
dynamic dtype;
if (ElementType == typeof(int))
dtype = np.int32;
else if (ElementType == typeof(double))
dtype = np.float64;
else
throw new System.Exception("Datatype not supported!");
dynamic pydata = np.empty(shape, dtype);
// Copy the data to that array
System.IntPtr ptr = (System.IntPtr)PyInt.AsInt(pydata.__array_interface__["data"][0]).ToInt32();
Marshal.Copy(data, 0, ptr, nbytes);
// Push the variable to local dictionary
UpdateLocals(name, pydata);
}
else
{
if (ValueType == typeof(int))
UpdateLocals(name, new PyInt(content));
else if (ValueType == typeof(string))
UpdateLocals(name, new PyString(content));
else if (ValueType == typeof(double))
UpdateLocals(name, new PyFloat(content));
else if (ValueType == typeof(bool))
{
UpdateLocals(name, new PyInt(System.Convert.ToInt32(content)));
RunStringTry(name + " = (" + name + " == 1)");
}
else
throw new PythonException("Datatype not supported!");
}
}
}
previously, I thought was due to regression of Numpy. With the latest compile python.Runtime, the regression issue is gone, yet, there is a problem of converting double[] array to python.net
@JimSEOW please don't hijack this issue with a separate feature request,
mapping containers between languages is not easy. Especially arrays, since
Python does not have built-in arrays. There is array module in Python, but
everybody uses numpy arrays.
@JimSEOW I tried the SimplePythonGraph project. I guess you ran the program in x64 mode. If so, the bug you encountered was caused by the limitation of method PyInt.AsInt().
A solution is,
replace all the expressions PyInt.AsInt(...).ToInt32() and PyInt.AsInt(...).ToInt64() with (...).AsManagedObject(typeof(long)). They appear in both the Get() and Set() methods of PythonConnection class.
P.S.
Since AsManagedObject method is widely used and not very convenient, I am trying to add a new Generic method As<T> to the PyObject class, after that, one can use (...).As<long>()
instead of (...).AsManagedObject(typeof(long))
The limitation of the PyInt.AsInt method is,
This method called the CPython API PyNumber_Int, which converts a python number to C int (maybe C long?). When the target platform of the program was x64, the address of a variable may out of the range of integer. PyNumber_Long is also not working here, because on windows the length of C long is also 4 bytes, no matter the target platform is x86 or x64.
Activity
vmuriart commentedon Feb 27, 2017
Here's a list of whats currently publicly exposed but with no xml docs.
Python.Runtime.PythonDerivedType.InvokeMethodVoid(Python.Runtime.IPythonDerivedType, string, string, object[])Python.Runtime.PythonDerivedType.InvokeGetProperty<T>(Python.Runtime.IPythonDerivedType, string)Python.Runtime.PythonDerivedType.InvokeSetProperty<T>(Python.Runtime.IPythonDerivedType, string, T)Python.Runtime.PythonDerivedType.InvokeCtor(Python.Runtime.IPythonDerivedType, string, object[])Python.Runtime.PythonDerivedType.Finalize(Python.Runtime.IPythonDerivedType)Python.Runtime.ConverterExtensionPython.Runtime.ConverterExtension.ToPython(this object)Python.Runtime.DispatcherPython.Runtime.Dispatcher.targetPython.Runtime.Dispatcher.dtypePython.Runtime.Dispatcher.Dispatcher(System.IntPtr, System.Type)Python.Runtime.Dispatcher.~Dispatcher()Python.Runtime.Dispatcher.Dispatch(System.Collections.ArrayList)Python.Runtime.Dispatcher.TrueDispatch(System.Collections.ArrayList)Python.Runtime.ConversionExceptionPython.Runtime.ConversionException.ConversionException()Python.Runtime.ConversionException.ConversionException(string)Python.Runtime.Exceptions.warn(string, System.IntPtr)Python.Runtime.Exceptions.deprecation(string, int)Python.Runtime.Exceptions.deprecation(string)Python.Runtime.Exceptions.BaseExceptionPython.Runtime.Exceptions.ExceptionPython.Runtime.Exceptions.StopIterationPython.Runtime.Exceptions.GeneratorExitPython.Runtime.Exceptions.StandardErrorPython.Runtime.Exceptions.ArithmeticErrorPython.Runtime.Exceptions.LookupErrorPython.Runtime.Exceptions.AssertionErrorPython.Runtime.Exceptions.AttributeErrorPython.Runtime.Exceptions.EOFErrorPython.Runtime.Exceptions.FloatingPointErrorPython.Runtime.Exceptions.EnvironmentErrorPython.Runtime.Exceptions.IOErrorPython.Runtime.Exceptions.OSErrorPython.Runtime.Exceptions.ImportErrorPython.Runtime.Exceptions.IndexErrorPython.Runtime.Exceptions.KeyErrorPython.Runtime.Exceptions.KeyboardInterruptPython.Runtime.Exceptions.MemoryErrorPython.Runtime.Exceptions.NameErrorPython.Runtime.Exceptions.OverflowErrorPython.Runtime.Exceptions.RuntimeErrorPython.Runtime.Exceptions.NotImplementedErrorPython.Runtime.Exceptions.SyntaxErrorPython.Runtime.Exceptions.IndentationErrorPython.Runtime.Exceptions.TabErrorPython.Runtime.Exceptions.ReferenceErrorPython.Runtime.Exceptions.SystemErrorPython.Runtime.Exceptions.SystemExitPython.Runtime.Exceptions.TypeErrorPython.Runtime.Exceptions.UnboundLocalErrorPython.Runtime.Exceptions.UnicodeErrorPython.Runtime.Exceptions.UnicodeEncodeErrorPython.Runtime.Exceptions.UnicodeDecodeErrorPython.Runtime.Exceptions.UnicodeTranslateErrorPython.Runtime.Exceptions.ValueErrorPython.Runtime.Exceptions.ZeroDivisionErrorPython.Runtime.Exceptions.WarningPython.Runtime.Exceptions.UserWarningPython.Runtime.Exceptions.DeprecationWarningPython.Runtime.Exceptions.PendingDeprecationWarningPython.Runtime.Exceptions.SyntaxWarningPython.Runtime.Exceptions.RuntimeWarningPython.Runtime.Exceptions.FutureWarningPython.Runtime.Exceptions.ImportWarningPython.Runtime.Exceptions.UnicodeWarningPython.Runtime.DocStringAttribute.DocStringAttribute(string)Python.Runtime.DocStringAttribute.DocStringPython.Runtime.INativeCall.Void_Call_0(System.IntPtr)Python.Runtime.INativeCall.Void_Call_1(System.IntPtr, System.IntPtr)Python.Runtime.INativeCall.Int_Call_3(System.IntPtr, System.IntPtr, System.IntPtr, System.IntPtr)Python.Runtime.INativeCall.Call_3(System.IntPtr, System.IntPtr, System.IntPtr, System.IntPtr)Python.Runtime.PyAnsiStringPython.Runtime.PyIter.Dispose(bool)Python.Runtime.PyIter.MoveNext()Python.Runtime.PyIter.Reset()Python.Runtime.PyIter.CurrentPython.Runtime.PyNumber.PyNumber(System.IntPtr)Python.Runtime.PyNumber.PyNumber()Python.Runtime.PyObject.objPython.Runtime.PyObject.PyObject()Python.Runtime.PyObject.~PyObject()Python.Runtime.PyObject.Dispose()Python.Runtime.PyObject.RefcountPython.Runtime.PyObject.TryGetMember(System.Dynamic.GetMemberBinder, out object)Python.Runtime.PyObject.TrySetMember(System.Dynamic.SetMemberBinder, object)Python.Runtime.PyObject.TryInvokeMember(System.Dynamic.InvokeMemberBinder, object[], out object)Python.Runtime.PyObject.TryInvoke(System.Dynamic.InvokeBinder, object[], out object)Python.Runtime.PyObject.TryConvert(System.Dynamic.ConvertBinder, out object)Python.Runtime.PyObject.TryBinaryOperation(System.Dynamic.BinaryOperationBinder, object, out object)Python.Runtime.PyObject.TryUnaryOperation(System.Dynamic.UnaryOperationBinder, out object)Python.Runtime.PySequence.PySequence(System.IntPtr)Python.Runtime.PySequence.PySequence()Python.Runtime.PythonEngine.PythonEngine()Python.Runtime.PythonEngine.PythonEngine(params string[])Python.Runtime.PythonEngine.PythonEngine(System.Collections.Generic.IEnumerable<string>)Python.Runtime.PythonEngine.Dispose()Python.Runtime.PythonEngine.IsInitializedPython.Runtime.PythonEngine.ProgramNamePython.Runtime.PythonEngine.PythonHomePython.Runtime.PythonEngine.PythonPathPython.Runtime.PythonEngine.VersionPython.Runtime.PythonEngine.BuildInfoPython.Runtime.PythonEngine.PlatformPython.Runtime.PythonEngine.CopyrightPython.Runtime.PythonEngine.RunSimpleString(string)Python.Runtime.PythonEngine.Initialize()Python.Runtime.PythonEngine.Initialize(bool)Python.Runtime.RunFlagTypePython.Runtime.RunFlagType.SinglePython.Runtime.RunFlagType.FilePython.Runtime.RunFlagType.EvalPython.Runtime.PyPython.Runtime.Py.GIL()Python.Runtime.Py.GILStatePython.Runtime.Py.GILState.Dispose()Python.Runtime.Py.GILState.~GILState()Python.Runtime.Py.KeywordArgumentsPython.Runtime.Py.kw(params object[])Python.Runtime.Py.Import(string)Python.Runtime.Py.SetArgv()Python.Runtime.Py.SetArgv(params string[])Python.Runtime.Py.SetArgv(System.Collections.Generic.IEnumerable<string>)Python.Runtime.PythonException.PythonException()Python.Runtime.PythonException.~PythonException()Python.Runtime.Runtime.UCSPython.Runtime.Runtime.pyversionPython.Runtime.Runtime.pyversionnumberPython.Runtime.Runtime.dllPython.Runtime.Runtime.Py_Main(int, string[])vmuriart commentedon Feb 27, 2017
The easier approach might to write a few more example based on the unittests and limit those examples to use only
APIthat will remain public.yagweb commentedon Feb 28, 2017
@denfromufa I'm not going very far in pythonnet. currently, I have used these methods,
In the future, I will dig deep, such as using threading and asynchronous callback, and share my experience here.
Before writing the docs, I think we need to do some work on the embedding API design.
For the embedding API design, I hold the same view as @filmor,
According to this principle, some functions and properties can be removed from the current API list, such as the Handle property of PyObject, the BeginAllowThreads method, the EndAllowThreads.
In order to remove these APIs related to the IntPtr, some new APIs need to be designed and provided. Use the PythonEngine.AcquireLock and PythonEngine.ReleaseLock as example, these two methods should be removed according to this principle. Their problems include, programe will crash if the ReleaseLock is called redundantly, and CPython will be blocked if forge to call the ReleaseLock method. The Py.GIL class can be extended to cover their usage, such as the PyScope.GIL class in the PyScope proposal.
Following are my other proposals for the embedding API design,
For the docs of embedding CPython, @vmuriart said the easier approach is writing a few more example based on the unittests, supplementary approach is providing a doc according to topics. Topics come from the list of issues users encontered. For example, following is what I have currently,
how to redirect sys.stdout and sys.stdin
how to call a python function of signature "def func(arg1, *arg2, **kwargs)"
how to convert a CPython OrderedDict object into C# Dictionary
how to pass CPython object to the callback function defined in .NET (I encontered a bug here)
den-run-ai commentedon Mar 1, 2017
here is a library for embedding python with pythonnet and using numpy, matplotlib:
https://github.com/Lodomir/PythonInterface
JimSEOW commentedon Apr 5, 2017
@denfromufa
Can you take a look why in PythonInterface
the pyplot.cs
Line 96 and 97 fail with the latest Python.Runtime.dll (compile from git clone)
using example
previously, I thought was due to regression of Numpy. With the latest compile python.Runtime, the regression issue is gone, yet, there is a problem of converting double[] array to python.net
Appreciate
JimSEOW commentedon Apr 5, 2017
PyPlot for matplotlib
#442
den-run-ai commentedon Apr 5, 2017
JimSEOW commentedon Apr 5, 2017
@denfromufa sorry, I am not aware.
yagweb commentedon Apr 6, 2017
@JimSEOW I tried the SimplePythonGraph project. I guess you ran the program in x64 mode. If so, the bug you encountered was caused by the limitation of method PyInt.AsInt().
A solution is,
replace all the expressions
PyInt.AsInt(...).ToInt32()andPyInt.AsInt(...).ToInt64()with(...).AsManagedObject(typeof(long)). They appear in both the Get() and Set() methods of PythonConnection class.P.S.
Since AsManagedObject method is widely used and not very convenient, I am trying to add a new Generic method As<T> to the PyObject class, after that, one can use
(...).As<long>()instead of
(...).AsManagedObject(typeof(long))The limitation of the PyInt.AsInt method is,
This method called the CPython API PyNumber_Int, which converts a python number to C int (maybe C long?). When the target platform of the program was x64, the address of a variable may out of the range of integer. PyNumber_Long is also not working here, because on windows the length of C long is also 4 bytes, no matter the target platform is x86 or x64.
JimSEOW commentedon Apr 9, 2017
I get error of {"Specified cast is not valid."}
public dynamic Get(string
name_in)RunString("__" + name + "__dtype = str(" + name + ".dtype)");<=========@yagweb Do you have a running SimplePythonGraph project to share?
Relevant issue
JimSEOW commentedon Apr 27, 2017
@yagweb will your scope class address the GET, SET issues above?
filmor commentedon Nov 22, 2022
The reference documentation is auto-generated now.