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

Skip to content

Commit cfc3ef3

Browse files
committed
Subclasses written in Python can now have their properties and methods
reflected back into .NET. Added decorators 'clrproperty' and 'clrmethod' to the clr module which are used to declare which properties and methods should be reflected, and to supply the .net argument and return types.
1 parent b64091b commit cfc3ef3

File tree

10 files changed

+709
-161
lines changed

10 files changed

+709
-161
lines changed

pythonnet/src/runtime/Python.Runtime.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@
234234
<None Include="x64\clrmodule-platform.il" />
235235
<None Include="x86\clrmodule-platform.il" />
236236
</ItemGroup>
237+
<ItemGroup>
238+
<EmbeddedResource Include="resources\clr.py" />
239+
</ItemGroup>
237240
<Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
238241
<ProjectExtensions>
239242
<VisualStudio AllowExistingFolder="true" />

pythonnet/src/runtime/classderived.cs

Lines changed: 392 additions & 114 deletions
Large diffs are not rendered by default.

pythonnet/src/runtime/converter.cs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private Converter() {}
3434
static Type int64Type;
3535
static Type flagsType;
3636
static Type boolType;
37-
//static Type typeType;
37+
static Type typeType;
3838

3939
static Converter () {
4040
nfi = NumberFormatInfo.InvariantInfo;
@@ -45,7 +45,7 @@ static Converter () {
4545
doubleType = typeof(Double);
4646
flagsType = typeof(FlagsAttribute);
4747
boolType = typeof(Boolean);
48-
//typeType = typeof(Type);
48+
typeType = typeof(Type);
4949
}
5050

5151

@@ -335,6 +335,57 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
335335
return false;
336336
}
337337

338+
// Conversion to 'Type' is done using the same mappings as above
339+
// for objects.
340+
341+
if (obType == typeType)
342+
{
343+
if (value == Runtime.PyStringType)
344+
{
345+
result = stringType;
346+
return true;
347+
}
348+
349+
else if (value == Runtime.PyBoolType)
350+
{
351+
result = boolType;
352+
return true;
353+
}
354+
355+
else if (value == Runtime.PyIntType)
356+
{
357+
result = int32Type;
358+
return true;
359+
}
360+
361+
else if (value == Runtime.PyLongType)
362+
{
363+
result = int64Type;
364+
return true;
365+
}
366+
367+
else if (value == Runtime.PyFloatType)
368+
{
369+
result = doubleType;
370+
return true;
371+
}
372+
373+
else if (value == Runtime.PyListType || value == Runtime.PyTupleType)
374+
{
375+
result = typeof(object[]);
376+
return true;
377+
}
378+
379+
if (setError)
380+
{
381+
Exceptions.SetError(Exceptions.TypeError,
382+
"value cannot be converted to Type"
383+
);
384+
}
385+
386+
return false;
387+
}
388+
338389
return ToPrimitive(value, obType, out result, setError);
339390

340391
}

pythonnet/src/runtime/pyobject.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System;
1111
using System.Dynamic;
1212
using System.Linq.Expressions;
13+
using System.Collections;
1314

1415
namespace Python.Runtime {
1516

@@ -561,6 +562,21 @@ public PyObject GetIterator() {
561562
return new PyObject(r);
562563
}
563564

565+
/// <summary>
566+
/// GetEnumerator Method
567+
/// </summary>
568+
///
569+
/// <remarks>
570+
/// Return a new PyIter object for the object. This allows any iterable
571+
/// python object to be iterated over in C#. A PythonException will be
572+
/// raised if the object is not iterable.
573+
/// </remarks>
574+
575+
public IEnumerator GetEnumerator()
576+
{
577+
return new PyIter(this);
578+
}
579+
564580

565581
/// <summary>
566582
/// Invoke Method
@@ -760,6 +776,22 @@ public bool IsCallable() {
760776
}
761777

762778

779+
/// <summary>
780+
/// IsIterable Method
781+
/// </summary>
782+
///
783+
/// <remarks>
784+
/// Returns true if the object is iterable object. This method
785+
/// always succeeds.
786+
/// </remarks>
787+
788+
public bool IsIterable()
789+
{
790+
return Runtime.PyIter_Check(obj);
791+
}
792+
793+
794+
763795
/// <summary>
764796
/// IsTrue Method
765797
/// </summary>

pythonnet/src/runtime/pysequence.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,15 +158,6 @@ public PyObject Repeat(int count) {
158158
}
159159
return new PyObject(op);
160160
}
161-
162-
#region IEnumerable Members
163-
164-
public IEnumerator GetEnumerator()
165-
{
166-
return new PyIter(this);
167-
}
168-
169-
#endregion
170161
}
171162

172163
}

pythonnet/src/runtime/pythonengine.cs

Lines changed: 97 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
// ==========================================================================
99

1010
using System;
11+
using System.IO;
1112
using System.Threading;
13+
using System.Reflection;
1214

