Skip to content

Commit fba7586

Browse files
committed
Merge pull request #41 from tonyroberts/develop
merge changes to get npython working again on windows fixes #39
2 parents 0ac66b3 + 56bebfa commit fba7586

File tree

4 files changed

+64
-26
lines changed

4 files changed

+64
-26
lines changed

appveyor.yml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ install:
1616
- ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:\get-pip.py')
1717
# appveyor has python 2.7.6 x86 preinstalled, but in the wrong directory, this works around this
1818
- ps: if ($env:pythonurl -eq "http://www.python.org/ftp/python/2.7.6/python-2.7.6.msi") {mi c:\python27 c:\python}
19+
- set PATH=C:\Python;%PATH%
1920
- C:\Python\python.exe c:\get-pip.py
2021
- C:\Python\Scripts\pip.exe install wheel
2122

pythonnet/src/console/pythonconsole.cs

+17-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
using System;
1111
using System.Reflection;
12+
using System.Collections.Generic;
1213
using Python.Runtime;
1314

1415
namespace Python.Runtime {
@@ -19,6 +20,9 @@ private PythonConsole() {}
1920

2021
[STAThread]
2122
public static int Main(string[] args) {
23+
// reference the static assemblyLoader to stop it being optimized away
24+
AssemblyLoader a = assemblyLoader;
25+
2226
string [] cmd = Environment.GetCommandLineArgs();
2327
PythonEngine.Initialize();
2428

@@ -31,16 +35,27 @@ public static int Main(string[] args) {
3135
// Register a callback function to load embedded assmeblies.
3236
// (Python.Runtime.dll is included as a resource)
3337
private sealed class AssemblyLoader {
38+
Dictionary<string, Assembly> loadedAssemblies;
39+
3440
public AssemblyLoader() {
41+
loadedAssemblies = new Dictionary<string, Assembly>();
42+
3543
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
36-
String resourceName = new AssemblyName(args.Name).Name + ".dll";
44+
string shortName = args.Name.Split(',')[0];
45+
String resourceName = shortName + ".dll";
46+
47+
if (loadedAssemblies.ContainsKey(resourceName)) {
48+
return loadedAssemblies[resourceName];
49+
}
3750

3851
// looks for the assembly from the resources and load it
3952
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {
4053
if (stream != null) {
4154
Byte[] assemblyData = new Byte[stream.Length];
4255
stream.Read(assemblyData, 0, assemblyData.Length);
43-
return Assembly.Load(assemblyData);
56+
Assembly assembly = Assembly.Load(assemblyData);
57+
loadedAssemblies[resourceName] = assembly;
58+
return assembly;
4459
}
4560
}
4661

pythonnet/src/runtime/assemblymanager.cs

+15-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ internal class AssemblyManager {
3030
static ResolveEventHandler rhandler;
3131
static Dictionary<string, int> probed;
3232
static List<Assembly> assemblies;
33+
static Dictionary<string, Assembly> loadedAssemblies;
3334
internal static List<string> pypath;
3435

3536
private AssemblyManager() {}
@@ -46,6 +47,7 @@ internal static void Initialize() {
4647
probed = new Dictionary<string, int>(32);
4748
//generics = new Dictionary<string, Dictionary<string, string>>();
4849
assemblies = new List<Assembly>(16);
50+
loadedAssemblies = new Dictionary<string, Assembly>();
4951
pypath = new List<string>(16);
5052

5153
AppDomain domain = AppDomain.CurrentDomain;
@@ -202,7 +204,19 @@ public static Assembly LoadAssemblyPath(string name) {
202204
string path = FindAssembly(name);
203205
Assembly assembly = null;
204206
if (path != null) {
205-
try { assembly = Assembly.LoadFrom(path); }
207+
if (loadedAssemblies.ContainsKey(path)) {
208+
return loadedAssemblies[path];
209+
}
210+
// Avoid using Assembly.LoadFrom as referenced assemblies that exist
211+
// in the same path will be loaded directly from there, rather than
212+
// using other versions already loaded. This is a problem if there
213+
// is a Python.Runtime.dll in the same folder as the assembly being
214+
// loaded, as that will result in two instances being loaded.
215+
try {
216+
byte[] bytes = System.IO.File.ReadAllBytes(path);
217+
assembly = Assembly.Load(bytes);
218+
loadedAssemblies[path] = assembly;
219+
}
206220
catch {}
207221
}
208222
return assembly;

pythonnet/src/testing/threadtest.cs

+31-23
Original file line numberDiff line numberDiff line change
@@ -39,35 +39,43 @@ public class ThreadTest {
3939

4040
public static string CallEchoString(string arg) {
4141
IntPtr gs = PythonEngine.AcquireLock();
42-
if (module == null) {
43-
module = PythonEngine.ModuleFromString("tt", testmod);
42+
try {
43+
if (module == null) {
44+
module = PythonEngine.ModuleFromString("tt", testmod);
45+
}
46+
PyObject func = module.GetAttr("echostring");
47+
PyString parg = new PyString(arg);
48+
PyObject temp = func.Invoke(parg);
49+
string result = (string)temp.AsManagedObject(typeof(String));
50+
func.Dispose();
51+
parg.Dispose();
52+
temp.Dispose();
53+
return result;
54+
}
55+
finally {
56+
PythonEngine.ReleaseLock(gs);
4457
}
45-
PyObject func = module.GetAttr("echostring");
46-
PyString parg = new PyString(arg);
47-
PyObject temp = func.Invoke(parg);
48-
string result = (string)temp.AsManagedObject(typeof(String));
49-
func.Dispose();
50-
parg.Dispose();
51-
temp.Dispose();
52-
PythonEngine.ReleaseLock(gs);
53-
return result;
5458
}
5559

5660
public static string CallEchoString2(string arg) {
5761
IntPtr gs = PythonEngine.AcquireLock();
58-
if (module == null) {
59-
module = PythonEngine.ModuleFromString("tt", testmod);
60-
}
62+
try {
63+
if (module == null) {
64+
module = PythonEngine.ModuleFromString("tt", testmod);
65+
}
6166

62-
PyObject func = module.GetAttr("echostring2");
63-
PyString parg = new PyString(arg);
64-
PyObject temp = func.Invoke(parg);
65-
string result = (string)temp.AsManagedObject(typeof(String));
66-
func.Dispose();
67-
parg.Dispose();
68-
temp.Dispose();
69-
PythonEngine.ReleaseLock(gs);
70-
return result;
67+
PyObject func = module.GetAttr("echostring2");
68+
PyString parg = new PyString(arg);
69+
PyObject temp = func.Invoke(parg);
70+
string result = (string)temp.AsManagedObject(typeof(String));
71+
func.Dispose();
72+
parg.Dispose();
73+
temp.Dispose();
74+
return result;
75+
}
76+
finally {
77+
PythonEngine.ReleaseLock(gs);
78+
}
7179
}
7280

7381

0 commit comments

Comments
 (0)