Skip to content

Commit 022be19

Browse files
authored
Merge branch 'master' into amos-interop-changes
2 parents 8e1fa20 + 451fae6 commit 022be19

16 files changed

+231
-166
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1414
- `clr.AddReference` may now throw errors besides `FileNotFoundException`, that provide more
1515
details about the cause of the failure
1616
- `clr.AddReference` no longer adds ".dll" implicitly
17+
- `PyIter(PyObject)` constructor replaced with static `PyIter.GetIter(PyObject)` method
1718

1819
### Fixed
1920

src/embed_tests/TestFinalizer.cs

+12
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ public void CollectBasicObject()
8787
Assert.GreaterOrEqual(objectCount, 1);
8888
}
8989

90+
[Test]
91+
public void CollectOnShutdown()
92+
{
93+
MakeAGarbage(out var shortWeak, out var longWeak);
94+
FullGCCollect();
95+
var garbage = Finalizer.Instance.GetCollectedObjects();
96+
Assert.IsNotEmpty(garbage);
97+
PythonEngine.Shutdown();
98+
garbage = Finalizer.Instance.GetCollectedObjects();
99+
Assert.IsEmpty(garbage);
100+
}
101+
90102
private static void MakeAGarbage(out WeakReference shortWeak, out WeakReference longWeak)
91103
{
92104
PyLong obj = new PyLong(1024);

src/perf_tests/Python.PerformanceTests.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
</ItemGroup>
2929

3030
<Target Name="GetRuntimeLibBuildOutput" BeforeTargets="Build">
31-
<MSBuild Projects="..\runtime\Python.Runtime.15.csproj" Properties="PYTHONNET_PY3_VERSION=PYTHON35;Configuration=$(Configuration);TargetFramework=net40;Python3Version=PYTHON35;OutputPath=bin\for_perf\">
31+
<MSBuild Projects="..\runtime\Python.Runtime.15.csproj" Properties="PYTHONNET_PY3_VERSION=PYTHON38;Configuration=$(Configuration);TargetFramework=net40;Python3Version=PYTHON38;OutputPath=bin\for_perf\">
3232
<Output TaskParameter="TargetOutputs" ItemName="NewPythonRuntime" />
3333
</MSBuild>
3434
</Target>

src/runtime/pyansistring.cs

+18-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ public PyAnsiString(IntPtr ptr) : base(ptr)
1717
}
1818

1919

20+
private static IntPtr FromObject(PyObject o)
21+
{
22+
if (o == null || !IsStringType(o))
23+
{
24+
throw new ArgumentException("object is not a string");
25+
}
26+
Runtime.XIncref(o.obj);
27+
return o.obj;
28+
}
29+
2030
/// <summary>
2131
/// PyString Constructor
2232
/// </summary>
@@ -25,14 +35,14 @@ public PyAnsiString(IntPtr ptr) : base(ptr)
2535
/// An ArgumentException will be thrown if the given object is not
2636
/// a Python string object.
2737
/// </remarks>
28-
public PyAnsiString(PyObject o)
38+
public PyAnsiString(PyObject o) : base(FromObject(o))
2939
{
30-
if (!IsStringType(o))
31-
{
32-
throw new ArgumentException("object is not a string");
33-
}
34-
Runtime.XIncref(o.obj);
35-
obj = o.obj;
40+
}
41+
private static IntPtr FromString(string s)
42+
{
43+
IntPtr val = Runtime.PyString_FromString(s);
44+
PythonException.ThrowIfIsNull(val);
45+
return val;
3646
}
3747

3848

@@ -42,10 +52,8 @@ public PyAnsiString(PyObject o)
4252
/// <remarks>
4353
/// Creates a Python string from a managed string.
4454
/// </remarks>
45-
public PyAnsiString(string s)
55+
public PyAnsiString(string s) : base(FromString(s))
4656
{
47-
obj = Runtime.PyString_FromString(s);
48-
PythonException.ThrowIfIsNull(obj);
4957
}
5058

5159

src/runtime/pydict.cs

