pythonnet-2.0-alpha2: PyString cannot create 8-bit Python strings
Hi all While trying to call Python code from within C# using "Python.Runtime" from pythonnet-2.0-alpha2, I ran into a problem using "PyString", which can only create *unicode* python strings and I needed a way to create 8-bit (single byte character) Python strings in order to call "PyObject.Invoke(PyTuple, PyDict)". Detailed report follows below. [Side note: .Net "string" (which is "System.String") is a unicode string] I've tried calling Python code from within C# code using: Python.Runtime.PyObject.Invoke(PyTuple, PyDict) I prepared the PyDict by using: Python.Runtime.PyObject.this[string] The original code I tried was: <code-snip-1> PythonEngine.Initialize(); IntPtr lck = PythonEngine.AcquireLock(); PyObject mod_builtin = PythonEngine.ImportModule("__builtin__"); PyObject False = mod_builtin.GetAttr("False"); PyObject mod_hg = PythonEngine.ImportModule("mercurial"); PyObject mod_ui = PythonEngine.ImportModule("mercurial.ui"); PyObject ui_ctor = mod_ui.GetAttr("ui"); PyDict d = new PyDict(); d["interactive"] = False; PyTuple noargs = new PyTuple(); PyObject ui = ui_ctor.Invoke(noargs, d); </code-snip-1> (For the Mercurial details see: http://www.selenic.com/mercurial/wiki/ http://selenic.com/repo/hg/file/23889160905a/mercurial/ui.py) The relevant called python code is: <code-snip-2> class ui(object): def __init__(self, verbose=False, debug=False, quiet=False, interactive=True, traceback=False, report_untrusted=True, parentui=None): </code-snip-2> Problem is, my code-snip-1 didn't work, because that adds a *unicode* key string to the dict, because it uses: Python.Runtime.PyString.PyString(string) which creates a *unicode" python string. But Invoke() works only when using 8-bit (single byte) strings for the keys in the dict. To fix this I changed "src/runtime/pydict.cs" (mercurial patch): <hg-patch1> # HG changeset patch # User Adrian Buehlmann # Date 1199891100 -3600 # Node ID 89623ba76fd3d72c56e05981f2504dd2872560fb # Parent 3c3b7151ad596a4e6cf3012c33246418c641a66d New SetItemString() on PyDict diff -r 3c3b7151ad59 -r 89623ba76fd3 runtime/pydict.cs --- a/runtime/pydict.cs Wed Jan 09 15:59:24 2008 +0100 +++ b/runtime/pydict.cs Wed Jan 09 16:05:00 2008 +0100 @@ -201,6 +201,22 @@ namespace Python.Runtime { public void Clear() { Runtime.PyDict_Clear(obj); } + + + /// <summary> + /// SetItemString Method + /// </summary> + /// + /// <remarks> + /// Inserts value into this dictionary using ansi string key as a key. + /// </remarks> + + public void SetItemString(string key, PyObject value) { + int result = Runtime.PyDict_SetItemString(obj, key, value.obj); + if (result < 0) { + throw new PythonException(); + } + } } </hg-patch1> which adds a new SetItemString() method to PyDict and then did: <code-snip-3> PythonEngine.Initialize(); IntPtr lck = PythonEngine.AcquireLock(); PyObject mod_builtin = PythonEngine.ImportModule("__builtin__"); PyObject False = mod_builtin.GetAttr("False"); PyObject mod_hg = PythonEngine.ImportModule("mercurial"); PyObject mod_ui = PythonEngine.ImportModule("mercurial.ui"); PyObject ui_ctor = mod_ui.GetAttr("ui"); PyDict d = new PyDict(); d.SetItemString("interactive", False); PyTuple noargs = new PyTuple(); PyObject ui = ui_ctor.Invoke(noargs, d); </code-snip-3> I didn't see a better way to create a PyObject that represents an ansi python string. With PyString I can only create *unicode* python strings. I was tempted to do: <code-snip-4> public PyString(string s) : base() { // obj = Runtime.PyUnicode_FromUnicode(s, s.Length); // orig code obj = Runtime.PyString_FromString(s); // create ansi string instead if (obj == IntPtr.Zero) { throw new PythonException(); } } </code-snip-4> but that would break existing code (not mine). Adrian
participants (1)
-
Adrian Buehlmann