Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9449a04

Browse files
committed
Merge branch 'fix-getPythonPath'
Closes #414
2 parents 6f3f357 + ffe6448 commit 9449a04

File tree

6 files changed

+101
-34
lines changed

6 files changed

+101
-34
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
5252
- Fixed `Py_Main` & `PySys_SetArgvEx` `no mem error` on `UCS4/PY3` (#399)
5353
- Fixed `Python.Runtime.dll.config` on macOS (#120)
5454
- Fixed crash on `PythonEngine.Version` (#413)
55+
- Fixed `PythonEngine.PythonPath` issues (#414)
5556

5657
### Removed
5758

appveyor.yml

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ init:
2727
# Put desired Python version first in PATH
2828
- set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
2929

30+
# Needed for test `GetPythonHomeDefault`
31+
- set PYTHONHOME=%PYTHON%
32+
3033
install:
3134
- pip install --upgrade -r requirements.txt --quiet
3235

src/embed_tests/TestPythonEngineProperties.cs

+39
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,44 @@ public static void GetVersionDoesntCrash()
6666
Assert.IsTrue(s.Contains(","));
6767
}
6868
}
69+
70+
[Test]
71+
public static void GetPythonPathDefault()
72+
{
73+
PythonEngine.Initialize();
74+
string s = PythonEngine.PythonPath;
75+
76+
StringAssert.Contains("python", s.ToLower());
77+
PythonEngine.Shutdown();
78+
}
79+
80+
[Test]
81+
public static void GetProgramNameDefault()
82+
{
83+
PythonEngine.Initialize();
84+
string s = PythonEngine.PythonHome;
85+
86+
Assert.NotNull(s);
87+
PythonEngine.Shutdown();
88+
}
89+
90+
/// <summary>
91+
/// Test default behavior of PYTHONHOME. If ENVVAR is set it will
92+
/// return the same value. If not, returns EmptyString.
93+
/// </summary>
94+
/// <remarks>
95+
/// AppVeyor.yml has been update to tests with ENVVAR set.
96+
/// </remarks>
97+
[Test]
98+
public static void GetPythonHomeDefault()
99+
{
100+
string envPythonHome = Environment.GetEnvironmentVariable("PYTHONHOME") ?? "";
101+
102+
PythonEngine.Initialize();
103+
string enginePythonHome = PythonEngine.PythonHome;
104+
105+
Assert.AreEqual(envPythonHome, enginePythonHome);
106+
PythonEngine.Shutdown();
107+
}
69108
}
70109
}

src/runtime/CustomMarshaler.cs

