Skip to content

Commit 2e347b5

Browse files
committed
Backport more changes
1 parent be7c273 commit 2e347b5

File tree

18 files changed

+161
-147
lines changed

18 files changed

+161
-147
lines changed

Src/IronPython.Modules/_collections.cs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -551,20 +551,13 @@ public void __delitem__(CodeContext/*!*/ context, object index) {
551551
}
552552
}
553553

554-
public PythonTuple __reduce__() {
555-
lock (_lockObj) {
556-
object[] items = new object[_itemCnt];
557-
int curItem = 0;
558-
WalkDeque(delegate(int curIndex) {
559-
items[curItem++] = _data[curIndex];
560-
return true;
561-
});
562-
563-
return PythonTuple.MakeTuple(
564-
DynamicHelpers.GetPythonType(this),
565-
PythonTuple.MakeTuple(PythonList.FromArrayNoCopy(items))
566-
);
567-
}
554+
public PythonTuple __reduce__(CodeContext context) {
555+
return PythonTuple.MakeTuple(
556+
DynamicHelpers.GetPythonType(this),
557+
_maxLen == -1 ? PythonTuple.EMPTY : PythonTuple.MakeTuple(PythonTuple.EMPTY, maxlen),
558+
GetType() == typeof(deque) ? null : PythonOps.GetBoundAttr(context, this, "__dict__"),
559+
PythonOps.GetEnumeratorObject(context, this)
560+
);
568561
}
569562

570563
public int __len__() {

Src/IronPython.Modules/_socket.cs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,27 @@ public void __init__(CodeContext/*!*/ context, int family = DefaultAddressFamily
136136
throw MakeException(context, new SocketException((int)SocketError.ProtocolNotSupported));
137137
}
138138

139-
Socket? socket;
139+
Socket? socket = null;
140140
if (fileno is socket sock) {
141141
socket = sock._socket;
142142
_hostName = sock._hostName;
143143
// we now own the lifetime of the socket
144144
GC.SuppressFinalize(sock);
145-
} else if (fileno != null && (socket = HandleToSocket((long)fileno)) != null) {
146-
// nothing to do here
145+
} else if (fileno != null) {
146+
if (!PythonOps.TryToIndex(fileno, out object? handleObj)) {
147+
throw PythonOps.TypeErrorForUnIndexableObject(fileno);
148+
}
149+
long handle = Converter.ConvertToInt64(handleObj);
150+
// Windows reserves only INVALID_SOCKET (~0) as an invalid handle
151+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? handle == -1 : handle < 0) {
152+
throw PythonOps.ValueError("negative file descriptor");
153+
}
154+
socket = HandleToSocket(handle);
155+
if (socket is null) {
156+
throw PythonOps.OSError(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
157+
? PythonErrorNumber.WSAENOTSOCK : PythonErrorNumber.EBADF,
158+
"Bad file descriptor");
159+
}
147160
} else {
148161
try {
149162
socket = new Socket(addressFamily, socketType, protocolType);
@@ -413,7 +426,7 @@ public Bytes recv(int bufsize, int flags = 0) {
413426
try {
414427
bytesRead = _socket.Receive(buffer, bufsize, (SocketFlags)flags);
415428
} catch (Exception e) {
416-
throw MakeRecvException(e, SocketError.NotConnected);
429+
throw MakeException(_context, e);
417430
}
418431

419432
var bytes = new byte[bytesRead];
@@ -449,7 +462,7 @@ public int recv_into([NotNone] IBufferProtocol buffer, int nbytes = 0, int flags
449462
try {
450463
bytesRead = _socket.Receive(byteBuffer, nbytes, (SocketFlags)flags);
451464
} catch (Exception e) {
452-
throw MakeRecvException(e, SocketError.NotConnected);
465+
throw MakeException(_context, e);
453466
}
454467

455468
byteBuffer.AsSpan(0, bytesRead).CopyTo(span);
@@ -486,7 +499,7 @@ public PythonTuple recvfrom(int bufsize, int flags = 0) {
486499
try {
487500
bytesRead = _socket.ReceiveFrom(buffer, bufsize, (SocketFlags)flags, ref remoteEP);
488501
} catch (Exception e) {
489-
throw MakeRecvException(e, SocketError.InvalidArgument);
502+
throw MakeException(_context, e);
490503
}
491504

492505
var bytes = new byte[bytesRead];
@@ -519,7 +532,7 @@ public PythonTuple recvfrom_into([NotNone] IBufferProtocol buffer, int nbytes =
519532
try {
520533
bytesRead = _socket.ReceiveFrom(byteBuffer, nbytes, (SocketFlags)flags, ref remoteEP);
521534
} catch (Exception e) {
522-
throw MakeRecvException(e, SocketError.InvalidArgument);
535+
throw MakeException(_context, e);
523536
}
524537

525538
byteBuffer.AsSpan(0, bytesRead).CopyTo(span);
@@ -551,18 +564,6 @@ private static int byteBufferSize(string funcName, int nbytes, int bufLength, in
551564
}
552565
}
553566

554-
private Exception MakeRecvException(Exception e, SocketError errorCode = SocketError.InvalidArgument) {
555-
if (e is ObjectDisposedException) return MakeException(_context, e);
556-
557-
// on the socket recv throw a special socket error code when SendTimeout is zero
558-
if (_socket.SendTimeout == 0) {
559-
var s = new SocketException((int)errorCode);
560-
return PythonExceptions.CreateThrowable(error, s.ErrorCode, s.Message);
561-
} else {
562-
return MakeException(_context, e);
563-
}
564-
}
565-
566567
[Documentation("send(string[, flags]) -> bytes_sent\n\n"
567568
+ "Send data to the remote socket. The socket must be connected to a remote\n"
568569
+ "socket (by calling either connect() or accept(). Returns the number of bytes\n"
@@ -1787,7 +1788,7 @@ internal static Exception MakeException(CodeContext/*!*/ context, Exception exce
17871788
}
17881789
} else if (exception is ObjectDisposedException) {
17891790
return PythonExceptions.CreateThrowable(error, PythonErrorNumber.EBADF, "Socket is closed");
1790-
} else if (exception is InvalidOperationException) {
1791+
} else if (exception is InvalidOperationException or ArgumentException) {
17911792
return MakeException(context, new SocketException((int)SocketError.InvalidArgument));
17921793
} else {
17931794
return exception;

Src/IronPython.Modules/array.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,7 @@ public array InPlaceMultiply(int value) {
196196
if (value <= 0) {
197197
_data.Clear();
198198
} else {
199-
var myData = __copy__();
200-
201-
for (int i = 0; i < (value - 1); i++) {
202-
ExtendArray(myData);
203-
}
199+
_data.InPlaceMultiply(value);
204200
}
205201
return this;
206202
}

Src/IronPython.Modules/time.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,12 @@ private static List<FormatInfo> PythonFormatToCLIFormat(string format) {
340340
List<FormatInfo> newFormat = new List<FormatInfo>();
341341

342342
for (int i = 0; i < format.Length; i++) {
343-
if (format[i] == '%') {
343+
var ch = format[i];
344+
if (ch == '%') {
344345
if (i + 1 == format.Length) throw PythonOps.ValueError("Invalid format string");
345346

346347
switch (format[++i]) {
348+
case '\0': throw PythonOps.ValueError("embedded null character");
347349
case 'a': newFormat.Add(new FormatInfo("ddd")); break;
348350
case 'A': newFormat.Add(new FormatInfo("dddd")); break;
349351
case 'b': newFormat.Add(new FormatInfo("MMM")); break;
@@ -379,10 +381,11 @@ private static List<FormatInfo> PythonFormatToCLIFormat(string format) {
379381
throw PythonOps.ValueError("Invalid format string");
380382
}
381383
} else {
384+
if (ch == '\0') throw PythonOps.ValueError("embedded null character");
382385
if (newFormat.Count == 0 || newFormat[newFormat.Count - 1].Type != FormatInfoType.UserText)
383-
newFormat.Add(new FormatInfo(FormatInfoType.UserText, format[i].ToString()));
386+
newFormat.Add(new FormatInfo(FormatInfoType.UserText, ch.ToString()));
384387
else
385-
newFormat[newFormat.Count - 1].Text += format[i];
388+
newFormat[newFormat.Count - 1].Text += ch;
386389
}
387390
}
388391

Src/IronPython.Modules/winreg.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44

55
#if FEATURE_REGISTRY
66

7-
using Microsoft.Win32;
8-
using Microsoft.Win32.SafeHandles;
97
using System;
8+
using System.Buffers.Binary;
109
using System.Collections.Concurrent;
1110
using System.ComponentModel;
1211
using System.Diagnostics;
@@ -22,6 +21,9 @@
2221
using IronPython.Runtime.Exceptions;
2322
using IronPython.Runtime.Types;
2423

24+
using Microsoft.Win32;
25+
using Microsoft.Win32.SafeHandles;
26+
2527
[assembly: PythonModule("winreg", typeof(IronPython.Modules.PythonWinReg), PlatformsAttribute.PlatformFamily.Windows)]
2628
namespace IronPython.Modules {
2729
[SupportedOSPlatform("windows")]
@@ -70,6 +72,7 @@ public static class PythonWinReg {
7072
public const int REG_FULL_RESOURCE_DESCRIPTOR = 0X9;
7173
public const int REG_RESOURCE_REQUIREMENTS_LIST = 0XA;
7274
public const int REG_QWORD = 0xB;
75+
public const int REG_QWORD_LITTLE_ENDIAN = 0XB;
7376

7477
public const int REG_NOTIFY_CHANGE_NAME = 0X1;
7578
public const int REG_NOTIFY_CHANGE_ATTRIBUTES = 0X2;
@@ -346,19 +349,22 @@ private static void QueryValueExImpl(SafeRegistryHandle handle, string valueName
346349
break;
347350
case REG_EXPAND_SZ:
348351
case REG_SZ:
349-
if (length >= 2 && data[length - 1] == 0 && data[length - 2] == 0) {
350-
value = ExtractString(data, 0, (int)length - 2);
351-
} else {
352-
value = ExtractString(data, 0, (int)length);
353-
}
352+
var span = MemoryMarshal.Cast<byte, char>(data.AsSpan());
353+
var len = span.IndexOf((char)0);
354+
if (len != -1) span = span.Slice(0, len);
355+
value = span.ToString();
354356
break;
355357
case REG_DWORD:
356-
if (BitConverter.IsLittleEndian) {
357-
value = (uint)((data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0]);
358-
} else {
359-
value = (uint)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
360-
}
358+
var dval = BitConverter.ToUInt32(data, 0);
359+
if (!BitConverter.IsLittleEndian) dval = BinaryPrimitives.ReverseEndianness(dval);
360+
value = dval > int.MaxValue ? (BigInteger)dval : unchecked((int)dval);
361361
break;
362+
case REG_QWORD:
363+
var qval = BitConverter.ToUInt64(data, 0);
364+
if (!BitConverter.IsLittleEndian) qval = BinaryPrimitives.ReverseEndianness(qval);
365+
value = (BigInteger)qval;
366+
break;
367+
362368
default:
363369
value = null;
364370
break;

Src/IronPython.Modules/winsound.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,20 @@ public static void PlaySound(CodeContext/*!*/ context, [NotNone] IBufferProtocol
120120
This parameter must be in the range 37 through 32,767.
121121
The duration argument specifies the number of milliseconds.
122122
")]
123-
public static void Beep(CodeContext/*!*/ context, int freq, int dur) {
124-
if (freq < 37 || freq > 32767) {
123+
public static void Beep(CodeContext/*!*/ context, int frequency, int duration) {
124+
if (frequency < 37 || frequency > 32767) {
125125
throw PythonOps.ValueError("frequency must be in 37 thru 32767");
126126
}
127127

128-
bool ok = Beep(freq, dur);
128+
bool ok = Beep(frequency, duration);
129129
if (!ok) {
130130
throw PythonOps.RuntimeError("Failed to beep");
131131
}
132132
}
133133

134134
[Documentation("MessageBeep(x) - call Windows MessageBeep(x). x defaults to MB_OK.")]
135-
public static void MessageBeep(CodeContext/*!*/ context, int x=MB_OK) {
136-
MessageBeep(x);
135+
public static void MessageBeep(CodeContext/*!*/ context, int type=MB_OK) {
136+
MessageBeep(type);
137137
}
138138

139139
#endregion

Src/IronPython/Lib/iptest/ipunittest.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,24 +206,25 @@ def _flatten_suite(suite):
206206

207207
def generate_suite(tests, failing_tests, skip_tests=[]):
208208
all_tests = _flatten_suite(tests)
209+
test_indices = {t: i for i, t in enumerate(all_tests)}
209210
unknown_tests = []
210211

211212
for t in skip_tests:
212213
try:
213-
all_tests.remove(t)
214+
all_tests[test_indices.pop(t)] = None
214215
except ValueError:
215216
unknown_tests.append(t)
216217

217218
for t in failing_tests:
218219
try:
219-
all_tests[all_tests.index(t)] = unittest.expectedFailure(t)
220-
except:
220+
all_tests[test_indices.pop(t)] = unittest.expectedFailure(t)
221+
except ValueError:
221222
unknown_tests.append(t)
222223

223224
if unknown_tests:
224225
raise ValueError("Unknown tests:\n - {}".format('\n - '.join(str(t) for t in unknown_tests)))
225226

226-
return unittest.TestSuite(all_tests)
227+
return unittest.TestSuite(t for t in all_tests if t is not None)
227228

228229
# class testpath:
229230
# # find the ironpython root directory

Src/IronPython/Modules/Builtin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public static string bin(object? number) {
135135

136136
public static PythonType bytes => TypeCache.Bytes;
137137

138-
public static PythonType bytearray => DynamicHelpers.GetPythonTypeFromType(typeof(ByteArray));
138+
public static PythonType bytearray => TypeCache.ByteArray;
139139

140140
[Documentation("callable(object) -> bool\n\nReturn whether the object is callable (i.e., some kind of function).")]
141141
public static bool callable(CodeContext/*!*/ context, object? o) {

Src/IronPython/Runtime/ArrayData.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ internal interface ArrayData : IList {
2727
void InsertRange(int index, int count, ArrayData value);
2828
void RemoveSlice(Slice slice);
2929
ArrayData Multiply(int count);
30+
void InPlaceMultiply(int count);
3031
new bool Remove(object? item);
3132
void Reverse();
3233
Span<byte> AsByteSpan();

Src/IronPython/Runtime/ByteArray.cs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
using System.Collections.Generic;
1010
using System.Numerics;
1111
using System.Runtime.CompilerServices;
12-
using System.Runtime.InteropServices;
1312
using System.Text;
1413

15-
using Microsoft.Scripting.Runtime;
16-
using Microsoft.Scripting.Utils;
17-
1814
using IronPython.Runtime.Exceptions;
1915
using IronPython.Runtime.Operations;
2016
using IronPython.Runtime.Types;
2117

18+
using Microsoft.Scripting;
19+
using Microsoft.Scripting.Runtime;
20+
using Microsoft.Scripting.Utils;
21+
2222
namespace IronPython.Runtime {
2323
/// <summary>
2424
/// bytearray(string, encoding[, errors]) -> bytearray
@@ -56,6 +56,12 @@ internal ByteArray(IEnumerable<byte> bytes) {
5656
_bytes = new ArrayData<byte>(bytes);
5757
}
5858

59+
[StaticExtensionMethod]
60+
public static object __new__(CodeContext context, [NotNone] PythonType cls, [ParamDictionary, NotNone] IDictionary<object, object> dict, [NotNone] params object[] args) {
61+
if (cls == TypeCache.ByteArray) return new ByteArray();
62+
return cls.CreateInstance(context);
63+
}
64+
5965
public void __init__() {
6066
lock (this) {
6167
_bytes.Clear();
@@ -74,7 +80,7 @@ public void __init__(int source) {
7480
}
7581

7682
public void __init__([NotNone] IBufferProtocol source) {
77-
if (Converter.TryConvertToIndex(source, out int size, throwNonInt: false)) {
83+
if (Converter.TryConvertToIndex(source, out int size, throwTypeError: false)) {
7884
__init__(size);
7985
} else {
8086
lock (this) {
@@ -86,7 +92,7 @@ public void __init__([NotNone] IBufferProtocol source) {
8692
}
8793

8894
public void __init__(CodeContext context, object? source) {
89-
if (Converter.TryConvertToIndex(source, out int size, throwNonInt: false)) {
95+
if (Converter.TryConvertToIndex(source, out int size, throwTypeError: false)) {
9096
__init__(size);
9197
} else if (source is IEnumerable<byte> en) {
9298
lock (this) {
@@ -466,8 +472,13 @@ public int find(BigInteger @byte, object? start, object? end) {
466472
}
467473
}
468474

469-
public static ByteArray fromhex([NotNone] string @string) {
470-
return new ByteArray(IListOfByteOps.FromHex(@string));
475+
[ClassMethod]
476+
public static object fromhex(CodeContext context, [NotNone] PythonType cls, [NotNone] string @string) {
477+
var hex = IListOfByteOps.FromHex(@string);
478+
if (cls == TypeCache.ByteArray) {
479+
return new ByteArray(hex);
480+
}
481+
return PythonTypeOps.CallParams(context, cls, new Bytes(hex));
471482
}
472483

473484
public string hex() => Bytes.ToHex(_bytes.AsByteSpan()); // new in CPython 3.5

0 commit comments

Comments
 (0)