From 94565b444bd202f325735919373e7b86485992f4 Mon Sep 17 00:00:00 2001 From: slozier Date: Mon, 25 Nov 2024 08:44:54 -0500 Subject: [PATCH] Improve performance on struct.unpack (#1817) * Improve performance on struct * Fix some struct issues * Remove array overloads * Clean up unpack_iterator * Fix packaging on .NET 9 SDK --- Directory.Build.props | 2 +- Src/IronPython.Modules/_ctypes/_ctypes.cs | 4 - Src/IronPython.Modules/_struct.cs | 262 +++++++++------------- Src/IronPython.Modules/re.cs | 7 +- Src/StdLib/Lib/test/test_struct.py | 6 +- Tests/test_struct_stdlib.py | 10 +- 6 files changed, 121 insertions(+), 170 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e7e2231de..76a677d7d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -121,7 +121,7 @@ - false + true portable true false diff --git a/Src/IronPython.Modules/_ctypes/_ctypes.cs b/Src/IronPython.Modules/_ctypes/_ctypes.cs index 1ac41dad2..a1f5807e7 100644 --- a/Src/IronPython.Modules/_ctypes/_ctypes.cs +++ b/Src/IronPython.Modules/_ctypes/_ctypes.cs @@ -688,10 +688,6 @@ private static IntPtr GetHandleFromObject(object dll, string errorMsg) { return intPtrHandle; } - private static void ValidateArraySizes(ArrayModule.array array, int offset, int size) { - ValidateArraySizes(array.__len__() * array.itemsize, offset, size); - } - private static void ValidateArraySizes(int arraySize, int offset, int size) { if (offset < 0) { throw PythonOps.ValueError("offset cannot be negative"); diff --git a/Src/IronPython.Modules/_struct.cs b/Src/IronPython.Modules/_struct.cs index de4c8989b..ba89527d7 100644 --- a/Src/IronPython.Modules/_struct.cs +++ b/Src/IronPython.Modules/_struct.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Numerics; @@ -60,7 +61,7 @@ public Struct(params object[] args) { } [Documentation("creates a new uninitialized struct object - all arguments are ignored")] - public Struct([ParamDictionary]IDictionary kwArgs, params object[] args) { + public Struct([ParamDictionary] IDictionary kwArgs, params object[] args) { } [Documentation("initializes or re-initializes the compiled struct object with a new format")] @@ -207,10 +208,10 @@ public void __init__(CodeContext/*!*/ context, object fmt) { } [Documentation("Stores the deserialized data into the provided array")] - public void pack_into(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer, int offset, params object[] args) { - byte[] existing = buffer.ToByteArray(); + public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer, int offset, params object[] args) { + var existing = buffer.UnsafeByteList; - if (offset + size > existing.Length) { + if (offset + size > existing.Count) { throw Error(context, $"pack_into requires a buffer of at least {size} bytes"); } @@ -219,23 +220,21 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ for (int i = 0; i < data.Length; i++) { existing[i + offset] = data[i]; } - - buffer.Clear(); - buffer.FromStream(new MemoryStream(existing)); } - public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer, int offset, params object[] args) { - IList existing = buffer.UnsafeByteList; + public void pack_into(CodeContext/*!*/ context, [NotNone] IBufferProtocol/*!*/ buffer, int offset, params object[] args) { + using var existing = buffer.GetBufferNoThrow(BufferFlags.Writable) + ?? throw PythonOps.TypeError("argument must be read-write bytes-like object, not {0}", PythonOps.GetPythonTypeName(buffer)); - if (offset + size > existing.Count) { + var span = existing.AsSpan(); + + if (offset + size > span.Length) { throw Error(context, $"pack_into requires a buffer of at least {size} bytes"); } var data = pack(context, args).UnsafeByteArray; - for (int i = 0; i < data.Length; i++) { - existing[i + offset] = data[i]; - } + data.CopyTo(span.Slice(offset)); } [Documentation("deserializes the string using the structs specified format")] @@ -372,12 +371,8 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer, System.Diagnostics.Debug.Assert(res_idx == res.Length); return PythonTuple.MakeTuple(res); - } - public PythonTuple/*!*/ unpack(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer) - => unpack(context, buffer.ToByteArray()); - [Documentation("reads the current format from the specified array")] public PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [BytesLike][NotNone] IList/*!*/ buffer, int offset = 0) { int bytesAvail = buffer.Count - offset; @@ -388,19 +383,9 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer, return unpack(context, buffer.Substring(offset, size)); } - [Documentation("reads the current format from the specified array")] - public PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) { - return unpack_from(context, buffer.ToByteArray(), offset); - } - - [Documentation("iteratively unpack the current format from the specified array.")] - public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [BytesLike][NotNone] IList/*!*/ buffer, int offset = 0) { - return new PythonUnpackIterator(this, context, buffer, offset); - } - [Documentation("iteratively unpack the current format from the specified array.")] - public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) { - return new PythonUnpackIterator(this, context, buffer, offset); + public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [BytesLike][NotNone] IList/*!*/ buffer) { + return new PythonUnpackIterator(this, context, buffer); } [Documentation("gets the number of bytes that the serialized string will occupy or are required to deserialize the data")] @@ -560,14 +545,19 @@ private static Struct CompileAndCache(CodeContext/*!*/ context, string/*!*/ fmt) fLittleEndian = false; fStandardized = true; break; + case '\x00': + throw Error(context, "embedded null character"); default: if (char.IsDigit(fmt[i])) { count = 0; while (char.IsDigit(fmt[i])) { count = count * 10 + (fmt[i] - '0'); i++; + if (i >= fmt.Length) { + throw Error(context, "repeat count given without format specifier"); + } } - if (char.IsWhiteSpace(fmt[i])) Error(context, "white space not allowed between count and format"); + if (char.IsWhiteSpace(fmt[i])) throw Error(context, "white space not allowed between count and format"); i--; break; } @@ -628,51 +618,44 @@ internal static Struct Create(string/*!*/ format) { } [PythonType("unpack_iterator"), Documentation("Represents an iterator returned by _struct.iter_unpack()")] - public class PythonUnpackIterator : System.Collections.IEnumerator, System.Collections.IEnumerable { + public sealed class PythonUnpackIterator : IEnumerator, IEnumerable { private object _iter_current; private int _next_offset; private readonly CodeContext _context; private readonly IList _buffer; - private readonly int _start_offset; private readonly Struct _owner; - private PythonUnpackIterator() { } - - internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, IList/*!*/ buffer, int offset) { + internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, IList/*!*/ buffer) { _context = context; _buffer = buffer; - _start_offset = offset; _owner = owner; - Reset(); - ValidateBufferLength(); - } - - internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, ArrayModule.array/*!*/ buffer, int offset) { - _context = context; - _buffer = buffer.ToByteArray(); - _start_offset = offset; - _owner = owner; - - Reset(); + _iter_current = null; + _next_offset = 0; ValidateBufferLength(); } private void ValidateBufferLength() { - if (_buffer.Count - _start_offset < _owner.size) { + if (_owner.size == 0) { + throw Error(_context, "cannot iteratively unpack with a struct of length 0"); + } + if (_buffer.Count % _owner.size != 0) { throw Error(_context, $"iterative unpacking requires a buffer of a multiple of {_owner.size} bytes"); } } - #region IEnumerable + #region IEnumerable Members + [PythonHidden] - public System.Collections.IEnumerator GetEnumerator() { - return this; - } + public System.Collections.IEnumerator GetEnumerator() => this; + + IEnumerator IEnumerable.GetEnumerator() => this; + #endregion - #region IEnumerator + #region IEnumerator Members + [PythonHidden] public object Current => _iter_current; @@ -687,28 +670,17 @@ public bool MoveNext() { return true; } - [PythonHidden] - public void Reset() { - _iter_current = null; - _next_offset = _start_offset; - } - #endregion + void IEnumerator.Reset() => throw new NotSupportedException(); - public object __iter__() { - return this; - } + [PythonHidden] + public void Dispose() { } - public object __next__() { - if (!MoveNext()) { - throw PythonOps.StopIteration(); - } - return Current; - } + #endregion - public int __length_hint__() { - return (_buffer.Count - _next_offset) / _owner.size; - } + public int __length_hint__() + => (_buffer.Count - _next_offset) / _owner.size; } + #endregion #region Compiled Format @@ -841,11 +813,11 @@ public static int calcsize(CodeContext/*!*/ context, object fmt) { } [Documentation("Pack the values v1, v2, ... according to fmt.\nWrite the packed bytes into the writable buffer buf starting at offset.")] - public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer, int offset, params object[] args) { + public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] ByteArray/*!*/ buffer, int offset, params object[] args) { GetStructFromCache(context, fmt).pack_into(context, buffer, offset, args); } - public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] ByteArray/*!*/ buffer, int offset, params object[] args) { + public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] IBufferProtocol/*!*/ buffer, int offset, params object[] args) { GetStructFromCache(context, fmt).pack_into(context, buffer, offset, args); } @@ -854,30 +826,16 @@ public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] Byt return GetStructFromCache(context, fmt).unpack(context, buffer); } - [Documentation("Unpack the string containing packed C structure data, according to fmt.\nRequires len(string) == calcsize(fmt).")] - public static PythonTuple/*!*/ unpack(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer) { - return GetStructFromCache(context, fmt).unpack(context, buffer); - } - [Documentation("Unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")] public static PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, object fmt, [BytesLike][NotNone] IList/*!*/ buffer, int offset = 0) { return GetStructFromCache(context, fmt).unpack_from(context, buffer, offset); } - [Documentation("Unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")] - public static PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) { - return GetStructFromCache(context, fmt).unpack_from(context, buffer, offset); - } - [Documentation("Iteratively unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")] - public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [BytesLike][NotNone] IList/*!*/ buffer, int offset = 0) { - return GetStructFromCache(context, fmt).iter_unpack(context, buffer, offset); + public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [BytesLike][NotNone] IList/*!*/ buffer) { + return GetStructFromCache(context, fmt).iter_unpack(context, buffer); } - [Documentation("Iteratively unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")] - public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) { - return GetStructFromCache(context, fmt).iter_unpack(context, buffer, offset); - } #endregion #region Write Helpers @@ -1207,16 +1165,16 @@ private static void CheckRange(CodeContext context, int val, int min, int max, s #region Data creater helpers internal static bool CreateBoolValue(CodeContext/*!*/ context, ref int index, IList data) { - return (int)ReadData(context, ref index, data) != 0; + return data[index++] != 0; } internal static byte CreateCharValue(CodeContext/*!*/ context, ref int index, IList data) { - return ReadData(context, ref index, data); + return data[index++]; } internal static short CreateShortValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - byte b1 = (byte)ReadData(context, ref index, data); - byte b2 = (byte)ReadData(context, ref index, data); + byte b1 = data[index++]; + byte b2 = data[index++]; if (fLittleEndian) { return (short)((b2 << 8) | b1); @@ -1226,8 +1184,8 @@ internal static short CreateShortValue(CodeContext/*!*/ context, ref int index, } internal static ushort CreateUShortValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - byte b1 = (byte)ReadData(context, ref index, data); - byte b2 = (byte)ReadData(context, ref index, data); + byte b1 = data[index++]; + byte b2 = data[index++]; if (fLittleEndian) { return (ushort)((b2 << 8) | b1); @@ -1238,16 +1196,16 @@ internal static ushort CreateUShortValue(CodeContext/*!*/ context, ref int index internal static float CreateFloatValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { byte[] bytes = new byte[4]; - if (fLittleEndian) { - bytes[0] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[2] = (byte)ReadData(context, ref index, data); - bytes[3] = (byte)ReadData(context, ref index, data); + if (fLittleEndian == BitConverter.IsLittleEndian) { + bytes[0] = data[index++]; + bytes[1] = data[index++]; + bytes[2] = data[index++]; + bytes[3] = data[index++]; } else { - bytes[3] = (byte)ReadData(context, ref index, data); - bytes[2] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[0] = (byte)ReadData(context, ref index, data); + bytes[3] = data[index++]; + bytes[2] = data[index++]; + bytes[1] = data[index++]; + bytes[0] = data[index++]; } float res = BitConverter.ToSingle(bytes, 0); @@ -1261,10 +1219,10 @@ internal static float CreateFloatValue(CodeContext/*!*/ context, ref int index, } internal static int CreateIntValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - byte b1 = (byte)ReadData(context, ref index, data); - byte b2 = (byte)ReadData(context, ref index, data); - byte b3 = (byte)ReadData(context, ref index, data); - byte b4 = (byte)ReadData(context, ref index, data); + byte b1 = data[index++]; + byte b2 = data[index++]; + byte b3 = data[index++]; + byte b4 = data[index++]; if (fLittleEndian) return (int)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1); @@ -1273,10 +1231,10 @@ internal static int CreateIntValue(CodeContext/*!*/ context, ref int index, bool } internal static uint CreateUIntValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - byte b1 = (byte)ReadData(context, ref index, data); - byte b2 = (byte)ReadData(context, ref index, data); - byte b3 = (byte)ReadData(context, ref index, data); - byte b4 = (byte)ReadData(context, ref index, data); + byte b1 = data[index++]; + byte b2 = data[index++]; + byte b3 = data[index++]; + byte b4 = data[index++]; if (fLittleEndian) return (uint)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1); @@ -1285,14 +1243,14 @@ internal static uint CreateUIntValue(CodeContext/*!*/ context, ref int index, bo } internal static long CreateLongValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - long b1 = (byte)ReadData(context, ref index, data); - long b2 = (byte)ReadData(context, ref index, data); - long b3 = (byte)ReadData(context, ref index, data); - long b4 = (byte)ReadData(context, ref index, data); - long b5 = (byte)ReadData(context, ref index, data); - long b6 = (byte)ReadData(context, ref index, data); - long b7 = (byte)ReadData(context, ref index, data); - long b8 = (byte)ReadData(context, ref index, data); + long b1 = data[index++]; + long b2 = data[index++]; + long b3 = data[index++]; + long b4 = data[index++]; + long b5 = data[index++]; + long b6 = data[index++]; + long b7 = data[index++]; + long b8 = data[index++]; if (fLittleEndian) return (long)((b8 << 56) | (b7 << 48) | (b6 << 40) | (b5 << 32) | @@ -1303,14 +1261,14 @@ internal static long CreateLongValue(CodeContext/*!*/ context, ref int index, bo } internal static ulong CreateULongValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - ulong b1 = (byte)ReadData(context, ref index, data); - ulong b2 = (byte)ReadData(context, ref index, data); - ulong b3 = (byte)ReadData(context, ref index, data); - ulong b4 = (byte)ReadData(context, ref index, data); - ulong b5 = (byte)ReadData(context, ref index, data); - ulong b6 = (byte)ReadData(context, ref index, data); - ulong b7 = (byte)ReadData(context, ref index, data); - ulong b8 = (byte)ReadData(context, ref index, data); + ulong b1 = data[index++]; + ulong b2 = data[index++]; + ulong b3 = data[index++]; + ulong b4 = data[index++]; + ulong b5 = data[index++]; + ulong b6 = data[index++]; + ulong b7 = data[index++]; + ulong b8 = data[index++]; if (fLittleEndian) return (ulong)((b8 << 56) | (b7 << 48) | (b6 << 40) | (b5 << 32) | (b4 << 24) | (b3 << 16) | (b2 << 8) | b1); @@ -1321,24 +1279,24 @@ internal static ulong CreateULongValue(CodeContext/*!*/ context, ref int index, internal static double CreateDoubleValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { byte[] bytes = new byte[8]; - if (fLittleEndian) { - bytes[0] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[2] = (byte)ReadData(context, ref index, data); - bytes[3] = (byte)ReadData(context, ref index, data); - bytes[4] = (byte)ReadData(context, ref index, data); - bytes[5] = (byte)ReadData(context, ref index, data); - bytes[6] = (byte)ReadData(context, ref index, data); - bytes[7] = (byte)ReadData(context, ref index, data); + if (fLittleEndian == BitConverter.IsLittleEndian) { + bytes[0] = data[index++]; + bytes[1] = data[index++]; + bytes[2] = data[index++]; + bytes[3] = data[index++]; + bytes[4] = data[index++]; + bytes[5] = data[index++]; + bytes[6] = data[index++]; + bytes[7] = data[index++]; } else { - bytes[7] = (byte)ReadData(context, ref index, data); - bytes[6] = (byte)ReadData(context, ref index, data); - bytes[5] = (byte)ReadData(context, ref index, data); - bytes[4] = (byte)ReadData(context, ref index, data); - bytes[3] = (byte)ReadData(context, ref index, data); - bytes[2] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[0] = (byte)ReadData(context, ref index, data); + bytes[7] = data[index++]; + bytes[6] = data[index++]; + bytes[5] = data[index++]; + bytes[4] = data[index++]; + bytes[3] = data[index++]; + bytes[2] = data[index++]; + bytes[1] = data[index++]; + bytes[0] = data[index++]; } double res = BitConverter.ToDouble(bytes, 0); @@ -1354,30 +1312,26 @@ internal static double CreateDoubleValue(CodeContext/*!*/ context, ref int index internal static Bytes CreateString(CodeContext/*!*/ context, ref int index, int count, IList data) { using var res = new MemoryStream(); for (int i = 0; i < count; i++) { - res.WriteByte(ReadData(context, ref index, data)); + res.WriteByte(data[index++]); } return Bytes.Make(res.ToArray()); } internal static Bytes CreatePascalString(CodeContext/*!*/ context, ref int index, int count, IList data) { - int realLen = (int)ReadData(context, ref index, data); + int realLen = (int)data[index++]; + if (realLen > count) realLen = count; using var res = new MemoryStream(); for (int i = 0; i < realLen; i++) { - res.WriteByte(ReadData(context, ref index, data)); + res.WriteByte(data[index++]); } for (int i = realLen; i < count; i++) { // throw away null bytes - ReadData(context, ref index, data); + index++; } return Bytes.Make(res.ToArray()); } - private static byte ReadData(CodeContext/*!*/ context, ref int index, IList data) { - if (index >= data.Count) throw Error(context, "not enough data while reading"); - - return data[index++]; - } #endregion #region Misc. Private APIs diff --git a/Src/IronPython.Modules/re.cs b/Src/IronPython.Modules/re.cs index c2a371819..0046a66be 100644 --- a/Src/IronPython.Modules/re.cs +++ b/Src/IronPython.Modules/re.cs @@ -734,12 +734,15 @@ static string ValidateString(object? str) { return bytes.MakeString(); case ByteArray byteArray: return byteArray.MakeString(); - case ArrayModule.array array: - return Bytes.Make(array.ToByteArray()).MakeString(); #if FEATURE_MMAP case MmapModule.MmapDefault mmapFile: return mmapFile.GetSearchString().MakeString(); #endif + case IBufferProtocol bufferProtocol: { + using var buffer = bufferProtocol.GetBuffer(); + return buffer.AsReadOnlySpan().MakeString(); + } + default: throw PythonOps.TypeError($"expected string or bytes-like object"); } diff --git a/Src/StdLib/Lib/test/test_struct.py b/Src/StdLib/Lib/test/test_struct.py index 0107eebca..866a70048 100644 --- a/Src/StdLib/Lib/test/test_struct.py +++ b/Src/StdLib/Lib/test/test_struct.py @@ -542,13 +542,13 @@ def test_trailing_counter(self): # format lists containing only count spec should result in an error self.assertRaises(struct.error, struct.pack, '12345') - self.assertRaises(struct.error, struct.unpack, '12345', '') + self.assertRaises(struct.error, struct.unpack, '12345', b'') self.assertRaises(struct.error, struct.pack_into, '12345', store, 0) self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0) # Format lists with trailing count spec should result in an error self.assertRaises(struct.error, struct.pack, 'c12345', 'x') - self.assertRaises(struct.error, struct.unpack, 'c12345', 'x') + self.assertRaises(struct.error, struct.unpack, 'c12345', b'x') self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0, 'x') self.assertRaises(struct.error, struct.unpack_from, 'c12345', store, @@ -557,7 +557,7 @@ def test_trailing_counter(self): # Mixed format tests self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs') self.assertRaises(struct.error, struct.unpack, '14s42', - 'spam and eggs') + b'spam and eggs') self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0, 'spam and eggs') self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0) diff --git a/Tests/test_struct_stdlib.py b/Tests/test_struct_stdlib.py index 5acf05afa..bd23acb06 100644 --- a/Tests/test_struct_stdlib.py +++ b/Tests/test_struct_stdlib.py @@ -15,12 +15,10 @@ def load_tests(loader, standard_tests, pattern): if is_ironpython: failing_tests = [ - test.test_struct.StructTest('test_705836'), # TODO: figure out - test.test_struct.StructTest('test_bool'), # TODO: figure out - test.test_struct.StructTest('test_calcsize'), # TODO: figure out - test.test_struct.StructTest('test_count_overflow'), # TODO: figure out - test.test_struct.StructTest('test_trailing_counter'), # TODO: figure out - test.test_struct.UnpackIteratorTest('test_construct'), # TODO: figure out + test.test_struct.StructTest('test_705836'), # AssertionError: OverflowError not raised by pack + test.test_struct.StructTest('test_bool'), # struct.error: expected bool value got IronPython.NewTypes.System.Object_1$1 + test.test_struct.StructTest('test_calcsize'), # AssertionError: 4 not greater than or equal to 8 + test.test_struct.StructTest('test_count_overflow'), # AssertionError: error not raised by calcsize ] return generate_suite(tests, failing_tests)