diff --git a/Src/IronPython.Modules/nt.cs b/Src/IronPython.Modules/nt.cs index 741cd7715..a8098d9d1 100644 --- a/Src/IronPython.Modules/nt.cs +++ b/Src/IronPython.Modules/nt.cs @@ -22,6 +22,7 @@ using Microsoft.Scripting; using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; using IronPython.Runtime; using IronPython.Runtime.Exceptions; @@ -99,6 +100,12 @@ public static void PerformModuleReload([NotNull] PythonContext context, [NotNull #region Public API Surface + [PythonHidden(PlatformsAttribute.PlatformFamily.Unix)] + public static PythonTuple _getdiskusage([NotNull] string path) { + var driveInfo = new DriveInfo(path); + return PythonTuple.MakeTuple((BigInteger)driveInfo.TotalSize, (BigInteger)driveInfo.AvailableFreeSpace); + } + [DllImport("kernel32.dll", EntryPoint = "GetFinalPathNameByHandleW", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int GetFinalPathNameByHandle([In] SafeFileHandle hFile, [Out] StringBuilder lpszFilePath, [In] int cchFilePath, [In] int dwFlags); @@ -508,6 +515,12 @@ static void linkUnix(string src, string dst) { } } + public static bool isatty(CodeContext context, int fd) { + if (context.LanguageContext.FileManager.TryGetFileFromId(context.LanguageContext, fd, out var file)) + return file.isatty(context); + return false; + } + [Documentation("")] public static void link([NotNull] Bytes src, [NotNull] Bytes dst, [ParamDictionary, NotNull] IDictionary kwargs) => link(src.ToFsString(), dst.ToFsString(), kwargs); @@ -941,10 +954,18 @@ public static void rename([NotNull] string src, [NotNull] string dst, [ParamDict } } - try { - Directory.Move(src, dst); - } catch (Exception e) { - throw ToPythonException(e); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + if (!MoveFileEx(src, dst, 0)) { + throw GetLastWin32Error(src, dst); + } + } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { + renameUnix(src, dst); + } else { + try { + Directory.Move(src, dst); + } catch (Exception e) { + throw ToPythonException(e); + } } } @@ -961,7 +982,7 @@ public static void rename(CodeContext context, object? src, object? dst, [ParamD [DllImport("kernel32.dll", EntryPoint = "MoveFileExW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] private static extern bool MoveFileEx(string src, string dst, uint flags); - private static void replaceUnix(string src, string dst) { + private static void renameUnix(string src, string dst) { if (Mono.Unix.Native.Syscall.rename(src, dst) == 0) return; throw GetLastUnixError(src, dst); } @@ -984,7 +1005,7 @@ public static void replace([NotNull] string src, [NotNull] string dst, [ParamDic throw GetLastWin32Error(src, dst); } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - replaceUnix(src, dst); + renameUnix(src, dst); } else { throw new NotImplementedException(); } @@ -1208,17 +1229,19 @@ public sealed class stat_result : PythonTuple { private const long nanosecondsPerSeconds = 1_000_000_000; + private static object ToInt(BigInteger x) => x.AsInt32(out int i) ? i : (object)x; + internal stat_result(int mode) : this(new object[10] { mode, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, null) { } internal stat_result(Mono.Unix.Native.Stat stat) - : this(new object[16] {(int)stat.st_mode, stat.st_ino, stat.st_dev, stat.st_nlink, stat.st_uid, stat.st_gid, stat.st_size, stat.st_atime, stat.st_mtime, stat.st_ctime, + : this(new object[16] {(int)stat.st_mode, ToInt(stat.st_ino), ToInt(stat.st_dev), ToInt(stat.st_nlink), ToInt(stat.st_uid), ToInt(stat.st_gid), ToInt(stat.st_size), ToInt(stat.st_atime), ToInt(stat.st_mtime), ToInt(stat.st_ctime), stat.st_atime + stat.st_atime_nsec / (double)nanosecondsPerSeconds, stat.st_mtime + stat.st_mtime_nsec / (double)nanosecondsPerSeconds, stat.st_ctime + stat.st_ctime_nsec / (double)nanosecondsPerSeconds, - stat.st_atime * nanosecondsPerSeconds + stat.st_atime_nsec, stat.st_mtime * nanosecondsPerSeconds + stat.st_mtime_nsec, stat.st_ctime * nanosecondsPerSeconds + stat.st_ctime_nsec }, null) { } + ToInt(stat.st_atime * nanosecondsPerSeconds + stat.st_atime_nsec), ToInt(stat.st_mtime * nanosecondsPerSeconds + stat.st_mtime_nsec), ToInt(stat.st_ctime * nanosecondsPerSeconds + stat.st_ctime_nsec) }, null) { } internal stat_result(int mode, ulong fileidx, long size, long st_atime_ns, long st_mtime_ns, long st_ctime_ns) - : this(new object[16] { mode, fileidx, 0, 0, 0, 0, size, st_atime_ns / nanosecondsPerSeconds, st_mtime_ns / nanosecondsPerSeconds, st_ctime_ns / nanosecondsPerSeconds, + : this(new object[16] { mode, ToInt(fileidx), 0, 0, 0, 0, ToInt(size), ToInt(st_atime_ns / nanosecondsPerSeconds), ToInt(st_mtime_ns / nanosecondsPerSeconds), ToInt(st_ctime_ns / nanosecondsPerSeconds), st_atime_ns / (double)nanosecondsPerSeconds, st_mtime_ns / (double)nanosecondsPerSeconds, st_ctime_ns / (double)nanosecondsPerSeconds, - st_atime_ns, st_mtime_ns, st_ctime_ns }, null) { } + ToInt(st_atime_ns), ToInt(st_mtime_ns), ToInt(st_ctime_ns) }, null) { } private stat_result(object?[] statResult, PythonDictionary? dict) : base(statResult.Take(n_sequence_fields).ToArray()) { if (statResult.Length < n_sequence_fields) { @@ -1320,7 +1343,7 @@ public PythonTuple __reduce__() { return MakeTuple( DynamicHelpers.GetPythonTypeFromType(typeof(stat_result)), - MakeTuple(MakeTuple(this), timeDict) + MakeTuple(new PythonTuple(this), timeDict) ); } } diff --git a/Src/IronPythonTest/Cases/CPythonCasesManifest.ini b/Src/IronPythonTest/Cases/CPythonCasesManifest.ini index aa03f10ac..388cc52e6 100644 --- a/Src/IronPythonTest/Cases/CPythonCasesManifest.ini +++ b/Src/IronPythonTest/Cases/CPythonCasesManifest.ini @@ -847,8 +847,7 @@ IsolationLevel=PROCESS # Also weakref failures; https://github.com/IronLanguages NotParallelSafe=true [CPython.test_shutil] -Ignore=true -Reason=AttributeError: 'module' object has no attribute 'isatty' +RunCondition=NOT $(IS_POSIX) # TODO: debug [CPython.test_signal] Ignore=true diff --git a/Src/StdLib/Lib/test/test_shutil.py b/Src/StdLib/Lib/test/test_shutil.py index d2d4d0308..37bab7de2 100644 --- a/Src/StdLib/Lib/test/test_shutil.py +++ b/Src/StdLib/Lib/test/test_shutil.py @@ -126,9 +126,7 @@ def test_rmtree_works_on_bytes(self): write_file(os.path.join(victim, 'somefile'), 'foo') victim = os.fsencode(victim) self.assertIsInstance(victim, bytes) - win = (os.name == 'nt') - with self.assertWarns(DeprecationWarning) if win else ExitStack(): - shutil.rmtree(victim) + shutil.rmtree(victim) # ironpython: deprecation warning check is removed in 3.6 due to https://github.com/IronLanguages/ironpython3/issues/1156 @support.skip_unless_symlink def test_rmtree_fails_on_symlink(self):