+32-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Python.Runtime
99
/// Abstract class defining boiler plate methods that
1010
/// Custom Marshalers will use.
1111
/// </summary>
12-
public abstract class MarshalerBase : ICustomMarshaler
12+
internal abstract class MarshalerBase : ICustomMarshaler
1313
{
1414
public object MarshalNativeToManaged(IntPtr pNativeData)
1515
{
@@ -39,9 +39,9 @@ public int GetNativeDataSize()
3939
/// Custom Marshaler to deal with Managed String to Native
4040
/// conversion differences on UCS2/UCS4.
4141
/// </summary>
42-
public class StrMarshaler : MarshalerBase
42+
internal class UcsMarshaler : MarshalerBase
4343
{
44-
private static readonly MarshalerBase Instance = new StrMarshaler();
44+
private static readonly MarshalerBase Instance = new UcsMarshaler();
4545
private static readonly Encoding PyEncoding = Runtime.PyEncoding;
4646

4747
public override IntPtr MarshalManagedToNative(object managedObj)
@@ -72,14 +72,41 @@ public static ICustomMarshaler GetInstance(string cookie)
7272
{
7373
return Instance;
7474
}
75+
76+
public static string PtrToStringUni(IntPtr p)
77+
{
78+
if (p == IntPtr.Zero)
79+
{
80+
return null;
81+
}
82+
83+
int size = GetUnicodeByteLength(p);
84+
var buffer = new byte[size];
85+
Marshal.Copy(p, buffer, 0, size);
86+
return PyEncoding.GetString(buffer, 0, size);
87+
}
88+
89+
public static int GetUnicodeByteLength(IntPtr p)
90+
{
91+
var len = 0;
92+
while (true)
93+
{
94+
int c = Runtime.UCS == 2
95+
? Marshal.ReadInt16(p, len * 2)
96+
: Marshal.ReadInt32(p, len * 4);
97+
98+
if (c == 0) return len* Runtime.UCS;
99+
checked{ ++len; }
100+
}
101+
}
75102
}
76103

77104

78105
/// <summary>
79106
/// Custom Marshaler to deal with Managed String Arrays to Native
80107
/// conversion differences on UCS2/UCS4.
81108
/// </summary>
82-
public class StrArrayMarshaler : MarshalerBase
109+
internal class StrArrayMarshaler : MarshalerBase
83110
{
84111
private static readonly MarshalerBase Instance = new StrArrayMarshaler();
85112
private static readonly Encoding PyEncoding = Runtime.PyEncoding;
@@ -134,7 +161,7 @@ public static ICustomMarshaler GetInstance(string cookie)
134161
/// If instead we used `MarshalAs(UnmanagedType.LPWStr)` the output to
135162
/// `foo` would be `f\x00o\x00o\x00`.
136163
/// </remarks>
137-
public class Utf8Marshaler : MarshalerBase
164+
internal class Utf8Marshaler : MarshalerBase
138165
{
139166
private static readonly MarshalerBase Instance = new Utf8Marshaler();
140167
private static readonly Encoding PyEncoding = Encoding.UTF8;

src/runtime/pythonengine.cs

+18-18
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ public static string ProgramName
5757
{
5858
get
5959
{
60-
string result = Runtime.Py_GetProgramName();
61-
if (result == null)
62-
{
63-
return "";
64-
}
65-
return result;
60+
IntPtr p = Runtime.Py_GetProgramName();
61+
string result = Runtime.IsPython3
62+
? UcsMarshaler.PtrToStringUni(p)
63+
: Marshal.PtrToStringAnsi(p);
64+
65+
return result ?? "";
6666
}
6767
set { Runtime.Py_SetProgramName(value); }
6868
}
@@ -71,12 +71,12 @@ public static string PythonHome
7171
{
7272
get
7373
{
74-
string result = Runtime.Py_GetPythonHome();
75-
if (result == null)
76-
{
77-
return "";
78-
}
79-
return result;
74+
IntPtr p = Runtime.Py_GetPythonHome();
75+
string result = Runtime.IsPython3
76+
? UcsMarshaler.PtrToStringUni(p)
77+
: Marshal.PtrToStringAnsi(p);
78+
79+
return result ?? "";
8080
}
8181
set { Runtime.Py_SetPythonHome(value); }
8282
}
@@ -85,12 +85,12 @@ public static string PythonPath
8585
{
8686
get
8787
{
88-
string result = Runtime.Py_GetPath();
89-
if (result == null)
90-
{
91-
return "";
92-
}
93-
return result;
88+
IntPtr p = Runtime.Py_GetPath();
89+
string result = Runtime.IsPython3
90+
? UcsMarshaler.PtrToStringUni(p)
91+
: Marshal.PtrToStringAnsi(p);
92+
93+
return result ?? "";
9494
}
9595
set { Runtime.Py_SetPath(value); }
9696
}

src/runtime/runtime.cs

+8-11
Original file line numberDiff line numberDiff line change
@@ -683,46 +683,43 @@ public static extern int Py_Main(
683683

684684
#if PYTHON3
685685
[DllImport(PythonDll)]
686-
[return: MarshalAs(UnmanagedType.LPWStr)]
687-
internal static extern string Py_GetProgramName();
686+
internal static extern IntPtr Py_GetProgramName();
688687

689688
[DllImport(PythonDll)]
690689
internal static extern void Py_SetProgramName(
691690
[MarshalAs(UnmanagedType.LPWStr)] string name
692691
);
693692

694693
[DllImport(PythonDll)]
695-
[return: MarshalAs(UnmanagedType.LPWStr)]
696-
internal static extern string Py_GetPythonHome();
694+
internal static extern IntPtr Py_GetPythonHome();
697695

698696
[DllImport(PythonDll)]
699697
internal static extern void Py_SetPythonHome(
700698
[MarshalAs(UnmanagedType.LPWStr)] string home
701699
);
702700

703701
[DllImport(PythonDll)]
704-
[return: MarshalAs(UnmanagedType.LPWStr)]
705-
internal static extern string Py_GetPath();
702+
internal static extern IntPtr Py_GetPath();
706703

707704
[DllImport(PythonDll)]
708705
internal static extern void Py_SetPath(
709706
[MarshalAs(UnmanagedType.LPWStr)] string home
710707
);
711708
#elif PYTHON2
712709
[DllImport(PythonDll)]
713-
internal static extern string Py_GetProgramName();
710+
internal static extern IntPtr Py_GetProgramName();
714711

715712
[DllImport(PythonDll)]
716713
internal static extern void Py_SetProgramName(string name);
717714

718715
[DllImport(PythonDll)]
719-
internal static extern string Py_GetPythonHome();
716+
internal static extern IntPtr Py_GetPythonHome();
720717

721718
[DllImport(PythonDll)]
722719
internal static extern void Py_SetPythonHome(string home);
723720

724721
[DllImport(PythonDll)]
725-
internal static extern string Py_GetPath();
722+
internal static extern IntPtr Py_GetPath();
726723

727724
[DllImport(PythonDll)]
728725
internal static extern void Py_SetPath(string home);
@@ -1242,7 +1239,7 @@ internal static bool PyUnicode_Check(IntPtr ob)
12421239
[DllImport(PythonDll)]
12431240
internal static extern IntPtr PyUnicode_FromKindAndData(
12441241
int kind,
1245-
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrMarshaler))] string s,
1242+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s,
12461243
int size
12471244
);
12481245

@@ -1268,7 +1265,7 @@ internal static IntPtr PyUnicode_FromUnicode(string s, int size)
12681265

12691266
[DllImport(PythonDll, EntryPoint = PyUnicodeEntryPoint + "FromUnicode")]
12701267
internal static extern IntPtr PyUnicode_FromUnicode(
1271-
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrMarshaler))] string s,
1268+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s,
12721269
int size
12731270
);
12741271

0 commit comments

Comments
 (0)