Skip to content

Commit ae7e6ac

Browse files
authored
Misc changes (#1397)
* Allow cast of empty memoryview * Use IBufferProtocol in some _socket methods * Add sys._platform_version * Misc _ssl changes * Mark test_zlib as NotParallelSafe * Avoid intermittent StackOverflow * Fix comment * Allow None when setting __annotations__
1 parent 84319ad commit ae7e6ac

9 files changed

Lines changed: 61 additions & 33 deletions

File tree

Src/IronPython.Modules/_socket.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ public PythonTuple recvfrom(int bufsize, int flags = 0) {
498498
}
499499

500500
[Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
501-
+"Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
501+
+ "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
502502
)]
503503
public PythonTuple recvfrom_into([NotNull] IBufferProtocol buffer, int nbytes = 0, int flags = 0) {
504504
using var buf = buffer.GetBufferNoThrow(BufferFlags.Writable);
@@ -1480,18 +1480,23 @@ public static Bytes inet_pton(CodeContext/*!*/ context, int addressFamily, [NotN
14801480
+ "\n"
14811481
+ "inet_ntop() supports IPv4 and IPv6."
14821482
)]
1483-
public static string inet_ntop(CodeContext/*!*/ context, int addressFamily, [NotNull] Bytes packedIP) {
1483+
public static string inet_ntop(CodeContext/*!*/ context, int addressFamily, [NotNull] IBufferProtocol packedIP) {
1484+
using var buffer = packedIP.GetBuffer();
1485+
var span = buffer.AsReadOnlySpan();
14841486
if (!(
1485-
(packedIP.Count == IPv4AddrBytes && addressFamily == (int)AddressFamily.InterNetwork)
1486-
|| (packedIP.Count == IPv6AddrBytes && addressFamily == (int)AddressFamily.InterNetworkV6)
1487+
(span.Length == IPv4AddrBytes && addressFamily == (int)AddressFamily.InterNetwork)
1488+
|| (span.Length == IPv6AddrBytes && addressFamily == (int)AddressFamily.InterNetworkV6)
14871489
)) {
14881490
throw PythonOps.ValueError("invalid length of packed IP address string");
14891491
}
1490-
byte[] ipBytes = packedIP.UnsafeByteArray;
14911492
if (addressFamily == (int)AddressFamily.InterNetworkV6) {
1492-
return IPv6BytesToColonHex(ipBytes);
1493+
return IPv6BytesToColonHex(span);
14931494
}
1494-
return (new IPAddress(ipBytes)).ToString();
1495+
#if NETCOREAPP
1496+
return new IPAddress(span).ToString();
1497+
#else
1498+
return new IPAddress(buffer.AsUnsafeArray() ?? buffer.ToArray()).ToString();
1499+
#endif
14951500
}
14961501

14971502
[Documentation("inet_aton(ip_string) -> packed_ip\n"
@@ -1517,7 +1522,7 @@ public static Bytes inet_aton(CodeContext/*!*/ context, [NotNull] string ipStrin
15171522
+ "\n"
15181523
+ "inet_ntoa() supports only IPv4."
15191524
)]
1520-
public static string inet_ntoa(CodeContext/*!*/ context, [NotNull] Bytes packedIP) {
1525+
public static string inet_ntoa(CodeContext/*!*/ context, [NotNull] IBufferProtocol packedIP) {
15211526
return inet_ntop(context, (int)AddressFamily.InterNetwork, packedIP);
15221527
}
15231528

@@ -1731,7 +1736,7 @@ internal static Exception MakeException(CodeContext/*!*/ context, Exception exce
17311736
/// which differs from the normal Python implementation (but is allowed by the IETF);
17321737
/// this method returns the standard (no dotted-quad) colon-hex form.
17331738
/// </summary>
1734-
private static string IPv6BytesToColonHex(byte[] ipBytes) {
1739+
private static string IPv6BytesToColonHex(ReadOnlySpan<byte> ipBytes) {
17351740
Debug.Assert(ipBytes.Length == IPv6AddrBytes);
17361741

17371742
const int bytesPerWord = 2; // in bytes

Src/IronPython.Modules/_ssl.cs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,15 @@ public _SSLContext(CodeContext context, int protocol) {
135135
}
136136

137137
public void set_ciphers(CodeContext context, string ciphers) {
138+
// TODO
139+
}
140+
141+
public void _set_alpn_protocols(CodeContext context, IBufferProtocol protos) {
142+
// TODO
143+
}
138144

145+
public void _set_npn_protocols(CodeContext context, IBufferProtocol protos) {
146+
// TODO
139147
}
140148

141149
public int options {
@@ -270,23 +278,28 @@ public class _SSLSocket {
270278
private SslStream _sslStream;
271279
private readonly PythonSocket.socket _socket;
272280
private readonly X509Certificate2Collection _certCollection;
273-
private readonly int _protocol, _certsMode;
281+
private readonly int _certsMode;
274282
private readonly bool _validate, _serverSide;
275283
private readonly CodeContext _context;
276284
private readonly RemoteCertificateValidationCallback _callback;
277285
private Exception _validationFailure;
278-
internal string _serverHostName;
279286

280287
public _SSLContext context { get; }
281288

289+
public object owner { get; set; } // TODO
290+
291+
public string server_hostname { get; }
292+
293+
public string version() => ProtocolToPython();
294+
282295
internal _SSLSocket(CodeContext context, _SSLContext sslcontext, PythonSocket.socket sock, bool server_side, string server_hostname) {
283296
if (sock == null) {
284297
throw PythonOps.TypeError("expected socket object, got None");
285298
}
286299

287300
this.context = sslcontext;
288301
_serverSide = server_side;
289-
_serverHostName = server_hostname;
302+
this.server_hostname = server_hostname;
290303

291304
_certsMode = sslcontext.verify_mode;
292305

@@ -319,7 +332,6 @@ internal _SSLSocket(CodeContext context, _SSLContext sslcontext, PythonSocket.so
319332

320333
EnsureSslStream(false);
321334

322-
_protocol = sslcontext.protocol | sslcontext.options;
323335
_validate = validate;
324336
_context = context;
325337
}
@@ -429,7 +441,7 @@ public void do_handshake() {
429441

430442
EnsureSslStream(true);
431443

432-
var enabledSslProtocols = GetProtocolType(_protocol);
444+
var enabledSslProtocols = GetProtocolType(context.protocol, context.options);
433445

434446
try {
435447
if (_serverSide) {
@@ -439,7 +451,7 @@ public void do_handshake() {
439451
}
440452
_sslStream.AuthenticateAsServer(_cert, _certsMode == PythonSsl.CERT_REQUIRED, enabledSslProtocols, false);
441453
} else {
442-
_sslStream.AuthenticateAsClient(_serverHostName ?? _socket._hostName, context._cert_store, enabledSslProtocols, false);
454+
_sslStream.AuthenticateAsClient(server_hostname ?? _socket._hostName, context._cert_store, enabledSslProtocols, false);
443455
}
444456
} catch (AuthenticationException e) {
445457
((IDisposable)_socket._socket).Dispose();
@@ -467,10 +479,10 @@ TLSv1.1 no no yes no yes no
467479
TLSv1.2 no no yes no no yes
468480
*/
469481

470-
private static SslProtocols GetProtocolType(int type) {
482+
private static SslProtocols GetProtocolType(int protocol, int options) {
471483
SslProtocols result = SslProtocols.None;
472484

473-
switch (type & ~PythonSsl.OP_NO_ALL) {
485+
switch (protocol) {
474486
#pragma warning disable CA5397 // Do not use deprecated SslProtocols values
475487
#pragma warning disable CS0618 // Type or member is obsolete
476488
case PythonSsl.PROTOCOL_SSLv2:
@@ -494,17 +506,17 @@ private static SslProtocols GetProtocolType(int type) {
494506
result = SslProtocols.Tls12;
495507
break;
496508
default:
497-
throw new InvalidOperationException("bad ssl protocol type: " + type);
509+
throw new InvalidOperationException("bad ssl protocol type: " + protocol);
498510
}
499511
// Filter out requested protocol exclusions:
500512
#pragma warning disable CA5397 // Do not use deprecated SslProtocols values
501513
#pragma warning disable CS0618 // Type or member is obsolete
502-
result &= (type & PythonSsl.OP_NO_SSLv3) != 0 ? ~SslProtocols.Ssl3 : ~SslProtocols.None;
503-
result &= (type & PythonSsl.OP_NO_SSLv2) != 0 ? ~SslProtocols.Ssl2 : ~SslProtocols.None;
514+
result &= (options & PythonSsl.OP_NO_SSLv3) != 0 ? ~SslProtocols.Ssl3 : ~SslProtocols.None;
515+
result &= (options & PythonSsl.OP_NO_SSLv2) != 0 ? ~SslProtocols.Ssl2 : ~SslProtocols.None;
504516
#pragma warning restore CS0618 // Type or member is obsolete
505-
result &= (type & PythonSsl.OP_NO_TLSv1) != 0 ? ~SslProtocols.Tls : ~SslProtocols.None;
506-
result &= (type & PythonSsl.OP_NO_TLSv1_1) != 0 ? ~SslProtocols.Tls11 : ~SslProtocols.None;
507-
result &= (type & PythonSsl.OP_NO_TLSv1_2) != 0 ? ~SslProtocols.Tls12 : ~SslProtocols.None;
517+
result &= (options & PythonSsl.OP_NO_TLSv1) != 0 ? ~SslProtocols.Tls : ~SslProtocols.None;
518+
result &= (options & PythonSsl.OP_NO_TLSv1_1) != 0 ? ~SslProtocols.Tls11 : ~SslProtocols.None;
519+
result &= (options & PythonSsl.OP_NO_TLSv1_2) != 0 ? ~SslProtocols.Tls12 : ~SslProtocols.None;
508520
#pragma warning restore CA5397 // Do not use deprecated SslProtocols values
509521
return result;
510522
}
@@ -1179,6 +1191,7 @@ private static Exception ErrorDecoding(CodeContext context, params object[] args
11791191
private const int PROTOCOL_SSLv2 = 0;
11801192
private const int PROTOCOL_SSLv3 = 1;
11811193
public const int PROTOCOL_SSLv23 = 2;
1194+
public const int PROTOCOL_TLS = 2;
11821195
public const int PROTOCOL_TLSv1 = 3;
11831196
public const int PROTOCOL_TLSv1_1 = 4;
11841197
public const int PROTOCOL_TLSv1_2 = 5;

Src/IronPython/Modules/sys.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ private windows_version(int major, int minor, int build, int platform, string se
256256
public readonly int suite_mask;
257257
public readonly PythonTuple platform_version;
258258

259+
public PythonTuple _platform_version => platform_version; // TODO: remove in 3.6 (for compat with 3.5)
260+
259261
public const int n_fields = 10;
260262
public const int n_sequence_fields = 5;
261263
public const int n_unnamed_fields = 0;

Src/IronPython/Runtime/MemoryView.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ public MemoryView cast([NotNull]string format, [NotNull, AllowNull]object shape)
455455
throw PythonOps.TypeError("memoryview: casts are restricted to C-contiguous views");
456456
}
457457

458-
if (_shape.Contains(0) || _strides.Contains(0)) {
458+
if ((shape != null || _numDims != 1) && (_shape.Contains(0) || _strides.Contains(0))) {
459459
throw PythonOps.TypeError("memoryview: cannot cast view with zeros in shape or strides");
460460
}
461461

Src/IronPython/Runtime/PythonFunction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public PythonDictionary __annotations__ {
123123
return _annotations;
124124
}
125125
set {
126-
_annotations = value ?? throw PythonOps.TypeError("__annotations__ must be set to a dict object");
126+
_annotations = value ?? new PythonDictionary();
127127
}
128128
}
129129

Src/IronPythonTest/Cases/IronPythonCasesManifest.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ IsolationLevel=PROCESS # causes failures in IronPython.test_ast and IronPython.s
145145
[IronPython.modules.misc.test__weakref]
146146
RetryCount=2
147147

148+
[IronPython.modules.misc.test_zlib]
149+
NotParallelSafe=true # test_data.gz
150+
148151
[IronPython.modules.system_related.test_nt]
149152
RunCondition=NOT $(IS_POSIX)
150153
NotParallelSafe=true # Uses fixed file, directory, and environment variable names

Tests/IndicesTest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# The .NET Foundation licenses this file to you under the Apache 2.0 License.
33
# See the LICENSE file in the project root for more information.
44

5-
# generated by IndicesTest.py
5+
# generated by generate_indicestest.py
66

77
def test_indices(self):
88
def t(i, j, k, l, r):

Tests/test_int.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ def test_to_bytes_clrint(self):
5050
continue
5151
for length in range(0, 10):
5252
try:
53-
expeced = big(v).to_bytes(length, byteorder, signed)
53+
expected = big(v).to_bytes(length, byteorder, signed)
5454
except OverflowError:
55-
continue # length too short
56-
57-
actual = t(v).to_bytes(length, byteorder, signed)
58-
self.assertEqual(actual, expeced)
55+
pass # length too short
56+
else:
57+
actual = t(v).to_bytes(length, byteorder, signed)
58+
self.assertEqual(actual, expected)
5959

6060
def test_int(self):
6161
class MyTrunc:

Tests/test_memoryview.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ def __bytes__(self):
454454

455455
self.assertEqual(mvc[1], b"a")
456456

457-
@unittest.skipUnless(is_64, "asssumes 64-bit pointers")
457+
@unittest.skipUnless(is_64, "assumes 64-bit pointers")
458458
def test_cast_pointer(self):
459459
ba = bytearray(range(16))
460460
mv = memoryview(ba)
@@ -478,7 +478,7 @@ def test_cast_pointer(self):
478478
with self.assertRaises(ValueError):
479479
mvp[0] = -0x8000000000000001
480480

481-
@unittest.skipUnless(is_64 and is_cli, "CLI interop, asssumes 64-bit pointers")
481+
@unittest.skipUnless(is_64 and is_cli, "CLI interop, assumes 64-bit pointers")
482482
def test_cast_netpointer(self):
483483
import System
484484
ba = bytearray(range(16))
@@ -564,5 +564,10 @@ def test_cast_reshape_then_slice(self):
564564
self.assertEqual(mv_2.tolist(), [[[0, 1], [2, 3]], [[8, 9], [10, 11]]])
565565
self.assertEqual(mv_2.tobytes(), b'\x00\x01\x02\x03\x08\x09\x0a\x0b')
566566

567+
def test_cast_empty(self):
568+
memoryview(b'').cast('b')
569+
memoryview(bytearray(b'')).cast('b')
570+
self.assertRaises(TypeError, memoryview(b'').cast, 'b', object()) # fails with any 2nd argument
571+
567572

568573
run_test(__name__)

0 commit comments

Comments
 (0)