diff --git a/.gitattributes b/.gitattributes index 5c5441dd2..699a864e1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14,8 +14,8 @@ *.ps1 text # Explicitly declare files that should not have line endings modified, ever -Tests/file_with_BOM.txt -text -Tests/file_without_BOM.txt -text +tests/suite/file_with_BOM.txt -text +tests/suite/file_without_BOM.txt -text # Declare files that will always have CRLF line endings on checkout. *.bat text eol=crlf @@ -44,3 +44,6 @@ Tests/file_without_BOM.txt -text # Do not normalize on commit. *.pdf -text + +*.pck linguist-detectable=false +*.html linguist-documentation=true diff --git a/.gitignore b/.gitignore index a4159815e..d958128bc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,16 +13,13 @@ bin/ Package/Release/ *.binlog -# NuGet Packages -packages/ - # Python cache files __pycache__/ # Generated files -Src/IronPythonTest/TestResults/ -Src/IronPythonTest/runsettings.*.xml +tests/IronPython.Tests/TestResults/ +tests/IronPython.Tests/runsettings.*.xml # created by CPython tests -Src/StdLib/Lib/lib2to3/Grammar*.pickle -Src/StdLib/Lib/lib2to3/PatternGrammar*.pickle +src/core/IronPython.StdLib/lib/lib2to3/Grammar*.pickle +src/core/IronPython.StdLib/lib/lib2to3/PatternGrammar*.pickle diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 6e8567eb4..5f4312181 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -8,7 +8,7 @@ jobs: pool: vmImage: windows-latest steps: - - template: Build/steps.yml + - template: eng/steps.yml parameters: os: 'Windows' @@ -20,7 +20,7 @@ jobs: pool: vmImage: ubuntu-latest steps: - - template: Build/steps.yml + - template: eng/steps.yml parameters: os: 'Linux' @@ -32,6 +32,6 @@ jobs: pool: vmImage: macOS-latest steps: - - template: Build/steps.yml + - template: eng/steps.yml parameters: os: 'macOS' diff --git a/Build.proj b/Build.proj index 21c6967d6..929b39f17 100644 --- a/Build.proj +++ b/Build.proj @@ -9,10 +9,9 @@ $(MSBuildThisFileDirectory) $(RootDir)IronPython.sln - $(RootDir)Util - $(RootDir)Util\References + $(RootDir)eng\utils $(RootDir)bin - $(RootDir)Build + $(RootDir)eng @@ -40,7 +39,7 @@ - $(UtilDir)\NuGet\nuget.exe + $(UtilsDir)\NuGet\nuget.exe @@ -117,7 +116,7 @@ - @@ -138,5 +137,5 @@ - + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 03064d297..8d7e2bb80 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,9 @@ The steps to contribute a change are: -1. Fork the IronPython3 repository. For more information see [Getting the Sources](Documentation/getting-the-sources.md). -2. Build the repository. For more information see [Building](Documentation/building.md). -1. Make your changes on your machine, ensure ```make.ps1 test-all``` runs successfully, and commit your changes. For more information see [Modifying the Sources](Documentation/modifying-the-sources.md). +1. Fork the IronPython3 repository. For more information see [Getting the Sources](docs/getting-the-sources.md). +2. Build the repository. For more information see [Building](docs/building.md). +1. Make your changes on your machine, ensure ```make.ps1 test-all``` runs successfully, and commit your changes. For more information see [Modifying the Sources](docs/modifying-the-sources.md). 1. Push the commits to your fork. This way your name will be the author of the commit in the main IronPython3 tree (once the commits are pulled into the main tree). 1. Create a pull request on Github, this will initiate a code review and CLA signing request 1. The IronPython team will review, and possibly request changes, to your PR diff --git a/Directory.Build.props b/Directory.Build.props index 709636925..2beab9202 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,8 +5,8 @@ $(MSBuildThisFileDirectory) - $(RootDir)Build - $(RootDir)Util\References + $(RootDir)eng + $(RootDir)eng\utils true diff --git a/IronPython.sln b/IronPython.sln index f7c936d83..6a760c366 100644 --- a/IronPython.sln +++ b/IronPython.sln @@ -3,17 +3,17 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.9.34714.143 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython", "Src\IronPython\IronPython.csproj", "{95289EA9-5778-489D-AB48-F81F2CE2DA32}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython", "src\core\IronPython\IronPython.csproj", "{95289EA9-5778-489D-AB48-F81F2CE2DA32}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Modules", "Src\IronPython.Modules\IronPython.Modules.csproj", "{155CE436-1669-4A48-8095-410F2430237F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Modules", "src\core\IronPython.Modules\IronPython.Modules.csproj", "{155CE436-1669-4A48-8095-410F2430237F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Wpf", "Src\IronPython.Wpf\IronPython.Wpf.csproj", "{65E997B7-E99B-4C83-B29E-9951429BB293}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Wpf", "src\extensions\IronPython.Wpf\IronPython.Wpf.csproj", "{65E997B7-E99B-4C83-B29E-9951429BB293}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPythonConsole", "Src\IronPythonConsole\IronPythonConsole.csproj", "{811AC32C-11F3-4ED8-92A7-A7E39C2BB704}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Console", "src\executables\IronPython.Console\IronPython.Console.csproj", "{811AC32C-11F3-4ED8-92A7-A7E39C2BB704}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPythonTest", "Src\IronPythonTest\IronPythonTest.csproj", "{B6B42537-07F8-4F6C-A99A-B155CAEB124E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Tests", "tests\IronPython.Tests\IronPython.Tests.csproj", "{B6B42537-07F8-4F6C-A99A-B155CAEB124E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPythonWindow", "Src\IronPythonWindow\IronPythonWindow.csproj", "{81DA19C7-4FEC-47E7-981B-D9310D549F95}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Window", "src\executables\IronPython.Window\IronPython.Window.csproj", "{81DA19C7-4FEC-47E7-981B-D9310D549F95}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3A14D070-628F-44EF-92DD-47C8BE5C33CD}" ProjectSection(SolutionItems) = preProject @@ -29,81 +29,81 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.SQLite", "Src\IronPython.SQLite\IronPython.SQLite.csproj", "{4A617A40-2BA7-4713-AAFE-F90C4325C581}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.SQLite", "src\extensions\IronPython.SQLite\IronPython.SQLite.csproj", "{4A617A40-2BA7-4713-AAFE-F90C4325C581}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{17737ACB-40C6-41A6-83DA-3203A4DCEC19}" ProjectSection(SolutionItems) = preProject - Build\After.targets = Build\After.targets - Build\net462.props = Build\net462.props - Build\net6.0-windows.props = Build\net6.0-windows.props - Build\net6.0.props = Build\net6.0.props - Build\net8.0-windows.props = Build\net8.0-windows.props - Build\net8.0.props = Build\net8.0.props - Build\net9.0-windows.props = Build\net9.0-windows.props - Build\net9.0.props = Build\net9.0.props - Build\netstandard2.0.props = Build\netstandard2.0.props - Build\steps.yml = Build\steps.yml - Build\Tasks.Targets = Build\Tasks.Targets + eng\After.targets = eng\After.targets + eng\net462.props = eng\net462.props + eng\net6.0-windows.props = eng\net6.0-windows.props + eng\net6.0.props = eng\net6.0.props + eng\net8.0-windows.props = eng\net8.0-windows.props + eng\net8.0.props = eng\net8.0.props + eng\net9.0-windows.props = eng\net9.0-windows.props + eng\net9.0.props = eng\net9.0.props + eng\netstandard2.0.props = eng\netstandard2.0.props + eng\steps.yml = eng\steps.yml + eng\Tasks.Targets = eng\Tasks.Targets EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPythonCompiler", "Src\IronPythonCompiler\IronPythonCompiler.csproj", "{3DFB096E-AC09-4E7A-9288-7F7C33C288C7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Compiler", "src\executables\IronPython.Compiler\IronPython.Compiler.csproj", "{3DFB096E-AC09-4E7A-9288-7F7C33C288C7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DLR", "DLR", "{AC38EFB1-820D-4E90-BF40-BEF3AC825542}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Dynamic", "Src\DLR\Src\Microsoft.Dynamic\Microsoft.Dynamic.csproj", "{EB66B766-6354-4208-A3D4-AACBDCB5C3B3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Dynamic", "src\dlr\Src\Microsoft.Dynamic\Microsoft.Dynamic.csproj", "{EB66B766-6354-4208-A3D4-AACBDCB5C3B3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Scripting", "Src\DLR\Src\Microsoft.Scripting\Microsoft.Scripting.csproj", "{02FF0909-F5AD-48CF-A86A-345E721B7E40}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Scripting", "src\dlr\Src\Microsoft.Scripting\Microsoft.Scripting.csproj", "{02FF0909-F5AD-48CF-A86A-345E721B7E40}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Scripting.Metadata", "Src\DLR\Src\Microsoft.Scripting.Metadata\Microsoft.Scripting.Metadata.csproj", "{ACDD9B9E-8FE6-439C-9521-1CCBA47F6143}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Scripting.Metadata", "src\dlr\Src\Microsoft.Scripting.Metadata\Microsoft.Scripting.Metadata.csproj", "{ACDD9B9E-8FE6-439C-9521-1CCBA47F6143}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{60836ADE-CAB7-4587-B6FB-8C4FEB872752}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClrAssembly", "Src\DLR\Tests\ClrAssembly\ClrAssembly.csproj", "{BEE737B9-18D5-48D9-8672-9A896213C98B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClrAssembly", "src\dlr\Tests\ClrAssembly\ClrAssembly.csproj", "{BEE737B9-18D5-48D9-8672-9A896213C98B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{CE610DDE-D1DB-44D8-BAE9-BAAB00DA98F0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{EE77D917-27F7-4E54-B72F-C8CEE4AEDCAA}" ProjectSection(SolutionItems) = preProject - Package\nuget\IronPython.nuspec = Package\nuget\IronPython.nuspec - Package\nuget\IronPython.StdLib.nuspec = Package\nuget\IronPython.StdLib.nuspec + eng\package\nuget\IronPython.nuspec = eng\package\nuget\IronPython.nuspec + eng\package\nuget\IronPython.StdLib.nuspec = eng\package\nuget\IronPython.StdLib.nuspec EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPythonConsole32", "Src\IronPythonConsole32\IronPythonConsole32.csproj", "{AD21022F-E7C1-4B74-97C1-0A0E48EFF992}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Console32", "src\executables\IronPython.Console32\IronPython.Console32.csproj", "{AD21022F-E7C1-4B74-97C1-0A0E48EFF992}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPythonAnalyzer", "IronPythonAnalyzer\IronPythonAnalyzer\IronPythonAnalyzer.csproj", "{DA3415F3-6922-42D0-93D7-BEE2E8603A18}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Analyzer", "src\roslyn\IronPython.Analyzer\IronPython.Analyzer.csproj", "{DA3415F3-6922-42D0-93D7-BEE2E8603A18}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "choco", "choco", "{EA550FD8-2241-4131-8292-619D009E0199}" ProjectSection(SolutionItems) = preProject - Package\choco\Choco.Packaging.targets = Package\choco\Choco.Packaging.targets - Package\choco\IronPython.nuspec = Package\choco\IronPython.nuspec + eng\package\choco\Choco.Packaging.targets = eng\package\choco\Choco.Packaging.targets + eng\package\choco\IronPython.nuspec = eng\package\choco\IronPython.nuspec EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pkg", "pkg", "{01CE1AE6-CD7F-491B-8150-58CD738B20AC}" ProjectSection(SolutionItems) = preProject - Package\pkg\Pkg.Packaging.targets = Package\pkg\Pkg.Packaging.targets + eng\package\pkg\Pkg.Packaging.targets = eng\package\pkg\Pkg.Packaging.targets EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deb", "deb", "{676093FF-CB44-4BD5-B83C-A28FE88D5017}" ProjectSection(SolutionItems) = preProject - Package\deb\Deb.Packaging.targets = Package\deb\Deb.Packaging.targets + eng\package\deb\Deb.Packaging.targets = eng\package\deb\Deb.Packaging.targets EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "zip", "zip", "{8FC07B92-D2AC-4921-9E97-A92A84D2B461}" ProjectSection(SolutionItems) = preProject - Package\zip\Zip.Packaging.targets = Package\zip\Zip.Packaging.targets + eng\package\zip\Zip.Packaging.targets = eng\package\zip\Zip.Packaging.targets EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "msi", "msi", "{450F93D5-DF02-4C04-960B-AE7E454668AA}" ProjectSection(SolutionItems) = preProject - Package\msi\Dlr.wxs = Package\msi\Dlr.wxs - Package\msi\IronPython.Installer.wixproj = Package\msi\IronPython.Installer.wixproj - Package\msi\IronPython.wxs = Package\msi\IronPython.wxs - Package\msi\Msi.Packaging.targets = Package\msi\Msi.Packaging.targets - Package\msi\Product.wxs = Package\msi\Product.wxs - Package\msi\Version.wxi = Package\msi\Version.wxi + eng\package\msi\Dlr.wxs = eng\package\msi\Dlr.wxs + eng\package\msi\IronPython.Installer.wixproj = eng\package\msi\IronPython.Installer.wixproj + eng\package\msi\IronPython.wxs = eng\package\msi\IronPython.wxs + eng\package\msi\Msi.Packaging.targets = eng\package\msi\Msi.Packaging.targets + eng\package\msi\Product.wxs = eng\package\msi\Product.wxs + eng\package\msi\Version.wxi = eng\package\msi\Version.wxi EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPythonWindow32", "Src\IronPythonWindow32\IronPythonWindow32.csproj", "{8F177DC2-9822-45BD-AB05-1F40FCA86168}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IronPython.Window32", "src\executables\IronPython.Window32\IronPython.Window32.csproj", "{8F177DC2-9822-45BD-AB05-1F40FCA86168}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/NuGet.config b/NuGet.config deleted file mode 100644 index b486c587e..000000000 --- a/NuGet.config +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/README.md b/README.md index 42d8e6881..292b07a44 100644 --- a/README.md +++ b/README.md @@ -71,19 +71,19 @@ See the following lists for features from each version of CPython that have been For details on contributing see the [Contributing](CONTRIBUTING.md) article. ## Upgrading from IronPython 2 -For details on upgrading from IronPython 2 to 3 see the [Upgrading from IronPython 2 to 3](Documentation/upgrading-from-ipy2.md) article. +For details on upgrading from IronPython 2 to 3 see the [Upgrading from IronPython 2 to 3](docs/upgrading-from-ipy2.md) article. ## Differences with CPython -While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](Documentation/differences-from-c-python.md) for details. +While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](docs/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](Documentation/package-compatibility.md) document for information on compatibility with popular packages. +See the [Package compatibility](docs/package-compatibility.md) document for information on compatibility with popular packages. ## Installation -Binaries of IronPython 3 can be downloaded from the [release page](https://github.com/IronLanguages/ironpython3/releases/latest), available in various formats: `.msi`, `.zip`, `.deb`, `.pkg`. The IronPython package is also available on [NuGet](https://www.nuget.org/packages/IronPython/3.4.0). See the [installation document](Documentation/installing.md) for detailed instructions on how to install a standalone IronPython interpreter on various operating systems and .NET frameworks. +Binaries of IronPython 3 can be downloaded from the [release page](https://github.com/IronLanguages/ironpython3/releases/latest), available in various formats: `.msi`, `.zip`, `.deb`, `.pkg`. The IronPython package is also available on [NuGet](https://www.nuget.org/packages/IronPython/3.4.0). See the [installation document](docs/installing.md) for detailed instructions on how to install a standalone IronPython interpreter on various operating systems and .NET frameworks. ## Build -See the [building document](Documentation/building.md). Since the main development is on Windows, bugs on other platforms may inadvertently be introduced - please report them! +See the [building document](docs/building.md). Since the main development is on Windows, bugs on other platforms may inadvertently be introduced - please report them! ## Supported Platforms IronPython 3 targets .NET Framework 4.6.2, .NET Standard 2.0, .NET 6.0 and .NET 8.0. The support for .NET and .NET Core follow the lifecycle defined on [.NET and .NET Core Support Policy](https://dotnet.microsoft.com/platform/support/policy/dotnet-core). diff --git a/docs/building.md b/docs/building.md index 3a8879a29..4e04fbd1b 100644 --- a/docs/building.md +++ b/docs/building.md @@ -45,6 +45,6 @@ If the build is successful the binaries are stored in `ironpython3/bin/{Configur ## Running -The standard library is not copied over to the `bin` folder during the build process, it lives in `Src/StdLib/Lib`. +The standard library is not copied over to the `bin` folder during the build process, it lives in `src/core/IronPython.StdLib/lib`. - When running the `Release` configuration executable, you should set the environment variable `IRONPYTHONPATH` to this folder. - When running the `Debug` configuration executable, this folder is automatically added to `sys.path`. diff --git a/docs/feature-symbols.md b/docs/feature-symbols.md index c179e1da1..23258312f 100644 --- a/docs/feature-symbols.md +++ b/docs/feature-symbols.md @@ -1,6 +1,6 @@ # Feature Symbols -Feature Symbols (named FEATURE_{feature name}, all caps) are compilation symbols defined for features whose availability vary across platforms that IronPython supports. The symbols are defined in Build/{framework}.props file, which get included by all .csproj files that contribute to IronPython. +Feature Symbols (named FEATURE_{feature name}, all caps) are compilation symbols defined for features whose availability vary across platforms that IronPython supports. The symbols are defined in eng/{framework}.props file, which get included by all .csproj files that contribute to IronPython. **The following list needs a major update** diff --git a/docs/installing.md b/docs/installing.md index 7371f20c5..7b978bc11 100644 --- a/docs/installing.md +++ b/docs/installing.md @@ -87,7 +87,7 @@ Use Powershell's `help` command on the script for information about available op The script is also available online, so it can be downloaded and invoked without unzipping the archive first. ``` -PS> Invoke-WebRequest https://raw.githubusercontent.com/IronLanguages/ironpython3/main/Src/Scripts/Install-IronPython.ps1 -OutFile ./Install-IronPython.ps1 +PS> Invoke-WebRequest https://raw.githubusercontent.com/IronLanguages/ironpython3/main/eng/scripts/Install-IronPython.ps1 -OutFile ./Install-IronPython.ps1 PS> ./Install-IronPython ~/ipyenv ~/Downloads/IronPython.3.X.Y.zip PS> ~/ipyenv/Enter-IronPythonEnvironment «ipyenv» PS> ipy @@ -158,7 +158,7 @@ Go to the project's [_Actions_ page](https://github.com/IronLanguages/ironpython # Installing from Sources -To build and install IronPython from sources, first follow instructions in [_Getting the Sources_](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/getting-the-sources.md) and [_Building IronPython3_](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/building.md). +To build and install IronPython from sources, first follow instructions in [_Getting the Sources_](https://github.com/IronLanguages/ironpython3/blob/main/docs/getting-the-sources.md) and [_Building IronPython3_](https://github.com/IronLanguages/ironpython3/blob/main/docs/building.md). When the command `./make.ps1 debug` completes successfully, runnable and usable `ipy` executables are available in subdirectories of `./bin/Debug`. To run executables from the release configuration (produced by a successful run of `./make.ps1`), first set environment variable `IRONPYTHONPATH`. @@ -170,10 +170,10 @@ If those executables test out successfully, the binaries can be installed outsid The artifacts are placed in directory `./Package/Release/Packages/IronPython-3.X.Y`. Pick a package suitable for your installation target and follow instructions above for the officially released packages. -Note: as a convenience, if you run `Install-IronPython.ps1` directly from directory `./Src/Scripts` to install IronPython from the zip file, there is no need to pass the location to the zip file; the script finds it automatically using the relative path. +Note: as a convenience, if you run `Install-IronPython.ps1` directly from directory `./eng/scripts` to install IronPython from the zip file, there is no need to pass the location to the zip file; the script finds it automatically using the relative path. Installation example: ``` -./Src/Scripts/Install-IronPython.ps1 /path/to/install/directory -framework net462 +./eng/scripts/Install-IronPython.ps1 /path/to/install/directory -framework net462 ``` diff --git a/docs/modifying-the-sources.md b/docs/modifying-the-sources.md index 7016f075d..895587d2a 100644 --- a/docs/modifying-the-sources.md +++ b/docs/modifying-the-sources.md @@ -1,6 +1,6 @@ # TDD -Bug fixes should be accompanied by a test that shows that the bug has been fixed. If the bug fix is fixing something that is covered by a test in the C Python test suite (Src\StdLib\Lib\test) and that test is not currently enabled, try enabling the test in Src\IronPythonTest\Cases\*.ini depending on the type of test it is. +Bug fixes should be accompanied by a test that shows that the bug has been fixed. If the bug fix is fixing something that is covered by a test in the C Python test suite (`src/core/IronPython.StdLib/lib/test`) and that test is not currently enabled, try enabling the test in `tests\IronPython.Tests\Cases\*.ini` depending on the type of test it is. Most PR's will not be accepted if there is not a test included. diff --git a/eng/package/choco/Choco.Packaging.targets b/eng/package/choco/Choco.Packaging.targets index 6aa617ce3..c6c100013 100644 --- a/eng/package/choco/Choco.Packaging.targets +++ b/eng/package/choco/Choco.Packaging.targets @@ -6,7 +6,7 @@ 0.10.8 - + diff --git a/eng/package/choco/README.md b/eng/package/choco/README.md index fbd5d23a1..a7d3adba0 100644 --- a/eng/package/choco/README.md +++ b/eng/package/choco/README.md @@ -9,7 +9,7 @@ The current target is Python 3.4, although features and behaviors from later ver ## Differences with CPython -While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/differences-from-c-python.md) for details. +While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](https://github.com/IronLanguages/ironpython3/blob/main/docs/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/package-compatibility.md) document for information on compatibility with popular Python packages. +See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/docs/package-compatibility.md) document for information on compatibility with popular Python packages. diff --git a/eng/package/deb/Deb.Packaging.targets b/eng/package/deb/Deb.Packaging.targets index 184aadb9b..0650d246d 100644 --- a/eng/package/deb/Deb.Packaging.targets +++ b/eng/package/deb/Deb.Packaging.targets @@ -3,7 +3,7 @@ temp - Package/deb + eng/package/deb $(PackageDebFolder)/$(TempFolder) diff --git a/eng/package/dotnettool/IronPython.Console.csproj b/eng/package/dotnettool/IronPython.Console.csproj index 068b735ff..8fcbc13dc 100644 --- a/eng/package/dotnettool/IronPython.Console.csproj +++ b/eng/package/dotnettool/IronPython.Console.csproj @@ -55,7 +55,7 @@ This package contains a standalone Python interpreter, invokable from the comman - + diff --git a/eng/package/dotnettool/README.md b/eng/package/dotnettool/README.md index f6e7118d2..690f64324 100644 --- a/eng/package/dotnettool/README.md +++ b/eng/package/dotnettool/README.md @@ -9,8 +9,8 @@ The current target is Python 3.4, although features and behaviors from later ver ## Differences with CPython -While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/differences-from-c-python.md) for details. +While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](https://github.com/IronLanguages/ironpython3/blob/main/docs/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/package-compatibility.md) document for information on compatibility with popular Python packages. +See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/docs/package-compatibility.md) document for information on compatibility with popular Python packages. diff --git a/eng/package/msi/Msi.Packaging.targets b/eng/package/msi/Msi.Packaging.targets index 87cfe329c..bfc8ee807 100644 --- a/eng/package/msi/Msi.Packaging.targets +++ b/eng/package/msi/Msi.Packaging.targets @@ -1,9 +1,9 @@ - + diff --git a/eng/package/msi/Product.wxs b/eng/package/msi/Product.wxs index 243f17fd6..7570878cf 100644 --- a/eng/package/msi/Product.wxs +++ b/eng/package/msi/Product.wxs @@ -19,7 +19,7 @@ WHEN PERFORMING MAJOR IP UPGRADES (e.g., 2.5 => 2.6): - + diff --git a/eng/package/nuget/IronPython.StdLib.nuspec b/eng/package/nuget/IronPython.StdLib.nuspec index f62df7e74..b3b8ce2c3 100644 --- a/eng/package/nuget/IronPython.StdLib.nuspec +++ b/eng/package/nuget/IronPython.StdLib.nuspec @@ -24,6 +24,6 @@ - + diff --git a/eng/package/nuget/IronPython.nuspec b/eng/package/nuget/IronPython.nuspec index 491d14977..1c3b0e0cd 100644 --- a/eng/package/nuget/IronPython.nuspec +++ b/eng/package/nuget/IronPython.nuspec @@ -40,7 +40,7 @@ This package contains the IronPython interpreter engine. - - + + diff --git a/eng/package/nuget/NuGet.Packaging.targets b/eng/package/nuget/NuGet.Packaging.targets index c0afa28a4..9234c8ab6 100644 --- a/eng/package/nuget/NuGet.Packaging.targets +++ b/eng/package/nuget/NuGet.Packaging.targets @@ -2,11 +2,11 @@ - $(RootDir)Package\nuget + $(MSBuildThisFileDirectory) - $(RootDir)Package\nuget + $(MSBuildThisFileDirectory) IncludeSymbols=false diff --git a/eng/package/nuget/README.md b/eng/package/nuget/README.md index 0365dcb75..afcc1f187 100644 --- a/eng/package/nuget/README.md +++ b/eng/package/nuget/README.md @@ -22,8 +22,8 @@ System.Console.WriteLine(greetings("world")); ## Differences with CPython -While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/differences-from-c-python.md) for details. +While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](https://github.com/IronLanguages/ironpython3/blob/main/docs/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/package-compatibility.md) document for information on compatibility with popular Python packages. Note that to run most packages, IronPython Standard Library must be present. +See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/docs/package-compatibility.md) document for information on compatibility with popular Python packages. Note that to run most packages, IronPython Standard Library must be present. diff --git a/eng/package/pkg/Pkg.Packaging.targets b/eng/package/pkg/Pkg.Packaging.targets index ff8bee9a3..b577584cf 100644 --- a/eng/package/pkg/Pkg.Packaging.targets +++ b/eng/package/pkg/Pkg.Packaging.targets @@ -5,7 +5,7 @@ temp - Package/pkg + eng/package/pkg $(PackageDebFolder)/$(TempFolder) $(PackageTempFolder)/Library/Frameworks/IronPython.framework/Versions/$(PackageVersion) diff --git a/eng/package/zip/README.md b/eng/package/zip/README.md index a39ca5ec6..e245c0305 100644 --- a/eng/package/zip/README.md +++ b/eng/package/zip/README.md @@ -50,8 +50,8 @@ System.Console.WriteLine(greetings("world")); ## Differences with CPython -While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/differences-from-c-python.md) for details. +While compatibility with CPython is one of our main goals with IronPython 3, there are still some differences that may cause issues. See [Differences from CPython](https://github.com/IronLanguages/ironpython3/blob/main/docs/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/package-compatibility.md) document for information on compatibility with popular packages. Note that to run most packages, IronPython Standard Library must be present. +See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/docs/package-compatibility.md) document for information on compatibility with popular packages. Note that to run most packages, IronPython Standard Library must be present. diff --git a/eng/package/zip/Zip.Packaging.targets b/eng/package/zip/Zip.Packaging.targets index cb5db9c81..ce29d0fb7 100644 --- a/eng/package/zip/Zip.Packaging.targets +++ b/eng/package/zip/Zip.Packaging.targets @@ -6,8 +6,8 @@ - - + + diff --git a/eng/scripts/Install-IronPython.ps1 b/eng/scripts/Install-IronPython.ps1 index b549450be..c231142ec 100755 --- a/eng/scripts/Install-IronPython.ps1 +++ b/eng/scripts/Install-IronPython.ps1 @@ -30,7 +30,7 @@ PS>./make PS>./make package - PS>./Src/Scripts/Install-IronPython.ps1 env + PS>./eng/scripts/Install-IronPython.ps1 env These commands should be issued on a Powershell prompt with the current directory set to the project root. The project is first built, then packaged, and finally the script uses the zipfile produced during packaging to install IronPython in directory "env". @@ -60,7 +60,7 @@ if (-not $ZipFile) { if ($splitPSScriptRoot[-1] -eq "scripts" -and (Test-Path (Join-Path (Split-Path $PSScriptRoot) "lib"))) { # Script run from within already expanded zip file $unzipDir = $PSScriptRoot | Split-Path - } elseif ($splitPSScriptRoot[-2] -eq "Src" -and $splitPSScriptRoot[-1] -eq "Scripts") { + } elseif ($splitPSScriptRoot[-2] -eq "eng" -and $splitPSScriptRoot[-1] -eq "scripts") { # Script run from within a checked out code base # Locate the zip archive in the standard location of the package target $projectRoot = $PSScriptRoot | Split-Path | Split-Path diff --git a/eng/scripts/generate.py b/eng/scripts/generate.py index 6b7ac5b2f..7c819a378 100755 --- a/eng/scripts/generate.py +++ b/eng/scripts/generate.py @@ -15,13 +15,13 @@ def get_root_dir(): root_dir = get_root_dir() source_directories = [ - os.path.join(root_dir, "Src"), - os.path.join(root_dir, "Src", "DLR", "Src"), + os.path.join(root_dir, "src"), + os.path.join(root_dir, "src", "dlr", "Src"), ] exclude_directories = [ - os.path.join(root_dir, "Src", "DLR"), - os.path.join(root_dir, "Src", "StdLib"), + os.path.join(root_dir, "src", "dlr"), + os.path.join(root_dir, "src", "core", "IronPython.StdLib"), ] START_COMMON = "#region Generated" diff --git a/eng/scripts/generate_exception_factory.py b/eng/scripts/generate_exception_factory.py index ec1e4e4f8..8775f748c 100644 --- a/eng/scripts/generate_exception_factory.py +++ b/eng/scripts/generate_exception_factory.py @@ -172,7 +172,7 @@ def gen_expr_factory_com(cw): gen_expr_factory(cw, generate.root_dir + "\\..\\..\\ndp\\fx\\src\\Dynamic\\System\\Dynamic\\System.Dynamic.txt") def gen_expr_factory_scripting(cw): - gen_expr_factory(cw, generate.root_dir + "\\Src\\DLR\\Src\\Microsoft.Dynamic\\Microsoft.Scripting.txt") + gen_expr_factory(cw, generate.root_dir + "\\src\\dlr\\Src\\Microsoft.Dynamic\\Microsoft.Scripting.txt") def main(): return generate.generate( diff --git a/eng/scripts/generate_os_codes.py b/eng/scripts/generate_os_codes.py index 8975bf7fc..a020d1cb0 100644 --- a/eng/scripts/generate_os_codes.py +++ b/eng/scripts/generate_os_codes.py @@ -216,10 +216,11 @@ def generate_codes(cw, codeval, access, fmt, unix_only=False): value = windows_code_expr(codes, fmt) typ = "int" - if (all(c.isdigit() for c in value) or re.match(r'^0x[0-9a-fA-F]+$', value)): - n = eval(value) + for match in re.findall(r'0x[0-9a-fA-F]+', value): + n = eval(match) if n > 2**31 - 1 or n < -2**31: typ = "long" + break cw.write(f"{access} static {typ} {name} => {value};") @@ -286,6 +287,23 @@ def generate_LOCK_flags(cw): generate_codes(cw, codeval, 'public', hex, unix_only=True) +# python3 -c 'import termios;print(dict(sorted((s, getattr(termios, s)) for s in dir(termios) if s.startswith("TIOC"))))' +# Python 3.6.15 [GCC 12.2.0] on linux 6.10.14 +# Python 3.12.3 [GCC 13.2.0] on linux 6.8.0 +TIOC_cmd_linux = {'TIOCCONS': 21533, 'TIOCEXCL': 21516, 'TIOCGETD': 21540, 'TIOCGICOUNT': 21597, 'TIOCGLCKTRMIOS': 21590, 'TIOCGPGRP': 21519, 'TIOCGSERIAL': 21534, 'TIOCGSOFTCAR': 21529, 'TIOCGWINSZ': 21523, 'TIOCINQ': 21531, 'TIOCLINUX': 21532, 'TIOCMBIC': 21527, 'TIOCMBIS': 21526, 'TIOCMGET': 21525, 'TIOCMIWAIT': 21596, 'TIOCMSET': 21528, 'TIOCM_CAR': 64, 'TIOCM_CD': 64, 'TIOCM_CTS': 32, 'TIOCM_DSR': 256, 'TIOCM_DTR': 2, 'TIOCM_LE': 1, 'TIOCM_RI': 128, 'TIOCM_RNG': 128, 'TIOCM_RTS': 4, 'TIOCM_SR': 16, 'TIOCM_ST': 8, 'TIOCNOTTY': 21538, 'TIOCNXCL': 21517, 'TIOCOUTQ': 21521, 'TIOCPKT': 21536, 'TIOCPKT_DATA': 0, 'TIOCPKT_DOSTOP': 32, 'TIOCPKT_FLUSHREAD': 1, 'TIOCPKT_FLUSHWRITE': 2, 'TIOCPKT_NOSTOP': 16, 'TIOCPKT_START': 8, 'TIOCPKT_STOP': 4, 'TIOCSCTTY': 21518, 'TIOCSERCONFIG': 21587, 'TIOCSERGETLSR': 21593, 'TIOCSERGETMULTI': 21594, 'TIOCSERGSTRUCT': 21592, 'TIOCSERGWILD': 21588, 'TIOCSERSETMULTI': 21595, 'TIOCSERSWILD': 21589, 'TIOCSER_TEMT': 1, 'TIOCSETD': 21539, 'TIOCSLCKTRMIOS': 21591, 'TIOCSPGRP': 21520, 'TIOCSSERIAL': 21535, 'TIOCSSOFTCAR': 21530, 'TIOCSTI': 21522, 'TIOCSWINSZ': 21524} +# Python 3.12.0 [Clang 14.0.6 ] on darwin 24.2.0 +TIOC_cmd_darwin = {'TIOCCONS': 2147775586, 'TIOCEXCL': 536900621, 'TIOCGETD': 1074033690, 'TIOCGPGRP': 1074033783, 'TIOCGSIZE': 1074295912, 'TIOCGWINSZ': 1074295912, 'TIOCMBIC': 2147775595, 'TIOCMBIS': 2147775596, 'TIOCMGET': 1074033770, 'TIOCMSET': 2147775597, 'TIOCM_CAR': 64, 'TIOCM_CD': 64, 'TIOCM_CTS': 32, 'TIOCM_DSR': 256, 'TIOCM_DTR': 2, 'TIOCM_LE': 1, 'TIOCM_RI': 128, 'TIOCM_RNG': 128, 'TIOCM_RTS': 4, 'TIOCM_SR': 16, 'TIOCM_ST': 8, 'TIOCNOTTY': 536900721, 'TIOCNXCL': 536900622, 'TIOCOUTQ': 1074033779, 'TIOCPKT': 2147775600, 'TIOCPKT_DATA': 0, 'TIOCPKT_DOSTOP': 32, 'TIOCPKT_FLUSHREAD': 1, 'TIOCPKT_FLUSHWRITE': 2, 'TIOCPKT_NOSTOP': 16, 'TIOCPKT_START': 8, 'TIOCPKT_STOP': 4, 'TIOCSCTTY': 536900705, 'TIOCSETD': 2147775515, 'TIOCSPGRP': 2147775606, 'TIOCSSIZE': 2148037735, 'TIOCSTI': 2147578994, 'TIOCSWINSZ': 2148037735} + +def generate_TIOC_commands(cw): + codeval = {} + for name in TIOC_cmd_linux: + set_value(codeval, name, TIOC_cmd_linux[name], linux_idx) + for name in TIOC_cmd_darwin: + set_value(codeval, name, TIOC_cmd_darwin[name], darwin_idx) + codeval = OrderedDict(sorted(codeval.items())) + generate_codes(cw, codeval, 'public', hex, unix_only=True) + + def main(): return generate( ("Errno Codes", generate_errno_codes), @@ -296,6 +314,7 @@ def main(): ("FD Commands", generate_FD_commands), ("Directory Notify Flags", generate_DN_flags), ("LOCK Flags", generate_LOCK_flags), + ("TIOC Commands", generate_TIOC_commands), ) if __name__ == "__main__": diff --git a/make.ps1 b/make.ps1 index e4575bee7..3f02b5aa6 100755 --- a/make.ps1 +++ b/make.ps1 @@ -43,7 +43,7 @@ function EnsureMSBuild() { function Main([String] $target, [String] $configuration) { # verify that the DLR submodule has been initialized - if(![System.Linq.Enumerable]::Any([System.IO.Directory]::EnumerateFileSystemEntries([System.IO.Path]::Combine($_BASEDIR, "Src/DLR")))) { + if(![System.Linq.Enumerable]::Any([System.IO.Directory]::EnumerateFileSystemEntries([System.IO.Path]::Combine($_BASEDIR, "src/dlr")))) { if(Get-Command git -ErrorAction SilentlyContinue) { & git submodule update --init } else { @@ -106,11 +106,30 @@ function GenerateRunSettings([String] $framework, [String] $platform, [String] $ $doc.AppendChild($runSettings) | Out-Null - $fileName = [System.IO.Path]::Combine($_BASEDIR, "Src", "IronPythonTest", "runsettings.$framework.xml") + $fileName = [System.IO.Path]::Combine($_BASEDIR, "tests", "IronPython.Tests", "runsettings.$framework.xml") $doc.Save($fileName) return $fileName } +function RunTestTasksInForeground($tasks) { + $failedTests = @() + foreach ($task in $tasks) { + & dotnet test $task.params + Write-Host + if($LastExitCode -ne 0) { + $global:Result = $LastExitCode + Write-Host -ForegroundColor Red "$($task.name) failed" + $failedTests += $task.name + } else { + Write-Host "$($task.name) succeeded" + } + if ($failedTests) { + Write-Host -ForegroundColor Red "$($failedTests.Count) test task(s) failed: $($failedTests -Join ", ")" + } + Write-Host + } +} + function RunTestTasks($tasks) { $maxJobs = $jobs if ($tasks.Count -lt $maxJobs) { @@ -148,7 +167,7 @@ function RunTestTasks($tasks) { $testName = $tasks[$bgJobs.$finished].name Write-Host if ($finished.State -eq 'Failed') { - Write-Host "$testName failed" + Write-Host -ForegroundColor Red "$testName failed" $global:Result = $finished.ChildJobs[0].JobStateInfo.Reason.ErrorRecord.TargetObject $failedTests += $testName } else { @@ -165,7 +184,7 @@ function RunTestTasks($tasks) { Write-Host "$($bgJobs.Count) jobs running: $(($bgJobs.values | ForEach-Object {$tasks[$_].name}) -Join ", ")" Write-Host "$($tasks.Count - $nextJob) jobs pending: $(($nextJob..$tasks.Count | ForEach-Object {$tasks[$_].name}) -Join ", ")" if ($failedTests) { - Write-Host "$($failedTests.Count) jobs failed: $($failedTests -Join ", ")" + Write-Host -ForegroundColor Red "$($failedTests.Count) jobs failed: $($failedTests -Join ", ")" } Write-Host } @@ -182,7 +201,7 @@ function Test([String] $target, [String] $configuration, [String[]] $frameworks, $runSettings = GenerateRunSettings $framework $platform $configuration $runIgnored function createTask($filtername, $filter) { - [Object[]] $args = @("$_BASEDIR/Src/IronPythonTest/IronPythonTest.csproj", '-f', "$framework", '-o', "$_BASEDIR/bin/$configuration/$framework", '-c', "$configuration", '--no-build', '-v', 'n', '-l', "trx;LogFileName=$filtername-$framework-$configuration-result.trx", '-s', "$runSettings", "--filter=$filter"); + [Object[]] $args = @("$_BASEDIR/tests/IronPython.Tests/IronPython.Tests.csproj", '-f', "$framework", '-o', "$_BASEDIR/bin/$configuration/$framework", '-c', "$configuration", '--no-build', '-v', 'n', '-l', "trx;LogFileName=$filtername-$framework-$configuration-result.trx", '-s', "$runSettings", "--filter=$filter"); Write-Host "Enqueue [$framework $filtername]:" Write-Host "dotnet test $args" Write-Host @@ -211,7 +230,11 @@ function Test([String] $target, [String] $configuration, [String[]] $frameworks, } } - RunTestTasks $tasks + if ($jobs -eq 0) { + RunTestTasksInForeground $tasks + } else { + RunTestTasks $tasks + } } function Purge() { @@ -222,7 +245,7 @@ function Purge() { Get-ChildItem -Name "obj" -Directory -Path "$_BASEDIR" -Recurse | Remove-Item -Force -Recurse Write-Verbose "Deleting ""bin"" directories..." - foreach ($dir in @("", (Join-Path "IronPythonAnalyzer" "IronPythonAnalyzer"))) { + foreach ($dir in @("", (Join-Path "src" "roslyn" "IronPython.Analyzer"))) { if (Test-Path (Join-Path $_BASEDIR $dir "bin" -OutVariable targetPath)) { Remove-Item -Path $targetPath -Force -Recurse } @@ -239,7 +262,7 @@ function Purge() { } Write-Verbose "Deleting test run settings..." - Remove-Item -Path (Join-Path $_BASEDIR "Src" "IronPythonTest" "runsettings.*.xml") + Remove-Item -Path (Join-Path $_BASEDIR "tests" "IronPython.Tests" "runsettings.*.xml") Write-Information "Done. Consider restoring dependencies." -InformationAction Continue } diff --git a/src/core/IronPython.Modules/IronPython.Modules.csproj b/src/core/IronPython.Modules/IronPython.Modules.csproj index 4fc2771d2..1f6f3c1a8 100644 --- a/src/core/IronPython.Modules/IronPython.Modules.csproj +++ b/src/core/IronPython.Modules/IronPython.Modules.csproj @@ -10,7 +10,7 @@ True - ..\..\Util\References\Mono.Posix.dll + $(UtilsDir)\References\Mono.Posix.dll @@ -26,7 +26,7 @@ - + false Analyzer diff --git a/src/core/IronPython.Modules/_ctypes_test.cs b/src/core/IronPython.Modules/_ctypes_test.cs index 3ab176d33..7acf17617 100644 --- a/src/core/IronPython.Modules/_ctypes_test.cs +++ b/src/core/IronPython.Modules/_ctypes_test.cs @@ -14,11 +14,11 @@ namespace IronPython.Modules { public static class CTypesTest { private static string FindRoot() { - // we start at the current directory and look up until we find the "Src" directory + // we start at the current directory and look up until we find the "src" directory var current = System.Reflection.Assembly.GetExecutingAssembly().Location; var found = false; while (!found && !string.IsNullOrEmpty(current)) { - var test = Path.Combine(current, "Src", "StdLib", "Lib"); + var test = Path.Combine(current, "src", "core", "IronPython.StdLib", "lib"); if (Directory.Exists(test)) { return current; } @@ -28,7 +28,7 @@ private static string FindRoot() { return string.Empty; } - public static string __file__ = Path.Combine(FindRoot(), "Tests", string.Format("_ctypes_test_{0}{1}.pyd", Environment.OSVersion.Platform == PlatformID.Win32NT ? "win" : Environment.OSVersion.Platform == PlatformID.MacOSX ? "macOS" : "linux", Environment.Is64BitProcess ? 64 : 32)); + public static string __file__ = Path.Combine(FindRoot(), "tests", "suite", string.Format("_ctypes_test_{0}{1}.pyd", Environment.OSVersion.Platform == PlatformID.Win32NT ? "win" : Environment.OSVersion.Platform == PlatformID.MacOSX ? "macOS" : "linux", Environment.Is64BitProcess ? 64 : 32)); } } diff --git a/src/core/IronPython.Modules/fcntl.cs b/src/core/IronPython.Modules/fcntl.cs index 657914e91..a5fc4bd61 100644 --- a/src/core/IronPython.Modules/fcntl.cs +++ b/src/core/IronPython.Modules/fcntl.cs @@ -27,6 +27,33 @@ a file object. """; + // supporting fcntl.ioctl(fileno, termios.TIOCGWINSZ, buf) + // where buf = array.array('h', [0, 0, 0, 0]) + public static object ioctl(CodeContext context, int fd, int cmd, [NotNone] IBufferProtocol arg, int mutate_flag = 1) { + if (cmd == PythonTermios.TIOCGWINSZ) { + using IPythonBuffer buf = arg.GetBuffer(); + + Span winsize = stackalloc short[4]; + winsize[0] = (short)Console.WindowHeight; + winsize[1] = (short)Console.WindowWidth; + winsize[2] = (short)Console.BufferHeight; // buffer height and width are not accurate on macOS + winsize[3] = (short)Console.BufferWidth; + Span payload = MemoryMarshal.Cast(winsize); + + if (buf.IsReadOnly || mutate_flag == 0) { + byte[] res = buf.ToArray(); + payload.Slice(0, Math.Min(payload.Length, res.Length)).CopyTo(res); + return Bytes.Make(res); + } else { + var res = buf.AsSpan(); + payload.Slice(0, Math.Min(payload.Length, res.Length)).CopyTo(res); + return 0; + } + } + throw new NotImplementedException($"ioctl: unsupported command {cmd}"); + } + + // FD Flags public static int FD_CLOEXEC = 1; public static int FASYNC => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0040 : 0x2000; diff --git a/src/core/IronPython.Modules/mmap.cs b/src/core/IronPython.Modules/mmap.cs index b59d7868f..8453bcb8e 100644 --- a/src/core/IronPython.Modules/mmap.cs +++ b/src/core/IronPython.Modules/mmap.cs @@ -289,20 +289,23 @@ public class MmapDefault : IWeakReferenceable { private readonly MemoryMappedFileAccess _fileAccess; private readonly SafeFileHandle? _handle; - // RefCount | Closed | Meaning - // ---------+--------+-------------------------------- - // 0 | 0 | Not fully initialized - // 1 | 0 | Fully initialized, not being used by any threads - // >1 | 0 | Object in use by one or more threads - // >0 | 1 | Close/dispose requested, no more addrefs allowed, some threads may still be using it - // 0 | 1 | Fully disposed - private volatile int _state; // Combined ref count and closed/disposed flags (so we can atomically modify them). + // RefCount | Closed | Exclusive |Meaning + // ---------+--------+-----------+--------------------- + // 0 | 0 | 0 | Not fully initialized + // 1 | 0 | 0 | Fully initialized, not being used by any threads + // >1 | 0 | 0 | Object in regular use by one or more threads + // 2 | 0 | 1 | Object in exclusive use (`resize` in progress) + // >0 | 1 | - | Close/dispose requested, no more addrefs allowed, some threads may still be using it + // 0 | 1 | 0 | Fully disposed + // Other combinations are invalid state + private volatile int _state; // Combined ref count and state flags (so we can atomically modify them). private static class StateBits { - public const int Closed = 0b_01; // close/dispose requested; no more addrefs allowed - public const int Exclusive = 0b_10; // TODO: to manage exclusive access for resize - public const int RefCount = unchecked(~0b_11); // 2 bits reserved for state management; ref count gets 29 bits (sign bit unused) - public const int RefCountOne = 1 << 2; // ref count 1 shifted over 2 state bits + public const int Closed = 0b_001; // close/dispose requested; no more addrefs allowed + public const int Exclusive = 0b_010; // exclusive access for resize requested/in progress + public const int Exporting = 0b_100; // TODO: buffer exports extant; exclusive addrefs temporarily not allowed + public const int RefCount = unchecked(~0b_111); // 3 bits reserved for state management; ref count gets 29 bits (sign bit unused) + public const int RefCountOne = 1 << 3; // ref count 1 shifted over 3 state bits } @@ -563,33 +566,74 @@ public void __exit__(CodeContext/*!*/ context, params object[] excinfo) { public bool closed => (_state & StateBits.Closed) == StateBits.Closed; // Dispose already requested, will self-dispose when ref count drops to 0. - private bool AddRef() { + /// + /// Try to add a reference to the mmap object. Return true on success. + /// + /// + /// The reference count is incremented atomically and kept in the mmap state variable. + /// The reference count is not incremented if the state variable indicates that the mmap + /// in in the process of closing or currently in exclusive use. + /// + /// + /// If true, requests an exclusive reference. + /// + /// + /// If the reference could not be added, this parameter will contain the bit that was set preventing the addref. + /// + private bool TryAddRef(bool exclusive, out int reason) { int oldState, newState; do { oldState = _state; if ((oldState & StateBits.Closed) == StateBits.Closed) { // mmap closed, dispose already requested, no more addrefs allowed + reason = StateBits.Closed; + return false; + } + if ((oldState & StateBits.Exclusive) == StateBits.Exclusive) { + // mmap in exclusive use, temporarily no more addrefs allowed + reason = StateBits.Exclusive; + return false; + } + if (exclusive && (oldState & StateBits.Exporting) == StateBits.Exporting) { + // mmap exporting, exclusive addrefs temporarily not allowed + reason = StateBits.Exporting; return false; } Debug.Assert((oldState & StateBits.RefCount) > 0, "resurrecting disposed mmap object (disposed without being closed)"); newState = oldState + StateBits.RefCountOne; + if (exclusive) { + newState |= StateBits.Exclusive; + } } while (Interlocked.CompareExchange(ref _state, newState, oldState) != oldState); + reason = 0; return true; } - private void Release() { + /// + /// Atomically release a reference to the mmap object, and optionally reset the exclusive state flag. + /// + /// + /// If the reference count drops to 0, the mmap object is disposed. + /// + /// + /// If true, the exclusive reference is released. + /// + private void Release(bool exclusive) { bool performDispose; int oldState, newState; do { oldState = _state; + Debug.Assert(!exclusive || (oldState & StateBits.Exclusive) == StateBits.Exclusive, "releasing exclusive reference without being exclusive"); Debug.Assert((oldState & StateBits.RefCount) > 0, "mmap ref count underflow (too many releases)"); performDispose = (oldState & StateBits.RefCount) == StateBits.RefCountOne; + Debug.Assert(!performDispose || (oldState & StateBits.Closed) == StateBits.Closed, "disposing mmap object without being closed"); + newState = oldState - StateBits.RefCountOne; - if (performDispose) { - newState |= StateBits.Closed; // most likely already closed + if (exclusive) { + newState &= ~StateBits.Exclusive; } } while (Interlocked.CompareExchange(ref _state, newState, oldState) != oldState); @@ -610,25 +654,17 @@ public void close() { #if NET5_0_OR_GREATER if ((Interlocked.Or(ref _state, StateBits.Closed) & StateBits.Closed) != StateBits.Closed) { // freshly closed, release the construction time reference - Release(); + Release(exclusive: false); } #else - int current = _state; - while (true) - { - int newState = current | StateBits.Closed; - int oldState = Interlocked.CompareExchange(ref _state, newState, current); - if (oldState == current) - { - // didn't change in the meantime, exchange with newState completed - if ((oldState & StateBits.Closed) != StateBits.Closed) { - // freshly closed, release the construction time reference - Release(); - } - return; - } - // try again to set the bit - current = oldState; + int oldState, newState; + do { + oldState = _state; + newState = oldState | StateBits.Closed; + } while (Interlocked.CompareExchange(ref _state, newState, oldState) != oldState); + if ((oldState & StateBits.Closed) != StateBits.Closed) { + // freshly closed, release the construction time reference + Release(exclusive: false); } #endif } @@ -861,8 +897,9 @@ public string readline() { } } + public void resize(long newsize) { - using (new MmapLocker(this)) { + using (new MmapLocker(this, exclusive: true)) { if (_fileAccess is not MemoryMappedFileAccess.ReadWrite and not MemoryMappedFileAccess.ReadWriteExecute) { throw PythonOps.TypeError("mmap can't resize a readonly or copy-on-write memory map."); } @@ -961,6 +998,7 @@ public void resize(long newsize) { } } + public object rfind([NotNone] IBufferProtocol s) { using (new MmapLocker(this)) { return RFindWorker(s, Position, _view.Capacity); @@ -1210,18 +1248,32 @@ private static long GetFileSizeUnix(SafeFileHandle handle) { private readonly struct MmapLocker : IDisposable { private readonly MmapDefault _mmap; - - public MmapLocker(MmapDefault mmap) { - if (!mmap.AddRef()) { - throw PythonOps.ValueError("mmap closed or invalid"); + private readonly bool _exclusive; + + public MmapLocker(MmapDefault mmap, bool exclusive = false) { + if (!mmap.TryAddRef(exclusive, out int reason)) { + if (reason == StateBits.Closed) { + // mmap is permanently closed + throw PythonOps.ValueError("mmap closed or invalid"); + } else if (reason == StateBits.Exporting) { + // map is temporarily exporting buffers obtained through the buffer protocol + throw PythonOps.BufferError("mmap can't perform the operation with extant buffers exported"); + } else if (reason == StateBits.Exclusive) { + // mmap is temporarily in exclusive use + throw PythonNT.GetOsError(PythonErrno.EAGAIN); + } else { + // should not happen + throw new InvalidOperationException("mmap state error"); + } } _mmap = mmap; + _exclusive = exclusive; } #region IDisposable Members public readonly void Dispose() { - _mmap.Release(); + _mmap.Release(_exclusive); } #endregion diff --git a/src/core/IronPython.Modules/termios.cs b/src/core/IronPython.Modules/termios.cs new file mode 100644 index 000000000..61696b8c8 --- /dev/null +++ b/src/core/IronPython.Modules/termios.cs @@ -0,0 +1,538 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Collections; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +using Microsoft.Scripting.Runtime; + +using IronPython.Runtime; +using IronPython.Runtime.Operations; + +using static IronPython.Modules.PythonIOModule; + + +[assembly: PythonModule("termios", typeof(IronPython.Modules.PythonTermios), PlatformsAttribute.PlatformFamily.Unix)] +namespace IronPython.Modules; + +[SupportedOSPlatform("linux")] +[SupportedOSPlatform("macos")] +public static class PythonTermios { + + public const string __doc__ = "Stub of termios, just enough to support module tty."; + // and also prompt_toolkit.terminal.vt100_input + +#pragma warning disable IPY01 // Parameter which is marked not nullable does not have the NotNullAttribute + [SpecialName] + public static void PerformModuleReload(PythonContext context, PythonDictionary dict) + => context.EnsureModuleException("termioserror", dict, "error", "termios"); +#pragma warning restore IPY01 // Parameter which is marked not nullable does not have the NotNullAttribute + + + #region Generated TIOC Commands + + // *** BEGIN GENERATED CODE *** + // generated by function: generate_TIOC_commands from: generate_os_codes.py + + + public static long TIOCCONS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80047462 : 0x541d; + + public static int TIOCEXCL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x2000740d : 0x540c; + + public static int TIOCGETD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x4004741a : 0x5424; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCGICOUNT => 0x545d; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCGLCKTRMIOS => 0x5456; + + public static int TIOCGPGRP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x40047477 : 0x540f; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCGSERIAL => 0x541e; + + [PythonHidden(PlatformID.Unix)] + [SupportedOSPlatform("macos")] + public static int TIOCGSIZE => 0x40087468; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCGSOFTCAR => 0x5419; + + public static int TIOCGWINSZ => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x40087468 : 0x5413; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCINQ => 0x541b; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCLINUX => 0x541c; + + public static long TIOCMBIC => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8004746b : 0x5417; + + public static long TIOCMBIS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8004746c : 0x5416; + + public static int TIOCMGET => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x4004746a : 0x5415; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCMIWAIT => 0x545c; + + public static long TIOCMSET => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8004746d : 0x5418; + + public static int TIOCM_CAR => 0x40; + + public static int TIOCM_CD => 0x40; + + public static int TIOCM_CTS => 0x20; + + public static int TIOCM_DSR => 0x100; + + public static int TIOCM_DTR => 0x2; + + public static int TIOCM_LE => 0x1; + + public static int TIOCM_RI => 0x80; + + public static int TIOCM_RNG => 0x80; + + public static int TIOCM_RTS => 0x4; + + public static int TIOCM_SR => 0x10; + + public static int TIOCM_ST => 0x8; + + public static int TIOCNOTTY => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x20007471 : 0x5422; + + public static int TIOCNXCL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x2000740e : 0x540d; + + public static int TIOCOUTQ => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x40047473 : 0x5411; + + public static long TIOCPKT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80047470 : 0x5420; + + public static int TIOCPKT_DATA => 0x0; + + public static int TIOCPKT_DOSTOP => 0x20; + + public static int TIOCPKT_FLUSHREAD => 0x1; + + public static int TIOCPKT_FLUSHWRITE => 0x2; + + public static int TIOCPKT_NOSTOP => 0x10; + + public static int TIOCPKT_START => 0x8; + + public static int TIOCPKT_STOP => 0x4; + + public static int TIOCSCTTY => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x20007461 : 0x540e; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSERCONFIG => 0x5453; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSERGETLSR => 0x5459; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSERGETMULTI => 0x545a; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSERGSTRUCT => 0x5458; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSERGWILD => 0x5454; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSERSETMULTI => 0x545b; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSERSWILD => 0x5455; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSER_TEMT => 0x1; + + public static long TIOCSETD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8004741b : 0x5423; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSLCKTRMIOS => 0x5457; + + public static long TIOCSPGRP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80047476 : 0x5410; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSSERIAL => 0x541f; + + [PythonHidden(PlatformID.Unix)] + [SupportedOSPlatform("macos")] + public static long TIOCSSIZE => 0x80087467; + + [PythonHidden(PlatformID.MacOSX)] + [SupportedOSPlatform("linux")] + public static int TIOCSSOFTCAR => 0x541a; + + public static long TIOCSTI => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80017472 : 0x5412; + + public static long TIOCSWINSZ => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80087467 : 0x5414; + + // *** END GENERATED CODE *** + + #endregion + + + #region Other Public Constants + // Linux: glibc/bits/termios.h (/usr/include/{x86_64,aarch64}-linux-gnu/) + // macOS: usr/include/sys/termios.h (/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk) + + // iflag + public const int IGNBRK = 0x0001; // ignore break condition + public const int BRKINT = 0x0002; // signal interrupt on break + public const int IGNPAR = 0x0004; // ignore characters with parity errors + public const int PARMRK = 0x0008; // mark parity and framing errors + public const int INPCK = 0x0010; // enable input parity check + public const int ISTRIP = 0x0020; // mask off 8th bit + public const int INLCR = 0x0040; // map NL into CR on input + public const int IGNCR = 0x0080; // ignore CR + public const int ICRNL = 0x0100; // map CR to NL on input + public static int IXON => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? + 0x0200 : 0x0400; // enable start output control + public static int IXOFF => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? + 0x0400 : 0x1000; // enable stop output control + public const int IXANY = 0x0800; // any char will restart after stop + public const int IMAXBEL = 0x2000; // ring bell on input queue full + public const int IUTF8 = 0x4000; // maintain state for UTF-8 VERASE + + + // oflag + public const int OPOST = 0x0001; // enable output processing + public static int ONLCR => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? + 0x0002 : 0x0004; // map NL to CR-NL + + + // cflag + public static int CSIZE => CS5 | CS6 | CS7 | CS8; // number of bits per character + public static int CS5 => 0x0000; // 5 bits per character + public static int CS6 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0100 : 0x0010; // 6 bits per character + public static int CS7 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0200 : 0x0020; // 7 bits per character + public static int CS8 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0300 : 0x0030; // 8 bits per character + public static int CREAD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0800 : 0x0080; // enable receiver + public static int PARENB => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x1000 : 0x0100; // parity enable + public static int HUPCL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x4000 : 0x0400; // hang up on last close + + [PythonHidden(PlatformID.MacOSX)] + public static int CBAUD => 0x100f; // mask for baud rate + [PythonHidden(PlatformID.MacOSX)] + public static int CBAUDEX => 0x1000; // extra baud speed mask + + + // lflag + public static uint ECHOKE => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0001u : 0x0800u; // visual erase for line kill + public static uint ECHOE => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0002u : 0x0010u; // visually erase chars + public static uint ECHOK => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0004u : 0x0020u; // echo NL after line kill + public static uint ECHO => 0x0008u; // enable echoing of input characters + public static uint ECHONL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0010u : 0x0040u; // echo NL even if ECHO is off + public static uint ECHOPRT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0020u : 0x0400u; // visual erase mode for hardcopy + public static uint ECHOCTL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0040u : 0x0200u; // echo control characters as ^(Char) + public static uint ISIG => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0080u : 0x0001u; // enable signals + public static uint ICANON => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0100u : 0x0002u; // canonical mode + public static uint IEXTEN => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0400u : 0x8000u; // enable extended input character processing + public static uint TOSTOP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0040_0000u : 0x0100u; // stop background jobs from output + public static uint FLUSHO => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0080_0000u : 0x1000u; // output being flushed + public static uint PENDIN => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x2000_0000u : 0x4000u; // retype pending input + public static uint NOFLSH => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8000_0000u : 0x0080u; // don't flush after interrupt + + + // when the changes take effect: + public const int TCSANOW = 0; // change immediately + public const int TCSADRAIN = 1; // flush output, then change + public const int TCSAFLUSH = 2; // discard input, flush output, then change + + + // control characters + public static int VEOF => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0 : 4; + public static int VEOL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1 : 11; + public static int VEOL2 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 2 : 16; + public static int VERASE => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 3 : 2; + public static int VWERASE => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 4 : 14; + public static int VKILL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 5 : 3; + public static int VREPRINT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 6 : 12; + public static int VINTR => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 8 : 0; + public static int VQUIT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 9 : 1; + public static int VSUSP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 10 : 10; + public static int VSTART => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 12 : 8; + public static int VSTOP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 13 : 9; + public static int VLNEXT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 14 : 15; + public static int VDISCARD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 15 : 13; + public static int VMIN => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 16 : 6; + public static int VTIME => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 17 : 5; + [PythonHidden(PlatformID.MacOSX)] + public static int VSWTC => 7; + public static int NCCS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 20 : 32; + + + // tcflush() uses these + public static int TCIFLUSH => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1 : 0; // flush input + public static int TCOFLUSH => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 2 : 1; // flush output + public static int TCIOFLUSH => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 3 : 2; // flush both + + + // tcflow() uses these + public static int TCOOFF => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1 : 0; // suspend output + public static int TCOON => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 2 : 1; // restart output + public static int TCIOFF => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 3 : 2; // transmit STOP character + public static int TCION => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 4 : 3; // transmit START character + + // baud rates + public static int B0 => 0; + public static int B50 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 50 : 1; + public static int B75 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 75 : 2; + public static int B110 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 110 : 3; + public static int B134 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 134 : 4; + public static int B150 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 150 : 5; + public static int B200 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 200 : 6; + public static int B300 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 300 : 7; + public static int B600 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 600 : 8; + public static int B1200 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1200 : 9; + public static int B1800 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1800 : 10; + public static int B2400 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 2400 : 11; + public static int B4800 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 4800 : 12; + public static int B9600 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 9600 : 13; + public static int B19200 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 19200 : 14; + public static int B38400 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 38400 : 15; + public static int B57600 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 57600 : 0x1001; + public static int B115200 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 115200 : 0x1002; + public static int B230400 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 230400 : 0x1003; + // higher baud rates are not defined on macOS + + public static object tcgetattr(CodeContext context, int fd) { + if (fd < 0) throw PythonOps.ValueError("file descriptor cannot be a negative integer ({0})", fd); + if (fd > 0) throw new NotImplementedException("termios support only for stdin"); + + if (context.LanguageContext.SystemStandardIn is not TextIOWrapper stdin) { + throw new NotImplementedException("termios support only for stdin"); + } + if (stdin.closed || !stdin.isatty(context) || stdin.fileno(context) != 0 || Console.IsInputRedirected) { + throw new NotImplementedException("termios support only for stdin connected to tty"); + } + + var cc = new PythonList(NCCS); + var specialChars = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? macos__specialChars : linux__specialChars; + for (int i = 0; i < NCCS; i++) { + byte c = i < specialChars.Length ? specialChars[i] : (byte)0; + cc.Add(Bytes.FromByte(c)); + } + return PythonList.FromArrayNoCopy([ + _iflag, + _oflag, + _cflag, + _lflag, + _ispeed, + _ospeed, + cc + ]); + } + + public static object tcgetattr(CodeContext context, object? file) { + if (!ReferenceEquals(file, context.LanguageContext.SystemStandardIn)) { + throw new NotImplementedException("termios support only for stdin"); + } + return tcgetattr(context, 0); + } + + + public static void tcsetattr(CodeContext context, int fd, int when, object? attributes) { + if (fd != 0) throw new NotImplementedException(); + + if (context.LanguageContext.SystemStandardIn is not TextIOWrapper stdin) { + throw new NotImplementedException("termios support only for stdin"); + } + if (stdin.closed || !stdin.isatty(context) || stdin.fileno(context) != 0 || Console.IsInputRedirected) { + throw new NotImplementedException("termios support only for stdin connected to tty"); + } + + if (attributes is not IList attrs || attrs.Count != 7) { + throw PythonOps.TypeError("tcsetattr, arg 3: must be 7 element list"); + } + + uint newLflag = attrs[LFlagIdx] switch { + int i => (uint)i, + uint ui => ui, + long l => (uint)l, + BigInteger bi => (uint)bi, + Extensible ebi => (uint)ebi.Value, + _ => throw PythonOps.TypeErrorForBadInstance("tcsetattr: an integer is required (got type {0})", attrs[LFlagIdx]) + }; + + if (attrs[SpecialCharsIdx] is not IList chars || chars.Count != NCCS) { + throw PythonOps.TypeError("tcsetattr, atributes[{0}] must be {1} element list", SpecialCharsIdx, NCCS); + } + + var specialChars = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? macos__specialChars : linux__specialChars; + for (int i = 0; i < chars.Count; i++) { + object? o = chars[i]; + int newVal; + if (o is Bytes b && b.Count == 1) { + newVal = b[0]; + } else if (!Converter.TryConvertToInt32(o, out newVal)) { + throw PythonOps.TypeError("tcsetattr: elements of attributes must be characters or integers"); + } + int expected = i < specialChars.Length ? specialChars[i] : 0; + if (newVal != expected) { + throw new NotImplementedException("tcsetattr: setting special characters is not supported"); + } + } + + if (when != TCSANOW) { + stdin.flush(context); + } + + if ((newLflag & (ECHO | ICANON | IEXTEN | ISIG)) == 0) { + setraw(context, stdin); + } else { + setcbreak(context, stdin); + } + } + + + public static void tcsetattr(CodeContext context, object? file, int when, [NotNone] object attributes) { + if (!ReferenceEquals(file, context.LanguageContext.SystemStandardIn)) { + throw new NotImplementedException("termios support only for stdin"); + } + tcsetattr(context, 0, when, attributes); + } + + #endregion + + + private const int IFlagIdx = 0; + private const int OFlagIdx = 1; + private const int CFlagIdx = 2; + private const int LFlagIdx = 3; + private const int ISpeedIdx = 4; + private const int OSpeedIdx = 5; + private const int SpecialCharsIdx = 6; + + private static int _iflag => BRKINT | ICRNL | IXON | IXANY | IMAXBEL | IUTF8; + private static int _oflag => OPOST | ONLCR; + private static int _cflag => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? + CS8 | CREAD | HUPCL + : CS8 | CREAD | HUPCL | (CBAUD & ~CBAUDEX); + private static uint _lflag => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? + ECHOKE | ECHOE | ECHOK | ECHO | ECHOCTL | ISIG | ICANON | IEXTEN | PENDIN + : ECHOKE | ECHOE | ECHOK | ECHO | ECHOCTL | ISIG | ICANON | IEXTEN; + private static int _ispeed => B38400; + private static int _ospeed => B38400; + + private static readonly byte[] macos__specialChars = [ + (byte)0x04, // VEOF ^D + (byte)0xff, // VEOL + (byte)0xff, // VEOL2 + (byte)0x7f, // VERASE DEL + (byte)0x17, // VWERASE ^W + (byte)0x15, // VKILL ^U + (byte)0x12, // VREPRINT ^R + (byte)0x00, // reserved + (byte)0x03, // VINTR ^C + (byte)0x1c, // VQUIT ^\ + (byte)0x1a, // VSUSP ^Z + (byte)0x19, // VDSUSP ^Y + (byte)0x11, // VSTART ^Q + (byte)0x13, // VSTOP ^S + (byte)0x16, // VLNEXT ^V + (byte)0x0f, // VDISCARD ^O + (byte)0x01, // VMIN + (byte)0x00, // VTIME + (byte)0x14, // VSTATUS ^T + (byte)0x00, // reserved + ]; + + private static readonly byte[] linux__specialChars = [ + (byte)0x03, // VINTR ^C + (byte)0x1c, // VQUIT ^\ + (byte)0x7f, // VERASE DEL + (byte)0x15, // VKILL ^U + (byte)0x04, // VEOF ^D + (byte)0x00, // VTIME + (byte)0x01, // VMIN + (byte)0x00, // VSWTC + (byte)0x11, // VSTART ^Q + (byte)0x13, // VSTOP ^S + (byte)0x1a, // VSUSP ^Z + (byte)0xff, // VEOL + (byte)0x12, // VREPRINT ^R + (byte)0x0f, // VDISCARD ^O + (byte)0x17, // VWERASE ^W + (byte)0x16, // VLNEXT ^V + (byte)0xff, // VEOL2 + // rest are reserved + ]; + + + private static object? _savedRawStdin; + + private static void setraw(CodeContext context, TextIOWrapper stdin) { + if (_savedRawStdin is null && stdin.buffer is BufferedReader reader) { + _savedRawStdin = reader.raw; + reader.raw = new RawConsole(context); + } + } + + private static void setcbreak(CodeContext context, TextIOWrapper stdin) { + if (_savedRawStdin is not null + && stdin.buffer is BufferedReader reader + && reader.raw is RawConsole) { + + reader.raw = _savedRawStdin; + _savedRawStdin = null; + } + } + + private class RawConsole : _RawIOBase { + public RawConsole(CodeContext context) : base(context) { + } + + public override object? read(CodeContext context, object? size=null) { + int intSize = size switch { + null => -1, + int i => i, + BigInteger bi => (int)bi, + Extensible ebi => (int)ebi.Value, + _ => throw PythonOps.TypeErrorForBadInstance("integer argument expected, got '{0}'", size) + }; + if (intSize == 0) return null; + + ConsoleKeyInfo info = Console.ReadKey(intercept: true); + return Bytes.FromByte(unchecked((byte)info.KeyChar)); + } + + public override int fileno(CodeContext context) => 0; + public override bool isatty(CodeContext context) => true; + } + + private static int ToInt(this object? o) + => o switch { + int i => i, + BigInteger bi => (int)bi, + Extensible ebi => (int)ebi.Value, + _ => throw PythonOps.TypeErrorForBadInstance("an integer is required (got type {0})", o) + }; +} diff --git a/src/core/IronPython.StdLib/.gitattributes b/src/core/IronPython.StdLib/.gitattributes index 73895670c..59ca9de07 100644 --- a/src/core/IronPython.StdLib/.gitattributes +++ b/src/core/IronPython.StdLib/.gitattributes @@ -18,15 +18,15 @@ *.zip binary # Specific binary files -Lib/test/sndhdrdata/sndhdr.* binary +lib/test/sndhdrdata/sndhdr.* binary # Text files that should not be subject to eol conversion -Lib/test/cjkencodings/* -text -Lib/test/decimaltestdata/*.decTest -text -Lib/test/test_email/data/*.txt -text -Lib/test/xmltestdata/* -text -Lib/test/coding20731.py -text -Lib/test/test_importlib/data01/* -text +lib/test/cjkencodings/* -text +lib/test/decimaltestdata/*.decTest -text +lib/test/test_email/data/*.txt -text +lib/test/xmltestdata/* -text +lib/test/coding20731.py -text +lib/test/test_importlib/data01/* -text # CRLF files *.bat text eol=crlf diff --git a/src/core/IronPython.StdLib/StdLib.pyproj b/src/core/IronPython.StdLib/IronPython.StdLib.pyproj similarity index 97% rename from src/core/IronPython.StdLib/StdLib.pyproj rename to src/core/IronPython.StdLib/IronPython.StdLib.pyproj index da4316dbc..c4f05252e 100644 --- a/src/core/IronPython.StdLib/StdLib.pyproj +++ b/src/core/IronPython.StdLib/IronPython.StdLib.pyproj @@ -9,7 +9,7 @@ PyStdLib PyStdLib PyStdLib - Lib + lib lib diff --git a/src/core/IronPython.StdLib/stdlib-upgrade.txt b/src/core/IronPython.StdLib/stdlib-upgrade.txt index 6bc4eb7e6..95b8567b8 100644 --- a/src/core/IronPython.StdLib/stdlib-upgrade.txt +++ b/src/core/IronPython.StdLib/stdlib-upgrade.txt @@ -5,7 +5,7 @@ Process for upgrading the stdlib to a new cpython version 0. Update a CPython checkout to latest. 1. git checkout python-stdlib -2. ./Src/StdLib/upgrade-stdlib.sh ~/path/to/cpython +2. ./src/core/IronPython.StdLib/upgrade-stdlib.sh ~/path/to/cpython 3. git checkout -b update-stdlib master 4. git merge --no-ff python-stdlib 5. Fix conflicts, etc. diff --git a/src/core/IronPython/IronPython.csproj b/src/core/IronPython/IronPython.csproj index 1736ecd4e..a87163fe2 100644 --- a/src/core/IronPython/IronPython.csproj +++ b/src/core/IronPython/IronPython.csproj @@ -8,7 +8,7 @@ - + @@ -23,7 +23,7 @@ True - ..\..\Util\References\Mono.Posix.dll + $(UtilsDir)\References\Mono.Posix.dll @@ -38,7 +38,7 @@ PreserveNewest - + PreserveNewest @@ -46,8 +46,8 @@ - - + + @@ -59,7 +59,7 @@ - + false Analyzer diff --git a/src/core/IronPython/Lib/iptest/ipunittest.py b/src/core/IronPython/Lib/iptest/ipunittest.py index 91c4cddb9..b92e8195c 100644 --- a/src/core/IronPython/Lib/iptest/ipunittest.py +++ b/src/core/IronPython/Lib/iptest/ipunittest.py @@ -85,7 +85,7 @@ def t(*args, **kwargs): return t def _find_root(): - test_dirs = ['Src', 'Build', 'Package', 'Tests', 'Util'] + test_dirs = ['src', 'eng', 'tests'] root = os.getcwd() test = all([os.path.exists(os.path.join(root, x)) for x in test_dirs]) while not test: @@ -128,8 +128,8 @@ def setUp(self): self.ensure_directory_present(self._temporary_dir) self._iron_python_test_dll = _iron_python_test_dll - self._test_dir = os.path.join(_root, 'Tests') - self._test_inputs_dir = os.path.join(_root, 'Tests', 'Inputs') + self._test_dir = os.path.join(_root, 'tests', 'suite') + self._test_inputs_dir = os.path.join(_root, 'tests', 'suite', 'Inputs') def add_reference_to_dlr_core(self): _add_reference_to_dlr_core() @@ -241,9 +241,9 @@ def generate_suite(tests, failing_tests, skip_tests=[]): # ip_root = path_combine(rowan_root, basePyDir) # external_dir = path_combine(rowan_root, 'External.LCA_RESTRICTED/Languages/IronPython') # clean_external_dir = path_combine(rowan_root, 'External.LCA_RESTRICTED/Languages/CPython/27') -# public_testdir = path_combine(ip_root, 'Tests') -# compat_testdir = path_combine(ip_root, 'Tests/compat') -# test_inputs_dir = path_combine(ip_root, 'Tests/Inputs') +# public_testdir = path_combine(ip_root, 'tests/suite') +# compat_testdir = path_combine(ip_root, 'tests/suite/compat') +# test_inputs_dir = path_combine(ip_root, 'tests/suite/Inputs') # script_testdir = path_combine(ip_root, 'Scripts') # math_testdir = path_combine(external_dir, 'Math') diff --git a/src/core/IronPython/Runtime/PythonContext.cs b/src/core/IronPython/Runtime/PythonContext.cs index 1c1a34863..fe4cece00 100644 --- a/src/core/IronPython/Runtime/PythonContext.cs +++ b/src/core/IronPython/Runtime/PythonContext.cs @@ -230,8 +230,8 @@ public PythonContext(ScriptDomainManager/*!*/ manager, IDictionary _libpaths = new List(); diff --git a/src/executables/IronPython.Compiler/Config.cs b/src/executables/IronPython.Compiler/Config.cs index 72e0d6747..59600f799 100644 --- a/src/executables/IronPython.Compiler/Config.cs +++ b/src/executables/IronPython.Compiler/Config.cs @@ -1,16 +1,17 @@ -using System; -using System.IO; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; -using System.Linq; +using System.IO; using System.Text; -using System.Text.RegularExpressions; -using IKVM.Reflection; + using IKVM.Reflection.Emit; -using System.Resources; -using System.Reflection; + using Microsoft.Scripting.Runtime; -namespace IronPythonCompiler { +namespace IronPython.Compiler { public class Config { public Config() { diff --git a/src/executables/IronPython.Compiler/ConsoleOps.cs b/src/executables/IronPython.Compiler/ConsoleOps.cs index 93f1b7cf9..eea8940e4 100644 --- a/src/executables/IronPython.Compiler/ConsoleOps.cs +++ b/src/executables/IronPython.Compiler/ConsoleOps.cs @@ -1,9 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. -namespace IronPythonCompiler { +using System; + +namespace IronPython.Compiler { public static class ConsoleOps { public static void Error(string format, params object[] args) { diff --git a/src/executables/IronPython.Compiler/IronPythonCompiler.csproj b/src/executables/IronPython.Compiler/IronPython.Compiler.csproj similarity index 66% rename from src/executables/IronPython.Compiler/IronPythonCompiler.csproj rename to src/executables/IronPython.Compiler/IronPython.Compiler.csproj index ffa1d0cb4..1452938e1 100644 --- a/src/executables/IronPython.Compiler/IronPythonCompiler.csproj +++ b/src/executables/IronPython.Compiler/IronPython.Compiler.csproj @@ -3,24 +3,24 @@ net462 Exe - IronPythonCompiler + IronPython.Compiler ipyc - IronPythonCompiler.Program + IronPython.Compiler.Program true - + - + - ..\..\Util\References\IKVM\IKVM.Reflection.dll + $(UtilsDir)\References\IKVM\IKVM.Reflection.dll diff --git a/src/executables/IronPython.Compiler/Program.cs b/src/executables/IronPython.Compiler/Program.cs index 115b8f502..2caf6684e 100644 --- a/src/executables/IronPython.Compiler/Program.cs +++ b/src/executables/IronPython.Compiler/Program.cs @@ -19,7 +19,7 @@ using Type = IKVM.Reflection.Type; -namespace IronPythonCompiler { +namespace IronPython.Compiler { public class Program { diff --git a/src/executables/IronPython.Console/IronPythonConsole.csproj b/src/executables/IronPython.Console/IronPython.Console.csproj similarity index 87% rename from src/executables/IronPython.Console/IronPythonConsole.csproj rename to src/executables/IronPython.Console/IronPython.Console.csproj index a66fcd7a3..3c75121b2 100644 --- a/src/executables/IronPython.Console/IronPythonConsole.csproj +++ b/src/executables/IronPython.Console/IronPython.Console.csproj @@ -3,7 +3,7 @@ net462;net6.0;net8.0 Exe - IronPythonConsole + IronPython.Console ipy ipy.ico true @@ -12,8 +12,8 @@ - - + + false Content PreserveNewest diff --git a/src/executables/IronPython.Console32/IronPythonConsole32.csproj b/src/executables/IronPython.Console32/IronPython.Console32.csproj similarity index 55% rename from src/executables/IronPython.Console32/IronPythonConsole32.csproj rename to src/executables/IronPython.Console32/IronPython.Console32.csproj index ec88a8b4c..c8b938c10 100644 --- a/src/executables/IronPython.Console32/IronPythonConsole32.csproj +++ b/src/executables/IronPython.Console32/IronPython.Console32.csproj @@ -4,22 +4,22 @@ net462 x86 Exe - IronPythonConsole + IronPython.Console32 ipy32 - ..\IronPythonConsole\ipy.ico + ..\IronPython.Console\ipy.ico true - - + + false - - + + diff --git a/src/executables/IronPython.Window/IronPythonWindow.csproj b/src/executables/IronPython.Window/IronPython.Window.csproj similarity index 81% rename from src/executables/IronPython.Window/IronPythonWindow.csproj rename to src/executables/IronPython.Window/IronPython.Window.csproj index 536086341..7b6e12f5a 100644 --- a/src/executables/IronPython.Window/IronPythonWindow.csproj +++ b/src/executables/IronPython.Window/IronPython.Window.csproj @@ -3,14 +3,14 @@ net462 WinExe - IronPythonWindow + IronPython.Window ipyw ipyw.ico true - + diff --git a/src/executables/IronPython.Window32/IronPythonWindow32.csproj b/src/executables/IronPython.Window32/IronPython.Window32.csproj similarity index 59% rename from src/executables/IronPython.Window32/IronPythonWindow32.csproj rename to src/executables/IronPython.Window32/IronPython.Window32.csproj index 0ed23ee55..d79c8588e 100644 --- a/src/executables/IronPython.Window32/IronPythonWindow32.csproj +++ b/src/executables/IronPython.Window32/IronPython.Window32.csproj @@ -4,14 +4,14 @@ net462 x86 WinExe - IronPythonWindow + IronPython.Window32 ipyw32 - ..\IronPythonWindow\ipyw.ico + ..\IronPython.Window\ipyw.ico true - + @@ -19,8 +19,8 @@ - - + + diff --git a/src/extensions/IronPython.SQLite/IronPython.SQLite.csproj b/src/extensions/IronPython.SQLite/IronPython.SQLite.csproj index 60466e71a..063140db6 100644 --- a/src/extensions/IronPython.SQLite/IronPython.SQLite.csproj +++ b/src/extensions/IronPython.SQLite/IronPython.SQLite.csproj @@ -24,9 +24,9 @@ - - - + + + diff --git a/src/extensions/IronPython.Wpf/IronPython.Wpf.csproj b/src/extensions/IronPython.Wpf/IronPython.Wpf.csproj index 97f2aebb6..53618a818 100644 --- a/src/extensions/IronPython.Wpf/IronPython.Wpf.csproj +++ b/src/extensions/IronPython.Wpf/IronPython.Wpf.csproj @@ -13,9 +13,9 @@ - - - + + + diff --git a/src/roslyn/IronPython.Analyzer/IronPythonAnalyzer/IronPythonAnalyzer.csproj b/src/roslyn/IronPython.Analyzer/IronPython.Analyzer.csproj similarity index 100% rename from src/roslyn/IronPython.Analyzer/IronPythonAnalyzer/IronPythonAnalyzer.csproj rename to src/roslyn/IronPython.Analyzer/IronPython.Analyzer.csproj diff --git a/src/roslyn/IronPython.Analyzer/IronPythonAnalyzer/IronPythonAnalyzerAnalyzer.cs b/src/roslyn/IronPython.Analyzer/IronPythonDiagnosticAnalyzer.cs similarity index 98% rename from src/roslyn/IronPython.Analyzer/IronPythonAnalyzer/IronPythonAnalyzerAnalyzer.cs rename to src/roslyn/IronPython.Analyzer/IronPythonDiagnosticAnalyzer.cs index d392b4230..bdbc354a9 100644 --- a/src/roslyn/IronPython.Analyzer/IronPythonAnalyzer/IronPythonAnalyzerAnalyzer.cs +++ b/src/roslyn/IronPython.Analyzer/IronPythonDiagnosticAnalyzer.cs @@ -13,9 +13,9 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; -namespace IronPythonAnalyzer { +namespace IronPython.Analyzer { [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class IronPythonAnalyzerAnalyzer : DiagnosticAnalyzer { + public class IronPythonDiagnosticAnalyzer : DiagnosticAnalyzer { public const string DiagnosticId = "IronPythonAnalyzer"; #pragma warning disable RS2008 // Enable analyzer release tracking diff --git a/tests/IronPython.Tests/Cases/CPythonCases.cs b/tests/IronPython.Tests/Cases/CPythonCases.cs index f3d568064..a863c2549 100644 --- a/tests/IronPython.Tests/Cases/CPythonCases.cs +++ b/tests/IronPython.Tests/Cases/CPythonCases.cs @@ -18,7 +18,7 @@ public override int Test(TestInfo testcase) { internal class CPythonCaseGenerator : CommonCaseGenerator { protected override IEnumerable GetTests() { - var libFolder = Path.Combine("Src", "StdLib", "Lib"); + var libFolder = Path.Combine("src", "core", "IronPython.StdLib", "lib"); return GetFilenames(new [] { System.Tuple.Create(category, Path.Combine(libFolder, "test")), System.Tuple.Create($"{category}.ctypes", Path.Combine(libFolder, "ctypes", "test")), diff --git a/tests/IronPython.Tests/Cases/CaseExecuter.cs b/tests/IronPython.Tests/Cases/CaseExecuter.cs index d75cbc047..0af23b672 100644 --- a/tests/IronPython.Tests/Cases/CaseExecuter.cs +++ b/tests/IronPython.Tests/Cases/CaseExecuter.cs @@ -11,7 +11,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text.RegularExpressions; -using System.Threading.Tasks; +using System.Threading; using IronPython; using IronPython.Hosting; @@ -65,11 +65,11 @@ public static ScriptEngine CreateEngine(TestOptions options) { } internal static string FindRoot() { - // we start at the current directory and look up until we find the "Src" directory + // we start at the current directory and look up until we find the "src" directory var current = System.Reflection.Assembly.GetExecutingAssembly().Location; var found = false; while (!found && !string.IsNullOrEmpty(current)) { - var test = Path.Combine(current, "Src", "StdLib", "Lib"); + var test = Path.Combine(current, "src", "core", "IronPython.StdLib", "lib"); if (Directory.Exists(test)) { return current; } @@ -84,7 +84,7 @@ private static void AddSearchPaths(ScriptEngine engine) { if (!paths.Any(x => x.Contains("stdlib", StringComparison.OrdinalIgnoreCase))) { var root = FindRoot(); if (!string.IsNullOrEmpty(root)) { - paths.Insert(0, Path.Combine(root, "Src", "StdLib", "Lib")); + paths.Insert(0, Path.Combine(root, "src", "core", "IronPython.StdLib", "lib")); } } engine.SetSearchPaths(paths); @@ -140,7 +140,7 @@ public string FormatException(Exception ex) { } private static string GetIronPythonPath() { - var path = Path.Combine(FindRoot(), "Src", "StdLib", "Lib"); + var path = Path.Combine(FindRoot(), "src", "core", "IronPython.StdLib", "lib"); if (Directory.Exists(path)) { return path; } @@ -289,18 +289,34 @@ private int GetResult(TestInfo testcase, ScriptEngine engine, ScriptSource sourc engine.GetSysModule().SetVariable("argv", PythonList.FromArrayNoCopy(new object[] { source.Path })); var compiledCode = source.Compile(new IronPython.Compiler.PythonCompilerOptions() { ModuleName = "__main__" }); - var task = Task.Run(() => { + int res = 0; + int maxStackSize = 2 * 1024 * 1024; // 2 MiB + var thread = new Thread(() => { try { - return engine.Operations.ConvertTo(compiledCode.Execute(scope) ?? 0); + res = engine.Operations.ConvertTo(compiledCode.Execute(scope) ?? 0); } catch (SystemExitException ex) { - return ex.GetExitCode(out _); + res = ex.GetExitCode(out object otherCode); + } catch (ThreadAbortException) { + #pragma warning disable SYSLIB0006 // 'Thread.ResetAbort is not supported and throws PlatformNotSupportedException.' + Thread.ResetAbort(); + #pragma warning restore SYSLIB0006 + } + }, maxStackSize) { + IsBackground = true + }; + + thread.Start(); + + if (!thread.Join(testcase.Options.Timeout)) { + if(!ClrModule.IsNetCoreApp) { + #pragma warning disable SYSLIB0006 // 'Thread.Abort is not supported and throws PlatformNotSupportedException.' + thread.Abort(); + #pragma warning restore SYSLIB0006 } - }); - if (!task.Wait(testcase.Options.Timeout)) { NUnit.Framework.TestContext.Error.WriteLine($"{testcase.Name} timed out after {testcase.Options.Timeout / 1000.0} seconds."); return -1; } - return task.Result; + return res; } finally { Environment.CurrentDirectory = cwd; } diff --git a/tests/IronPython.Tests/Cases/IronPythonCases.cs b/tests/IronPython.Tests/Cases/IronPythonCases.cs index 2cd431625..85d3c1f8b 100644 --- a/tests/IronPython.Tests/Cases/IronPythonCases.cs +++ b/tests/IronPython.Tests/Cases/IronPythonCases.cs @@ -19,8 +19,8 @@ public override int Test(TestInfo testcase) { internal class IronPythonCaseGenerator : CommonCaseGenerator { protected override IEnumerable GetTests() { return GetFilenames(new[] { - System.Tuple.Create(category, "Tests"), - System.Tuple.Create($"{category}.scripts", Path.Combine("Src", "Scripts")), + System.Tuple.Create(category, Path.Combine("tests", "suite")), + System.Tuple.Create($"{category}.scripts", Path.Combine("eng", "scripts")), }) .OrderBy(testcase => testcase.Name); diff --git a/tests/IronPython.Tests/EngineTest.cs b/tests/IronPython.Tests/EngineTest.cs index f6cd8b21f..67fe9d3d6 100644 --- a/tests/IronPython.Tests/EngineTest.cs +++ b/tests/IronPython.Tests/EngineTest.cs @@ -53,16 +53,16 @@ internal class Common { static Common() { RuntimeDirectory = Path.GetDirectoryName(typeof(PythonContext).Assembly.Location); RootDirectory = FindRoot(); - ScriptTestDirectory = Path.Combine(RootDirectory, "Tests"); + ScriptTestDirectory = Path.Combine(RootDirectory, "tests", "suite"); InputTestDirectory = Path.Combine(ScriptTestDirectory, "Inputs"); } private static string FindRoot() { - // we start at the current directory and look up until we find the "Src" directory + // we start at the current directory and look up until we find the "src" directory var current = System.Reflection.Assembly.GetExecutingAssembly().Location; var found = false; while (!found && !string.IsNullOrEmpty(current)) { - var test = Path.Combine(current, "Src", "StdLib", "Lib"); + var test = Path.Combine(current, "src", "core", "IronPython.StdLib", "lib"); if (Directory.Exists(test)) { return current; } diff --git a/tests/IronPython.Tests/IronPythonTest.csproj b/tests/IronPython.Tests/IronPython.Tests.csproj similarity index 70% rename from tests/IronPython.Tests/IronPythonTest.csproj rename to tests/IronPython.Tests/IronPython.Tests.csproj index 4a76e9f88..6ff811e82 100644 --- a/tests/IronPython.Tests/IronPythonTest.csproj +++ b/tests/IronPython.Tests/IronPython.Tests.csproj @@ -2,11 +2,12 @@ net462;net6.0;net8.0 + IronPythonTest true - + @@ -26,15 +27,15 @@ - + false - - + + diff --git a/tests/IronPython.Tests/Util/TestManifest.cs b/tests/IronPython.Tests/Util/TestManifest.cs index af01c800e..890ece9e8 100644 --- a/tests/IronPython.Tests/Util/TestManifest.cs +++ b/tests/IronPython.Tests/Util/TestManifest.cs @@ -13,7 +13,7 @@ public class TestManifest { private IniParser manifest; public TestManifest(Type parent) { - var file = parent.Assembly.GetManifestResourceStream($"IronPythonTest.Cases.{parent.Name}Manifest.ini"); + var file = parent.Assembly.GetManifestResourceStream($"IronPython.Tests.Cases.{parent.Name}Manifest.ini"); this.manifest = new IniParser(file); } diff --git a/tests/suite/gen_stdlib_test.py b/tests/suite/gen_stdlib_test.py index 8cc27aac4..1d328a5a3 100644 --- a/tests/suite/gen_stdlib_test.py +++ b/tests/suite/gen_stdlib_test.py @@ -51,7 +51,7 @@ def load_tests(loader, standard_tests, pattern): filepath = os.path.join(location, name + ("_" + package if package else "") + "_stdlib.py") - sys.path.insert(0, os.path.abspath(os.path.join(__file__, "../../Src/StdLib/Lib"))) + sys.path.insert(0, os.path.abspath(os.path.join(__file__, "../../src/core/IronPython.StdLib/lib"))) module = importlib.import_module("{package}test.{name}".format(name=name, package=package + "." if package else "")) tests = [] diff --git a/tests/suite/modules/io_related/test_termios.py b/tests/suite/modules/io_related/test_termios.py new file mode 100644 index 000000000..247b87bd6 --- /dev/null +++ b/tests/suite/modules/io_related/test_termios.py @@ -0,0 +1,112 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the Apache 2.0 License. +# See the LICENSE file in the project root for more information. + +# tests for module 'termios' (Posix only) + +import unittest + +from iptest import is_posix, is_linux, is_osx + +if is_posix: + import termios +else: + try: + import termios + except ImportError: + pass + else: + raise AssertionError("There should be no module termios on Windows") + + +@unittest.skipUnless(is_posix, "Posix-specific test") +class TermiosTest(unittest.TestCase): + + def verify_flags(self, names, values, typ=int): + for i, flag in enumerate(names): + with self.subTest(flag=flag): + self.assertTrue(hasattr(termios, flag)) + self.assertEqual(getattr(termios, flag), values[i]) + + + def test_iflags(self): + iflags = ["IGNBRK", "BRKINT", "IGNPAR", "PARMRK", "INPCK", "ISTRIP", "INLCR", "IGNCR", "ICRNL", "IXON", "IXOFF", "IXANY"] + if is_osx: + iflag_values = [0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800] + elif is_linux: + iflag_values = [0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x400, 0x1000, 0x800] + self.verify_flags(iflags, iflag_values) + + + def test_oflags(self): + oflags = ["OPOST", "ONLCR"] + if is_osx: + oflag_values = [0x1, 0x2] + elif is_linux: + oflag_values = [0x1, 0x4] + self.verify_flags(oflags, oflag_values) + + + def test_cflags(self): + cflags = ["CSIZE", "CS5", "CS6", "CS7", "CS8", "CREAD", "PARENB", "HUPCL"] + if is_osx: + cflag_values = [0x300, 0x0, 0x100, 0x200, 0x300, 0X800, 0x1000, 0x4000] + elif is_linux: + cflags += ["CBAUD", "CBAUDEX"] + cflag_values = [0x30, 0x0, 0x10, 0x20, 0x30, 0x80, 0x0100, 0x400, 0x100f, 0x1000] + self.verify_flags(cflags, cflag_values) + + + def test_lflags(self): + lflags = ["ECHOKE", "ECHOE", "ECHOK", "ECHO", "ECHONL", "ECHOPRT", "ECHOCTL", "ISIG", "ICANON", "IEXTEN", "TOSTOP", "FLUSHO", "PENDIN", "NOFLSH"] + if is_osx: + lflag_values = [0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x400, 0x400000, 0x800000, 0x20000000, 0x80000000] + elif is_linux: + lflag_values = [0x800, 0x10, 0x20, 0x8, 0x40, 0x400, 0x200, 0x1, 0x2, 0x8000, 0x100, 0x1000, 0x4000, 0x80] + self.verify_flags(lflags, lflag_values) + + + def test_when_enum(self): + when = ["TCSANOW", "TCSADRAIN", "TCSAFLUSH"] + when_values = [0, 1, 2] + self.verify_flags(when, when_values) + + + def test_tcflush_queue(self): + queue = ["TCIFLUSH", "TCOFLUSH", "TCIOFLUSH"] + if is_osx: + queue_values = [1, 2, 3] + elif is_linux: + queue_values = [0, 1, 2] + self.verify_flags(queue, queue_values) + + + def test_tcflow_action(self): + action = ["TCOOFF", "TCOON", "TCIOFF", "TCION"] + if is_osx: + action_values = [1, 2, 3, 4] + elif is_linux: + action_values = [0, 1, 2, 3] + self.verify_flags(action, action_values) + + + def test_cc(self): + if is_osx: + cc = ["VEOF", "VEOL", "VEOL2", "VERASE", "VWERASE", "VKILL", "VREPRINT", "VINTR", "VQUIT", "VSUSP", "VSTART", "VSTOP", "VLNEXT", "VDISCARD", "VMIN", "VTIME", "NCCS"] + cc_values = [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 16, 17, 20] + elif is_linux: + cc = ["VEOF", "VEOL", "VEOL2", "VERASE", "VWERASE", "VKILL", "VREPRINT", "VINTR", "VQUIT", "VSUSP", "VSTART", "VSTOP", "VLNEXT", "VDISCARD", "VMIN", "VTIME", "VSWTC", "NCCS"] + cc_values = [4, 11, 16, 2, 14, 3, 12, 0, 1, 10, 8, 9, 15, 13, 6, 5, 7, 32] + self.verify_flags(cc, cc_values) + + def test_baud_rates(self): + rates = ["B0", "B50", "B75", "B110", "B134", "B150", "B200", "B300", "B600", "B1200", "B1800", "B2400", "B4800", "B9600", "B19200", "B38400", "B57600", "B115200", "B230400"] + if is_osx: + rates_values = [0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400] + elif is_linux: + rates_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 4097, 4098, 4099] + self.verify_flags(rates, rates_values) + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/tests/suite/test_builtin_stdlib.py b/tests/suite/test_builtin_stdlib.py index 1a50d9da4..09538223f 100644 --- a/tests/suite/test_builtin_stdlib.py +++ b/tests/suite/test_builtin_stdlib.py @@ -6,7 +6,7 @@ ## Run selected tests from test_builtin from StdLib ## -from iptest import is_ironpython, generate_suite, run_test, is_netcoreapp +from iptest import is_ironpython, generate_suite, run_test import test.test_builtin @@ -21,6 +21,10 @@ def load_tests(loader, standard_tests, pattern): test.test_builtin.BuiltinTest('test_input'), test.test_builtin.BuiltinTest('test_len'), test.test_builtin.BuiltinTest('test_open_non_inheritable'), # https://github.com/IronLanguages/ironpython3/issues/1225 + ] + + skip_tests = [ + # module `pty` is importable but not functional on .NET Core test.test_builtin.PtyTests('test_input_no_stdout_fileno'), test.test_builtin.PtyTests('test_input_tty'), test.test_builtin.PtyTests('test_input_tty_non_ascii'), @@ -34,14 +38,9 @@ def load_tests(loader, standard_tests, pattern): test.test_builtin.TestType('test_type_name'), # AssertionError: ValueError not raised test.test_builtin.TestType('test_type_nokwargs'), # AssertionError: TypeError not raised test.test_builtin.TestType('test_type_qualname'), # https://github.com/IronLanguages/ironpython3/issues/30 + test.test_builtin.ShutdownTest('test_cleanup'), ] - skip_tests = [] - if is_netcoreapp: - skip_tests += [ - test.test_builtin.ShutdownTest('test_cleanup'), - ] - return generate_suite(tests, failing_tests, skip_tests) else: diff --git a/tests/suite/test_dict.py b/tests/suite/test_dict.py index 6e3bf81e9..90036fe71 100644 --- a/tests/suite/test_dict.py +++ b/tests/suite/test_dict.py @@ -956,7 +956,7 @@ def test_cp16519(self): self.assertEqual(sys.Dict["1"], "b") del sys.Dict - with path_modifier(os.path.join(source_root(), 'Tests')): + with path_modifier(os.path.join(source_root(), 'tests', 'suite')): import testpkg1 testpkg1.Dict = {"1": "c"} self.assertEqual(testpkg1.Dict["1"], "c") diff --git a/tests/suite/test_exceptions_generated.py b/tests/suite/test_exceptions_generated.py index 079224089..5ae91770f 100644 --- a/tests/suite/test_exceptions_generated.py +++ b/tests/suite/test_exceptions_generated.py @@ -30,7 +30,7 @@ def setUp(self): clr.AddReference("IronPython") if is_cli: - with path_modifier(os.path.join(source_root(), 'Src', 'Scripts')): + with path_modifier(os.path.join(source_root(), 'eng', 'scripts')): from generate_exceptions import pythonExcs as test_cases test_cases = [x.replace('Error', '') + 'Exception' for x in test_cases] for exc_name in test_cases: