10000 Fix custom decoders not working for DateTime and Decimal (#1497) · pythonnet/pythonnet@4b7a23c · GitHub
[go: up one dir, main page]

Skip to content

Commit 4b7a23c

Browse files
authored
Fix custom decoders not working for DateTime and Decimal (#1497)
1 parent 9555248 commit 4b7a23c

File tree

2 files changed

+61
-7
lines changed

2 files changed

+61
-7
lines changed

src/embed_tests/Codecs.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,24 @@ public void ExceptionDecoded()
355355
Assert.AreEqual(TestExceptionMessage, error.Message);
356356
}
357357

358+
[Test]
359+
public void DateTimeDecoded()
360+
{
361+
using var scope = Py.CreateScope();
362+
scope.Exec(@"
363+
import clr
364+
from datetime import datetime
365+
366+
367+
from Python.EmbeddingTest import Codecs, DateTimeDecoder
368+
369+
DateTimeDecoder.Setup()
370+
");
371+
scope.Exec("Codecs.AcceptsDateTime(datetime(2021, 1, 22))");
372+
}
373+
374+
public static void AcceptsDateTime(DateTime v) {}
375+
358376
class ValueErrorWrapper : Exception
359377
{
360378
public ValueErrorWrapper(string message) : base(message) { }
@@ -419,4 +437,30 @@ public bool TryDecode<T>(PyObject pyObj, out T value)
419437
return true;
420438
}
421439
}
440+
441+
public class DateTimeDecoder : IPyObjectDecoder
442+
{
443+
public static void Setup()
444+
{
445+
PyObjectConversions.RegisterDecoder(new DateTimeDecoder());
446+
}
447+
448+
public bool CanDecode(PyObject objectType, Type targetType)
449+
{
450+
return targetType == typeof(DateTime);
451+
}
452+
453+
public bool TryDecode<T>(PyObject pyObj, out T value)
454+
{
455+
var dt = new DateTime(
456+
pyObj.GetAttr("year").As<int>(),
457+
pyObj.GetAttr("month").As<int>(),
458+
pyObj.GetAttr("day").As<int>(),
459+
pyObj.GetAttr("hour").As<int>(),
460+
pyObj.GetAttr("minute").As<int>(),
461+
pyObj.GetAttr("second").As<int>());
462+
value = (T)(object)dt;
463+
return true;
464+
}
465+
}
422466
}

src/runtime/converter.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,8 @@ internal static IntPtr ToPython(object value, Type type)
149149
return result;
150150
}
151151

152-
if (Type.GetTypeCode(type) == TypeCode.Object
153-
&& value.GetType() != typeof(object)
154-
&& value is not Type
155-
|| type.IsEnum
156-
) {
152+
if (EncodableByUser(type, value))
153+
{
157154
var encoded = PyObjectConversions.TryEncode(value, type);
158155
if (encoded != null) {
159156
result = encoded.Handle;
@@ -301,6 +298,13 @@ internal static IntPtr ToPython(object value, Type type)
301298
}
302299
}
303300

301+
static bool EncodableByUser(Type type, object value)
302+
{
303+
TypeCode typeCode = Type.GetTypeCode(type);
304+
return type.IsEnum
305+
|| typeCode is TypeCode.DateTime or TypeCode.Decimal
306+
|| typeCode == TypeCode.Object && value.GetType() != typeof(object) && value is not Type;
307+
}
304308

305309
/// <summary>
306310
/// In a few situations, we don't have any advisory type information
@@ -523,8 +527,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
523527
return false;
524528
}
525529

526-
TypeCode typeCode = Type.GetTypeCode(obType);
527-
if (typeCode == TypeCode.Object || obType.IsEnum)
530+
if (DecodableByUser(obType))
528531
{
529532
IntPtr pyType = Runtime.PyObject_TYPE(value);
530533
if (PyObjectConversions.TryDecode(value, pyType, obType, out result))
@@ -536,6 +539,13 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
536539
return ToPrimitive(value, obType, out result, setError);
537540
}
538541

542+
static bool DecodableByUser(Type type)
543+
{
544+
TypeCode typeCode = Type.GetTypeCode(type);
545+
return type.IsEnum
546+
|| typeCode is TypeCode.Object or TypeCode.Decimal or TypeCode.DateTime;
547+
}
548+
539549
internal delegate bool TryConvertFromPythonDelegate(IntPtr pyObj, out object result);
540550

541551
internal static int ToInt32(BorrowedReference value)

0 commit comments

Comments
 (0)
0