+3-5
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ public PyDict(IntPtr ptr) : base(ptr)
2929
/// <remarks>
3030
/// Creates a new Python dictionary object.
3131
/// </remarks>
32-
public PyDict()
32+
public PyDict() : base(Runtime.PyDict_New())
3333
{
34-
obj = Runtime.PyDict_New();
3534
if (obj == IntPtr.Zero)
3635
{
3736
throw new PythonException();
@@ -47,14 +46,13 @@ public PyDict()
4746
/// ArgumentException will be thrown if the given object is not a
4847
/// Python dictionary object.
4948
/// </remarks>
50-
public PyDict(PyObject o)
49+
public PyDict(PyObject o) : base(o.obj)
5150
{
51+
Runtime.XIncref(o.obj);
5252
if (!IsDictType(o))
5353
{
5454
throw new ArgumentException("object is not a dict");
5555
}
56-
Runtime.XIncref(o.obj);
57-
obj = o.obj;
5856
}
5957

6058

src/runtime/pyfloat.cs

+29-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ namespace Python.Runtime
44
{
55
/// <summary>
66
/// Represents a Python float object. See the documentation at
7-
/// PY2: https://docs.python.org/2/c-api/float.html
87
/// PY3: https://docs.python.org/3/c-api/float.html
98
/// for details.
109
/// </summary>
@@ -31,14 +30,8 @@ public PyFloat(IntPtr ptr) : base(ptr)
3130
/// ArgumentException will be thrown if the given object is not a
3231
/// Python float object.
3332
/// </remarks>
34-
public PyFloat(PyObject o)
33+
public PyFloat(PyObject o) : base(FromObject(o))
3534
{
36-
if (!IsFloatType(o))
37-
{
38-
throw new ArgumentException("object is not a float");
39-
}
40-
Runtime.XIncref(o.obj);
41-
obj = o.obj;
4235
}
4336

4437

@@ -48,26 +41,45 @@ public PyFloat(PyObject o)
4841
/// <remarks>
4942
/// Creates a new Python float from a double value.
5043
/// </remarks>
51-
public PyFloat(double value)
44+
public PyFloat(double value) : base(FromDouble(value))
45+
{
46+
}
47+
48+
private static IntPtr FromObject(PyObject o)
49+
{
50+
if (o == null || !IsFloatType(o))
51+
{
52+
throw new ArgumentException("object is not a float");
53+
}
54+
Runtime.XIncref(o.obj);
55+
return o.obj;
56+
}
57+
58+
private static IntPtr FromDouble(double value)
5259
{
53-
obj = Runtime.PyFloat_FromDouble(value);
54-
PythonException.ThrowIfIsNull(obj);
60+
IntPtr val = Runtime.PyFloat_FromDouble(value);
61+
PythonException.ThrowIfIsNull(val);
62+
return val;
5563
}
5664

65+
private static IntPtr FromString(string value)
66+
{
67+
using (var s = new PyString(value))
68+
{
69+
IntPtr val = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero);
70+
PythonException.ThrowIfIsNull(val);
71+
return val;
72+
}
73+
}
5774

5875
/// <summary>
5976
/// PyFloat Constructor
6077
/// </summary>
6178
/// <remarks>
6279
/// Creates a new Python float from a string value.
6380
/// </remarks>
64-
public PyFloat(string value)
81+
public PyFloat(string value) : base(FromString(value))
6582
{
66-
using (var s = new PyString(value))
67-
{
68-
obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero);
69-
PythonException.ThrowIfIsNull(obj);
70-
}
7183
}
7284

7385

src/runtime/pyint.cs

+32-18
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,35 @@ public PyInt(IntPtr ptr) : base(ptr)
3131
/// ArgumentException will be thrown if the given object is not a
3232
/// Python int object.
3333
/// </remarks>
34-
public PyInt(PyObject o)
34+
public PyInt(PyObject o) : base(FromObject(o))
3535
{
36-
if (!IsIntType(o))
36+
}
37+
38+
private static IntPtr FromObject(PyObject o)
39+
{
40+
if (o == null || !IsIntType(o))
3741
{
3842
throw new ArgumentException("object is not an int");
3943
}
4044
Runtime.XIncref(o.obj);
41-
obj = o.obj;
45+
return o.obj;
4246
}
4347

48+
private static IntPtr FromInt(int value)
49+
{
50+
IntPtr val = Runtime.PyInt_FromInt32(value);
51+
PythonException.ThrowIfIsNull(val);
52+
return val;
53+
}
4454

4555
/// <summary>
4656
/// PyInt Constructor
4757
/// </summary>
4858
/// <remarks>
4959
/// Creates a new Python int from an int32 value.
5060
/// </remarks>
51-
public PyInt(int value)
61+
public PyInt(int value) : base(FromInt(value))
5262
{
53-
obj = Runtime.PyInt_FromInt32(value);
54-
PythonException.ThrowIfIsNull(obj);
5563
}
5664

5765

@@ -62,10 +70,8 @@ public PyInt(int value)
6270
/// Creates a new Python int from a uint32 value.
6371
/// </remarks>
6472
[CLSCompliant(false)]
65-
public PyInt(uint value)
73+
public PyInt(uint value) : base(FromLong(value))
6674
{
67-
obj = Runtime.PyInt_FromInt64(value);
68-
PythonException.ThrowIfIsNull(obj);
6975
}
7076

7177

@@ -75,10 +81,15 @@ public PyInt(uint value)
7581
/// <remarks>
7682
/// Creates a new Python int from an int64 value.
7783
/// </remarks>
78-
public PyInt(long value)
84+
public PyInt(long value) : base(FromLong(value))
7985
{
80-
obj = Runtime.PyInt_FromInt64(value);
81-
PythonException.ThrowIfIsNull(obj);
86+
}
87+
88+
private static IntPtr FromLong(long value)
89+
{
90+
IntPtr val = Runtime.PyInt_FromInt64(value);
91+
PythonException.ThrowIfIsNull(val);
92+
return val;
8293
}
8394

8495

@@ -89,10 +100,8 @@ public PyInt(long value)
89100
/// Creates a new Python int from a uint64 value.
90101
/// </remarks>
91102
[CLSCompliant(false)]
92-
public PyInt(ulong value)
103+
public PyInt(ulong value) : base(FromLong((long)value))
93104
{
94-
obj = Runtime.PyInt_FromInt64((long)value);
95-
PythonException.ThrowIfIsNull(obj);
96105
}
97106

98107

@@ -142,16 +151,21 @@ public PyInt(sbyte value) : this((int)value)
142151
}
143152

144153

154+
private static IntPtr FromString(string value)
155+
{
156+
IntPtr val = Runtime.PyInt_FromString(value, IntPtr.Zero, 0);
157+
PythonException.ThrowIfIsNull(val);
158+
return val;
159+
}
160+
145161
/// <summary>
146162
/// PyInt Constructor
147163
/// </summary>
148164
/// <remarks>
149165
/// Creates a new Python int from a string value.
150166
/// </remarks>
151-
public PyInt(string value)
167+
public PyInt(string value) : base(FromString(value))
152168
{
153-
obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0);
154-
PythonException.ThrowIfIsNull(obj);
155169
}
156170

157171

src/runtime/pyiter.cs

+10-6
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,22 @@ public PyIter(IntPtr ptr) : base(ptr)
2626
}
2727

2828
/// <summary>
29-
/// PyIter Constructor
29+
/// PyIter factory function.
3030
/// </summary>
3131
/// <remarks>
32-
/// Creates a Python iterator from an iterable. Like doing "iter(iterable)" in python.
32+
/// Create a new PyIter from a given iterable. Like doing "iter(iterable)" in python.
3333
/// </remarks>
34-
public PyIter(PyObject iterable)
34+
/// <param name="iterable"></param>
35+
/// <returns></returns>
36+
public static PyIter GetIter(PyObject iterable)
3537
{
36-
obj = Runtime.PyObject_GetIter(iterable.obj);
37-
if (obj == IntPtr.Zero)
38+
if (iterable == null)
3839
{
39-
throw new PythonException();
40+
throw new ArgumentNullException();
4041
}
42+
IntPtr val = Runtime.PyObject_GetIter(iterable.obj);
43+
PythonException.ThrowIfIsNull(val);
44+
return new PyIter(val);
4145
}
4246

4347
protected override void Dispose(bool disposing)

0 commit comments

Comments
 (0)