1315
namespace Python.Runtime {
1416

@@ -143,10 +145,47 @@ public static void Initialize() {
143145
PyObject r = PythonEngine.RunString(code);
144146
if (r != null)
145147
r.Dispose();
148+
149+
// Load the clr.py resource into the clr module
150+
IntPtr clr = Python.Runtime.ImportHook.GetCLRModule();
151+
IntPtr clr_dict = Runtime.PyModule_GetDict(clr);
152+
153+
IntPtr globals = Runtime.PyEval_GetGlobals();
154+
PyDict locals = new PyDict();
155+
try
156+
{
157+
IntPtr builtins = Runtime.PyEval_GetBuiltins();
158+
Runtime.PyDict_SetItemString(locals.Handle, "__builtins__", builtins);
159+
160+
var assembly = Assembly.GetExecutingAssembly();
161+
using (Stream stream = assembly.GetManifestResourceStream("Python.Runtime.resources.clr.py"))
162+
using (StreamReader reader = new StreamReader(stream))
163+
{
164+
// add the contents of clr.py to the module
165+
string clr_py = reader.ReadToEnd();
166+
PyObject result = RunString(clr_py, globals, locals.Handle);
167+
if (null == result)
168+
throw new PythonException();
169+
result.Dispose();
170+
}
171+
172+
foreach (PyObject key in locals.Keys())
173+
{
174+
if (!key.ToString().StartsWith("_")){
175+
PyObject value = locals[key];
176+
Runtime.PyDict_SetItem(clr_dict, key.Handle, value.Handle);
177+
value.Dispose();
178+
}
179+
key.Dispose();
180+
}
181+
}
182+
finally
183+
{
184+
locals.Dispose();
185+
}
146186
}
147187
}
148188

149-
150189
//====================================================================
151190
// A helper to perform initialization from the context of an active
152191
// CPython interpreter process - this bootstraps the managed runtime
@@ -157,41 +196,51 @@ public static IntPtr InitExt() {
157196
#else
158197
public static void InitExt() {
159198
#endif
160-
Initialize();
161-
162-
// Trickery - when the import hook is installed into an already
163-
// running Python, the standard import machinery is still in
164-
// control for the duration of the import that caused bootstrap.
165-
//
166-
// That is problematic because the std machinery tries to get
167-
// sub-names directly from the module __dict__ rather than going
168-
// through our module object's getattr hook. This workaround is
169-
// evil ;) We essentially climb up the stack looking for the
170-
// import that caused the bootstrap to happen, then re-execute
171-
// the import explicitly after our hook has been installed. By
172-
// doing this, the original outer import should work correctly.
173-
//
174-
// Note that this is only needed during the execution of the
175-
// first import that installs the CLR import hook. This hack
176-
// still doesn't work if you use the interactive interpreter,
177-
// since there is no line info to get the import line ;(
178-
179-
string code =
180-
181-
"import traceback\n" +
182-
"for item in traceback.extract_stack():\n" +
183-
" line = item[3]\n" +
184-
" if line is not None:\n" +
185-
" if line.startswith('import CLR') or \\\n" +
186-
" line.startswith('import clr') or \\\n" +
187-
" line.startswith('from clr') or \\\n" +
188-
" line.startswith('from CLR'):\n" +
189-
" exec(line)\n" +
190-
" break\n";
191-
192-
PyObject r = PythonEngine.RunString(code);
193-
if (r != null) {
194-
r.Dispose();
199+
try
200+
{
201+
Initialize();
202+
203+
// Trickery - when the import hook is installed into an already
204+
// running Python, the standard import machinery is still in
205+
// control for the duration of the import that caused bootstrap.
206+
//
207+
// That is problematic because the std machinery tries to get
208+
// sub-names directly from the module __dict__ rather than going
209+
// through our module object's getattr hook. This workaround is
210+
// evil ;) We essentially climb up the stack looking for the
211+
// import that caused the bootstrap to happen, then re-execute
212+
// the import explicitly after our hook has been installed. By
213+
// doing this, the original outer import should work correctly.
214+
//
215+
// Note that this is only needed during the execution of the
216+
// first import that installs the CLR import hook. This hack
217+
// still doesn't work if you use the interactive interpreter,
218+
// since there is no line info to get the import line ;(
219+
220+
string code =
221+
222+
"import traceback\n" +
223+
"for item in traceback.extract_stack():\n" +
224+
" line = item[3]\n" +
225+
" if line is not None:\n" +
226+
" if line.startswith('import CLR') or \\\n" +
227+
" line.startswith('import clr') or \\\n" +
228+
" line.startswith('from clr') or \\\n" +
229+
" line.startswith('from CLR'):\n" +
230+
" exec(line)\n" +
231+
" break\n";
232+
233+
PyObject r = PythonEngine.RunString(code);
234+
if (r != null) {
235+
r.Dispose();
236+
}
237+
}
238+
catch (PythonException e)
239+
{
240+
e.Restore();
241+
#if (PYTHON32 || PYTHON33 || PYTHON34)
242+
return IntPtr.Zero;
243+
#endif
195244
}
196245

197246
#if (PYTHON32 || PYTHON33 || PYTHON34)
@@ -378,6 +427,18 @@ public static PyObject RunString(string code) {
378427
}
379428
return new PyObject(result);
380429
}
430+
431+
public static PyObject RunString(string code, IntPtr globals, IntPtr locals)
432+
{
433+
IntPtr flag = (IntPtr)257; /* Py_file_input */
434+
IntPtr result = Runtime.PyRun_String(code, flag, globals, locals);
435+
Runtime.Decref(locals);
436+
if (result == IntPtr.Zero)
437+
{
438+
return null;
439+
}
440+
return new PyObject(result);
441+
}
381442
}
382443

383444
public static class Py

pythonnet/src/runtime/pythonexception.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ public PythonException() : base()
5353
Dispose();
5454
}
5555

56+
/// <summary>
57+
/// Restores python error.
58+
/// </summary>
59+
public void Restore()
60+
{
61+
IntPtr gs = PythonEngine.AcquireLock();
62+
Runtime.PyErr_Restore(_pyType, _pyValue, _pyTB);
63+
_pyType = IntPtr.Zero;
64+
_pyValue = IntPtr.Zero;
65+
_pyTB = IntPtr.Zero;
66+
PythonEngine.ReleaseLock(gs);
67+
}
5668

5769
/// <summary>
5870
/// PyType Property

0 commit comments

Comments
 (0)