diff --git a/src/core/IronPython.Modules/_winapi.cs b/src/core/IronPython.Modules/_winapi.cs index 6568c5467..414093fec 100644 --- a/src/core/IronPython.Modules/_winapi.cs +++ b/src/core/IronPython.Modules/_winapi.cs @@ -408,6 +408,16 @@ private static extern bool DuplicateHandlePI(IntPtr hSourceProcessHandle, public const int WAIT_ABANDONED_0 = 0x80; public const int WAIT_OBJECT_0 = 0x0; public const int WAIT_TIMEOUT = 0x102; + public const int ABOVE_NORMAL_PRIORITY_CLASS = 0x8000; + public const int BELOW_NORMAL_PRIORITY_CLASS = 0x4000; + public const int HIGH_PRIORITY_CLASS = 0x80; + public const int IDLE_PRIORITY_CLASS = 0x40; + public const int NORMAL_PRIORITY_CLASS = 0x20; + public const int REALTIME_PRIORITY_CLASS = 0x100; + public const int CREATE_NO_WINDOW = 0x8000000; + public const int DETACHED_PROCESS = 8; + public const int CREATE_DEFAULT_ERROR_MODE = 0x4000000; + public const int CREATE_BREAKAWAY_FROM_JOB = 0x1000000; #endregion } diff --git a/src/core/IronPython.Modules/nt.cs b/src/core/IronPython.Modules/nt.cs index 7d6d9c20b..15d537399 100644 --- a/src/core/IronPython.Modules/nt.cs +++ b/src/core/IronPython.Modules/nt.cs @@ -2185,6 +2185,17 @@ private static Exception ToPythonException(Exception e, string? filename = null) public const int W_OK = 2; public const int R_OK = 4; + [PythonHidden(PlatformsAttribute.PlatformFamily.Unix)] + public const int _LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x0100; + [PythonHidden(PlatformsAttribute.PlatformFamily.Unix)] + public const int _LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x1000; + [PythonHidden(PlatformsAttribute.PlatformFamily.Unix)] + public const int _LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x0200; + [PythonHidden(PlatformsAttribute.PlatformFamily.Unix)] + public const int _LOAD_LIBRARY_SEARCH_USER_DIRS = 0x0400; + [PythonHidden(PlatformsAttribute.PlatformFamily.Unix)] + public const int _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x0800; + private static void addBase(IEnumerable files, PythonList ret) { foreach (string file in files) { ret.AddNoLock(Path.GetFileName(file)); diff --git a/src/core/IronPython/Compiler/Ast/TupleExpression.cs b/src/core/IronPython/Compiler/Ast/TupleExpression.cs index cc80ecef3..f39b55514 100644 --- a/src/core/IronPython/Compiler/Ast/TupleExpression.cs +++ b/src/core/IronPython/Compiler/Ast/TupleExpression.cs @@ -73,6 +73,8 @@ public override void Walk(PythonWalker walker) { walker.PostWalk(this); } + public override string NodeName => "tuple"; + public bool IsExpandable { get; } internal override bool IsConstant { diff --git a/src/core/IronPython/Modules/_io.cs b/src/core/IronPython/Modules/_io.cs index b25cda459..59bd726ad 100644 --- a/src/core/IronPython/Modules/_io.cs +++ b/src/core/IronPython/Modules/_io.cs @@ -2912,6 +2912,9 @@ public static _IOBase open( return res; } + // new in Python 3.8 + public static _IOBase open_code(CodeContext/*!*/ context, string path) => open(context, path, "rb"); + internal static TextIOWrapper CreateConsole(PythonContext context, SharedIO io, ConsoleStreamType type, string name, out StreamBox sio) { var cc = context.SharedContext; if (type == ConsoleStreamType.Input) { diff --git a/src/core/IronPython/Runtime/ByteArray.cs b/src/core/IronPython/Runtime/ByteArray.cs index cde6ea61a..e1f20ac0f 100644 --- a/src/core/IronPython/Runtime/ByteArray.cs +++ b/src/core/IronPython/Runtime/ByteArray.cs @@ -483,6 +483,18 @@ public static object fromhex(CodeContext context, [NotNone] PythonType cls, [Not public string hex() => Bytes.ToHex(_bytes.AsByteSpan()); // new in CPython 3.5 + // new in CPython 3.8 + public string hex([NotNone] string sep, int bytes_per_sep = 1) { + if (sep.Length != 1) throw PythonOps.ValueError($"{nameof(sep)} must be length 1"); + return Bytes.ToHex(_bytes.AsByteSpan(), sep[0], bytes_per_sep); + } + + // new in CPython 3.8 + public string hex([BytesLike, NotNone] IList sep, int bytes_per_sep = 1) { + if (sep.Count != 1) throw PythonOps.ValueError($"{nameof(sep)} must be length 1"); + return Bytes.ToHex(_bytes.AsByteSpan(), (char)sep[0], bytes_per_sep); + } + public int index([BytesLike, NotNone] IList sub) { lock (this) { return index(sub, 0, _bytes.Count); @@ -544,6 +556,13 @@ public bool isalpha() { } } + // new in Python 3.7 + public bool isascii() { + lock (this) { + return _bytes.IsAscii(); + } + } + public bool isdigit() { lock (this) { return _bytes.IsDigit(); diff --git a/src/core/IronPython/Runtime/Bytes.cs b/src/core/IronPython/Runtime/Bytes.cs index cb89586a7..a04bfa7aa 100644 --- a/src/core/IronPython/Runtime/Bytes.cs +++ b/src/core/IronPython/Runtime/Bytes.cs @@ -392,6 +392,51 @@ static char ToAscii(int b) { } } + // new in CPython 3.8 + public string hex([NotNone] string sep, int bytes_per_sep = 1) { + if (sep.Length != 1) throw PythonOps.ValueError($"{nameof(sep)} must be length 1"); + return ToHex(_bytes.AsSpan(), sep[0], bytes_per_sep); + } + + // new in CPython 3.8 + public string hex([BytesLike, NotNone] IList sep, int bytes_per_sep = 1) { + if (sep.Count != 1) throw PythonOps.ValueError($"{nameof(sep)} must be length 1"); + return ToHex(_bytes.AsSpan(), (char)sep[0], bytes_per_sep); + } + + internal static string ToHex(ReadOnlySpan bytes, char sep, int bytes_per_sep) { + if (sep >= 0x80) throw PythonOps.ValueError($"{nameof(sep)} must be ASCII"); + if (bytes.Length == 0) return string.Empty; + if (bytes_per_sep == 0) return ToHex(bytes); + + int sepLoc; + if (bytes_per_sep < 0) { + bytes_per_sep = -bytes_per_sep; + sepLoc = 0; + } else { + sepLoc = bytes_per_sep - bytes.Length % bytes_per_sep; + if (sepLoc == bytes_per_sep) sepLoc = 0; + } + + var builder = new StringBuilder(bytes.Length * 2 + (bytes.Length - 1) / bytes_per_sep); + foreach (var b in bytes) { + if (sepLoc == bytes_per_sep) { + builder.Append(sep); + sepLoc = 1; + } else { + sepLoc++; + } + builder.Append(ToAscii(b >> 4)); + builder.Append(ToAscii(b & 0xf)); + } + Debug.Assert(builder.Length == bytes.Length * 2 + (bytes.Length - 1) / bytes_per_sep); + return builder.ToString(); + + static char ToAscii(int b) { + return (char)(b < 10 ? '0' + b : 'a' + (b - 10)); + } + } + public int index([BytesLike, NotNone] IList sub) => index(sub, 0, _bytes.Length); @@ -435,6 +480,9 @@ public int index(BigInteger @byte, object? start, object? end) public bool isalpha() => _bytes.IsLetter(); + // new in Python 3.7 + public bool isascii() => _bytes.IsAscii(); + public bool isdigit() => _bytes.IsDigit(); public bool islower() => _bytes.IsLower(); diff --git a/src/core/IronPython/Runtime/Operations/IListOfByteOps.cs b/src/core/IronPython/Runtime/Operations/IListOfByteOps.cs index 1418bd013..efebc4272 100644 --- a/src/core/IronPython/Runtime/Operations/IListOfByteOps.cs +++ b/src/core/IronPython/Runtime/Operations/IListOfByteOps.cs @@ -984,6 +984,15 @@ internal static bool IsAlphaNumeric(this IList bytes) { return true; } + internal static bool IsAscii(this IList bytes) { + foreach (byte b in bytes) { + if (b > 0x7f) { + return false; + } + } + return true; + } + internal static int Find(this IList bytes, IList sub, int start, int end) { if (!PythonOps.TryFixSubsequenceIndices(bytes.Count, ref start, ref end)) { return -1; @@ -1017,7 +1026,7 @@ internal static List FromHex(string @string) { iVal = (c - 'A' + 10) * 16; } else if (c >= 'a' && c <= 'f') { iVal = (c - 'a' + 10) * 16; - } else if (c == ' ') { + } else if (c < 0x80 && char.IsWhiteSpace(c)) { continue; } else { throw PythonOps.ValueError("non-hexadecimal number found in fromhex() arg at position {0}", i); diff --git a/src/core/IronPython/Runtime/Operations/StringOps.cs b/src/core/IronPython/Runtime/Operations/StringOps.cs index fd8ac3136..4b2cbddf6 100644 --- a/src/core/IronPython/Runtime/Operations/StringOps.cs +++ b/src/core/IronPython/Runtime/Operations/StringOps.cs @@ -623,6 +623,13 @@ public static bool isalpha([NotNone] this string self) { return true; } + public static bool isascii([NotNone] this string self) { + foreach (char c in self) { + if (c > 0x7f) return false; + } + return true; + } + public static bool isdigit([NotNone] this string self) { if (self.Length == 0) return false; string v = self; diff --git a/tests/suite/test_dict.py b/tests/suite/test_dict.py index 90036fe71..f9bba6bab 100644 --- a/tests/suite/test_dict.py +++ b/tests/suite/test_dict.py @@ -7,7 +7,7 @@ x = dir(dict) x = dir(dict.fromkeys) -import collections +import collections.abc import os import sys @@ -624,7 +624,7 @@ def test_same_but_different(self): def test_module_dict(self): me = sys.modules[__name__] moduleDict = me.__dict__ - self.assertTrue(isinstance(moduleDict, collections.Mapping)) + self.assertTrue(isinstance(moduleDict, collections.abc.Mapping)) self.assertTrue(moduleDict.__contains__("DictTest")) self.assertEqual(moduleDict["DictTest"], DictTest) self.assertTrue(moduleDict.keys().__contains__("DictTest"))