From f8f9added5cbe9ef9bbfd799396c01319dabe4ac Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Tue, 27 Oct 2020 16:18:27 -0300 Subject: [PATCH 1/7] Failing test for #268 --- examples/issues/source/issues.d | 5 +++++ tests/test_issues.py | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/examples/issues/source/issues.d b/examples/issues/source/issues.d index de598c80..a0376551 100644 --- a/examples/issues/source/issues.d +++ b/examples/issues/source/issues.d @@ -284,3 +284,8 @@ struct MethodWithScopeSafeDelegate { return cb(i, 33.3, Struct()); } } + + +struct Issue268 { + int i; +} diff --git a/tests/test_issues.py b/tests/test_issues.py index bad1dd71..39d41856 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -265,3 +265,11 @@ def test_method_delegate_safe_scope(): from issues import MethodWithScopeSafeDelegate m = MethodWithScopeSafeDelegate() assert m.fun(3, lambda i, d, s: i * 2) == 6 + + +def test_issue_268(): + import pytest + from issues import Issue268 + assert Issue268(1) != Issue268(2) + with pytest.raises(AssertionError): + assert Issue268(42) == Issue268(42) From 657553671d28715eb4307f3c6497b2c1cad81e5e Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Tue, 27 Oct 2020 16:27:46 -0300 Subject: [PATCH 2/7] WIP --- pynih/source/python/type.d | 16 ++++++++++++++++ tests/test_issues.py | 5 ++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pynih/source/python/type.d b/pynih/source/python/type.d index fa049832..97ddab25 100644 --- a/pynih/source/python/type.d +++ b/pynih/source/python/type.d @@ -215,6 +215,8 @@ struct PythonType(T) { } } + _pyType.tp_richcompare = &PythonCompare!T._py_cmp; + } else static if(isCallable!T) { _pyType.tp_basicsize = PythonCallable!T.sizeof; _pyType.tp_call = &PythonCallable!T._py_call; @@ -1462,6 +1464,20 @@ private template PythonIndexAssign(T) { } } + +private template PythonCompare(T) { + + static extern(C) PyObject* tp_richcompare(PyObject* self, PyObject* other, int op) nothrow { + + PyObject* impl() { + import python.raw: Py_True, Py_False; + return Py_False; + } + + return noThrowable!impl; + } +} + private bool isInstanceOf(T)(PyObject* obj) { import python.raw: PyObject_IsInstance; return cast(bool) PyObject_IsInstance(obj, cast(PyObject*) PythonType!T.pyType); diff --git a/tests/test_issues.py b/tests/test_issues.py index 39d41856..0305346e 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -271,5 +271,8 @@ def test_issue_268(): import pytest from issues import Issue268 assert Issue268(1) != Issue268(2) - with pytest.raises(AssertionError): + if is_pynih: assert Issue268(42) == Issue268(42) + else: + with pytest.raises(AssertionError): + assert Issue268(42) == Issue268(42) From cf46d77d8b57c02d67c9a3b5a2848af5cf30d6ec Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Tue, 27 Oct 2020 16:39:57 -0300 Subject: [PATCH 3/7] Fix the issue for pynih --- pynih/source/python/type.d | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/pynih/source/python/type.d b/pynih/source/python/type.d index 97ddab25..ceec6d37 100644 --- a/pynih/source/python/type.d +++ b/pynih/source/python/type.d @@ -1467,11 +1467,28 @@ private template PythonIndexAssign(T) { private template PythonCompare(T) { - static extern(C) PyObject* tp_richcompare(PyObject* self, PyObject* other, int op) nothrow { + static extern(C) PyObject* _py_cmp(PyObject* self, PyObject* other, int op) nothrow { + + PyObject* incAndRet(PyObject* obj) { + import python.raw: pyIncRef; + pyIncRef(obj); + return obj; + } PyObject* impl() { - import python.raw: Py_True, Py_False; - return Py_False; + import python.conv.python_to_d: to; + import python.raw: pyIncRef, _Py_TrueStruct, _Py_FalseStruct, _Py_NotImplementedStruct, + Py_EQ; + + auto pyTrue = cast(PyObject*) &_Py_TrueStruct; + auto pyFalse = cast(PyObject*) &_Py_FalseStruct; + auto pyNotImplemented = cast(PyObject*) &_Py_NotImplementedStruct; + + static if(__traits(compiles, T.init == T.init)) + if(op == Py_EQ) + return self.to!T == other.to!T ? pyTrue : pyFalse; + + return incAndRet(pyNotImplemented); } return noThrowable!impl; From cf0bdf835a72c2925562f1955a1ff18ab1468422 Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Wed, 28 Oct 2020 10:20:49 -0300 Subject: [PATCH 4/7] Fix test failure --- pynih/source/python/conv/d_to_python.d | 15 ++++++++ pynih/source/python/type.d | 50 +++++++++++++++++--------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/pynih/source/python/conv/d_to_python.d b/pynih/source/python/conv/d_to_python.d index 2c2f3f66..1f9784cb 100644 --- a/pynih/source/python/conv/d_to_python.d +++ b/pynih/source/python/conv/d_to_python.d @@ -12,6 +12,21 @@ import std.datetime: Date, DateTime; import core.time: Duration; +PyObject* toPython(in bool val) @trusted { + import python.raw: pyIncRef, _Py_TrueStruct, _Py_FalseStruct; + + auto pyTrue = cast(PyObject*) &_Py_TrueStruct; + auto pyFalse = cast(PyObject*) &_Py_FalseStruct; + + static PyObject* incAndRet(PyObject* obj) { + pyIncRef(obj); + return obj; + } + + return val ? incAndRet(pyTrue) : incAndRet(pyFalse); +} + + PyObject* toPython(T)(T value) @trusted if(isIntegral!T && !is(T == enum)) { import python.raw: PyLong_FromLong; return PyLong_FromLong(value); diff --git a/pynih/source/python/type.d b/pynih/source/python/type.d index ceec6d37..f2b2dd95 100644 --- a/pynih/source/python/type.d +++ b/pynih/source/python/type.d @@ -109,8 +109,11 @@ struct PythonType(T) { ) { _pyType.tp_richcompare = &PythonOpCmp!T._py_cmp; - } - } + } else + _pyType.tp_richcompare = &PythonCompare!T._py_cmp; + } else + _pyType.tp_richcompare = &PythonCompare!T._py_cmp; + static if(hasMember!(T, "opSlice")) { static if(AlwaysTry || __traits(compiles, &PythonIterViaList!T._py_iter)) @@ -215,8 +218,6 @@ struct PythonType(T) { } } - _pyType.tp_richcompare = &PythonCompare!T._py_cmp; - } else static if(isCallable!T) { _pyType.tp_basicsize = PythonCallable!T.sizeof; _pyType.tp_call = &PythonCallable!T._py_call; @@ -1469,32 +1470,47 @@ private template PythonCompare(T) { static extern(C) PyObject* _py_cmp(PyObject* self, PyObject* other, int op) nothrow { - PyObject* incAndRet(PyObject* obj) { - import python.raw: pyIncRef; - pyIncRef(obj); - return obj; - } - PyObject* impl() { import python.conv.python_to_d: to; - import python.raw: pyIncRef, _Py_TrueStruct, _Py_FalseStruct, _Py_NotImplementedStruct, - Py_EQ; + import python.conv.d_to_python: toPython; + import python.raw: pyIncRef, _Py_NotImplementedStruct, Py_EQ, Py_LT, Py_LE, Py_NE, Py_GT, Py_GE; - auto pyTrue = cast(PyObject*) &_Py_TrueStruct; - auto pyFalse = cast(PyObject*) &_Py_FalseStruct; auto pyNotImplemented = cast(PyObject*) &_Py_NotImplementedStruct; - static if(__traits(compiles, T.init == T.init)) + static if(is(typeof(T.init < T.init) == bool)) + if(op == Py_LT) + return (self.to!T < other.to!T).toPython; + + static if(is(typeof(T.init <= T.init) == bool)) + if(op == Py_LE) + return (self.to!T <= other.to!T).toPython; + + static if(is(typeof(T.init == T.init) == bool)) if(op == Py_EQ) - return self.to!T == other.to!T ? pyTrue : pyFalse; + return (self.to!T == other.to!T).toPython; + + static if(is(typeof(T.init != T.init) == bool)) + if(op == Py_NE) + return (self.to!T != other.to!T).toPython; - return incAndRet(pyNotImplemented); + static if(is(typeof(T.init > T.init) == bool)) + if(op == Py_GT) + return (self.to!T > other.to!T).toPython; + + static if(is(typeof(T.init >= T.init) == bool)) + if(op == Py_GE) + return (self.to!T >= other.to!T).toPython; + + + pyIncRef(pyNotImplemented); + return pyNotImplemented; } return noThrowable!impl; } } + private bool isInstanceOf(T)(PyObject* obj) { import python.raw: PyObject_IsInstance; return cast(bool) PyObject_IsInstance(obj, cast(PyObject*) PythonType!T.pyType); From 19f60034bb668be052b6a6f97d32810081e37ecc Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Wed, 28 Oct 2020 11:15:27 -0300 Subject: [PATCH 5/7] Fix unit tests --- pynih/source/python/conv/d_to_python.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynih/source/python/conv/d_to_python.d b/pynih/source/python/conv/d_to_python.d index 1f9784cb..c80cffa7 100644 --- a/pynih/source/python/conv/d_to_python.d +++ b/pynih/source/python/conv/d_to_python.d @@ -12,7 +12,7 @@ import std.datetime: Date, DateTime; import core.time: Duration; -PyObject* toPython(in bool val) @trusted { +PyObject* toPython(in bool val) @trusted @nogc { import python.raw: pyIncRef, _Py_TrueStruct, _Py_FalseStruct; auto pyTrue = cast(PyObject*) &_Py_TrueStruct; From ddc5c9765c769b7eb25179bdc0ba7776518c70b7 Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Wed, 28 Oct 2020 11:39:38 -0300 Subject: [PATCH 6/7] Fix std_date linker errors --- examples/phobos/std_datetime/source/app.d | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/phobos/std_datetime/source/app.d b/examples/phobos/std_datetime/source/app.d index 6f546dbf..a94ee264 100644 --- a/examples/phobos/std_datetime/source/app.d +++ b/examples/phobos/std_datetime/source/app.d @@ -15,3 +15,11 @@ enum str = wrapDlang!( // pragma(msg, str); mixin(str); + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8typecons__T10RebindableTyCQBf8datetime8timezone8TimeZoneZQBuZ7_py_cmpUNbPSQEh3raw7_objectQriZQv") +private void hack0() { assert(0); } + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8datetime8timezone13PosixTimeZone6TTInfoZ7_py_cmpUNbPSQDm3raw7_objectQriZQv") +private void hack1() { assert(0); } From 5b84ed80a291a6113048a5f0e38192e5da4fecf5 Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Wed, 28 Oct 2020 11:51:51 -0300 Subject: [PATCH 7/7] Fix phobos tests --- examples/phobos/std_experimental/source/app.d | 4 ++++ examples/phobos/std_file/source/app.d | 4 ++++ examples/phobos/std_net/source/app.d | 4 ++++ examples/phobos/std_zip/source/app.d | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/examples/phobos/std_experimental/source/app.d b/examples/phobos/std_experimental/source/app.d index 1049bac9..6e31c011 100644 --- a/examples/phobos/std_experimental/source/app.d +++ b/examples/phobos/std_experimental/source/app.d @@ -73,3 +73,7 @@ pragma(mangle, "_D6python4conv11python_to_d__T2toTxS3std12experimental9allocator extern(C) void hack3() { } + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std12experimental9allocator15building_blocks14allocator_list__T13AllocatorListTSQDdQDcQCr8showcase14mmapRegionListFmZ7FactoryTSQEyQExQEmQEf14null_allocator13NullAllocatorZQEe4NodeZ7_py_cmpUNbPSQIs3raw7_objectQriZQv") +private void hack4() { assert(0); } diff --git a/examples/phobos/std_file/source/app.d b/examples/phobos/std_file/source/app.d index b6668cdd..6c6e3687 100644 --- a/examples/phobos/std_file/source/app.d +++ b/examples/phobos/std_file/source/app.d @@ -21,3 +21,7 @@ void hack() { import std.file: dirEntries, SpanMode; auto id = typeid(dirEntries("path", "pattern", SpanMode.depth)); } + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8typecons__T10RebindableTyCQBf8datetime8timezone8TimeZoneZQBuZ7_py_cmpUNbPSQEh3raw7_objectQriZQv") +private void hack1() { assert(0); } diff --git a/examples/phobos/std_net/source/app.d b/examples/phobos/std_net/source/app.d index 1d60a6a0..9d162d58 100644 --- a/examples/phobos/std_net/source/app.d +++ b/examples/phobos/std_net/source/app.d @@ -12,3 +12,7 @@ enum str = wrapDlang!( // pragma(msg, str); mixin(str); + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8typecons__T10RebindableTyCQBf8datetime8timezone8TimeZoneZQBuZ7_py_cmpUNbPSQEh3raw7_objectQriZQv") +private void hack0() { assert(0); } diff --git a/examples/phobos/std_zip/source/app.d b/examples/phobos/std_zip/source/app.d index 42d134c5..86ce4a20 100644 --- a/examples/phobos/std_zip/source/app.d +++ b/examples/phobos/std_zip/source/app.d @@ -10,3 +10,7 @@ enum str = wrapDlang!( // pragma(msg, str); mixin(str); + + +pragma(mangle, "_D6python4type__T13PythonCompareTS3std8typecons__T10RebindableTyCQBf8datetime8timezone8TimeZoneZQBuZ7_py_cmpUNbPSQEh3raw7_objectQriZQv") +private void hack0() { assert(0); }