diff --git a/.editorconfig b/.editorconfig index d9c7ff3d7..f7658ff73 100644 --- a/.editorconfig +++ b/.editorconfig @@ -60,6 +60,9 @@ dotnet_diagnostic.CA1305.severity = none # CA1305: Specify IFormatProvide dotnet_diagnostic.CA1307.severity = suggestion # CA1307: Specify StringComparison for clarity dotnet_diagnostic.CA1309.severity = suggestion # CA1309: Use ordinal string comparison dotnet_diagnostic.CA1310.severity = warning # CA1310: Specify StringComparison for correctness +dotnet_diagnostic.CA1510.severity = none # CA1510: Use ArgumentNullException throw helper +dotnet_diagnostic.CA1512.severity = none # CA1512: Use ArgumentOutOfRangeException throw helper +dotnet_diagnostic.CA1513.severity = none # CA1513: Use ObjectDisposedException throw helper dotnet_diagnostic.CA1707.severity = none # CA1707: Identifiers should not contain underscores dotnet_diagnostic.CA1708.severity = none # CA1708: Identifiers should differ by more than case dotnet_diagnostic.CA1710.severity = none # CA1710: Identifiers should have correct suffix @@ -81,8 +84,10 @@ dotnet_diagnostic.CA1845.severity = none # CA1845: Use span-based 'string dotnet_diagnostic.CA1846.severity = none # CA1846: Prefer 'AsSpan' over 'Substring' dotnet_diagnostic.CA1847.severity = none # CA1847: Use char literal for a single character lookup dotnet_diagnostic.CA1852.severity = suggestion # CA1852: Seal internal types +dotnet_diagnostic.CA1854.severity = suggestion # CA1854: Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method dotnet_diagnostic.CA1859.severity = suggestion # CA1859: Use concrete types when possible for improved performance dotnet_diagnostic.CA1861.severity = suggestion # CA1861: Avoid constant arrays as arguments +dotnet_diagnostic.CA1863.severity = none # CA1863: Use 'CompositeFormat' dotnet_diagnostic.CA2101.severity = suggestion # CA2101: Specify marshaling for P/Invoke string arguments dotnet_diagnostic.CA2201.severity = none # CA2201: Do not raise reserved exception types dotnet_diagnostic.CA2208.severity = suggestion # CA2208: Instantiate argument exceptions correctly @@ -95,3 +100,6 @@ dotnet_diagnostic.CA5350.severity = suggestion # CA5350: Do Not Use Weak Crypto dotnet_diagnostic.CA5351.severity = suggestion # CA5351: Do Not Use Broken Cryptographic Algorithms dotnet_diagnostic.CA5359.severity = suggestion # CA5359: Do Not Disable Certificate Validation dotnet_diagnostic.CA5372.severity = suggestion # CA5372: Use XmlReader For XPathDocument + +dotnet_diagnostic.SYSLIB1045.severity = suggestion # SYSLIB1045: Use 'RegexGeneratorAttribute' to generate the regular expression implementation at compile-time +dotnet_diagnostic.SYSLIB1054.severity = suggestion # SYSLIB1054: Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0ddab2b28..8bd164487 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,23 +10,27 @@ jobs: strategy: fail-fast: false matrix: - os: [windows-latest, ubuntu-latest, macos-latest] + os: [windows-latest, ubuntu-latest, macos-latest-large] steps: - name: Install tools if: matrix.os == 'ubuntu-latest' run: sudo apt-get -yq install mono-vbnc dos2unix - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Setup .NET Core 3.1 - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: dotnet-version: '3.1.x' - name: Setup .NET 6.0 - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: dotnet-version: '6.0.x' + - name: Setup .NET 8.0 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' - name: Version Information run: | dotnet --info @@ -37,9 +41,9 @@ jobs: run: pwsh make.ps1 - name: Package run: pwsh make.ps1 package - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: - name: packages + name: packages-${{ matrix.os }} path: Package/Release/Packages - name: Test (net462) run: ./make.ps1 -frameworks net462 test-all @@ -50,3 +54,6 @@ jobs: - name: Test (net6.0) run: ./make.ps1 -frameworks net6.0 test-all shell: pwsh + - name: Test (net8.0) + run: ./make.ps1 -frameworks net8.0 test-all + shell: pwsh diff --git a/.gitmodules b/.gitmodules index e58c860e5..5cd8e15d8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "Src/DLR"] path = Src/DLR url = https://github.com/IronLanguages/dlr - branch = master + branch = main diff --git a/Build/net8.0-windows.props b/Build/net8.0-windows.props new file mode 100644 index 000000000..8e9067699 --- /dev/null +++ b/Build/net8.0-windows.props @@ -0,0 +1,9 @@ + + + false + $(BaseIntermediateOutputPath)$(Configuration)\net8.0 + $(BaseOutputPath)\net8.0 + + + + diff --git a/Build/net8.0.props b/Build/net8.0.props new file mode 100644 index 000000000..926dadc14 --- /dev/null +++ b/Build/net8.0.props @@ -0,0 +1,38 @@ + + + + false + + + + $(Features);FEATURE_APARTMENTSTATE + $(Features);FEATURE_ASSEMBLY_GETFORWARDEDTYPES + $(Features);FEATURE_ASSEMBLY_RESOLVE + $(Features);FEATURE_ASSEMBLYBUILDER_DEFINEDYNAMICASSEMBLY + $(Features);FEATURE_CODEDOM + $(Features);FEATURE_COM + $(Features);FEATURE_CONFIGURATION + $(Features);FEATURE_CTYPES + $(Features);FEATURE_CUSTOM_TYPE_DESCRIPTOR + $(Features);FEATURE_EXCEPTION_STATE + $(Features);FEATURE_FILESYSTEM + $(Features);FEATURE_FULL_CRYPTO + $(Features);FEATURE_FULL_NET + $(Features);FEATURE_LCG + $(Features);FEATURE_LOADWITHPARTIALNAME + $(Features);FEATURE_METADATA_READER + $(Features);FEATURE_MMAP + $(Features);FEATURE_NATIVE + $(Features);FEATURE_OSPLATFORMATTRIBUTE + $(Features);FEATURE_PIPES + $(Features);FEATURE_PROCESS + $(Features);FEATURE_REFEMIT + $(Features);FEATURE_REGISTRY + $(Features);FEATURE_RUNTIMEINFORMATION + $(Features);FEATURE_SECURITY_RULES + $(Features);FEATURE_STACK_TRACE + $(Features);FEATURE_SYNC_SOCKETS + $(Features);FEATURE_THREAD + $(Features);FEATURE_XMLDOC + + diff --git a/Build/net9.0-windows.props b/Build/net9.0-windows.props new file mode 100644 index 000000000..b64bb8ce9 --- /dev/null +++ b/Build/net9.0-windows.props @@ -0,0 +1,9 @@ + + + false + $(BaseIntermediateOutputPath)$(Configuration)\net9.0 + $(BaseOutputPath)\net9.0 + + + + diff --git a/Build/net9.0.props b/Build/net9.0.props new file mode 100644 index 000000000..926dadc14 --- /dev/null +++ b/Build/net9.0.props @@ -0,0 +1,38 @@ + + + + false + + + + $(Features);FEATURE_APARTMENTSTATE + $(Features);FEATURE_ASSEMBLY_GETFORWARDEDTYPES + $(Features);FEATURE_ASSEMBLY_RESOLVE + $(Features);FEATURE_ASSEMBLYBUILDER_DEFINEDYNAMICASSEMBLY + $(Features);FEATURE_CODEDOM + $(Features);FEATURE_COM + $(Features);FEATURE_CONFIGURATION + $(Features);FEATURE_CTYPES + $(Features);FEATURE_CUSTOM_TYPE_DESCRIPTOR + $(Features);FEATURE_EXCEPTION_STATE + $(Features);FEATURE_FILESYSTEM + $(Features);FEATURE_FULL_CRYPTO + $(Features);FEATURE_FULL_NET + $(Features);FEATURE_LCG + $(Features);FEATURE_LOADWITHPARTIALNAME + $(Features);FEATURE_METADATA_READER + $(Features);FEATURE_MMAP + $(Features);FEATURE_NATIVE + $(Features);FEATURE_OSPLATFORMATTRIBUTE + $(Features);FEATURE_PIPES + $(Features);FEATURE_PROCESS + $(Features);FEATURE_REFEMIT + $(Features);FEATURE_REGISTRY + $(Features);FEATURE_RUNTIMEINFORMATION + $(Features);FEATURE_SECURITY_RULES + $(Features);FEATURE_STACK_TRACE + $(Features);FEATURE_SYNC_SOCKETS + $(Features);FEATURE_THREAD + $(Features);FEATURE_XMLDOC + + diff --git a/Build/steps.yml b/Build/steps.yml index ab6945c4e..12a52759c 100644 --- a/Build/steps.yml +++ b/Build/steps.yml @@ -31,17 +31,23 @@ steps: version: '3.1.x' - task: UseDotNet@2 - displayName: Install .NET 6.0 SDK for build + displayName: Install .NET 6.0 runtime for testing inputs: - packageType: 'sdk' + packageType: 'runtime' version: '6.0.x' + - task: UseDotNet@2 + displayName: Install .NET 8.0 SDK for build + inputs: + packageType: 'sdk' + version: '8.0.x' + # Set Mono version on macOS - ${{ if eq(parameters.os, 'macOS') }}: - - task: ms-devlabs.utilitytasks.task-Shellpp.Shell++@0 + - task: Bash@3 displayName: Set Mono Version inputs: - type: InlineScript + targetType: inline script: | # use Mono 6.4.0 version SYMLINK=6.4.0 @@ -52,31 +58,22 @@ steps: # Install mono when running on Linux - ${{ if eq(parameters.os, 'Linux') }}: - - task: ms-devlabs.utilitytasks.task-Shellpp.Shell++@0 - displayName: Version Information + - task: Bash@3 + displayName: Install tools inputs: - type: InlineScript + targetType: inline script: | - # Testing and packaging tools - sudo apt-get -yq install mono-vbnc dos2unix fakeroot + sudo apt-get -yq install mono-vbnc dos2unix - # Dump some info about the tools - mono --version - msbuild /version - dotnet --info - df -Th - - # Dump version info on macOS - - ${{ if eq(parameters.os, 'macOS') }}: - - task: ms-devlabs.utilitytasks.task-Shellpp.Shell++@0 - displayName: Version Information - inputs: - type: InlineScript - script: | - # Dump some info about the tools - mono --version - msbuild /version - dotnet --info + # Dump version info + - task: PowerShell@2 + displayName: Version Information + inputs: + targetType: inline + script: | + dotnet --info + try { msbuild -version } catch { } + try { mono --version } catch { } - powershell: ./make.ps1 displayName: Build diff --git a/Directory.Build.props b/Directory.Build.props index e7e2231de..709636925 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -21,8 +21,8 @@ 1000 IronPython - IronPython Team - © IronPython Contributors + .NET Foundation + © .NET Foundation and Contributors $(MajorVersion).$(MinorVersion).$(MicroVersion).$(AssemblyRevision) $(MajorVersion).$(MinorVersion).$(MicroVersion).$(AssemblyFileRevision) $(MSBuildProjectName) $(MajorVersion).$(MinorVersion).$(MicroVersion) $(ReleaseLevel) $(ReleaseSerial) @@ -121,7 +121,7 @@ - false + true portable true false diff --git a/Documentation/getting-the-sources.md b/Documentation/getting-the-sources.md index 1e2e41c4d..b5bd5e4a9 100644 --- a/Documentation/getting-the-sources.md +++ b/Documentation/getting-the-sources.md @@ -2,7 +2,7 @@ The main IronPython3 git repository is at [http://github.com/IronLanguages/ironp ## Downloading the sources -You can [download a zipped copy](http://github.com/IronLanguages/ironpython3/zipball/master) of the latest IronPython3 sources as well. +You can [download a zipped copy](http://github.com/IronLanguages/ironpython3/zipball/main) of the latest IronPython3 sources as well. ### Installing GIT @@ -15,7 +15,7 @@ The following links include resources for installing and using GIT: ### Creating a local GIT repository -You will first need to fork the IronPython3 project. [Creating a fork](https://help.github.com/fork-a-repo/) is recommended as it will allow you to contribute patches back easily. Click the "Fork" button on [https://github.com/IronLanguages/ironpython3/](https://github.com/IronLanguages/ironpython3/). This should create your personal fork, with a web URL like http://github.com/janedoe/ironpython3 (where janedoe is your github username). +You will first need to fork the IronPython3 project. [Creating a fork](https://help.github.com/fork-a-repo/) is recommended as it will allow you to contribute patches back easily. Click the "Fork" button on [https://github.com/IronLanguages/ironpython3/](https://github.com/IronLanguages/ironpython3/). This should create your personal fork, with a web URL like http://github.com/janedoe/ironpython3 (where janedoe is your github username). You can now use the git command-line client with many Linux distributions, Mac OS, Cygwin, and Windows (msysgit) to get the sources onto your local computer using the following commands: @@ -27,13 +27,13 @@ git config --global user.email janedoe@example.com git clone git@github.com:janedoe/ironpython3.git cd ironpython3 git remote add ironpython3 git://github.com/IronLanguages/ironpython3.git -git pull ironpython3 master +git pull ironpython3 main ``` At a later date, to get the latest updates from the IronPython3 project, run the following command in the ironpython3 directory created above: ``` -git pull ironpython3 master +git pull ironpython3 main ``` If there is a merge conflict, edit the unmerged files to remove the conflict markers, and then run the following command: @@ -59,4 +59,4 @@ The DLR (Dynamic Language Runtime) is a submodule of the ironpython3 repository, git submodule update --init ``` -For more information there is an excellent tutorial on [getting started with git](http://kylecordes.com/2008/04/30/git-windows-go/) \ No newline at end of file +For more information there is an excellent tutorial on [getting started with git](http://kylecordes.com/2008/04/30/git-windows-go/) diff --git a/Documentation/installing.md b/Documentation/installing.md index a4f85153f..7371f20c5 100644 --- a/Documentation/installing.md +++ b/Documentation/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/master/Src/Scripts/Install-IronPython.ps1 -OutFile ./Install-IronPython.ps1 +PS> Invoke-WebRequest https://raw.githubusercontent.com/IronLanguages/ironpython3/main/Src/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 @@ -146,7 +146,7 @@ It is recommended to create one's own launcher script launching the newer IronPy After a release, the development of IronPython continues so it is possible that a bug or a feature that is important to you was handled after the latest release. As each commit to the main project branch creates precompiled artifacts, it is still possible to install the relevant (or latest development) version of IronPython without the need to compile the whole project from scratch. -Go to the project's [_Actions_ page](https://github.com/IronLanguages/ironpython3/actions) and find the commit you are interested in. Or simply find the topmost commit to `master` that has all tests passing. The _Status_ and _Branch_ filters in the top bar are helpful to narrow the list down. Then click on the commit hyperlink to access the CI run summary. At the bottom of that page there is artifact `packages`, which contains all binary artifacts the project produces. Download it and unzip. Choose the right package for your needs and follow instructions above for the officially released artifacts. For convenience, here is a table with usable packages: +Go to the project's [_Actions_ page](https://github.com/IronLanguages/ironpython3/actions) and find the commit you are interested in. Or simply find the topmost commit to `main` that has all tests passing. The _Status_ and _Branch_ filters in the top bar are helpful to narrow the list down. Then click on the commit hyperlink to access the CI run summary. At the bottom of that page there is artifact `packages`, which contains all binary artifacts the project produces. Download it and unzip. Choose the right package for your needs and follow instructions above for the officially released artifacts. For convenience, here is a table with usable packages: | Artifact | Framework | Operating System | | -------------------- | ------------------------------ | ----------------------------------- | @@ -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/master/Documentation/getting-the-sources.md) and [_Building IronPython3_](https://github.com/IronLanguages/ironpython3/blob/master/Documentation/building.md). +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). 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,7 +170,7 @@ 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 `./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. Installation example: diff --git a/Documentation/upgrading-from-ipy2.md b/Documentation/upgrading-from-ipy2.md index 7c330cb07..4f59586da 100644 --- a/Documentation/upgrading-from-ipy2.md +++ b/Documentation/upgrading-from-ipy2.md @@ -57,7 +57,7 @@ Another way of achieving the redirection behavior similar to IronPython 2 is to ```c# // IronPython 3 -var engine = Python.CreateEngine(new Dictionary { +var engine = Python.CreateEngine(new Dictionary { { "ConsoleSupportLevel", Microsoft.Scripting.Runtime.SharedIO.SupportLevel.Basic }, }); var textWriter = new MyTextWriter(); @@ -70,14 +70,14 @@ This method is particularly useful when embedding the IronPython 3 engine in a h ```c# // IronPython 3 in LINQPad -var engine = Python.CreateEngine(new Dictionary { +var engine = Python.CreateEngine(new Dictionary { { "ConsoleSupportLevel", Microsoft.Scripting.Runtime.SharedIO.SupportLevel.Basic }, }); engine.Execute("print('abc')"); // shows output in the "Results" pane dynamic ans = engine.Execute("input()"); // pauses the script and asks for input at the bottom of the "Results" pane; terminate your input with Ctrl+Z, Enter ``` -[TextStream]: https://github.com/IronLanguages/dlr/blob/master/Src/Microsoft.Scripting/Utils/TextStream.cs +[TextStream]: https://github.com/IronLanguages/dlr/blob/main/Src/Microsoft.Scripting/Utils/TextStream.cs [LINQPad]: https://www.linqpad.net/ ## `int` Type diff --git a/IronPython.sln b/IronPython.sln index d02363401..3de1c02d7 100644 --- a/IronPython.sln +++ b/IronPython.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28917.181 +# 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}" EndProject @@ -37,6 +37,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{17737ACB 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\netcoreapp3.1.props = Build\netcoreapp3.1.props Build\netstandard2.0.props = Build\netstandard2.0.props Build\steps.yml = Build\steps.yml Build\Tasks.Targets = Build\Tasks.Targets diff --git a/IronPythonAnalyzer/IronPythonAnalyzer/IronPythonAnalyzer.csproj b/IronPythonAnalyzer/IronPythonAnalyzer/IronPythonAnalyzer.csproj index 14e1f56a7..38c0895fe 100644 --- a/IronPythonAnalyzer/IronPythonAnalyzer/IronPythonAnalyzer.csproj +++ b/IronPythonAnalyzer/IronPythonAnalyzer/IronPythonAnalyzer.csproj @@ -2,11 +2,12 @@ netstandard2.0 + true - - + + diff --git a/Package/choco/IronPython.nuspec b/Package/choco/IronPython.nuspec index 5849bfc91..6a616379f 100644 --- a/Package/choco/IronPython.nuspec +++ b/Package/choco/IronPython.nuspec @@ -5,13 +5,13 @@ ironpython 3.4.0 - https://github.com/IronLanguages/ironpython3/tree/master/Package/choco + https://github.com/IronLanguages/ironpython3/tree/main/Package/choco IronPython IronPython Contributors, Microsoft © IronPython Contributors IronPython Community https://ironpython.net - https://github.com/IronLanguages/ironpython3/blob/master/LICENSE + https://github.com/IronLanguages/ironpython3/blob/main/LICENSE false IronPython is an open-source implementation of the Python programming language that is tightly integrated with the .NET Framework. IronPython can use the .NET Framework and Python libraries, and other .NET languages can use Python code just as easily. IronPython is an open-source implementation of the Python programming language that is tightly integrated with the .NET Framework. diff --git a/Package/choco/README.md b/Package/choco/README.md index 7d16742a3..fbd5d23a1 100644 --- a/Package/choco/README.md +++ b/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/master/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/Documentation/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/master/Documentation/package-compatibility.md) document for information on compatibility with popular Python packages. +See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/package-compatibility.md) document for information on compatibility with popular Python packages. diff --git a/Package/dotnettool/README.md b/Package/dotnettool/README.md index d521932da..f6e7118d2 100644 --- a/Package/dotnettool/README.md +++ b/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/master/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/Documentation/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/master/Documentation/package-compatibility.md) document for information on compatibility with popular Python packages. +See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/main/Documentation/package-compatibility.md) document for information on compatibility with popular Python packages. diff --git a/Package/msi/IronPython.Installer.wixproj b/Package/msi/IronPython.Installer.wixproj index b8e471091..e122f51c8 100644 --- a/Package/msi/IronPython.Installer.wixproj +++ b/Package/msi/IronPython.Installer.wixproj @@ -1,4 +1,4 @@ - + x64 3.4 @@ -44,10 +44,10 @@ - - - - + + + + diff --git a/Package/msi/Version.wxi b/Package/msi/Version.wxi index 8f7d4db54..4417c0e1a 100644 --- a/Package/msi/Version.wxi +++ b/Package/msi/Version.wxi @@ -1,4 +1,4 @@  - + diff --git a/Package/nuget/IronPython.nuspec b/Package/nuget/IronPython.nuspec index 3cc2a5d76..8711f555a 100644 --- a/Package/nuget/IronPython.nuspec +++ b/Package/nuget/IronPython.nuspec @@ -33,12 +33,16 @@ This package contains the IronPython interpreter engine. + + + + - - - + + + diff --git a/Package/nuget/README.md b/Package/nuget/README.md index f125651b9..0365dcb75 100644 --- a/Package/nuget/README.md +++ b/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/master/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/Documentation/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/master/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/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. diff --git a/Package/zip/README.md b/Package/zip/README.md index 5714284e7..a39ca5ec6 100644 --- a/Package/zip/README.md +++ b/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/master/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/Documentation/differences-from-c-python.md) for details. ## Package compatibility -See the [Package compatibility](https://github.com/IronLanguages/ironpython3/blob/master/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/Documentation/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/Package/zip/Zip.Packaging.targets b/Package/zip/Zip.Packaging.targets index cc1f64bb8..bec14c1fa 100644 --- a/Package/zip/Zip.Packaging.targets +++ b/Package/zip/Zip.Packaging.targets @@ -4,7 +4,7 @@ - + diff --git a/Src/DLR b/Src/DLR index 872730ab3..fe26cf45d 160000 --- a/Src/DLR +++ b/Src/DLR @@ -1 +1 @@ -Subproject commit 872730ab305d37f67179db8ca778d1cd22984e67 +Subproject commit fe26cf45d383be65a56f0d4b964644eff89e01a8 diff --git a/Src/IronPython.Modules/IronPython.Modules.csproj b/Src/IronPython.Modules/IronPython.Modules.csproj index 5a7b3cba0..4fc2771d2 100644 --- a/Src/IronPython.Modules/IronPython.Modules.csproj +++ b/Src/IronPython.Modules/IronPython.Modules.csproj @@ -1,7 +1,7 @@  - net462;netstandard2.0;net6.0 + net462;netstandard2.0;net6.0;net8.0 885063680 true true diff --git a/Src/IronPython.Modules/_codecs.cs b/Src/IronPython.Modules/_codecs.cs index 454b34e52..1bab21f30 100644 --- a/Src/IronPython.Modules/_codecs.cs +++ b/Src/IronPython.Modules/_codecs.cs @@ -620,7 +620,7 @@ private static Tuple DoEncode(CodeContext context, string encodingNa /// /// Optimized encoding mapping that can be consumed by charmap_encode/EncodingMapEncoding. /// - [PythonHidden] + [PythonType, PythonHidden] public class EncodingMap { private readonly string _smap; [DisallowNull] private Dictionary? _dmap; diff --git a/Src/IronPython.Modules/_csv.cs b/Src/IronPython.Modules/_csv.cs index e4a2a6ec7..6d6c86ba6 100644 --- a/Src/IronPython.Modules/_csv.cs +++ b/Src/IronPython.Modules/_csv.cs @@ -652,7 +652,7 @@ public bool MoveNext() { // If we ended on an escaped newline, then we want to continue onto // the nextline without processing the end of this one, as the newline // is in the middle of the field. - if ((line.EndsWith("\n", StringComparison.Ordinal) || line.EndsWith("\r", StringComparison.Ordinal)) && _state == State.InField) { + if ((line.EndsWith('\n') || line.EndsWith('\r')) && _state == State.InField) { continue; } } diff --git a/Src/IronPython.Modules/_ctypes/_ctypes.cs b/Src/IronPython.Modules/_ctypes/_ctypes.cs index fc5ed6665..47f4283ad 100644 --- a/Src/IronPython.Modules/_ctypes/_ctypes.cs +++ b/Src/IronPython.Modules/_ctypes/_ctypes.cs @@ -540,10 +540,12 @@ private static ModuleBuilder DynamicModule { lock (_nativeTypes) { if (!_nativeTypes.TryGetValue(size, out Type res)) { int sizeRemaining = size; +#pragma warning disable SYSLIB0050 // Type or member is obsolete TypeBuilder tb = DynamicModule.DefineType("interop_type_size_" + size, TypeAttributes.Public | TypeAttributes.SequentialLayout | TypeAttributes.Sealed | TypeAttributes.Serializable, typeof(ValueType), size); +#pragma warning restore SYSLIB0050 // Type or member is obsolete while (sizeRemaining > 8) { tb.DefineField("field" + sizeRemaining, typeof(long), FieldAttributes.Private); @@ -680,10 +682,6 @@ private static IntPtr GetHandleFromObject(object dll, string errorMsg) { return intPtrHandle; } - private static void ValidateArraySizes(ArrayModule.array array, int offset, int size) { - ValidateArraySizes(array.__len__() * array.itemsize, offset, size); - } - private static void ValidateArraySizes(int arraySize, int offset, int size) { if (offset < 0) { throw PythonOps.ValueError("offset cannot be negative"); diff --git a/Src/IronPython.Modules/_operator.cs b/Src/IronPython.Modules/_operator.cs index 92f262936..7dd04872a 100644 --- a/Src/IronPython.Modules/_operator.cs +++ b/Src/IronPython.Modules/_operator.cs @@ -59,7 +59,7 @@ private static object GetOneAttr(CodeContext context, object param, object val) int dotPos = s.IndexOf('.'); if (dotPos >= 0) { object nextParam = GetOneAttr(context, param, s.Substring(0, dotPos)); - return GetOneAttr(context, nextParam, s.Substring(dotPos + 1, s.Length - dotPos - 1)); + return GetOneAttr(context, nextParam, s.Substring(dotPos + 1)); } return PythonOps.GetBoundAttr(context, param, s); } diff --git a/Src/IronPython.Modules/_overlapped.cs b/Src/IronPython.Modules/_overlapped.cs index 0a39d7072..b0f468af7 100644 --- a/Src/IronPython.Modules/_overlapped.cs +++ b/Src/IronPython.Modules/_overlapped.cs @@ -22,7 +22,7 @@ public static class PythonOverlapped { private static extern IntPtr _CreateIoCompletionPort(IntPtr FileHandle, IntPtr ExistingCompletionPort, UIntPtr CompletionKey, uint NumberOfConcurrentThreads); public static BigInteger CreateIoCompletionPort(BigInteger handle, BigInteger port, BigInteger key, int concurrency) { - var res = _CreateIoCompletionPort((IntPtr)(long)handle, (IntPtr)(long)port, (UIntPtr)(ulong)key, (uint)concurrency); + var res = _CreateIoCompletionPort(checked((IntPtr)(long)handle), checked((IntPtr)(long)port), checked((UIntPtr)(ulong)key), (uint)concurrency); if (res == IntPtr.Zero) { throw PythonNT.GetLastWin32Error(); } diff --git a/Src/IronPython.Modules/_socket.cs b/Src/IronPython.Modules/_socket.cs index 9a59ee4bc..52bedab8c 100644 --- a/Src/IronPython.Modules/_socket.cs +++ b/Src/IronPython.Modules/_socket.cs @@ -863,7 +863,7 @@ public string __repr__(CodeContext context) { /// internal static Socket? HandleToSocket(Int64 handle) { lock (_handleToSocket) { - if (_handleToSocket.TryGetValue((IntPtr)handle, out WeakReference? weakref)) { + if (_handleToSocket.TryGetValue(checked((IntPtr)handle), out WeakReference? weakref)) { return weakref.Target as Socket; } } @@ -2216,10 +2216,6 @@ internal struct WSAData { [DllImport("ws2_32.dll", SetLastError = true)] private static extern Int32 WSACleanup(); - private static T PtrToStructure(IntPtr result) { - return (T)Marshal.PtrToStructure(result, typeof(T))!; - } - public static string GetServiceByPort(ushort port, string? protocol) { if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) return GetServiceByPortNonWindows(port, protocol); @@ -2236,9 +2232,9 @@ static string GetServiceByPortWindows(ushort port, string? protocol) { throw new SocketUtilException(string.Format("Could not resolve service for port {0}", port)); if (Environment.Is64BitProcess) - return PtrToStructure(result).s_name; + return Marshal.PtrToStructure(result).s_name; else - return PtrToStructure(result).s_name; + return Marshal.PtrToStructure(result).s_name; } static string GetServiceByPortNonWindows(ushort port, string? protocol) { @@ -2249,7 +2245,7 @@ static string GetServiceByPortNonWindows(ushort port, string? protocol) { string.Format("Could not resolve service for port {0}", port)); } - return PtrToStructure(result).s_name; + return Marshal.PtrToStructure(result).s_name; } } @@ -2268,9 +2264,9 @@ static ushort GetServiceByNameWindows(string service, string? protocol) { ushort port; if (Environment.Is64BitProcess) - port = PtrToStructure(result).s_port; + port = Marshal.PtrToStructure(result).s_port; else - port = PtrToStructure(result).s_port; + port = Marshal.PtrToStructure(result).s_port; var hostport = IPAddress.NetworkToHostOrder(unchecked((short)port)); return unchecked((ushort)hostport); @@ -2283,7 +2279,7 @@ static ushort GetServiceByNameNonWindows(string service, string? protocol) { string.Format("Could not resolve port for service {0}", service)); } - ushort port = PtrToStructure(result).s_port; + ushort port = Marshal.PtrToStructure(result).s_port; var hostport = IPAddress.NetworkToHostOrder(unchecked((short)port)); return unchecked((ushort)hostport); } diff --git a/Src/IronPython.Modules/_ssl.cs b/Src/IronPython.Modules/_ssl.cs index afd49f4ea..08ade85f6 100644 --- a/Src/IronPython.Modules/_ssl.cs +++ b/Src/IronPython.Modules/_ssl.cs @@ -5,6 +5,7 @@ #if FEATURE_FULL_NET using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -590,30 +591,61 @@ public string issuer() { [Documentation(@"read(size, [buffer]) Read up to size bytes from the SSL socket.")] - public object read(CodeContext/*!*/ context, int size, ByteArray buffer = null) { + public Bytes read(CodeContext/*!*/ context, int size) { EnsureSslStream(true); + if (size < 0) throw PythonOps.ValueError("size should not be negative"); + + var buf = ArrayPool.Rent(size); try { - byte[] buf = new byte[2048]; - MemoryStream result = new MemoryStream(size); - while (true) { - int readLength = (size < buf.Length) ? size : buf.Length; - int bytes = _sslStream.Read(buf, 0, readLength); - if (bytes > 0) { - result.Write(buf, 0, bytes); - size -= bytes; - } + int numRead; + try { + numRead = _sslStream.Read(buf, 0, size); + } catch (Exception e) { + throw PythonSocket.MakeException(context, e); + } + + var bytes = new byte[numRead]; + Array.Copy(buf, bytes, bytes.Length); + return Bytes.Make(bytes); + } finally { + ArrayPool.Return(buf); + } + } + + private static ArrayPool ArrayPool => ArrayPool.Shared; + + [Documentation(@"read(size, [buffer]) +Read up to size bytes from the SSL socket.")] + public int read(CodeContext/*!*/ context, int size, [NotNone] IBufferProtocol buffer) { + EnsureSslStream(true); + + using var pythonBuffer = buffer.GetBufferNoThrow(BufferFlags.Writable) + ?? throw PythonOps.TypeError("read() argument 2 must be read-write bytes-like object, not {0}", PythonOps.GetPythonTypeName(buffer)); - if (bytes == 0 || size == 0 || bytes < readLength) { - var res = result.ToArray(); - if (buffer == null) - return Bytes.Make(res); + var bufferLen = pythonBuffer.ItemCount; + if (size <= 0 || bufferLen < size) size = bufferLen; - // TODO: get rid of the MemoryStream and write directly to the buffer - buffer[new Slice(0, res.Length)] = res; - return res.Length; + try { +#if NETCOREAPP + return _sslStream.Read(pythonBuffer.AsSpan().Slice(0, size)); +#else + var buf = pythonBuffer.AsUnsafeWritableArray(); + if (buf is null) { + buf = ArrayPool.Rent(size); + try { + var numRead = _sslStream.Read(buf, 0, size); + buf.AsSpan(0, numRead).CopyTo(pythonBuffer.AsSpan()); + return numRead; + } + finally { + ArrayPool.Return(buf); } } + else { + return _sslStream.Read(buf, 0, size); + } +#endif } catch (Exception e) { throw PythonSocket.MakeException(context, e); } diff --git a/Src/IronPython.Modules/_struct.cs b/Src/IronPython.Modules/_struct.cs index 759dc2a53..d7b547704 100644 --- a/Src/IronPython.Modules/_struct.cs +++ b/Src/IronPython.Modules/_struct.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Numerics; @@ -220,10 +221,10 @@ public void __init__(CodeContext/*!*/ context, object fmt) { } [Documentation("Stores the deserialized data into the provided array")] - public void pack_into(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer, int offset, params object[] args) { - byte[] existing = buffer.ToByteArray(); + public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer, int offset, params object[] args) { + var existing = buffer.UnsafeByteList; - if (offset + size > existing.Length) { + if (offset + size > existing.Count) { throw Error(context, $"pack_into requires a buffer of at least {size} bytes"); } @@ -232,23 +233,21 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ for (int i = 0; i < data.Length; i++) { existing[i + offset] = data[i]; } - - buffer.Clear(); - buffer.FromStream(new MemoryStream(existing)); } - public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer, int offset, params object[] args) { - IList existing = buffer.UnsafeByteList; + public void pack_into(CodeContext/*!*/ context, [NotNone] IBufferProtocol/*!*/ buffer, int offset, params object[] args) { + using var existing = buffer.GetBufferNoThrow(BufferFlags.Writable) + ?? throw PythonOps.TypeError("argument must be read-write bytes-like object, not {0}", PythonOps.GetPythonTypeName(buffer)); - if (offset + size > existing.Count) { + var span = existing.AsSpan(); + + if (offset + size > span.Length) { throw Error(context, $"pack_into requires a buffer of at least {size} bytes"); } var data = pack(context, args).UnsafeByteArray; - for (int i = 0; i < data.Length; i++) { - existing[i + offset] = data[i]; - } + data.CopyTo(span.Slice(offset)); } [Documentation("deserializes the string using the structs specified format")] @@ -392,12 +391,8 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer, System.Diagnostics.Debug.Assert(res_idx == res.Length); return PythonTuple.MakeTuple(res); - } - public PythonTuple/*!*/ unpack(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer) - => unpack(context, buffer.ToByteArray()); - [Documentation("reads the current format from the specified array")] public PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [BytesLike][NotNone] IList/*!*/ buffer, int offset = 0) { int bytesAvail = buffer.Count - offset; @@ -408,19 +403,9 @@ public void pack_into(CodeContext/*!*/ context, [NotNone] ByteArray/*!*/ buffer, return unpack(context, buffer.Substring(offset, size)); } - [Documentation("reads the current format from the specified array")] - public PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) { - return unpack_from(context, buffer.ToByteArray(), offset); - } - [Documentation("iteratively unpack the current format from the specified array.")] - public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [BytesLike][NotNone] IList/*!*/ buffer, int offset = 0) { - return new PythonUnpackIterator(this, context, buffer, offset); - } - - [Documentation("iteratively unpack the current format from the specified array.")] - public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) { - return new PythonUnpackIterator(this, context, buffer, offset); + public PythonUnpackIterator iter_unpack(CodeContext/*!*/ context, [BytesLike][NotNone] IList/*!*/ buffer) { + return new PythonUnpackIterator(this, context, buffer); } [Documentation("gets the number of bytes that the serialized string will occupy or are required to deserialize the data")] @@ -586,14 +571,19 @@ private static Struct CompileAndCache(CodeContext/*!*/ context, string/*!*/ fmt) fLittleEndian = false; fStandardized = true; break; + case '\x00': + throw Error(context, "embedded null character"); default: if (char.IsDigit(fmt[i])) { count = 0; while (char.IsDigit(fmt[i])) { count = count * 10 + (fmt[i] - '0'); i++; + if (i >= fmt.Length) { + throw Error(context, "repeat count given without format specifier"); + } } - if (char.IsWhiteSpace(fmt[i])) Error(context, "white space not allowed between count and format"); + if (char.IsWhiteSpace(fmt[i])) throw Error(context, "white space not allowed between count and format"); i--; break; } @@ -654,51 +644,44 @@ internal static Struct Create(string/*!*/ format) { } [PythonType("unpack_iterator"), Documentation("Represents an iterator returned by _struct.iter_unpack()")] - public class PythonUnpackIterator : System.Collections.IEnumerator, System.Collections.IEnumerable { + public sealed class PythonUnpackIterator : IEnumerator, IEnumerable { private object _iter_current; private int _next_offset; private readonly CodeContext _context; private readonly IList _buffer; - private readonly int _start_offset; private readonly Struct _owner; - private PythonUnpackIterator() { } - - internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, IList/*!*/ buffer, int offset) { + internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, IList/*!*/ buffer) { _context = context; _buffer = buffer; - _start_offset = offset; - _owner = owner; - - Reset(); - ValidateBufferLength(); - } - - internal PythonUnpackIterator(Struct/*!*/ owner, CodeContext/*!*/ context, ArrayModule.array/*!*/ buffer, int offset) { - _context = context; - _buffer = buffer.ToByteArray(); - _start_offset = offset; _owner = owner; - Reset(); + _iter_current = null; + _next_offset = 0; ValidateBufferLength(); } private void ValidateBufferLength() { - if (_buffer.Count - _start_offset < _owner.size) { + if (_owner.size == 0) { + throw Error(_context, "cannot iteratively unpack with a struct of length 0"); + } + if (_buffer.Count % _owner.size != 0) { throw Error(_context, $"iterative unpacking requires a buffer of a multiple of {_owner.size} bytes"); } } - #region IEnumerable + #region IEnumerable Members + [PythonHidden] - public System.Collections.IEnumerator GetEnumerator() { - return this; - } + public System.Collections.IEnumerator GetEnumerator() => this; + + IEnumerator IEnumerable.GetEnumerator() => this; + #endregion - #region IEnumerator + #region IEnumerator Members + [PythonHidden] public object Current => _iter_current; @@ -713,28 +696,17 @@ public bool MoveNext() { return true; } - [PythonHidden] - public void Reset() { - _iter_current = null; - _next_offset = _start_offset; - } - #endregion + void IEnumerator.Reset() => throw new NotSupportedException(); - public object __iter__() { - return this; - } + [PythonHidden] + public void Dispose() { } - public object __next__() { - if (!MoveNext()) { - throw PythonOps.StopIteration(); - } - return Current; - } + #endregion - public int __length_hint__() { - return (_buffer.Count - _next_offset) / _owner.size; - } + public int __length_hint__() + => (_buffer.Count - _next_offset) / _owner.size; } + #endregion #region Compiled Format @@ -873,11 +845,11 @@ public static int calcsize(CodeContext/*!*/ context, object fmt) { } [Documentation("Pack the values v1, v2, ... according to fmt.\nWrite the packed bytes into the writable buffer buf starting at offset.")] - public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer, int offset, params object[] args) { + public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] ByteArray/*!*/ buffer, int offset, params object[] args) { GetStructFromCache(context, fmt).pack_into(context, buffer, offset, args); } - public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] ByteArray/*!*/ buffer, int offset, params object[] args) { + public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] IBufferProtocol/*!*/ buffer, int offset, params object[] args) { GetStructFromCache(context, fmt).pack_into(context, buffer, offset, args); } @@ -886,30 +858,16 @@ public static void pack_into(CodeContext/*!*/ context, object fmt, [NotNone] Byt return GetStructFromCache(context, fmt).unpack(context, buffer); } - [Documentation("Unpack the string containing packed C structure data, according to fmt.\nRequires len(string) == calcsize(fmt).")] - public static PythonTuple/*!*/ unpack(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer) { - return GetStructFromCache(context, fmt).unpack(context, buffer); - } - [Documentation("Unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")] public static PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, object fmt, [BytesLike][NotNone] IList/*!*/ buffer, int offset = 0) { return GetStructFromCache(context, fmt).unpack_from(context, buffer, offset); } - [Documentation("Unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")] - public static PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) { - return GetStructFromCache(context, fmt).unpack_from(context, buffer, offset); - } - [Documentation("Iteratively unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")] - public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [BytesLike][NotNone] IList/*!*/ buffer, int offset = 0) { - return GetStructFromCache(context, fmt).iter_unpack(context, buffer, offset); + public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [BytesLike][NotNone] IList/*!*/ buffer) { + return GetStructFromCache(context, fmt).iter_unpack(context, buffer); } - [Documentation("Iteratively unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")] - public static PythonUnpackIterator/*!*/ iter_unpack(CodeContext/*!*/ context, object fmt, [NotNone] ArrayModule.array/*!*/ buffer, int offset = 0) { - return GetStructFromCache(context, fmt).iter_unpack(context, buffer, offset); - } #endregion #region Write Helpers @@ -1251,16 +1209,16 @@ private static void CheckRange(CodeContext context, int val, int min, int max, s #region Data creater helpers internal static bool CreateBoolValue(CodeContext/*!*/ context, ref int index, IList data) { - return (int)ReadData(context, ref index, data) != 0; + return data[index++] != 0; } internal static byte CreateCharValue(CodeContext/*!*/ context, ref int index, IList data) { - return ReadData(context, ref index, data); + return data[index++]; } internal static short CreateShortValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - byte b1 = (byte)ReadData(context, ref index, data); - byte b2 = (byte)ReadData(context, ref index, data); + byte b1 = data[index++]; + byte b2 = data[index++]; if (fLittleEndian) { return (short)((b2 << 8) | b1); @@ -1270,8 +1228,8 @@ internal static short CreateShortValue(CodeContext/*!*/ context, ref int index, } internal static ushort CreateUShortValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - byte b1 = (byte)ReadData(context, ref index, data); - byte b2 = (byte)ReadData(context, ref index, data); + byte b1 = data[index++]; + byte b2 = data[index++]; if (fLittleEndian) { return (ushort)((b2 << 8) | b1); @@ -1283,12 +1241,12 @@ internal static ushort CreateUShortValue(CodeContext/*!*/ context, ref int index #if NET6_0_OR_GREATER internal static Half CreateHalfValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { byte[] bytes = new byte[2]; - if (fLittleEndian) { - bytes[0] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); + if (fLittleEndian == BitConverter.IsLittleEndian) { + bytes[0] = data[index++]; + bytes[1] = data[index++]; } else { - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[0] = (byte)ReadData(context, ref index, data); + bytes[1] = data[index++]; + bytes[0] = data[index++]; } Half res = BitConverter.ToHalf(bytes, 0); @@ -1304,16 +1262,16 @@ internal static Half CreateHalfValue(CodeContext/*!*/ context, ref int index, bo internal static float CreateFloatValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { byte[] bytes = new byte[4]; - if (fLittleEndian) { - bytes[0] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[2] = (byte)ReadData(context, ref index, data); - bytes[3] = (byte)ReadData(context, ref index, data); + if (fLittleEndian == BitConverter.IsLittleEndian) { + bytes[0] = data[index++]; + bytes[1] = data[index++]; + bytes[2] = data[index++]; + bytes[3] = data[index++]; } else { - bytes[3] = (byte)ReadData(context, ref index, data); - bytes[2] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[0] = (byte)ReadData(context, ref index, data); + bytes[3] = data[index++]; + bytes[2] = data[index++]; + bytes[1] = data[index++]; + bytes[0] = data[index++]; } float res = BitConverter.ToSingle(bytes, 0); @@ -1327,10 +1285,10 @@ internal static float CreateFloatValue(CodeContext/*!*/ context, ref int index, } internal static int CreateIntValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - byte b1 = (byte)ReadData(context, ref index, data); - byte b2 = (byte)ReadData(context, ref index, data); - byte b3 = (byte)ReadData(context, ref index, data); - byte b4 = (byte)ReadData(context, ref index, data); + byte b1 = data[index++]; + byte b2 = data[index++]; + byte b3 = data[index++]; + byte b4 = data[index++]; if (fLittleEndian) return (int)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1); @@ -1339,10 +1297,10 @@ internal static int CreateIntValue(CodeContext/*!*/ context, ref int index, bool } internal static uint CreateUIntValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - byte b1 = (byte)ReadData(context, ref index, data); - byte b2 = (byte)ReadData(context, ref index, data); - byte b3 = (byte)ReadData(context, ref index, data); - byte b4 = (byte)ReadData(context, ref index, data); + byte b1 = data[index++]; + byte b2 = data[index++]; + byte b3 = data[index++]; + byte b4 = data[index++]; if (fLittleEndian) return (uint)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1); @@ -1351,14 +1309,14 @@ internal static uint CreateUIntValue(CodeContext/*!*/ context, ref int index, bo } internal static long CreateLongValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - long b1 = (byte)ReadData(context, ref index, data); - long b2 = (byte)ReadData(context, ref index, data); - long b3 = (byte)ReadData(context, ref index, data); - long b4 = (byte)ReadData(context, ref index, data); - long b5 = (byte)ReadData(context, ref index, data); - long b6 = (byte)ReadData(context, ref index, data); - long b7 = (byte)ReadData(context, ref index, data); - long b8 = (byte)ReadData(context, ref index, data); + long b1 = data[index++]; + long b2 = data[index++]; + long b3 = data[index++]; + long b4 = data[index++]; + long b5 = data[index++]; + long b6 = data[index++]; + long b7 = data[index++]; + long b8 = data[index++]; if (fLittleEndian) return (long)((b8 << 56) | (b7 << 48) | (b6 << 40) | (b5 << 32) | @@ -1369,14 +1327,14 @@ internal static long CreateLongValue(CodeContext/*!*/ context, ref int index, bo } internal static ulong CreateULongValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { - ulong b1 = (byte)ReadData(context, ref index, data); - ulong b2 = (byte)ReadData(context, ref index, data); - ulong b3 = (byte)ReadData(context, ref index, data); - ulong b4 = (byte)ReadData(context, ref index, data); - ulong b5 = (byte)ReadData(context, ref index, data); - ulong b6 = (byte)ReadData(context, ref index, data); - ulong b7 = (byte)ReadData(context, ref index, data); - ulong b8 = (byte)ReadData(context, ref index, data); + ulong b1 = data[index++]; + ulong b2 = data[index++]; + ulong b3 = data[index++]; + ulong b4 = data[index++]; + ulong b5 = data[index++]; + ulong b6 = data[index++]; + ulong b7 = data[index++]; + ulong b8 = data[index++]; if (fLittleEndian) return (ulong)((b8 << 56) | (b7 << 48) | (b6 << 40) | (b5 << 32) | (b4 << 24) | (b3 << 16) | (b2 << 8) | b1); @@ -1387,24 +1345,24 @@ internal static ulong CreateULongValue(CodeContext/*!*/ context, ref int index, internal static double CreateDoubleValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, IList data) { byte[] bytes = new byte[8]; - if (fLittleEndian) { - bytes[0] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[2] = (byte)ReadData(context, ref index, data); - bytes[3] = (byte)ReadData(context, ref index, data); - bytes[4] = (byte)ReadData(context, ref index, data); - bytes[5] = (byte)ReadData(context, ref index, data); - bytes[6] = (byte)ReadData(context, ref index, data); - bytes[7] = (byte)ReadData(context, ref index, data); + if (fLittleEndian == BitConverter.IsLittleEndian) { + bytes[0] = data[index++]; + bytes[1] = data[index++]; + bytes[2] = data[index++]; + bytes[3] = data[index++]; + bytes[4] = data[index++]; + bytes[5] = data[index++]; + bytes[6] = data[index++]; + bytes[7] = data[index++]; } else { - bytes[7] = (byte)ReadData(context, ref index, data); - bytes[6] = (byte)ReadData(context, ref index, data); - bytes[5] = (byte)ReadData(context, ref index, data); - bytes[4] = (byte)ReadData(context, ref index, data); - bytes[3] = (byte)ReadData(context, ref index, data); - bytes[2] = (byte)ReadData(context, ref index, data); - bytes[1] = (byte)ReadData(context, ref index, data); - bytes[0] = (byte)ReadData(context, ref index, data); + bytes[7] = data[index++]; + bytes[6] = data[index++]; + bytes[5] = data[index++]; + bytes[4] = data[index++]; + bytes[3] = data[index++]; + bytes[2] = data[index++]; + bytes[1] = data[index++]; + bytes[0] = data[index++]; } double res = BitConverter.ToDouble(bytes, 0); @@ -1420,30 +1378,26 @@ internal static double CreateDoubleValue(CodeContext/*!*/ context, ref int index internal static Bytes CreateString(CodeContext/*!*/ context, ref int index, int count, IList data) { using var res = new MemoryStream(); for (int i = 0; i < count; i++) { - res.WriteByte(ReadData(context, ref index, data)); + res.WriteByte(data[index++]); } return Bytes.Make(res.ToArray()); } internal static Bytes CreatePascalString(CodeContext/*!*/ context, ref int index, int count, IList data) { - int realLen = (int)ReadData(context, ref index, data); + int realLen = (int)data[index++]; + if (realLen > count) realLen = count; using var res = new MemoryStream(); for (int i = 0; i < realLen; i++) { - res.WriteByte(ReadData(context, ref index, data)); + res.WriteByte(data[index++]); } for (int i = realLen; i < count; i++) { // throw away null bytes - ReadData(context, ref index, data); + index++; } return Bytes.Make(res.ToArray()); } - private static byte ReadData(CodeContext/*!*/ context, ref int index, IList data) { - if (index >= data.Count) throw Error(context, "not enough data while reading"); - - return data[index++]; - } #endregion #region Misc. Private APIs diff --git a/Src/IronPython.Modules/_thread.cs b/Src/IronPython.Modules/_thread.cs index 4bde8c6b5..e8df1f394 100644 --- a/Src/IronPython.Modules/_thread.cs +++ b/Src/IronPython.Modules/_thread.cs @@ -228,9 +228,9 @@ public void Start() { try { #pragma warning disable 618 // TODO: obsolete if (_kwargs != null) { - PythonOps.CallWithArgsTupleAndKeywordDictAndContext(_context, _func, ArrayUtils.EmptyObjects, ArrayUtils.EmptyStrings, _args, _kwargs); + PythonOps.CallWithArgsTupleAndKeywordDictAndContext(_context, _func, [], [], _args, _kwargs); } else { - PythonOps.CallWithArgsTuple(_func, ArrayUtils.EmptyObjects, _args); + PythonOps.CallWithArgsTuple(_func, [], _args); } #pragma warning restore 618 } catch (SystemExitException) { diff --git a/Src/IronPython.Modules/_winapi.cs b/Src/IronPython.Modules/_winapi.cs index 8a21f05dc..dcfacd5d4 100644 --- a/Src/IronPython.Modules/_winapi.cs +++ b/Src/IronPython.Modules/_winapi.cs @@ -26,7 +26,7 @@ public static class PythonWinApi { throw new NotImplementedException(); } else { - var result = ConnectNamedPipe((IntPtr)(long)handle, IntPtr.Zero); + var result = ConnectNamedPipe(checked((IntPtr)(long)handle), IntPtr.Zero); if (!result) throw PythonNT.GetLastWin32Error(); diff --git a/Src/IronPython.Modules/array.cs b/Src/IronPython.Modules/array.cs index fc6c00c26..2bee03a5f 100644 --- a/Src/IronPython.Modules/array.cs +++ b/Src/IronPython.Modules/array.cs @@ -248,7 +248,7 @@ public PythonTuple buffer_info() { } public void byteswap() { - Stream s = ToStream(); + MemoryStream s = ToStream(); byte[] bytes = new byte[s.Length]; s.Read(bytes, 0, bytes.Length); @@ -614,7 +614,7 @@ public PythonList tolist() { } public Bytes tobytes() { - Stream s = ToStream(); + MemoryStream s = ToStream(); byte[] bytes = new byte[s.Length]; s.Read(bytes, 0, (int)s.Length); return Bytes.Make(bytes); diff --git a/Src/IronPython.Modules/binascii.cs b/Src/IronPython.Modules/binascii.cs index 9049ab669..ed4e6f7ed 100644 --- a/Src/IronPython.Modules/binascii.cs +++ b/Src/IronPython.Modules/binascii.cs @@ -59,7 +59,7 @@ static Bytes a2b_uu_impl(CodeContext/*!*/ context, ReadOnlySpan data) { } using MemoryStream res = DecodeWorker(context, data, true, UuDecFunc); - if (suffix == null) { + if (suffix.IsEmpty) { var pad = new byte[lenDec - res.Length]; res.Write(pad, 0, pad.Length); } else { diff --git a/Src/IronPython.Modules/grp.cs b/Src/IronPython.Modules/grp.cs index 050bac7b7..dc0344358 100644 --- a/Src/IronPython.Modules/grp.cs +++ b/Src/IronPython.Modules/grp.cs @@ -76,7 +76,7 @@ internal struct_group(string gr_name, string gr_passwd, int gr_gid, PythonList g } private static struct_group Make(IntPtr pwd) { - group g = (group)Marshal.PtrToStructure(pwd, typeof(group)); + group g = Marshal.PtrToStructure(pwd); return new struct_group(g.gr_name, g.gr_passwd, g.gr_gid, PythonList.FromEnumerable(MarshalStringArray(g.gr_mem))); } diff --git a/Src/IronPython.Modules/pwd.cs b/Src/IronPython.Modules/pwd.cs index 510e47109..1eb3b015b 100644 --- a/Src/IronPython.Modules/pwd.cs +++ b/Src/IronPython.Modules/pwd.cs @@ -106,10 +106,10 @@ internal struct_passwd(string pw_name, string pw_passwd, int pw_uid, int pw_gid, private static struct_passwd Make(IntPtr pwd) { struct_passwd res = null; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - passwd_osx p = (passwd_osx)Marshal.PtrToStructure(pwd, typeof(passwd_osx)); + passwd_osx p = Marshal.PtrToStructure(pwd); res = new struct_passwd(p.pw_name, p.pw_passwd, p.pw_uid, p.pw_gid, p.pw_gecos, p.pw_dir, p.pw_shell); } else { - passwd_linux p = (passwd_linux)Marshal.PtrToStructure(pwd, typeof(passwd_linux)); + passwd_linux p = Marshal.PtrToStructure(pwd); res = new struct_passwd(p.pw_name, p.pw_passwd, p.pw_uid, p.pw_gid, p.pw_gecos, p.pw_dir, p.pw_shell); } diff --git a/Src/IronPython.Modules/re.cs b/Src/IronPython.Modules/re.cs index 28785c8bf..9d1405332 100644 --- a/Src/IronPython.Modules/re.cs +++ b/Src/IronPython.Modules/re.cs @@ -733,12 +733,15 @@ static string ValidateString(object? str) { return bytes.MakeString(); case ByteArray byteArray: return byteArray.MakeString(); - case ArrayModule.array array: - return Bytes.Make(array.ToByteArray()).MakeString(); #if FEATURE_MMAP case MmapModule.MmapDefault mmapFile: return mmapFile.GetSearchString().MakeString(); #endif + case IBufferProtocol bufferProtocol: { + using var buffer = bufferProtocol.GetBuffer(); + return buffer.AsReadOnlySpan().MakeString(); + } + default: throw PythonOps.TypeError($"expected string or bytes-like object"); } diff --git a/Src/IronPython.Modules/spwd.cs b/Src/IronPython.Modules/spwd.cs index 695ff6535..9445f7341 100644 --- a/Src/IronPython.Modules/spwd.cs +++ b/Src/IronPython.Modules/spwd.cs @@ -90,7 +90,7 @@ internal struct_spwd(string sp_nam, string sp_pwd, int sp_lstchg, int sp_min, in } private static struct_spwd Make(IntPtr pwd) { - spwd p = (spwd)Marshal.PtrToStructure(pwd, typeof(spwd)); + spwd p = Marshal.PtrToStructure(pwd); return new struct_spwd(p.sp_namp, p.sp_pwdp, p.sp_lstchg, p.sp_min, p.sp_max, p.sp_warn, p.sp_inact, p.sp_expire, p.sp_flag); } diff --git a/Src/IronPython.SQLite/IronPython.SQLite.csproj b/Src/IronPython.SQLite/IronPython.SQLite.csproj index f00505312..60466e71a 100644 --- a/Src/IronPython.SQLite/IronPython.SQLite.csproj +++ b/Src/IronPython.SQLite/IronPython.SQLite.csproj @@ -1,7 +1,7 @@  - net462;netstandard2.0;net6.0 + net462;netstandard2.0;net6.0;net8.0 true SQLITE_DEBUG;TRUE;WIN32;_MSC_VER;SQLITE_ASCII;SQLITE_MEM_POOL;SQLITE_ENABLE_COLUMN_METADATA;SQLITE_OS_WIN;SQLITE_SYSTEM_MALLOC;VDBE_PROFILE_OFF SQLITE_OMIT_AUTHORIZATION;SQLITE_OMIT_DEPRECATED;SQLITE_OMIT_GET_TABLE;SQLITE_OMIT_INCRBLOB;SQLITE_OMIT_LOOKASIDE;SQLITE_OMIT_SHARED_CACHE;SQLITE_OMIT_UTF16;SQLITE_OMIT_WAL diff --git a/Src/IronPython.SQLite/c#sqlite/ctime_c.cs b/Src/IronPython.SQLite/c#sqlite/ctime_c.cs index ad8dfbf01..5f7917a0e 100644 --- a/Src/IronPython.SQLite/c#sqlite/ctime_c.cs +++ b/Src/IronPython.SQLite/c#sqlite/ctime_c.cs @@ -1,3 +1,5 @@ +#pragma warning disable CA1865 // Use char overload + namespace Community.CsharpSqlite { using sqlite3_value = Sqlite3.Mem; diff --git a/Src/IronPython.SQLite/c#sqlite/tokenize_c.cs b/Src/IronPython.SQLite/c#sqlite/tokenize_c.cs index a326c7959..71b7f5aa4 100644 --- a/Src/IronPython.SQLite/c#sqlite/tokenize_c.cs +++ b/Src/IronPython.SQLite/c#sqlite/tokenize_c.cs @@ -627,7 +627,7 @@ static int sqlite3RunParser( Parse pParse, string zSql, ref string pzErrMsg ) } } abort_parse: - pParse.zTail = new StringBuilder( zSql.Length <= i ? "" : zSql.Substring( i, zSql.Length - i ) ); + pParse.zTail = new StringBuilder( zSql.Length <= i ? "" : zSql.Substring( i ) ); if ( zSql.Length >= i && nErr == 0 && pParse.rc == SQLITE_OK ) { if ( lastTokenParsed != TK_SEMI ) diff --git a/Src/IronPython.Wpf/IronPython.Wpf.csproj b/Src/IronPython.Wpf/IronPython.Wpf.csproj index 9d0ff5997..97f2aebb6 100644 --- a/Src/IronPython.Wpf/IronPython.Wpf.csproj +++ b/Src/IronPython.Wpf/IronPython.Wpf.csproj @@ -1,7 +1,7 @@  - net462;net6.0-windows + net462;net6.0-windows;net8.0-windows true true true diff --git a/Src/IronPython/Compiler/Ast/ClassDefinition.cs b/Src/IronPython/Compiler/Ast/ClassDefinition.cs index 1b126d4fe..8c68fab0b 100644 --- a/Src/IronPython/Compiler/Ast/ClassDefinition.cs +++ b/Src/IronPython/Compiler/Ast/ClassDefinition.cs @@ -15,7 +15,6 @@ using IronPython.Runtime; using Microsoft.Scripting; -using Microsoft.Scripting.Actions; using Microsoft.Scripting.Utils; using AstUtils = Microsoft.Scripting.Ast.Utils; @@ -403,7 +402,7 @@ public static string[] FindNames(FunctionDefinition function) { if (parameters.Count == 0) { // no point analyzing function with no parameters - return ArrayUtils.EmptyStrings; + return []; } var finder = new SelfNameFinder(function, parameters[0]); diff --git a/Src/IronPython/Compiler/Ast/FunctionDefinition.cs b/Src/IronPython/Compiler/Ast/FunctionDefinition.cs index 270725fad..36e74b0bb 100644 --- a/Src/IronPython/Compiler/Ast/FunctionDefinition.cs +++ b/Src/IronPython/Compiler/Ast/FunctionDefinition.cs @@ -5,21 +5,20 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Text; using System.Threading; -using System.Runtime.CompilerServices; - -using Microsoft.Scripting; -using Microsoft.Scripting.Interpreter; -using Microsoft.Scripting.Utils; using IronPython.Runtime; using IronPython.Runtime.Operations; -using MSAst = System.Linq.Expressions; +using Microsoft.Scripting; +using Microsoft.Scripting.Interpreter; +using Microsoft.Scripting.Utils; -using LightLambdaExpression = Microsoft.Scripting.Ast.LightLambdaExpression; using AstUtils = Microsoft.Scripting.Ast.Utils; +using LightLambdaExpression = Microsoft.Scripting.Ast.LightLambdaExpression; +using MSAst = System.Linq.Expressions; namespace IronPython.Compiler.Ast { using Ast = MSAst.Expression; @@ -85,8 +84,7 @@ internal override MSAst.Expression LocalContext { internal override int ArgCount { get { int argCount = 0; - for (argCount = 0; argCount < _parameters.Length; argCount++) - { + for (argCount = 0; argCount < _parameters.Length; argCount++) { Parameter p = _parameters[argCount]; if (p.IsDictionary || p.IsList || p.IsKeywordOnly) break; } @@ -256,7 +254,7 @@ internal override void Bind(PythonNameBinder binder) { NeedsLocalsDictionary = true; } } - + internal override void FinishBind(PythonNameBinder binder) { foreach (var param in _parameters) { _variableMapping[param.PythonVariable] = param.FinishBind(forceClosureCell: ExposesLocalVariable(param.PythonVariable)); @@ -286,7 +284,7 @@ public override MSAst.Expression Reduce() { new SourceSpan(GlobalParent.IndexToLocation(StartIndex), GlobalParent.IndexToLocation(HeaderIndex)) ); } - + /// /// Returns an expression which creates the function object. /// @@ -542,7 +540,7 @@ public override int Run(InterpretedFrame frame) { defaults[i] = frame.Pop(); } } else { - defaults = ArrayUtils.EmptyObjects; + defaults = []; } object modName; @@ -696,6 +694,7 @@ private LightLambdaExpression CreateFunctionLambda() { // wrap a scope if needed bodyStmt = Ast.Block(locals.ToReadOnlyCollection(), bodyStmt); +#pragma warning disable CA2263 // Prefer generic overload when type is known return AstUtils.LightLambda( typeof(object), delegateType, @@ -703,6 +702,7 @@ private LightLambdaExpression CreateFunctionLambda() { Name + "$" + Interlocked.Increment(ref _lambdaId), parameters ); +#pragma warning restore CA2263 // Prefer generic overload when type is known } internal override LightLambdaExpression GetLambda() => EnsureFunctionLambda(); @@ -777,7 +777,7 @@ internal override IList GetVarNames() { return res; } - + private void InitializeParameters(List init, bool needsWrapperMethod, MSAst.Expression[] parameters) { for (int i = 0; i < _parameters.Length; i++) { Parameter p = _parameters[i]; @@ -827,10 +827,10 @@ private static Type GetDelegateType(Parameter[] parameters, bool wrapper, out De internal override void RewriteBody(MSAst.ExpressionVisitor visitor) { _dlrBody = null; // clear the cached body if we've been reduced - + MSAst.Expression funcCode = GlobalParent.Constant(GetOrMakeFunctionCode()); FuncCodeExpr = funcCode; - + Body = new RewrittenBodyStatement(Body, visitor.Visit(Body)); } diff --git a/Src/IronPython/Compiler/Ast/ScopeStatement.cs b/Src/IronPython/Compiler/Ast/ScopeStatement.cs index 28d571804..55ddbee69 100644 --- a/Src/IronPython/Compiler/Ast/ScopeStatement.cs +++ b/Src/IronPython/Compiler/Ast/ScopeStatement.cs @@ -92,7 +92,7 @@ public abstract class ScopeStatement : Statement { /// /// It is used to ensure that the first argument is accessible through a closure cell. /// - internal bool ContainsSuperCall{ get; set; } + internal bool ContainsSuperCall { get; set; } public virtual string Name => ""; @@ -116,7 +116,7 @@ public abstract class ScopeStatement : Statement { internal bool NeedsLocalContext => NeedsLocalsDictionary || ContainsNestedFreeVariables || ContainsSuperCall; - internal virtual string[] ParameterNames => ArrayUtils.EmptyStrings; + internal virtual string[] ParameterNames => []; internal virtual int ArgCount => 0; @@ -439,7 +439,7 @@ private PythonVariable CreateNonlocalVariable(string name) { } internal void EnsureNonlocalVariable(string name, NonlocalStatement node) { - _nonlocalVars ??= new(); + _nonlocalVars ??= new(); if (!_nonlocalVars.ContainsKey(name)) { CreateNonlocalVariable(name); _nonlocalVars[name] = node; @@ -611,7 +611,7 @@ internal MSAst.Expression? FuncCodeExpr { internal MSAst.MethodCallExpression CreateLocalContext(MSAst.Expression parentContext, bool newNamespace = true) { var closureVariables = _closureVariables ?? Array.Empty(); - + int numFreeVars = FreeVariables?.Count ?? 0; int firstArgIdx = -1; if ((NeedsLocalsDictionary || ContainsSuperCall) && ArgCount > 0) { diff --git a/Src/IronPython/Compiler/Parser.cs b/Src/IronPython/Compiler/Parser.cs index 79814cb28..9161912bd 100644 --- a/Src/IronPython/Compiler/Parser.cs +++ b/Src/IronPython/Compiler/Parser.cs @@ -274,7 +274,7 @@ public static int GetNextAutoIndentSize(string text, int autoIndentTabWidth) { int autoIndentSize = startingSpaces; // Increase the indent if this looks like the start of a compounds statement. // Ideally, we would ask the parser to tell us the exact indentation level - if (lastLine.TrimEnd(whiteSpace).EndsWith(":", StringComparison.Ordinal)) + if (lastLine.TrimEnd(whiteSpace).EndsWith(':')) autoIndentSize += autoIndentTabWidth; return autoIndentSize; @@ -804,7 +804,7 @@ private ModuleName ParseRelativeModuleName() { dotCount++; } - string[] names = ArrayUtils.EmptyStrings; + string[] names = []; if (PeekToken() is NameToken) { names = ReadNames(); } diff --git a/Src/IronPython/Hosting/PythonCommandLine.cs b/Src/IronPython/Hosting/PythonCommandLine.cs index 3d1a9fee6..afc65ea3c 100644 --- a/Src/IronPython/Hosting/PythonCommandLine.cs +++ b/Src/IronPython/Hosting/PythonCommandLine.cs @@ -288,7 +288,7 @@ private void InitializeModules() { for (var i = 0; i < 2; i++) { if (File.Exists(path)) { foreach (var line in File.ReadAllLines(path, Encoding.UTF8)) { // TODO: this actually needs to be decoded with surrogateescape - if (line.StartsWith("#", StringComparison.Ordinal)) continue; + if (line.StartsWith('#')) continue; var split = line.Split(new[] { '=' }, 2); if (split.Length != 2) continue; if (split[0].Trim() == "home") { diff --git a/Src/IronPython/Hosting/PythonOptionsParser.cs b/Src/IronPython/Hosting/PythonOptionsParser.cs index 47de95239..1bd42ee80 100644 --- a/Src/IronPython/Hosting/PythonOptionsParser.cs +++ b/Src/IronPython/Hosting/PythonOptionsParser.cs @@ -157,7 +157,7 @@ protected override void ParseArgument(string/*!*/ arg) { return; } - if (arg.StartsWith("-", StringComparison.Ordinal)) { + if (arg.StartsWith('-')) { if (arg.StartsWith("-X:", StringComparison.Ordinal)) { // old implementation specific options for compat switch (arg) { diff --git a/Src/IronPython/IronPython.csproj b/Src/IronPython/IronPython.csproj index b44389ed9..1736ecd4e 100644 --- a/Src/IronPython/IronPython.csproj +++ b/Src/IronPython/IronPython.csproj @@ -1,7 +1,7 @@  - net462;netstandard2.0;net6.0 + net462;netstandard2.0;net6.0;net8.0 879755264 true true diff --git a/Src/IronPython/Lib/iptest/test_env.py b/Src/IronPython/Lib/iptest/test_env.py index 94006df20..bbcd239b5 100644 --- a/Src/IronPython/Lib/iptest/test_env.py +++ b/Src/IronPython/Lib/iptest/test_env.py @@ -21,6 +21,8 @@ is_netcoreapp31 = False is_net60 = False is_net70 = False +is_net80 = False +is_net90 = False is_mono = False is_netstandard = False if is_ironpython: @@ -30,6 +32,8 @@ is_netcoreapp31 = clr.FrameworkDescription.startswith(".NET Core 3.1") is_net60 = clr.FrameworkDescription.startswith(".NET 6.0") is_net70 = clr.FrameworkDescription.startswith(".NET 7.0") + is_net80 = clr.FrameworkDescription.startswith(".NET 8.0") + is_net90 = clr.FrameworkDescription.startswith(".NET 9.0") is_mono = clr.IsMono is_netstandard = clr.TargetFramework.startswith(".NETStandard") diff --git a/Src/IronPython/Modules/Builtin.cs b/Src/IronPython/Modules/Builtin.cs index c98617b89..0fba5cf66 100644 --- a/Src/IronPython/Modules/Builtin.cs +++ b/Src/IronPython/Modules/Builtin.cs @@ -1294,7 +1294,7 @@ private static void PrintHelper(CodeContext/*!*/ context, string/*!*/ sep, strin line = PythonOps.ReadLineFromSrc(context, context.LanguageContext.SystemStandardIn) as string; } - if (line != null && line.EndsWith("\n", StringComparison.Ordinal)) return line.Substring(0, line.Length - 1); + if (line != null && line.EndsWith('\n')) return line.Substring(0, line.Length - 1); return line; } diff --git a/Src/IronPython/Modules/_io.cs b/Src/IronPython/Modules/_io.cs index 347409715..99f290931 100644 --- a/Src/IronPython/Modules/_io.cs +++ b/Src/IronPython/Modules/_io.cs @@ -32,7 +32,7 @@ public static partial class PythonIOModule { private static readonly object _unsupportedOperationKey = new object(); // Values of the O_flags below has to be identical with flags defined in PythonNT - + #region Generated Common O_Flags // *** BEGIN GENERATED CODE *** @@ -93,11 +93,13 @@ public void __exit__(CodeContext/*!*/ context, params object[] excinfo) { close(context); } +#nullable enable + public void _checkClosed() { _checkClosed(null); } - public void _checkClosed(string msg) { + internal void _checkClosed(string? msg) { if (closed) { throw PythonOps.ValueError(msg ?? "I/O operation on closed file."); } @@ -107,7 +109,7 @@ public void _checkReadable() { _checkReadable(null); } - public void _checkReadable(string msg) { + internal void _checkReadable(string? msg) { if (!readable(context)) { throw UnsupportedOperationWithMessage(context, msg ?? "File or stream is not readable."); } @@ -117,9 +119,9 @@ public void _checkSeekable() { _checkSeekable(null); } - public void _checkSeekable(string msg) { + internal void _checkSeekable(string? msg) { if (!seekable(context)) { - throw PythonOps.ValueError(msg ?? "File or stream is not seekable."); + throw UnsupportedOperationWithMessage(context, msg ?? "File or stream is not seekable."); } } @@ -127,12 +129,14 @@ public void _checkWritable() { _checkWritable(null); } - public void _checkWritable(string msg) { + internal void _checkWritable(string? msg) { if (!writable(context)) { throw UnsupportedOperationWithMessage(context, msg ?? "File or stream is not writable."); } } +#nullable restore + public virtual void close(CodeContext/*!*/ context) { try { if (!_closed) { @@ -161,18 +165,18 @@ public virtual bool isatty(CodeContext/*!*/ context) { } [PythonHidden] - public virtual Bytes peek(CodeContext/*!*/ context, int length=0) { + public virtual Bytes peek(CodeContext/*!*/ context, int length = 0) { _checkClosed(); throw AttributeError("peek"); } [PythonHidden] - public virtual object read(CodeContext/*!*/ context, object length=null) { + public virtual object read(CodeContext/*!*/ context, object length = null) { throw AttributeError("read"); } [PythonHidden] - public virtual Bytes read1(CodeContext/*!*/ context, int length=0) { + public virtual Bytes read1(CodeContext/*!*/ context, int length = 0) { throw AttributeError("read1"); } @@ -190,7 +194,7 @@ public virtual object readline(CodeContext/*!*/ context, int limit) { if (cur == null) { break; } - + Bytes curBytes = GetBytes(cur, "read()"); if (curBytes.Count == 0) { break; @@ -206,7 +210,7 @@ public virtual object readline(CodeContext/*!*/ context, int limit) { return Bytes.Concat(res, count); } - public object readline(CodeContext/*!*/ context, object limit=null) { + public object readline(CodeContext/*!*/ context, object limit = null) { return readline(context, GetInt(limit, -1)); } @@ -214,7 +218,7 @@ public virtual PythonList readlines() { return readlines(null); } - public virtual PythonList readlines(object hint=null) { + public virtual PythonList readlines(object hint = null) { int size = GetInt(hint, -1); PythonList res = new PythonList(); @@ -251,7 +255,7 @@ public virtual PythonList readlines(object hint=null) { return res; } - public virtual BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optional]object whence) { + public virtual BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optional] object whence) { throw UnsupportedOperation(context, "seek"); } @@ -263,7 +267,7 @@ public virtual BigInteger tell(CodeContext/*!*/ context) { return seek(context, 0, 1); } - public virtual BigInteger truncate(CodeContext/*!*/ context, object pos=null) { + public virtual BigInteger truncate(CodeContext/*!*/ context, object pos = null) { throw UnsupportedOperation(context, "truncate"); } @@ -402,7 +406,7 @@ private PythonDictionary EnsureCustomAttributes() { DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) { return new MetaExpandable<_IOBase>(parameter, this); } - + #endregion #region Private implementation details @@ -424,7 +428,7 @@ internal Exception AttributeError(string attrName) { internal Exception InvalidPosition(BigInteger pos) { return PythonOps.IOError("Raw stream returned invalid position {0}", pos); } - + #endregion } @@ -434,7 +438,7 @@ public _RawIOBase(CodeContext/*!*/ context) : base(context) { } #region Public API - public override object read(CodeContext/*!*/ context, object size=null) { + public override object read(CodeContext/*!*/ context, object size = null) { int sizeInt = GetInt(size, -1); if (sizeInt < 0) { return readall(context); @@ -480,7 +484,7 @@ public override BigInteger write(CodeContext/*!*/ context, object buf) { } #endregion - + #region IDynamicMetaObjectProvider Members DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) { @@ -500,7 +504,7 @@ public virtual object detach(CodeContext/*!*/ context) { throw UnsupportedOperation(context, "detach"); } - public override object read(CodeContext/*!*/ context, object length=null) { + public override object read(CodeContext/*!*/ context, object length = null) { throw UnsupportedOperation(context, "read"); } @@ -573,15 +577,15 @@ public virtual object newlines { get { return null; } } - public override object read(CodeContext/*!*/ context, [DefaultParameterValue(-1)]object length) { + public override object read(CodeContext/*!*/ context, [DefaultParameterValue(-1)] object length) { throw UnsupportedOperation(context, "read"); } - public override object readline(CodeContext/*!*/ context, int limit=-1) { + public override object readline(CodeContext/*!*/ context, int limit = -1) { throw UnsupportedOperation(context, "readline"); } - public override BigInteger truncate(CodeContext/*!*/ context, object pos=null) { + public override BigInteger truncate(CodeContext/*!*/ context, object pos = null) { throw UnsupportedOperation(context, "truncate"); } @@ -608,8 +612,9 @@ public class BufferedReader : _BufferedIOBase, IDynamicMetaObjectProvider { private int _bufSize; private Bytes _readBuf; private int _readBufPos; + private long _absPos = -1; - internal static BufferedReader Create(CodeContext/*!*/ context, object raw, int buffer_size=DEFAULT_BUFFER_SIZE) { + internal static BufferedReader Create(CodeContext/*!*/ context, object raw, int buffer_size = DEFAULT_BUFFER_SIZE) { var res = new BufferedReader(context, raw, buffer_size); res.__init__(context, raw, buffer_size); return res; @@ -624,7 +629,7 @@ params object[] args public void __init__( CodeContext/*!*/ context, object raw, - int buffer_size=DEFAULT_BUFFER_SIZE + int buffer_size = DEFAULT_BUFFER_SIZE ) { this.raw = raw; @@ -659,17 +664,6 @@ public object raw { #region _BufferedIOMixin - public override BigInteger truncate(CodeContext/*!*/ context, object pos=null) { - if (_rawIO != null) { - return _rawIO.truncate(context, pos); - } - - return GetBigInt( - PythonOps.Invoke(context, _raw, "truncate", pos), - "truncate() should return integer" - ); - } - public override void close(CodeContext/*!*/ context) { if (!closed) { try { @@ -709,12 +703,7 @@ public override bool readable(CodeContext/*!*/ context) { return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "readable")); } - public override bool writable(CodeContext/*!*/ context) { - if (_rawIO != null) { - return _rawIO.writable(context); - } - return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "writable")); - } + public override bool writable(CodeContext/*!*/ context) => false; public override bool closed { get { @@ -756,7 +745,7 @@ public override bool isatty(CodeContext/*!*/ context) { #endregion - public override object read(CodeContext/*!*/ context, object length=null) { + public override object read(CodeContext/*!*/ context, object length = null) { int len = GetInt(length, -1); if (len < -1) { @@ -768,7 +757,21 @@ public override object read(CodeContext/*!*/ context, object length=null) { } } - private Bytes ReadNoLock(CodeContext/*!*/ context, int length, bool read1 = false) { +#nullable enable + + private Bytes? CallRawRead(CodeContext/*!*/ context, object length) { + object? obj = _rawIO != null ? _rawIO.read(context, length) : PythonOps.Invoke(context, _raw, "read", length); + if (obj is null) return null; + if (obj is Bytes bytes) { + if (_absPos != -1) { + _absPos += bytes.Count; + } + return bytes; + } + throw PythonOps.TypeError("'read()' should have returned bytes"); + } + + private Bytes? ReadNoLock(CodeContext/*!*/ context, int length, bool read1 = false) { if (length == 0) { return Bytes.Empty; } @@ -776,26 +779,19 @@ private Bytes ReadNoLock(CodeContext/*!*/ context, int length, bool read1 = fals if (length < 0) { List chunks = new List(); int count = 0; - if (_readBuf.Count > 0) { - chunks.Add(ResetReadBuf()); + if (_readBuf.Count > 0 && TryResetReadBuf(out Bytes res)) { + chunks.Add(res); count += chunks[0].Count; } for (; ; ) { - object chunkObj; - if (_rawIO != null) { - chunkObj = _rawIO.read(context, -1); - } else { - chunkObj = PythonOps.Invoke(context, _raw, "read", -1); - } - - Bytes chunk = GetBytes(chunkObj, "read()"); + var chunk = CallRawRead(context, -1); if (chunk == null || chunk.Count == 0) { if (count == 0) { return chunk; } break; } - chunks.Add(chunk); + chunks.Add(chunk); count += chunk.Count; if (read1) break; } @@ -819,20 +815,13 @@ private Bytes ReadNoLock(CodeContext/*!*/ context, int length, bool read1 = fals // a read is required to provide requested amount of data List chunks = new List(); int remaining = length; - if (_readBuf.Count > 0) { - chunks.Add(ResetReadBuf()); + if (_readBuf.Count > 0 && TryResetReadBuf(out Bytes res)) { + chunks.Add(res); remaining -= chunks[0].Count; } while (remaining > 0) { - object chunkObj; - if (_rawIO != null) { - chunkObj = _rawIO.read(context, _bufSize); - } else { - chunkObj = PythonOps.Invoke(context, _raw, "read", _bufSize); - } - - Bytes chunk = chunkObj != null ? GetBytes(chunkObj, "read()") : Bytes.Empty; + var chunk = CallRawRead(context, _bufSize) ?? Bytes.Empty; _readBuf = chunk; if (_readBuf.Count == 0) { @@ -840,7 +829,9 @@ private Bytes ReadNoLock(CodeContext/*!*/ context, int length, bool read1 = fals } if (remaining >= _readBuf.Count - _readBufPos) { remaining -= _readBuf.Count - _readBufPos; - chunks.Add(ResetReadBuf()); + if (TryResetReadBuf(out res)) { + chunks.Add(res); + } } else { byte[] bytes = new byte[remaining]; Array.Copy(_readBuf.UnsafeByteArray, 0, bytes, 0, remaining); @@ -856,7 +847,9 @@ private Bytes ReadNoLock(CodeContext/*!*/ context, int length, bool read1 = fals } } - public override Bytes peek(CodeContext/*!*/ context, int length=0) { +#nullable restore + + public override Bytes peek(CodeContext/*!*/ context, int length = 0) { _checkClosed(); if (length <= 0 || length > _bufSize) { @@ -877,20 +870,17 @@ private Bytes PeekNoLock(CodeContext/*!*/ context, int length) { return Bytes.Make(bytes); } - object nextObj; - if (_rawIO != null) { - nextObj = _rawIO.read(context, length - _readBuf.Count + _readBufPos); + var next = CallRawRead(context, length - _readBuf.Count + _readBufPos) ?? Bytes.Empty; + + if (TryResetReadBuf(out Bytes res)) { + _readBuf = res + next; } else { - nextObj = PythonOps.Invoke(context, _raw, "read", length - _readBuf.Count + _readBufPos); + _readBuf = next; } - - Bytes next = nextObj != null ? GetBytes(nextObj, "read()") : Bytes.Empty; - - _readBuf = ResetReadBuf() + next; return _readBuf; } - public override Bytes read1(CodeContext/*!*/ context, int length=0) { + public override Bytes read1(CodeContext/*!*/ context, int length = 0) { if (length == 0) { return Bytes.Empty; } else if (length < 0) { @@ -946,7 +936,9 @@ public override object readline(CodeContext context, int limit) { return Bytes.Concat(chunks, cnt); } - (chunks ??= new List()).Add(ResetReadBuf()); + if (TryResetReadBuf(out Bytes res)) { + (chunks ??= new List()).Add(res); + } cnt += buf.Length; } @@ -962,22 +954,14 @@ public override object readline(CodeContext context, int limit) { } bool TryReadNextChunk(CodeContext context) { - object chunkObj; - if (_rawIO != null) { - chunkObj = _rawIO.read(context, _bufSize); - } else { - chunkObj = PythonOps.Invoke(context, _raw, "read", _bufSize); - } - - Bytes chunk = chunkObj != null ? GetBytes(chunkObj, "read()") : Bytes.Empty; - + var chunk = CallRawRead(context, _bufSize) ?? Bytes.Empty; _readBuf = chunk; return chunk.Count != 0; } } public override BigInteger tell(CodeContext/*!*/ context) { - BigInteger res = _rawIO != null ? + var res = _rawIO != null ? _rawIO.tell(context) : GetBigInt( PythonOps.Invoke(context, _raw, "tell"), @@ -987,22 +971,42 @@ public override BigInteger tell(CodeContext/*!*/ context) { throw InvalidPosition(res); } + _absPos = checked((long)res); return res - _readBuf.Count + _readBufPos; } - public BigInteger seek(double offset, [Optional]object whence) { + public BigInteger seek(double offset, [Optional] object whence) { _checkClosed(); throw PythonOps.TypeError("an integer is required"); } - public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optional]object whence) { + public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optional] object whence) { int whenceInt = GetInt(whence); if (whenceInt < 0 || whenceInt > 2) { throw PythonOps.ValueError("invalid whence ({0}, should be 0, 1, or 2)", whenceInt); } + _checkSeekable(); + lock (this) { + // fast-path to seek within the buffer + if (_readBuf.Count > 0 && _absPos != -1) { + if (whenceInt == 0) { + var readBufPos = pos - _absPos + _readBuf.Count; + if (0 <= readBufPos && readBufPos < _readBuf.Count) { + _readBufPos = unchecked((int)readBufPos); + return _absPos - _readBuf.Count + _readBufPos; + } + } else if (whenceInt == 1) { + var readBufPos = _readBufPos + pos; + if (0 <= readBufPos && readBufPos < _readBuf.Count) { + _readBufPos = unchecked((int)readBufPos); + return _absPos - _readBuf.Count + _readBufPos; + } + } + } + if (whenceInt == 1) { pos -= _readBuf.Count - _readBufPos; } @@ -1015,10 +1019,11 @@ public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optio } pos = GetBigInt(posObj, "seek() should return integer"); + _absPos = checked((long)pos); ResetReadBuf(); if (pos < 0) { throw InvalidPosition(pos); - } + } GC.KeepAlive(this); return pos; @@ -1045,8 +1050,12 @@ DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) #region Private implementation details - private Bytes ResetReadBuf() { - Bytes res; + private void ResetReadBuf() { + _readBufPos = 0; + _readBuf = Bytes.Empty; + } + + private bool TryResetReadBuf(out Bytes res) { if (_readBufPos == 0) { res = _readBuf; } else { @@ -1056,8 +1065,8 @@ private Bytes ResetReadBuf() { _readBufPos = 0; } _readBuf = Bytes.Empty; - - return res; + + return res.Count > 0; } #endregion @@ -1073,8 +1082,8 @@ public class BufferedWriter : _BufferedIOBase, IDynamicMetaObjectProvider { internal static BufferedWriter Create(CodeContext/*!*/ context, object raw, - int buffer_size=DEFAULT_BUFFER_SIZE, - object max_buffer_size=null) { + int buffer_size = DEFAULT_BUFFER_SIZE, + object max_buffer_size = null) { var res = new BufferedWriter(context, raw, buffer_size, max_buffer_size); res.__init__(context, raw, buffer_size, max_buffer_size); @@ -1084,8 +1093,8 @@ internal static BufferedWriter Create(CodeContext/*!*/ context, public BufferedWriter( CodeContext/*!*/ context, object raw, - int buffer_size=DEFAULT_BUFFER_SIZE, - object max_buffer_size=null + int buffer_size = DEFAULT_BUFFER_SIZE, + object max_buffer_size = null ) : base(context) { } @@ -1093,8 +1102,8 @@ public BufferedWriter( public void __init__( CodeContext/*!*/ context, object raw, - int buffer_size=DEFAULT_BUFFER_SIZE, - object max_buffer_size=null + int buffer_size = DEFAULT_BUFFER_SIZE, + object max_buffer_size = null ) { if (max_buffer_size != null) { PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "max_buffer_size is deprecated"); @@ -1260,7 +1269,7 @@ public override BigInteger write(CodeContext/*!*/ context, object buf) { } } - public override BigInteger truncate(CodeContext/*!*/ context, object pos=null) { + public override BigInteger truncate(CodeContext/*!*/ context, object pos = null) { lock (this) { FlushNoLock(context); if (pos == null) { @@ -1342,13 +1351,13 @@ public override BigInteger tell(CodeContext/*!*/ context) { return res + _writeBuf.Count; } - public BigInteger seek(double offset, [Optional]object whence) { + public BigInteger seek(double offset, [Optional] object whence) { _checkClosed(); throw PythonOps.TypeError("an integer is required"); } - public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optional]object whence) { + public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optional] object whence) { int whenceInt = GetInt(whence); if (whenceInt < 0 || whenceInt > 2) { throw PythonOps.ValueError("invalid whence ({0}, should be 0, 1, or 2)", whenceInt); @@ -1392,7 +1401,7 @@ DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) [PythonType] public class BufferedRandom : _BufferedIOBase, IDynamicMetaObjectProvider { private _IOBase _inner; - + private int _bufSize; private Bytes _readBuf; private int _readBufPos; @@ -1400,8 +1409,8 @@ public class BufferedRandom : _BufferedIOBase, IDynamicMetaObjectProvider { internal static BufferedRandom Create(CodeContext/*!*/ context, _IOBase raw, - int buffer_size=DEFAULT_BUFFER_SIZE, - object max_buffer_size=null) { + int buffer_size = DEFAULT_BUFFER_SIZE, + object max_buffer_size = null) { var res = new BufferedRandom(context, raw, buffer_size, max_buffer_size); res.__init__(context, raw, buffer_size, max_buffer_size); return res; @@ -1410,16 +1419,16 @@ internal static BufferedRandom Create(CodeContext/*!*/ context, public BufferedRandom( CodeContext/*!*/ context, _IOBase raw, - int buffer_size=DEFAULT_BUFFER_SIZE, - object max_buffer_size=null + int buffer_size = DEFAULT_BUFFER_SIZE, + object max_buffer_size = null ) : base(context) { } public void __init__( CodeContext/*!*/ context, _IOBase raw, - int buffer_size=DEFAULT_BUFFER_SIZE, - object max_buffer_size=null + int buffer_size = DEFAULT_BUFFER_SIZE, + object max_buffer_size = null ) { if (max_buffer_size != null) { PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "max_buffer_size is deprecated"); @@ -1521,7 +1530,7 @@ public override bool isatty(CodeContext/*!*/ context) { #region BufferedReader - public override object read(CodeContext/*!*/ context, object length=null) { + public override object read(CodeContext/*!*/ context, object length = null) { flush(context); int len = GetInt(length, -1); @@ -1602,7 +1611,7 @@ private Bytes ReadNoLock(CodeContext/*!*/ context, int length) { } } - public override Bytes peek(CodeContext/*!*/ context, int length=0) { + public override Bytes peek(CodeContext/*!*/ context, int length = 0) { _checkClosed(); flush(context); @@ -1630,7 +1639,7 @@ private Bytes PeekNoLock(CodeContext/*!*/ context, int length) { return _readBuf; } - public override Bytes read1(CodeContext/*!*/ context, int length=0) { + public override Bytes read1(CodeContext/*!*/ context, int length = 0) { flush(context); if (length == 0) { return Bytes.Empty; @@ -1747,13 +1756,13 @@ public override BigInteger readinto(CodeContext/*!*/ context, object buf) { return base.readinto(context, buf); } - public BigInteger seek(double offset, [Optional]object whence) { + public BigInteger seek(double offset, [Optional] object whence) { _checkClosed(); throw PythonOps.TypeError("an integer is required"); } - public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optional]object whence) { + public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optional] object whence) { int whenceInt = GetInt(whence); if (whenceInt < 0 || whenceInt > 2) { throw PythonOps.ValueError("invalid whence ({0}, should be 0, 1, or 2)", whenceInt); @@ -1777,7 +1786,7 @@ public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [Optio } } - public override BigInteger truncate(CodeContext/*!*/ context, object pos=null) { + public override BigInteger truncate(CodeContext/*!*/ context, object pos = null) { lock (this) { FlushNoLock(context); if (pos == null) { @@ -1822,8 +1831,8 @@ public BufferedRWPair( CodeContext/*!*/ context, object reader, object writer, - int buffer_size=DEFAULT_BUFFER_SIZE, - object max_buffer_size=null + int buffer_size = DEFAULT_BUFFER_SIZE, + object max_buffer_size = null ) : base(context) { } @@ -1831,8 +1840,8 @@ public void __init__( CodeContext/*!*/ context, object reader, object writer, - int buffer_size=DEFAULT_BUFFER_SIZE, - object max_buffer_size=null + int buffer_size = DEFAULT_BUFFER_SIZE, + object max_buffer_size = null ) { if (max_buffer_size != null) { PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "max_buffer_size is deprecated"); @@ -1870,7 +1879,7 @@ public object writer { } } - public override object read(CodeContext/*!*/ context, object length=null) { + public override object read(CodeContext/*!*/ context, object length = null) { var res = _reader.read(context, length); GC.KeepAlive(this); return res; @@ -1888,7 +1897,7 @@ public override BigInteger write(CodeContext/*!*/ context, object buf) { return res; } - public override Bytes peek(CodeContext/*!*/ context, int length=0) { + public override Bytes peek(CodeContext/*!*/ context, int length = 0) { var res = _reader.peek(context, length); GC.KeepAlive(this); return res; @@ -1997,7 +2006,7 @@ public void __init__( bool line_buffering = false, bool write_through = false ) { - switch(newline) { + switch (newline) { case null: case "": case "\n": @@ -2199,7 +2208,7 @@ public override BigInteger tell(CodeContext/*!*/ context) { // skip backwards to snapshot point pos -= _nextInput.Count; - + // determine number of decoded chars used up after snapshot int skip = _decodedCharsUsed; if (skip == 0) { @@ -2279,7 +2288,7 @@ public override BigInteger tell(CodeContext/*!*/ context) { } } - public override BigInteger truncate(CodeContext/*!*/ context, object pos=null) { + public override BigInteger truncate(CodeContext/*!*/ context, object pos = null) { flush(context); if (pos == null) { pos = tell(context); @@ -2317,9 +2326,9 @@ public override object detach(CodeContext/*!*/ context) { return res; } - public BigInteger seek(double offset, [Optional]object whence) => throw PythonOps.TypeError("integer argument expected, got float"); + public BigInteger seek(double offset, [Optional] object whence) => throw PythonOps.TypeError("integer argument expected, got float"); - public override BigInteger seek(CodeContext/*!*/ context, BigInteger cookie, [Optional]object whence) { + public override BigInteger seek(CodeContext/*!*/ context, BigInteger cookie, [Optional] object whence) { int whenceInt = GetInt(whence); if (closed) { throw PythonOps.ValueError("tell on closed file"); @@ -2451,7 +2460,7 @@ public override BigInteger seek(CodeContext/*!*/ context, BigInteger cookie, [Op return cookie; } - public override object read(CodeContext/*!*/ context, object length=null) { + public override object read(CodeContext/*!*/ context, object length = null) { _checkClosed(); if (!readable(context)) { throw UnsupportedOperationWithMessage(context, "not readable"); @@ -2497,7 +2506,7 @@ public override object read(CodeContext/*!*/ context, object length=null) { } } - public override object readline(CodeContext/*!*/ context, int limit=-1) { + public override object readline(CodeContext/*!*/ context, int limit = -1) { _checkClosed("read from closed file"); if (!readable(context)) { throw UnsupportedOperationWithMessage(context, "not readable"); @@ -2577,7 +2586,7 @@ public override object readline(CodeContext/*!*/ context, int limit=-1) { } #endregion - + #region IEnumerator Members private object _current; @@ -2795,13 +2804,13 @@ private bool ReadChunk(CodeContext/*!*/ context) { public static _IOBase open( CodeContext/*!*/ context, object file, - string mode="r", - int buffering=-1, - string encoding=null, - string errors=null, - string newline=null, - bool closefd=true, - object opener=null + string mode = "r", + int buffering = -1, + string encoding = null, + string errors = null, + string newline = null, + bool closefd = true, + object opener = null ) { string fname = null; if (!Converter.TryConvertToIndex(file, out int fd, false, false)) { @@ -2898,15 +2907,13 @@ internal static TextIOWrapper CreateConsole(PythonContext context, SharedIO io, var fio = new FileIO(cc, sio) { name = name }; var buffer = BufferedReader.Create(cc, fio, DEFAULT_BUFFER_SIZE); return TextIOWrapper.Create(cc, buffer, encoding, null, null, true); - } - else if (type == ConsoleStreamType.Output) { + } else if (type == ConsoleStreamType.Output) { var encoding = StringOps.GetEncodingName(io.OutputEncoding); sio = new StreamBox(io.GetStreamProxy(type), type); var fio = new FileIO(cc, sio) { name = name }; var buffer = BufferedWriter.Create(cc, fio, DEFAULT_BUFFER_SIZE, null); return TextIOWrapper.Create(cc, buffer, encoding, null, null, true); - } - else { + } else { Debug.Assert(type == ConsoleStreamType.ErrorOutput); var encoding = StringOps.GetEncodingName(io.ErrorEncoding); sio = new StreamBox(io.GetStreamProxy(type), type); @@ -2936,13 +2943,13 @@ internal enum LineEnding { private string _errors; #pragma warning restore 414 - public IncrementalNewlineDecoder(object decoder, bool translate, string errors="strict") { + public IncrementalNewlineDecoder(object decoder, bool translate, string errors = "strict") { _decoder = decoder; _translate = translate; _errors = errors; } - public string decode(CodeContext/*!*/ context, [NotNone] IList input, bool final=false) { + public string decode(CodeContext/*!*/ context, [NotNone] IList input, bool final = false) { object output; if (_decoder == null) { output = input.MakeString(); @@ -2966,7 +2973,7 @@ public string decode(CodeContext/*!*/ context, [NotNone] IList input, bool return DecodeWorker(context, decoded, final); } - public string decode(CodeContext/*!*/ context, [NotNone] string input, bool final=false) { + public string decode(CodeContext/*!*/ context, [NotNone] string input, bool final = false) { if (_decoder == null) { return DecodeWorker(context, input, final); } @@ -3087,6 +3094,8 @@ public static PythonType BlockingIOError { #region Private implementation details +#nullable enable + private static readonly HashSet _validModes = MakeSet("abrtwxU+"); private static HashSet MakeSet(string chars) { @@ -3097,16 +3106,15 @@ private static HashSet MakeSet(string chars) { return res; } - private static BigInteger GetBigInt(object i, string msg) { - BigInteger res; - if (TryGetBigInt(i, out res)) { + private static BigInteger GetBigInt(object? i, string msg) { + if (TryGetBigInt(i, out BigInteger res)) { return res; } throw PythonOps.TypeError(msg); } - private static bool TryGetBigInt(object i, out BigInteger res) { + private static bool TryGetBigInt(object? i, out BigInteger res) { if (i is BigInteger bi) { res = bi; return true; @@ -3131,37 +3139,29 @@ private static bool TryGetBigInt(object i, out BigInteger res) { return false; } - private static int GetInt(object i) { - return GetInt(i, null, null); - } + private static int GetInt(object? i, string? msg = null) { + if (i == Missing.Value) return 0; - private static int GetInt(object i, int defaultValue) { - if (i is null) { - return defaultValue; - } if (Converter.TryConvertToIndex(i, out int index, throwOverflowError: true)) { return index; } - throw PythonOps.TypeError("integer argument expected, got '{0}'", PythonOps.GetPythonTypeName(i)); - } + if (msg == null) { + throw PythonOps.TypeError("integer argument expected, got '{0}'", PythonOps.GetPythonTypeName(i)); + } - private static int GetInt(object i, string msg, params object[] args) { - if (i == Missing.Value) return 0; + throw PythonOps.TypeError(msg); + } - int res; - if (TryGetInt(i, out res)) { - return res; + private static int GetInt(object? i, int defaultValue) { + if (i is null) { + return defaultValue; } - if (msg == null) { - throw PythonOps.TypeError("integer argument expected, got '{0}'", PythonOps.GetPythonTypeName(i)); - } - - throw PythonOps.TypeError(msg, args); + return GetInt(i); } - private static bool TryGetInt(object i, out int value) { + private static bool TryGetInt(object? i, out int value) { if (i == null) { value = int.MinValue; return false; @@ -3183,15 +3183,15 @@ private static bool TryGetInt(object i, out int value) { /// /// Convert string or bytes into bytes /// - private static Bytes GetBytes(object o, string name) { - if(o == null) + private static Bytes? GetBytes(object? o, string name) { + if (o == null) return null; if (o is Bytes bytes) { return bytes; } - string s = o as string; + string? s = o as string; if (s == null) { if (o is Extensible es) { s = es.Value; @@ -3205,6 +3205,8 @@ private static Bytes GetBytes(object o, string name) { throw PythonOps.TypeError("'" + name + "' should have returned bytes"); } +#nullable restore + #endregion } } diff --git a/Src/IronPython/Modules/sys.cs b/Src/IronPython/Modules/sys.cs index a74c8988e..aab7ef41d 100644 --- a/Src/IronPython/Modules/sys.cs +++ b/Src/IronPython/Modules/sys.cs @@ -29,7 +29,7 @@ public static class SysModule { // argv is set by PythonContext and only on the initial load public static readonly string byteorder = BitConverter.IsLittleEndian ? "little" : "big"; // builtin_module_names is set by PythonContext and updated on reload - public const string copyright = "Copyright (c) IronPython Team"; + public const string copyright = "Copyright (c) .NET Foundation and Contributors"; private static string GetPrefix() { string prefix; diff --git a/Src/IronPython/Modules/unicodedata.cs b/Src/IronPython/Modules/unicodedata.cs index 2f13b56e6..d6b08a8e1 100644 --- a/Src/IronPython/Modules/unicodedata.cs +++ b/Src/IronPython/Modules/unicodedata.cs @@ -391,7 +391,7 @@ private void BuildDatabase(StreamReader data) { private void BuildNameLookup() { var lookup = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var c in database) { - if (c.Value.Name.StartsWith("<", StringComparison.Ordinal)) continue; + if (c.Value.Name.StartsWith('<')) continue; lookup[c.Value.Name] = c.Key; foreach (var alias in c.Value.Aliases) { lookup[alias] = c.Key; diff --git a/Src/IronPython/Runtime/Binding/MetaPythonType.Calls.cs b/Src/IronPython/Runtime/Binding/MetaPythonType.Calls.cs index 71565a413..c61c530fa 100644 --- a/Src/IronPython/Runtime/Binding/MetaPythonType.Calls.cs +++ b/Src/IronPython/Runtime/Binding/MetaPythonType.Calls.cs @@ -443,7 +443,7 @@ public ConstructorNewAdapter(ArgumentValues/*!*/ ai, PythonType/*!*/ creating, P return binder.CallMethod( resolve, - _creating.UnderlyingSystemType.GetConstructors(), + PythonTypeOps.GetConstructors(_creating.UnderlyingSystemType, binder.PrivateBinding), Arguments.Self.Restrictions, _creating.Name ); diff --git a/Src/IronPython/Runtime/Binding/PythonBinder.cs b/Src/IronPython/Runtime/Binding/PythonBinder.cs index 8b287a927..50ae3404b 100644 --- a/Src/IronPython/Runtime/Binding/PythonBinder.cs +++ b/Src/IronPython/Runtime/Binding/PythonBinder.cs @@ -761,7 +761,8 @@ internal static void AssertNotExtensionType(Type t) { res[typeof(char)] = new Type[] { typeof(CharOps) }; res[typeof(decimal)] = new Type[] { typeof(DecimalOps) }; res[typeof(float)] = new Type[] { typeof(SingleOps) }; - + res[typeof(DateTime)] = new Type[] { typeof(DateTimeOps) }; + return res; } diff --git a/Src/IronPython/Runtime/Binding/PythonExtensionBinder.cs b/Src/IronPython/Runtime/Binding/PythonExtensionBinder.cs index 31be3aad7..276366231 100644 --- a/Src/IronPython/Runtime/Binding/PythonExtensionBinder.cs +++ b/Src/IronPython/Runtime/Binding/PythonExtensionBinder.cs @@ -65,7 +65,9 @@ internal static bool IsApplicableExtensionMethod(Type instanceType, Type extensi Type[] inferredTypes = new Type[genArgs.Length]; for (int i = 0; i < genArgs.Length; i++) { - if ((inferredTypes[i] = TypeInferer.GetInferedType(genArgs[i], extensionMethodThisType, instanceType, instanceType, binding)) == null) { + var genArg = genArgs[i]; + // https://github.com/IronLanguages/ironpython3/issues/1796 + if (!genArg.IsGenericParameter || (inferredTypes[i] = TypeInferer.GetInferedType(genArg, extensionMethodThisType, instanceType, instanceType, binding)) == null) { inferredTypes = null; break; } diff --git a/Src/IronPython/Runtime/Binding/WarningInfo.cs b/Src/IronPython/Runtime/Binding/WarningInfo.cs index 616ecd3af..b00e665c4 100644 --- a/Src/IronPython/Runtime/Binding/WarningInfo.cs +++ b/Src/IronPython/Runtime/Binding/WarningInfo.cs @@ -2,12 +2,12 @@ // 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.Dynamic; using System.Linq.Expressions; using IronPython.Runtime.Operations; using IronPython.Runtime.Types; -using Microsoft.Scripting.Utils; using AstUtils = Microsoft.Scripting.Ast.Utils; @@ -29,7 +29,7 @@ public WarningInfo(PythonType/*!*/ type, string/*!*/ message, Expression conditi codeContext, AstUtils.Constant(_type), AstUtils.Constant(_message), - AstUtils.Constant(ArrayUtils.EmptyObjects) + AstUtils.Constant(Array.Empty()) ); if (_condition != null) { diff --git a/Src/IronPython/Runtime/BuiltinPythonModule.cs b/Src/IronPython/Runtime/BuiltinPythonModule.cs index 65e973fd6..3ba2fe8be 100644 --- a/Src/IronPython/Runtime/BuiltinPythonModule.cs +++ b/Src/IronPython/Runtime/BuiltinPythonModule.cs @@ -2,9 +2,10 @@ // 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 IronPython.Compiler; + using Microsoft.Scripting.Utils; namespace IronPython.Runtime { @@ -50,7 +51,7 @@ protected internal virtual void Initialize(CodeContext/*!*/ codeContext, Diction /// direct access to global members. /// protected internal virtual IEnumerable/*!*/ GetGlobalVariableNames() { - return ArrayUtils.EmptyStrings; + return []; } /// diff --git a/Src/IronPython/Runtime/Bytes.cs b/Src/IronPython/Runtime/Bytes.cs index 282a93e47..e6d5ac5d3 100644 --- a/Src/IronPython/Runtime/Bytes.cs +++ b/Src/IronPython/Runtime/Bytes.cs @@ -1065,6 +1065,11 @@ private static Bytes JoinOne(object? curVal) { } internal static Bytes Concat(IList list, int length) { + if (list.Count == 1) { + Debug.Assert(list[0].Count == length); + return list[0]; + } + byte[] res = new byte[length]; int count = 0; for (int i = 0; i < list.Count; i++) { diff --git a/Src/IronPython/Runtime/Converter.cs b/Src/IronPython/Runtime/Converter.cs index 71df8dc2e..9dc49999e 100644 --- a/Src/IronPython/Runtime/Converter.cs +++ b/Src/IronPython/Runtime/Converter.cs @@ -538,7 +538,7 @@ public static bool CanConvertFrom(Type fromType, Type toType, NarrowingLevel all private static TypeConverter GetTypeConverter(TypeConverterAttribute tca) { try { ConstructorInfo ci = Type.GetType(tca.ConverterTypeName).GetConstructor(ReflectionUtils.EmptyTypes); - if (ci != null) return ci.Invoke(ArrayUtils.EmptyObjects) as TypeConverter; + if (ci != null) return ci.Invoke([]) as TypeConverter; } catch (TargetInvocationException) { } return null; diff --git a/Src/IronPython/Runtime/Exceptions/PythonExceptions.cs b/Src/IronPython/Runtime/Exceptions/PythonExceptions.cs index fe407032e..55e97d29b 100644 --- a/Src/IronPython/Runtime/Exceptions/PythonExceptions.cs +++ b/Src/IronPython/Runtime/Exceptions/PythonExceptions.cs @@ -6,11 +6,8 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; -using System.Dynamic; using System.IO; -using System.Linq.Expressions; using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; @@ -122,7 +119,7 @@ public override string ToString() { } public partial class _OSError { - public static new object __new__(PythonType cls, [ParamDictionary]IDictionary kwArgs, params object[] args) { + public static new object __new__(PythonType cls, [ParamDictionary] IDictionary kwArgs, params object[] args) { if (cls == OSError && args.Length >= 1 && args[0] is int errno) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (args.Length >= 4 && args[3] is int winerror) { @@ -223,8 +220,7 @@ private static Error ErrnoToErrorEnum(int errno) { } private static PythonType ErrnoToPythonType(Error errno) { - var res = errno switch - { + var res = errno switch { Error.EPERM => PermissionError, Error.ENOENT => FileNotFoundError, Error.ESRCH => ProcessLookupError, @@ -239,8 +235,7 @@ private static PythonType ErrnoToPythonType(Error errno) { _ => null }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - res ??= errno switch - { + res ??= errno switch { // Windows or remapped OSX Error.WSAEWOULDBLOCK => BlockingIOError, Error.WSAEINPROGRESS => BlockingIOError, @@ -253,8 +248,7 @@ private static PythonType ErrnoToPythonType(Error errno) { _ => null }; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - res ??= errno switch - { + res ??= errno switch { // Linux Error.ECONNABORTED => ConnectionAbortedError, Error.ECONNRESET => ConnectionResetError, @@ -529,7 +523,7 @@ internal static int WinErrorToErrno(int winerror) { } public partial class _ImportError { - public void __init__([ParamDictionary]IDictionary kwargs, params object[] args) { + public void __init__([ParamDictionary] IDictionary kwargs, params object[] args) { base.__init__(args); foreach (var pair in kwargs) { @@ -702,7 +696,7 @@ internal static BaseException CreateBaseExceptionForRaise(CodeContext/*!*/ conte if (PythonOps.IsInstance(value, type)) { pyEx = value; } else if (value is PythonTuple) { - pyEx = PythonOps.CallWithArgsTuple(type, ArrayUtils.EmptyObjects, value); + pyEx = PythonOps.CallWithArgsTuple(type, [], value); } else if (value != null) { pyEx = PythonCalls.Call(context, type, value); } else { diff --git a/Src/IronPython/Runtime/FunctionCode.cs b/Src/IronPython/Runtime/FunctionCode.cs index bbaef9e05..b0310185e 100644 --- a/Src/IronPython/Runtime/FunctionCode.cs +++ b/Src/IronPython/Runtime/FunctionCode.cs @@ -2,27 +2,26 @@ // 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.Linq.Expressions; -using Microsoft.Scripting.Ast; - using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; +using IronPython.Compiler; +using IronPython.Runtime.Operations; +using IronPython.Runtime.Types; + using Microsoft.Scripting; +using Microsoft.Scripting.Ast; using Microsoft.Scripting.Debugging.CompilerServices; using Microsoft.Scripting.Generation; using Microsoft.Scripting.Interpreter; using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; -using IronPython.Compiler; -using IronPython.Runtime.Operations; -using IronPython.Runtime.Types; - namespace IronPython.Runtime { /// /// Represents a piece of code. This can reference either a CompiledCode @@ -601,7 +600,7 @@ internal object Call(CodeContext/*!*/ context) { return optimizedModuleCode(this); } - var func = new PythonFunction(context, this, null, ArrayUtils.EmptyObjects, null, null, new MutableTuple()); + var func = new PythonFunction(context, this, null, [], null, null, new MutableTuple()); CallSite> site = context.LanguageContext.FunctionCallSite; return site.Target(site, context, func); } @@ -772,7 +771,7 @@ private LambdaExpression GetGeneratorOrNormalLambdaTracing(PythonContext context ); } - + /// /// Gets the correct final LambdaExpression for this piece of code. /// @@ -784,8 +783,8 @@ private LightLambdaExpression GetGeneratorOrNormalLambda() { finalCode = Code; } else { finalCode = Code.ToGenerator( - _lambda.ShouldInterpret, - _lambda.EmitDebugSymbols, + _lambda.ShouldInterpret, + _lambda.EmitDebugSymbols, _lambda.GlobalParent.PyContext.Options.CompilationThreshold ); } @@ -838,7 +837,7 @@ private Delegate CompileLambda(LambdaExpression code, EventHandler || + if (finalTarget is Func || finalTarget is Func || finalTarget is LookupCompilationDelegate) { // no recursion enforcement on classes or modules @@ -1185,7 +1184,6 @@ public Dictionary LoopOrFinallyIds { return _loopIds; } } - } } } diff --git a/Src/IronPython/Runtime/LiteralParser.cs b/Src/IronPython/Runtime/LiteralParser.cs index 8077f9924..1ef1adb68 100644 --- a/Src/IronPython/Runtime/LiteralParser.cs +++ b/Src/IronPython/Runtime/LiteralParser.cs @@ -890,9 +890,9 @@ private static double ParseFloatNoCatch(string text, bool replaceUnicode = true) try { res = double.Parse(s, NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture); } catch (OverflowException) { - res = text.lstrip().StartsWith("-", StringComparison.Ordinal) ? double.NegativeInfinity : double.PositiveInfinity; + res = text.lstrip().StartsWith('-') ? Double.NegativeInfinity : Double.PositiveInfinity; } - return (res == 0.0 && text.lstrip().StartsWith("-", StringComparison.Ordinal)) ? DoubleOps.NegativeZero : res; + return (res == 0.0 && text.lstrip().StartsWith('-')) ? DoubleOps.NegativeZero : res; } } @@ -927,7 +927,7 @@ public static Complex ParseComplex(string s) { string text = s.Trim().ToLowerInvariant(); // remove 1 layer of parens - if (text.StartsWith("(", StringComparison.Ordinal) && text.EndsWith(")", StringComparison.Ordinal)) { + if (text.StartsWith('(') && text.EndsWith(')')) { text = text.Substring(1, text.Length - 2); } diff --git a/Src/IronPython/Runtime/ModuleDictionaryStorage.cs b/Src/IronPython/Runtime/ModuleDictionaryStorage.cs index e4a7887ee..d94f78e48 100644 --- a/Src/IronPython/Runtime/ModuleDictionaryStorage.cs +++ b/Src/IronPython/Runtime/ModuleDictionaryStorage.cs @@ -6,11 +6,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.Reflection; + using IronPython.Compiler; using IronPython.Runtime.Types; + using Microsoft.Scripting.Actions; using Microsoft.Scripting.Runtime; -using Microsoft.Scripting.Utils; namespace IronPython.Runtime { /// @@ -162,7 +163,7 @@ private bool TryGetLazyValue(string name, bool publish, out object value) { var propInfo = (PropertyInfo)members[0]; if ((propInfo.GetGetMethod() ?? propInfo.GetSetMethod()).IsStatic) { - value = ((PropertyInfo)members[0]).GetValue(null, ArrayUtils.EmptyObjects); + value = ((PropertyInfo)members[0]).GetValue(null, []); } else { throw new InvalidOperationException("instance property declared on module. Propreties should be declared as static, marked as PythonHidden, or you should use a PythonGlobal."); } @@ -217,7 +218,7 @@ public override bool TryGetValue(object key, out object value) { return value != Uninitialized.Instance; } - if(key is string strKey) { + if (key is string strKey) { return TryGetLazyValue(strKey, out value); } diff --git a/Src/IronPython/Runtime/NewStringFormatter.cs b/Src/IronPython/Runtime/NewStringFormatter.cs index f7f84500c..84ca824ab 100644 --- a/Src/IronPython/Runtime/NewStringFormatter.cs +++ b/Src/IronPython/Runtime/NewStringFormatter.cs @@ -131,7 +131,7 @@ private StringFormatParser(string/*!*/ text) { if (_index == -1) { // no more formats, send the remaining text. yield return PythonTuple.MakeTuple( - _str.Substring(lastTextStart, _str.Length - lastTextStart), + _str.Substring(lastTextStart), null, null, null); diff --git a/Src/IronPython/Runtime/Operations/ArrayOps.cs b/Src/IronPython/Runtime/Operations/ArrayOps.cs index f80cd9734..87c4bcb62 100644 --- a/Src/IronPython/Runtime/Operations/ArrayOps.cs +++ b/Src/IronPython/Runtime/Operations/ArrayOps.cs @@ -10,11 +10,11 @@ using System.Diagnostics; using System.Text; +using IronPython.Runtime.Types; + using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; -using IronPython.Runtime.Types; - using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute; namespace IronPython.Runtime.Operations { @@ -87,6 +87,58 @@ public static object __new__(CodeContext context, PythonType pythonType, object return res; } + [StaticExtensionMethod] + public static object __eq__(CodeContext context, Array self, [NotNone] Array other) { + if (self is null) throw PythonOps.TypeError("expected Array, got None"); + if (other is null) throw PythonOps.TypeError("expected Array, got None"); + + if (self.GetType() != other.GetType()) return ScriptingRuntimeHelpers.False; + // same type implies: same rank, same element type + for (int d = 0; d < self.Rank; d++) { + if (self.GetLowerBound(d) != other.GetLowerBound(d)) return ScriptingRuntimeHelpers.False; + if (self.GetUpperBound(d) != other.GetUpperBound(d)) return ScriptingRuntimeHelpers.False; + } + if (self.Length == 0) return ScriptingRuntimeHelpers.True; // fast track + + if (self.Rank == 1 && self.GetLowerBound(0) == 0 ) { + // IStructuralEquatable.Equals only works for 1-dim, 0-based arrays + return ScriptingRuntimeHelpers.BooleanToObject( + ((IStructuralEquatable)self).Equals(other, context.LanguageContext.EqualityComparerNonGeneric) + ); + } else { + int[] ix = new int[self.Rank]; + for (int d = 0; d < self.Rank; d++) { + ix[d] = self.GetLowerBound(d); + } + for (int i = 0; i < self.Length; i++) { + if (!PythonOps.EqualRetBool(self.GetValue(ix), other.GetValue(ix))) { + return ScriptingRuntimeHelpers.False; + } + for (int d = self.Rank - 1; d >= 0; d--) { + if (ix[d] < self.GetUpperBound(d)) { + ix[d]++; + break; + } else { + ix[d] = self.GetLowerBound(d); + } + } + } + return ScriptingRuntimeHelpers.True; + } + } + + [StaticExtensionMethod] + [return: MaybeNotImplemented] + public static object __eq__(CodeContext context, object self, object? other) => NotImplementedType.Value; + + [StaticExtensionMethod] + public static object __ne__(CodeContext context, Array self, [NotNone] Array other) + => ScriptingRuntimeHelpers.BooleanToObject(ReferenceEquals(__eq__(context, self, other), ScriptingRuntimeHelpers.False)); + + [StaticExtensionMethod] + [return: MaybeNotImplemented] + public static object __ne__(CodeContext context, object self, object? other) => NotImplementedType.Value; + /// /// Multiply two object[] arrays - slow version, we need to get the type, etc... /// @@ -214,24 +266,29 @@ public static string __repr__(CodeContext/*!*/ context, [NotNone] Array/*!*/ sel ret.Append("Array["); Type elemType = self.GetType().GetElementType()!; ret.Append(DynamicHelpers.GetPythonTypeFromType(elemType).Name); - ret.Append("]"); + ret.Append(']'); ret.Append("(("); for (int i = 0; i < self.Length; i++) { if (i > 0) ret.Append(", "); ret.Append(PythonOps.Repr(context, self.GetValue(i + self.GetLowerBound(0)))); } - ret.Append("))"); + ret.Append(')'); + if (self.GetLowerBound(0) != 0) { + ret.Append(", base: "); + ret.Append(self.GetLowerBound(0)); + } + ret.Append(')'); } else { // multi dimensional arrays require multiple statements to construct so we just // give enough info to identify the object and its type. - ret.Append("<"); + ret.Append('<'); ret.Append(self.Rank); ret.Append(" dimensional Array["); Type elemType = self.GetType().GetElementType()!; ret.Append(DynamicHelpers.GetPythonTypeFromType(elemType).Name); ret.Append("] at "); ret.Append(PythonOps.HexId(self)); - ret.Append(">"); + ret.Append('>'); } return ret.ToString(); } finally { @@ -286,7 +343,7 @@ public static string __repr__(CodeContext/*!*/ context, [NotNone] Array/*!*/ sel } internal static object?[] GetSlice(object?[] data, int start, int stop) { - if (stop <= start) return ArrayUtils.EmptyObjects; + if (stop <= start) return []; var ret = new object?[stop - start]; int index = 0; @@ -304,7 +361,7 @@ public static string __repr__(CodeContext/*!*/ context, [NotNone] Array/*!*/ sel } int size = PythonOps.GetSliceCount(start, stop, step); - if (size <= 0) return ArrayUtils.EmptyObjects; + if (size <= 0) return []; var res = new object?[size]; for (int i = 0, index = start; i < res.Length; i++, index += step) { @@ -325,7 +382,7 @@ internal static Array GetSlice(Array data, int size, Slice slice) { if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) { if (data.GetType().GetElementType() == typeof(object)) - return ArrayUtils.EmptyObjects; + return Array.Empty(); return Array.CreateInstance(data.GetType().GetElementType()!, 0); } @@ -347,7 +404,7 @@ internal static Array GetSlice(Array data, int size, Slice slice) { } internal static object?[] CopyArray(object?[] data, int newSize) { - if (newSize == 0) return ArrayUtils.EmptyObjects; + if (newSize == 0) return []; var newData = new object?[newSize]; if (data.Length < 20) { diff --git a/Src/IronPython/Runtime/Operations/CharOps.cs b/Src/IronPython/Runtime/Operations/CharOps.cs index 3c1774e8f..10e76d84d 100644 --- a/Src/IronPython/Runtime/Operations/CharOps.cs +++ b/Src/IronPython/Runtime/Operations/CharOps.cs @@ -35,6 +35,8 @@ public static object __new__(PythonType cls, char value) { public static string __repr__(char self) => StringOps.__repr__(char.ToString(self)); + public static PythonTuple __getnewargs__(char self) => PythonTuple.MakeTuple(char.ToString(self)); + public static int __hash__(char self) => char.ToString(self).GetHashCode(); public static int __index__(char self) => self; diff --git a/Src/IronPython/Runtime/Operations/ComOps.cs b/Src/IronPython/Runtime/Operations/ComOps.cs index 3956074f2..53d81703a 100644 --- a/Src/IronPython/Runtime/Operations/ComOps.cs +++ b/Src/IronPython/Runtime/Operations/ComOps.cs @@ -20,7 +20,9 @@ public static class ComOps { } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-C000-000000000046")] +#pragma warning disable SYSLIB1096 // Convert to 'GeneratedComInterface' private interface IDispatch { +#pragma warning restore SYSLIB1096 // Convert to 'GeneratedComInterface' int GetTypeInfoCount(); [return: MarshalAs(UnmanagedType.Interface)] ITypeInfo GetTypeInfo([In, MarshalAs(UnmanagedType.U4)] int iTInfo, [In, MarshalAs(UnmanagedType.U4)] int lcid); diff --git a/Src/IronPython/Runtime/Operations/DBNullOps.cs b/Src/IronPython/Runtime/Operations/DBNullOps.cs index 364f50e56..f2b1628b7 100644 --- a/Src/IronPython/Runtime/Operations/DBNullOps.cs +++ b/Src/IronPython/Runtime/Operations/DBNullOps.cs @@ -6,8 +6,15 @@ using System; +using Microsoft.Scripting.Runtime; + namespace IronPython.Runtime.Operations { public static class DBNullOps { + [StaticExtensionMethod] + public static object __new__(object cls) { + return DBNull.Value; + } + public static bool __bool__(DBNull value) { return false; } diff --git a/Src/IronPython/Runtime/Operations/DateTimeOps.cs b/Src/IronPython/Runtime/Operations/DateTimeOps.cs new file mode 100644 index 000000000..83b8d6fd5 --- /dev/null +++ b/Src/IronPython/Runtime/Operations/DateTimeOps.cs @@ -0,0 +1,14 @@ +// 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.Numerics; + +namespace IronPython.Runtime.Operations { + public static class DateTimeOps { + public static PythonTuple __getnewargs__(DateTime self) => PythonTuple.MakeTuple((BigInteger)self.Ticks, self.Kind); + } +} diff --git a/Src/IronPython/Runtime/Operations/DecimalOps.cs b/Src/IronPython/Runtime/Operations/DecimalOps.cs index 3adeb1df3..28a6ee853 100644 --- a/Src/IronPython/Runtime/Operations/DecimalOps.cs +++ b/Src/IronPython/Runtime/Operations/DecimalOps.cs @@ -17,6 +17,13 @@ public static class DecimalOps { public static string __repr__(decimal x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(decimal self) { + var bits = decimal.GetBits(self); + var sign = bits[3] < 0; + var scale = unchecked((byte)(bits[3] >> 16)); + return PythonTuple.MakeTuple(bits[0], bits[1], bits[2], sign, scale); + } + [SpecialName] public static bool LessThan(decimal x, decimal y) => x < y; [SpecialName] diff --git a/Src/IronPython/Runtime/Operations/EnumOps.cs b/Src/IronPython/Runtime/Operations/EnumOps.cs index 3313c09e2..6c0085772 100644 --- a/Src/IronPython/Runtime/Operations/EnumOps.cs +++ b/Src/IronPython/Runtime/Operations/EnumOps.cs @@ -7,6 +7,9 @@ using System; using System.Runtime.CompilerServices; +using IronPython.Runtime.Types; + +using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; namespace IronPython.Runtime.Operations { @@ -50,6 +53,14 @@ public static object OnesComplement(object self) { throw PythonOps.ValueError("one's complement cannot be applied to {0}", self.GetType()); } + + [StaticExtensionMethod] + public static object __new__(PythonType cls, object value) { + // Note that this method is not required to construct enums but useful for serialization + if (!cls.UnderlyingSystemType.IsEnum) throw PythonOps.TypeError("Enum.__new__: first argument must be an Enum type."); + return Enum.ToObject(cls.UnderlyingSystemType, value); + } + public static bool __bool__(object self) { if (self is Enum) { Type selfType = self.GetType(); @@ -78,5 +89,7 @@ public static string __repr__(object self) { return $""; } + + public static object __getnewargs__(Enum self) => PythonTuple.MakeTuple(Convert.ChangeType(self, Enum.GetUnderlyingType(self.GetType()))); } } diff --git a/Src/IronPython/Runtime/Operations/FloatOps.Generated.cs b/Src/IronPython/Runtime/Operations/FloatOps.Generated.cs index ea2e1775f..113d646c0 100644 --- a/Src/IronPython/Runtime/Operations/FloatOps.Generated.cs +++ b/Src/IronPython/Runtime/Operations/FloatOps.Generated.cs @@ -32,6 +32,8 @@ public static partial class SingleOps { public static bool __bool__(Single x) => (x != 0); + public static PythonTuple __getnewargs__(Single self) => PythonTuple.MakeTuple(unchecked((double)self)); + public static object __trunc__(Single x) { if (x >= int.MaxValue || x <= int.MinValue) { return (BigInteger)x; diff --git a/Src/IronPython/Runtime/Operations/InstanceOps.cs b/Src/IronPython/Runtime/Operations/InstanceOps.cs index 2b6c6578f..bae065063 100644 --- a/Src/IronPython/Runtime/Operations/InstanceOps.cs +++ b/Src/IronPython/Runtime/Operations/InstanceOps.cs @@ -2,22 +2,19 @@ // 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.Linq.Expressions; - using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Dynamic; +using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; +using IronPython.Runtime.Types; + using Microsoft.Scripting; using Microsoft.Scripting.Runtime; -using Microsoft.Scripting.Utils; - -using IronPython.Runtime.Exceptions; -using IronPython.Runtime.Types; namespace IronPython.Runtime.Operations { /// @@ -107,7 +104,7 @@ public static object DefaultNew(CodeContext context, PythonType type\u00F8, para return type\u00F8.CreateInstance(context); } - public static object DefaultNewClsKW(CodeContext context, PythonType type\u00F8, [ParamDictionary]IDictionary kwargs\u00F8, params object[] args\u00F8) { + public static object DefaultNewClsKW(CodeContext context, PythonType type\u00F8, [ParamDictionary] IDictionary kwargs\u00F8, params object[] args\u00F8) { object res = DefaultNew(context, type\u00F8, args\u00F8); if (kwargs\u00F8.Count > 0) { @@ -127,13 +124,13 @@ public static object OverloadedNewBasic(CodeContext context, SiteLocalStorage kwargs\u00F8) { + public static object OverloadedNewKW(CodeContext context, BuiltinFunction overloads\u00F8, PythonType type\u00F8, [ParamDictionary] IDictionary kwargs\u00F8) { if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8))); - return overloads\u00F8.Call(context, null, null, ArrayUtils.EmptyObjects, kwargs\u00F8); + return overloads\u00F8.Call(context, null, null, [], kwargs\u00F8); } - public static object OverloadedNewClsKW(CodeContext context, BuiltinFunction overloads\u00F8, PythonType type\u00F8, [ParamDictionary]IDictionary kwargs\u00F8, params object[] args\u00F8) { + public static object OverloadedNewClsKW(CodeContext context, BuiltinFunction overloads\u00F8, PythonType type\u00F8, [ParamDictionary] IDictionary kwargs\u00F8, params object[] args\u00F8) { if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8))); if (args\u00F8 == null) args\u00F8 = new object[1]; @@ -145,7 +142,7 @@ public static void DefaultInit(CodeContext context, object self, params object[] } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "kwargs\u00F8"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "args\u00F8")] - public static void DefaultInitKW(CodeContext context, object self, [ParamDictionary]IDictionary kwargs\u00F8, params object[] args\u00F8) { + public static void DefaultInitKW(CodeContext context, object self, [ParamDictionary] IDictionary kwargs\u00F8, params object[] args\u00F8) { } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context")] @@ -158,23 +155,23 @@ public static object NonDefaultNew(CodeContext context, PythonType type\u00F8, p [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context")] [StaticExtensionMethod] - public static object NonDefaultNewKW(CodeContext context, PythonType type\u00F8, [ParamDictionary]IDictionary kwargs\u00F8, params object[] args\u00F8) { + public static object NonDefaultNewKW(CodeContext context, PythonType type\u00F8, [ParamDictionary] IDictionary kwargs\u00F8, params object[] args\u00F8) { if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8))); if (args\u00F8 == null) args\u00F8 = new object[1]; - string []names; + string[] names; GetKeywordArgs(kwargs\u00F8, args\u00F8, out args\u00F8, out names); return type\u00F8.CreateInstance(context, args\u00F8, names); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context")] [StaticExtensionMethod] - public static object NonDefaultNewKWNoParams(CodeContext context, PythonType type\u00F8, [ParamDictionary]IDictionary kwargs\u00F8) { + public static object NonDefaultNewKWNoParams(CodeContext context, PythonType type\u00F8, [ParamDictionary] IDictionary kwargs\u00F8) { if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8))); string[] names; object[] args; - GetKeywordArgs(kwargs\u00F8, ArrayUtils.EmptyObjects, out args, out names); + GetKeywordArgs(kwargs\u00F8, [], out args, out names); return type\u00F8.CreateInstance(context, args, names); } diff --git a/Src/IronPython/Runtime/Operations/IntOps.Generated.cs b/Src/IronPython/Runtime/Operations/IntOps.Generated.cs index 5c6d91640..4a6c512df 100644 --- a/Src/IronPython/Runtime/Operations/IntOps.Generated.cs +++ b/Src/IronPython/Runtime/Operations/IntOps.Generated.cs @@ -95,6 +95,8 @@ public static object Abs(SByte x) { public static string __repr__(SByte x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(SByte self) => PythonTuple.MakeTuple(unchecked((int)self)); + public static SByte __trunc__(SByte x) => x; public static int __int__(SByte x) => unchecked((int)x); @@ -366,6 +368,8 @@ public static object __new__(PythonType cls, object value) { public static string __repr__(Byte x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(Byte self) => PythonTuple.MakeTuple(unchecked((int)self)); + public static Byte __trunc__(Byte x) => x; public static int __int__(Byte x) => unchecked((int)x); @@ -739,6 +743,8 @@ public static object Abs(Int16 x) { public static string __repr__(Int16 x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(Int16 self) => PythonTuple.MakeTuple(unchecked((int)self)); + public static Int16 __trunc__(Int16 x) => x; public static int __int__(Int16 x) => unchecked((int)x); @@ -1015,6 +1021,8 @@ public static object __new__(PythonType cls, object value) { public static string __repr__(UInt16 x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(UInt16 self) => PythonTuple.MakeTuple(unchecked((int)self)); + public static UInt16 __trunc__(UInt16 x) => x; public static int __int__(UInt16 x) => unchecked((int)x); @@ -1398,6 +1406,8 @@ public static object Abs(Int32 x) { public static string __repr__(Int32 x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(Int32 self) => PythonTuple.MakeTuple(unchecked((int)self)); + public static Int32 __trunc__(Int32 x) => x; public static int __int__(Int32 x) => unchecked((int)x); @@ -1649,6 +1659,8 @@ public static object __new__(PythonType cls, object value) { public static string __repr__(UInt32 x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(UInt32 self) => PythonTuple.MakeTuple(unchecked((BigInteger)self)); + public static UInt32 __trunc__(UInt32 x) => x; public static BigInteger __int__(UInt32 x) => unchecked((BigInteger)x); @@ -2032,6 +2044,8 @@ public static object Abs(Int64 x) { public static string __repr__(Int64 x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(Int64 self) => PythonTuple.MakeTuple(unchecked((BigInteger)self)); + public static Int64 __trunc__(Int64 x) => x; public static BigInteger __int__(Int64 x) => unchecked((BigInteger)x); @@ -2306,6 +2320,8 @@ public static object __new__(PythonType cls, object value) { public static string __repr__(UInt64 x) => x.ToString(CultureInfo.InvariantCulture); + public static PythonTuple __getnewargs__(UInt64 self) => PythonTuple.MakeTuple(unchecked((BigInteger)self)); + public static UInt64 __trunc__(UInt64 x) => x; public static BigInteger __int__(UInt64 x) => unchecked((BigInteger)x); diff --git a/Src/IronPython/Runtime/Operations/IntPtrOps.cs b/Src/IronPython/Runtime/Operations/IntPtrOps.cs index 695347549..579bd4b08 100644 --- a/Src/IronPython/Runtime/Operations/IntPtrOps.cs +++ b/Src/IronPython/Runtime/Operations/IntPtrOps.cs @@ -59,6 +59,8 @@ public static object __new__(PythonType cls, object value) { #region Unary Operations + public static PythonTuple __getnewargs__(IntPtr self) => PythonTuple.MakeTuple(unchecked((BigInteger)(nint)self)); + public static BigInteger __index__(IntPtr x) => unchecked((BigInteger)(nint)x); #endregion diff --git a/Src/IronPython/Runtime/Operations/PythonOps.cs b/Src/IronPython/Runtime/Operations/PythonOps.cs index 31397c8b3..3d2b616cb 100644 --- a/Src/IronPython/Runtime/Operations/PythonOps.cs +++ b/Src/IronPython/Runtime/Operations/PythonOps.cs @@ -4045,7 +4045,7 @@ public static Exception StopIteration() { } public static Exception InvalidType(object o, RuntimeTypeHandle handle) { - return PythonOps.TypeErrorForTypeMismatch(DynamicHelpers.GetPythonTypeFromType(Type.GetTypeFromHandle(handle)).Name, o); + return PythonOps.TypeErrorForTypeMismatch(DynamicHelpers.GetPythonTypeFromType(Type.GetTypeFromHandle(handle)!).Name, o); } public static Exception ZeroDivisionError() { @@ -4243,6 +4243,7 @@ public static List PushFrame(CodeContext/*!*/ context, FunctionCo } internal static LightLambdaExpression ToGenerator(this LightLambdaExpression code, bool shouldInterpret, bool debuggable, int compilationThreshold) { +#pragma warning disable CA2263 // Prefer generic overload when type is known return Utils.LightLambda( typeof(object), code.Type, @@ -4250,6 +4251,7 @@ internal static LightLambdaExpression ToGenerator(this LightLambdaExpression cod code.Name, code.Parameters ); +#pragma warning restore CA2263 // Prefer generic overload when type is known } public static void UpdateStackTrace(Exception e, CodeContext context, FunctionCode funcCode, int line) { diff --git a/Src/IronPython/Runtime/Operations/PythonTypeOps.cs b/Src/IronPython/Runtime/Operations/PythonTypeOps.cs index 9edf44394..a96a60892 100644 --- a/Src/IronPython/Runtime/Operations/PythonTypeOps.cs +++ b/Src/IronPython/Runtime/Operations/PythonTypeOps.cs @@ -5,11 +5,13 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Reflection; using System.Dynamic; using System.Linq; +using System.Reflection; + using IronPython.Runtime.Binding; using IronPython.Runtime.Types; + using Microsoft.Scripting; using Microsoft.Scripting.Actions; using Microsoft.Scripting.Generation; @@ -56,7 +58,7 @@ internal static string GetModuleName(CodeContext/*!*/ context, Type type) { } internal static object CallParams(CodeContext/*!*/ context, PythonType cls, params object[] args\u03c4) { - if (args\u03c4 == null) args\u03c4 = ArrayUtils.EmptyObjects; + if (args\u03c4 == null) args\u03c4 = []; return CallWorker(context, cls, args\u03c4); } @@ -83,7 +85,7 @@ internal static object CallWorker(CodeContext/*!*/ context, PythonType dt, IDict argNames[i++ - args.Length] = kvp.Key; } - return CallWorker(context, dt, new KwCallInfo(allArgs, argNames)); + return CallWorker(context, dt, new KwCallInfo(allArgs, argNames)); } internal static object CallWorker(CodeContext/*!*/ context, PythonType dt, KwCallInfo args) { @@ -114,7 +116,7 @@ private static object GetInitMethod(CodeContext/*!*/ context, PythonType dt, obj PythonType cdt = dt.ResolutionOrder[i]; PythonTypeSlot dts; object value; - + if (cdt.TryLookupSlot(context, "__init__", out dts) && dts.TryGetValue(context, newObject, dt, out value)) { return value; @@ -170,7 +172,7 @@ private static bool ShouldInvokeInit(PythonType cls, PythonType newObjectType, i // or if this is the user doing type(x), or if it's a standard // .NET type which doesn't have an __init__ method (this is a perf optimization) return (!cls.IsSystemType || cls.IsPythonType) && - newObjectType.IsSubclassOf(cls) && + newObjectType.IsSubclassOf(cls) && (cls != TypeCache.PythonType || argCnt > 1); } @@ -230,7 +232,7 @@ internal static TrackerTypes GetMemberType(MemberGroup members) { group = FilterNewSlots(group); TrackerTypes tt = GetMemberType(group); - switch(tt) { + switch (tt) { case TrackerTypes.Method: bool checkStatic = false; List mems = new List(); @@ -241,37 +243,37 @@ internal static TrackerTypes GetMemberType(MemberGroup members) { } Type declType = group[0].DeclaringType; - MemberInfo[] memArray = mems.ToArray(); + MemberInfo[] memArray = mems.ToArray(); FunctionType ft = GetMethodFunctionType(declType, memArray, checkStatic); return GetFinalSlotForFunction(GetBuiltinFunction(declType, group[0].Name, name, ft, memArray)); - + case TrackerTypes.Field: return GetReflectedField(((FieldTracker)group[0]).Field); - + case TrackerTypes.Property: - return GetReflectedProperty((PropertyTracker)group[0], group, privateBinding); - + return GetReflectedProperty((PropertyTracker)group[0], group, privateBinding); + case TrackerTypes.Event: return GetReflectedEvent(((EventTracker)group[0])); - + case TrackerTypes.Type: TypeTracker type = (TypeTracker)group[0]; for (int i = 1; i < group.Count; i++) { type = TypeGroup.UpdateTypeEntity(type, (TypeTracker)group[i]); } - + if (type is TypeGroup) { return new PythonTypeUserDescriptorSlot(type, true); } return new PythonTypeUserDescriptorSlot(DynamicHelpers.GetPythonTypeFromType(type.Type), true); - + case TrackerTypes.Constructor: return GetConstructorFunction(group[0].DeclaringType, privateBinding); - + case TrackerTypes.Custom: return ((PythonCustomTracker)group[0]).GetSlot(); - + default: // if we have a new slot in the derived class filter out the // members from the base class. @@ -311,7 +313,7 @@ private static BuiltinFunction GetConstructorFunction(Type t, bool privateBindin return GetConstructor(t, ctorFunc, ctors); } - + internal static MethodBase[] GetConstructors(Type t, bool privateBinding, bool includeProtected = false) { MethodBase[] ctors = CompilerHelpers.GetConstructors(t, privateBinding, includeProtected); if (t.IsEnum) { @@ -320,7 +322,8 @@ internal static MethodBase[] GetConstructors(Type t, bool privateBinding, bool i } return ctors; } - // support for EnumType(number) + + // support for EnumType(number) private static T CreateEnum(object value) { if (value == null) { throw PythonOps.ValueError( @@ -364,7 +367,7 @@ internal static BuiltinFunction GetConstructorFunction(Type type, string name) { methods.Add(ci); } } - + if (type.IsValueType && !hasDefaultConstructor && type != typeof(void)) { try { methods.Add(typeof(ScriptingRuntimeHelpers).GetMethod(nameof(ScriptingRuntimeHelpers.CreateInstance), ReflectionUtils.EmptyTypes).MakeGenericMethod(type)); @@ -480,7 +483,7 @@ public static MemberInfo[] GetNonBaseHelperMemberInfos(MemberInfo[] members) { BuiltinFunction res = null; if (mems.Length != 0) { - FunctionType ft = funcType ?? GetMethodFunctionType(type, mems); + FunctionType ft = funcType ?? GetMethodFunctionType(type, mems); type = GetBaseDeclaringType(type, mems); BuiltinFunctionKey cache = new BuiltinFunctionKey(type, new ReflectionCache.MethodBaseCache(cacheName, GetNonBaseHelperMethodInfos(mems)), ft); @@ -540,7 +543,7 @@ private static Type GetCommonBaseType(Type xType, Type yType) { private static Type GetBaseDeclaringType(Type type, MemberInfo/*!*/[] mems) { // get the base most declaring type, first sort the list so that // the most derived class is at the beginning. - Array.Sort(mems, delegate(MemberInfo x, MemberInfo y) { + Array.Sort(mems, delegate (MemberInfo x, MemberInfo y) { if (x.DeclaringType.IsSubclassOf(y.DeclaringType)) { return -1; } else if (y.DeclaringType.IsSubclassOf(x.DeclaringType)) { @@ -602,7 +605,7 @@ internal static FunctionType GetMethodFunctionType(Type/*!*/ type, MemberInfo/*! if (mi.IsStatic && mi.IsSpecialName) { ParameterInfo[] pis = mi.GetParameters(); - if ((pis.Length == 2 && pis[0].ParameterType != typeof(CodeContext)) || + if ((pis.Length == 2 && pis[0].ParameterType != typeof(CodeContext)) || (pis.Length == 3 && pis[0].ParameterType == typeof(CodeContext))) { ft |= FunctionType.BinaryOperator; @@ -658,7 +661,7 @@ private static bool IsMethodAlwaysVisible(Type/*!*/ type, MemberInfo/*!*/[]/*!*/ } } else if (type.IsAssignableFrom(typeof(int))) { // GH #52 // only show methods defined outside of int - foreach (MethodInfo mi in methods) { + foreach (MethodInfo mi in methods) { Debug.Assert(!mi.DeclaringType.IsInterface || typeof(int).GetInterfaces().Contains(mi.DeclaringType)); if (PythonBinder.IsPythonSupportingType(mi.DeclaringType) || mi.DeclaringType.IsInterface || @@ -675,7 +678,7 @@ private static bool IsMethodAlwaysVisible(Type/*!*/ type, MemberInfo/*!*/[]/*!*/ /// a function is static if it's a static .NET method and it's defined on the type or is an extension method /// with StaticExtensionMethod decoration. /// - private static bool IsStaticFunction(Type type, MethodInfo mi) { + private static bool IsStaticFunction(Type type, MethodInfo mi) { return mi.IsStatic && // method must be truly static !mi.IsDefined(typeof(WrapperDescriptorAttribute), false) && // wrapper descriptors are instance methods (mi.DeclaringType.IsAssignableFrom(type) || mi.IsDefined(typeof(StaticExtensionMethodAttribute), false)); // or it's not an extension method or it's a static extension method @@ -814,7 +817,7 @@ internal static ReflectedGetterSetter GetReflectedProperty(PropertyTracker pt, M _propertyCache[pt] = rp; return rp; - } + } } private static MethodInfo FilterProtectedGetterOrSetter(MethodInfo info, bool privateBinding) { @@ -884,7 +887,7 @@ internal static bool TryInvokeTernaryOperator(CodeContext context, object o, obj /// internal static PythonTuple EnsureBaseType(PythonTuple bases) { bool hasInterface = false; - foreach (object baseClass in bases) { + foreach (object baseClass in bases) { PythonType dt = baseClass as PythonType; if (!dt.UnderlyingSystemType.IsInterface) { diff --git a/Src/IronPython/Runtime/Operations/StringOps.cs b/Src/IronPython/Runtime/Operations/StringOps.cs index f79855b95..4aa3dff0d 100644 --- a/Src/IronPython/Runtime/Operations/StringOps.cs +++ b/Src/IronPython/Runtime/Operations/StringOps.cs @@ -2091,7 +2091,9 @@ static CodecsInfo() { #if DEBUG foreach (KeyValuePair> kvp in d) { // all codecs should be stored in lowercase because we only look up from lowercase strings - Debug.Assert(kvp.Key.Equals(kvp.Key, StringComparison.OrdinalIgnoreCase)); + #pragma warning disable CA1862 // disable warning about comparing with ToLower() + Debug.Assert(kvp.Key.ToLower(CultureInfo.InvariantCulture) == kvp.Key); + #pragma warning restore // all codec names should use underscores instead of dashes to match lookup values Debug.Assert(kvp.Key.IndexOf('-') < 0); } diff --git a/Src/IronPython/Runtime/Operations/TypeGroupOps.cs b/Src/IronPython/Runtime/Operations/TypeGroupOps.cs index 19354664c..5aa615cc7 100644 --- a/Src/IronPython/Runtime/Operations/TypeGroupOps.cs +++ b/Src/IronPython/Runtime/Operations/TypeGroupOps.cs @@ -13,15 +13,14 @@ using Microsoft.Scripting; using Microsoft.Scripting.Actions; -using Microsoft.Scripting.Utils; namespace IronPython.Runtime.Operations { public static class TypeGroupOps { public static string __repr__(TypeGroup self) { StringBuilder sb = new StringBuilder(" PythonTuple.MakeTuple(unchecked((BigInteger)(nuint)self)); + public static BigInteger __index__(UIntPtr x) => unchecked((BigInteger)(nuint)x); #endregion diff --git a/Src/IronPython/Runtime/PythonFunction.cs b/Src/IronPython/Runtime/PythonFunction.cs index 104dd3bf2..a40f9378d 100644 --- a/Src/IronPython/Runtime/PythonFunction.cs +++ b/Src/IronPython/Runtime/PythonFunction.cs @@ -68,7 +68,7 @@ public PythonFunction(CodeContext context, FunctionCode code, PythonDictionary g _context = new CodeContext(new PythonDictionary(), new ModuleContext(globals, DefaultContext.DefaultPythonContext)); } - _defaults = defaults == null ? ArrayUtils.EmptyObjects : defaults.ToArray(); + _defaults = defaults == null ? [] : defaults.ToArray(); _code = code; _doc = code._initialDoc; _name = name ?? code.PythonCode.Name; @@ -90,7 +90,7 @@ internal PythonFunction(CodeContext/*!*/ context, FunctionCode funcInfo, object Assert.NotNull(context, funcInfo); _context = context; - _defaults = defaults ?? ArrayUtils.EmptyObjects; + _defaults = defaults ?? []; _kwdefaults = kwdefaults; _code = funcInfo; _doc = funcInfo._initialDoc; @@ -99,7 +99,7 @@ internal PythonFunction(CodeContext/*!*/ context, FunctionCode funcInfo, object _annotations = annotations ?? new PythonDictionary(); Debug.Assert(_defaults.Length <= _code.co_argcount); - Debug.Assert((__kwdefaults__ ?.Count ?? 0) <= _code.co_kwonlyargcount); + Debug.Assert((__kwdefaults__?.Count ?? 0) <= _code.co_kwonlyargcount); if (modName != Uninitialized.Instance) { _module = modName; } @@ -142,7 +142,7 @@ public PythonTuple __defaults__ { return new PythonTuple(_defaults); } set { - _defaults = value == null ? ArrayUtils.EmptyObjects : value.ToArray(); + _defaults = value == null ? [] : value.ToArray(); FunctionCompatibility = CalculatedCachedCompat(); } } @@ -211,7 +211,7 @@ public object __module__ { public FunctionCode __code__ { get { - return _code; + return _code; } set { if (value == null) { @@ -226,7 +226,7 @@ public object __call__(CodeContext/*!*/ context, params object[] args) { return PythonCalls.Call(context, this, args); } - public object __call__(CodeContext/*!*/ context, [ParamDictionary]IDictionary dict, params object[] args) { + public object __call__(CodeContext/*!*/ context, [ParamDictionary] IDictionary dict, params object[] args) { return PythonCalls.CallWithKeywordArgs(context, this, args, dict); } @@ -417,7 +417,7 @@ internal Exception BadKeywordArgumentError(int count) { } #endregion - + #region Custom member lookup operators IList IMembersList.GetMemberNames() { @@ -471,7 +471,7 @@ internal PythonDictionary EnsureDict() { } return _dict; } - + internal static int AddRecursionDepth(int change) { // ManagedThreadId starts at 1 and increases as we get more threads. // Therefore we keep track of a limited number of threads in an array @@ -523,8 +523,7 @@ internal override bool TryGetValue(CodeContext context, object instance, PythonT } [PythonType("cell")] - public sealed class ClosureCell : ICodeFormattable - { + public sealed class ClosureCell : ICodeFormattable { [PythonHidden] public object Value; diff --git a/Src/IronPython/Runtime/PythonList.cs b/Src/IronPython/Runtime/PythonList.cs index dcf717b4e..286d55010 100644 --- a/Src/IronPython/Runtime/PythonList.cs +++ b/Src/IronPython/Runtime/PythonList.cs @@ -12,15 +12,14 @@ using System.Text; using System.Threading; +using IronPython.Runtime.Operations; +using IronPython.Runtime.Types; + using Microsoft.Scripting; using Microsoft.Scripting.Generation; using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; -using IronPython.Runtime.Exceptions; -using IronPython.Runtime.Operations; -using IronPython.Runtime.Types; - using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute; namespace IronPython.Runtime { @@ -156,7 +155,7 @@ public PythonList(CodeContext context, [NotNone] object sequence) { internal PythonList(int capacity) { if (capacity == 0) { - _data = ArrayUtils.EmptyObjects; + _data = []; } else { _data = new object[capacity]; } @@ -871,8 +870,8 @@ public void insert(int index, object? value) { public object? pop(int index) { lock (this) { - index = PythonOps.FixIndex(index, _size); if (_size == 0) throw PythonOps.IndexError("pop off of empty list"); + index = PythonOps.FixIndex(index, _size); object? ret = _data[index]; _size -= 1; @@ -956,7 +955,7 @@ private void DoSort(CodeContext/*!*/ context, IComparer cmp, object? key, bool r try { // make the list appear empty for the duration of the sort... - _data = ArrayUtils.EmptyObjects; + _data = []; _size = 0; if (key != null) { diff --git a/Src/IronPython/Runtime/TypecodeOps.cs b/Src/IronPython/Runtime/TypecodeOps.cs index 7a60973c1..e11e97ae1 100644 --- a/Src/IronPython/Runtime/TypecodeOps.cs +++ b/Src/IronPython/Runtime/TypecodeOps.cs @@ -138,6 +138,7 @@ public static bool TryGetFromBytes(char typecode, ReadOnlySpan bytes, [Not } } +#pragma warning disable CS9191 // The 'ref' modifier for an argument corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. public static bool TryGetBytes(char typecode, object obj, Span dest) { switch (typecode) { case 'c': @@ -205,6 +206,7 @@ public static bool TryGetBytes(char typecode, object obj, Span dest) { return false; } } +#pragma warning restore CS9191 // The 'ref' modifier for an argument corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. /// /// Checks if the given value does overflow a single element field with the diff --git a/Src/IronPython/Runtime/Types/BuiltinFunctionOverloadMapper.cs b/Src/IronPython/Runtime/Types/BuiltinFunctionOverloadMapper.cs index 452b0517e..bdacd5e3b 100644 --- a/Src/IronPython/Runtime/Types/BuiltinFunctionOverloadMapper.cs +++ b/Src/IronPython/Runtime/Types/BuiltinFunctionOverloadMapper.cs @@ -130,7 +130,7 @@ public void ThrowOverloadException(Type[] sig, IList targets) { System.Text.StringBuilder sigInfo = new System.Text.StringBuilder(); sigInfo.Append((targets.Count > 0 ? targets[0].Name : "") + "["); foreach (var type in sig) { - if (!sigInfo.ToString().EndsWith("[", StringComparison.Ordinal)) { + if (!sigInfo.ToString().EndsWith('[')) { sigInfo.Append(", "); } @@ -148,7 +148,7 @@ public void ThrowOverloadException(Type[] sig, IList targets) { possibleOverloads.Append("["); foreach (var param in overload.GetParameters()) { - if (!possibleOverloads.ToString().EndsWith("[", StringComparison.Ordinal)) { + if (!possibleOverloads.ToString().EndsWith('[')) { possibleOverloads.Append(", "); } possibleOverloads.Append(param.ParameterType.Name); diff --git a/Src/IronPython/Runtime/Types/DocBuilder.cs b/Src/IronPython/Runtime/Types/DocBuilder.cs index 0f958bb29..e2aca6332 100644 --- a/Src/IronPython/Runtime/Types/DocBuilder.cs +++ b/Src/IronPython/Runtime/Types/DocBuilder.cs @@ -504,7 +504,7 @@ private static void AppendTypeFormat(Type curType, StringBuilder res, ParameterI res.Append('}'); } else { if (pi != null) { - if((pi.IsOut || pi.ParameterType.IsByRef) && curType.FullName.EndsWith("&", StringComparison.Ordinal)) { + if((pi.IsOut || pi.ParameterType.IsByRef) && curType.FullName.EndsWith('&')) { res.Append(curType.FullName.Replace("&", "@")); } else { res.Append(curType.FullName); diff --git a/Src/IronPython/Runtime/Types/NewTypeMaker.cs b/Src/IronPython/Runtime/Types/NewTypeMaker.cs index dec81ef2e..3b19916ce 100644 --- a/Src/IronPython/Runtime/Types/NewTypeMaker.cs +++ b/Src/IronPython/Runtime/Types/NewTypeMaker.cs @@ -6,20 +6,20 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.Dynamic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; -using System.Dynamic; using System.Text; +using IronPython.Runtime.Binding; +using IronPython.Runtime.Operations; + using Microsoft.Scripting; using Microsoft.Scripting.Actions; using Microsoft.Scripting.Generation; using Microsoft.Scripting.Utils; -using IronPython.Runtime.Binding; -using IronPython.Runtime.Operations; - namespace IronPython.Runtime.Types { /// /// Python class hierarchy is represented using the __class__ field in the object. It does not @@ -44,7 +44,7 @@ internal sealed class NewTypeMaker { private FieldInfo _dictField; private FieldInfo _slotsField; private FieldInfo _explicitMO; - + private ILGen _cctor; private int _site; @@ -70,7 +70,7 @@ internal sealed class NewTypeMaker { private static readonly Dictionary>> _overriddenMethods = new Dictionary>>(); [MultiRuntimeAware] private static readonly Dictionary>> _overriddenProperties = new Dictionary>>(); - + private NewTypeMaker(NewTypeInfo typeInfo) { _baseType = typeInfo.BaseType; @@ -105,7 +105,7 @@ private NewTypeMaker(NewTypeInfo typeInfo) { // creation code return new NewTypeMaker(typeInfo).CreateNewType(); }); - + return ret; } @@ -118,7 +118,7 @@ public static void SaveNewTypes(string assemblyName, IList types) { MethodBuilder mb = tb.DefineMethod(_constructorMethodName, MethodAttributes.Public | MethodAttributes.Static, typeof(CachedNewTypeInfo[]), ReflectionUtils.EmptyTypes); ILGenerator ilg = mb.GetILGenerator(); - + // new CachedTypeInfo[types.Count] // we leave this on the stack (duping it) and storing into it. EmitInt(ilg, types.Count); @@ -127,7 +127,7 @@ public static void SaveNewTypes(string assemblyName, IList types) { foreach (var v in types) { NewTypeInfo nti = NewTypeInfo.GetTypeInfo(String.Empty, v); - + var typeInfos = new NewTypeMaker(nti).SaveType(ag, "Python" + _typeCount++ + "$" + nti.BaseType.Name); // prepare for storing the element into our final array @@ -138,14 +138,14 @@ public static void SaveNewTypes(string assemblyName, IList types) { // load the type ilg.Emit(OpCodes.Ldtoken, typeInfos.Key); - ilg.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); + ilg.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); // create the dictionary of special names ilg.Emit(OpCodes.Newobj, typeof(Dictionary).GetConstructor(Array.Empty())); foreach (var specialName in typeInfos.Value) { // dup dict ilg.Emit(OpCodes.Dup); - + // emit key ilg.Emit(OpCodes.Ldstr, specialName.Key); @@ -161,7 +161,7 @@ public static void SaveNewTypes(string assemblyName, IList types) { } // assign to dict - ilg.Emit(OpCodes.Call, typeof(Dictionary).GetMethod("set_Item")); + ilg.Emit(OpCodes.Call, typeof(Dictionary).GetMethod("set_Item")); } // emit the interface types (if any) @@ -412,13 +412,13 @@ private void OverrideConstructor(ConstructorInfo parentConstructor) { // parameter based attribute logic if (pi.IsDefined(typeof(ParamArrayAttribute), false)) { pb.SetCustomAttribute(new CustomAttributeBuilder( - typeof(ParamArrayAttribute).GetConstructor(ReflectionUtils.EmptyTypes), ArrayUtils.EmptyObjects)); + typeof(ParamArrayAttribute).GetConstructor(ReflectionUtils.EmptyTypes), [])); } else if (pi.IsDefined(typeof(ParamDictionaryAttribute), false)) { pb.SetCustomAttribute(new CustomAttributeBuilder( - typeof(ParamDictionaryAttribute).GetConstructor(ReflectionUtils.EmptyTypes), ArrayUtils.EmptyObjects)); + typeof(ParamDictionaryAttribute).GetConstructor(ReflectionUtils.EmptyTypes), [])); } else if (pi.IsDefined(typeof(BytesLikeAttribute), false)) { pb.SetCustomAttribute(new CustomAttributeBuilder( - typeof(BytesLikeAttribute).GetConstructor(ReflectionUtils.EmptyTypes), ArrayUtils.EmptyObjects)); + typeof(BytesLikeAttribute).GetConstructor(ReflectionUtils.EmptyTypes), [])); } if ((pi.Attributes & ParameterAttributes.HasDefault) != 0) { @@ -465,7 +465,7 @@ private void OverrideConstructor(ConstructorInfo parentConstructor) { MethodInfo init = typeof(PythonOps).GetMethod(nameof(PythonOps.InitializeUserTypeSlots)); il.EmitLoadArg(0); - + il.EmitLoadArg(typeArg); il.EmitCall(init); @@ -531,6 +531,7 @@ private void ImplementCustomTypeDescriptor() { ImplementInterface(typeof(ICustomTypeDescriptor)); foreach (MethodInfo m in typeof(ICustomTypeDescriptor).GetMethods()) { + if (!m.IsAbstract) continue; ImplementCTDOverride(m); } } @@ -563,7 +564,7 @@ private bool NeedsPythonObject { private void ImplementDynamicObject() { // true if the user has explicitly included IDynamicMetaObjectProvider in the list of interfaces - bool explicitDynamicObject = false; + bool explicitDynamicObject = false; foreach (Type t in _interfaceTypes) { if (t == typeof(IDynamicMetaObjectProvider)) { explicitDynamicObject = true; @@ -633,7 +634,7 @@ private void ImplementDynamicObject() { il.Emit(OpCodes.Dup); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Beq, retNull); - + // store the local value il.Emit(OpCodes.Stloc_S, retVal.LocalIndex); @@ -643,7 +644,7 @@ private void ImplementDynamicObject() { // user returned null, fallback to base impl il.MarkLabel(retNull); il.Emit(OpCodes.Pop); - + // no override exists il.MarkLabel(noOverride); @@ -664,7 +665,7 @@ private void ImplementDynamicObject() { il.EmitLoadArg(0); // this il.EmitLoadArg(1); // parameter - + // baseMetaObject if (baseIdo) { InterfaceMapping imap = _baseType.GetInterfaceMap(typeof(IDynamicMetaObjectProvider)); @@ -735,7 +736,7 @@ private void ImplementIPythonObject() { il.Emit(OpCodes.Ret); _tg.DefineMethodOverride(impl, decl); } - + // Types w/ DynamicBaseType attribute still need new slots implementation _slotsField = _tg.DefineField(SlotsAndWeakRefFieldName, typeof(object[]), FieldAttributes.Public); @@ -804,7 +805,7 @@ private void ImplementProtectedFieldAccessors(Dictionary speci // we need to create public helper methods that expose them. These methods are // used by the IDynamicMetaObjectProvider implementation (in MetaUserObject) - foreach (FieldInfo fi in _baseType.GetInheritedFields(flattenHierarchy: true)) { + foreach (FieldInfo fi in _baseType.GetInheritedFields(flattenHierarchy: true)) { if (!fi.IsProtected()) { continue; } @@ -900,13 +901,13 @@ private void OverrideMethods(Type type, Dictionary specialName added[key] = mi; } } - + if (type.IsAbstract && !type.IsInterface) { // abstract types can define interfaces w/o implementations foreach (Type iface in type.GetInterfaces()) { InterfaceMapping mapping = type.GetInterfaceMap(iface); for (int i = 0; i < mapping.TargetMethods.Length; i++) { - + if (mapping.TargetMethods[i] == null) { MethodInfo mi = mapping.InterfaceMethods[i]; @@ -1149,7 +1150,7 @@ private LocalBuilder EmitBaseClassCallCheckForProperties(ILGen il, MethodInfo ba // we're accessing a property return callTarget; } - + private MethodBuilder CreateVTableGetterOverride(MethodInfo mi, string name) { MethodBuilder impl; ILGen il; @@ -1273,7 +1274,7 @@ private MethodBuilder CreateVTableMethodOverride(MethodInfo mi, string name) { DefineVTableMethodOverride(mi, out impl, out il); //CompilerHelpers.GetArgumentNames(parameters)); TODO: Set names - LocalBuilder callTarget = EmitNonInheritedMethodLookup(name, il); + LocalBuilder callTarget = EmitNonInheritedMethodLookup(name, il); Label instanceCall = il.DefineLabel(); il.Emit(OpCodes.Brtrue, instanceCall); @@ -1602,7 +1603,7 @@ private static void AddBaseMethods(Type finishedType, Dictionary GetOverriddenProperties(Type typ } #endregion - } } diff --git a/Src/IronPython/Runtime/Types/ParameterInfoWrapper.cs b/Src/IronPython/Runtime/Types/ParameterInfoWrapper.cs index 683eb1bd5..7330204e5 100644 --- a/Src/IronPython/Runtime/Types/ParameterInfoWrapper.cs +++ b/Src/IronPython/Runtime/Types/ParameterInfoWrapper.cs @@ -4,8 +4,6 @@ using System; using System.Reflection; -using Microsoft.Scripting.Utils; -using System.Collections.Generic; namespace Microsoft.Scripting.Generation { /// @@ -41,11 +39,11 @@ public override string Name { } public override object[] GetCustomAttributes(bool inherit) { - return ArrayUtils.EmptyObjects; + return []; } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { - return ArrayUtils.EmptyObjects; + return []; } } } diff --git a/Src/IronPython/Runtime/Types/PythonType.cs b/Src/IronPython/Runtime/Types/PythonType.cs index 6e774c591..e8c78ade8 100644 --- a/Src/IronPython/Runtime/Types/PythonType.cs +++ b/Src/IronPython/Runtime/Types/PythonType.cs @@ -504,7 +504,7 @@ public object __call__(CodeContext context, params object[] args) { return PythonTypeOps.CallParams(context, this, args); } - public object __call__(CodeContext context, [ParamDictionary]IDictionary kwArgs, params object[] args) { + public object __call__(CodeContext context, [ParamDictionary] IDictionary kwArgs, params object[] args) { return PythonTypeOps.CallWorker(context, this, kwArgs, args); } @@ -575,11 +575,12 @@ public object this[string member] { public static object Get__module__(CodeContext/*!*/ context, PythonType self) { PythonTypeSlot pts; object res; - if (self._dict != null && - self._dict.TryGetValue("__module__", out pts) && + if (self._dict != null && + self._dict.TryGetValue("__module__", out pts) && pts.TryGetValue(context, self, DynamicHelpers.GetPythonType(self), out res)) { return res; } + if (self.IsSystemType && !self.IsPythonType) return self.UnderlyingSystemType.Namespace; return PythonTypeOps.GetModuleName(context, self.UnderlyingSystemType); } @@ -637,7 +638,7 @@ public static void Set__qualname__(PythonType type, string name) { type.QualName = name; } - public static PythonDictionary __prepare__([ParamDictionary]IDictionary kwargs, params object[] args) + public static PythonDictionary __prepare__([ParamDictionary] IDictionary kwargs, params object[] args) => new PythonDictionary(); public string/*!*/ __repr__(CodeContext/*!*/ context) { @@ -788,13 +789,13 @@ internal IList ResolutionOrder { /// internal static PythonType/*!*/ GetPythonType(Type type) { object res; - + if (!_pythonTypes.TryGetValue(type, out res)) { lock (_pythonTypes) { if (!_pythonTypes.TryGetValue(type, out res)) { res = new PythonType(type); - _pythonTypes.Add(type, res); + _pythonTypes.Add(type, res); } } } @@ -872,7 +873,7 @@ internal object CreateInstance(CodeContext context, params object[] args) { case 1: return _instanceCtor.CreateInstance(context, args[0]); case 2: return _instanceCtor.CreateInstance(context, args[0], args[1]); case 3: return _instanceCtor.CreateInstance(context, args[0], args[1], args[2]); - default: + default: return _instanceCtor.CreateInstance(context, args); } } @@ -907,7 +908,7 @@ internal bool TryGetLength(CodeContext context, object o, out int length) { PythonTypeSlot lenSlot = _lenSlot; if (lenSlot == null && !PythonOps.TryResolveTypeSlot(context, this, "__len__", out lenSlot)) { length = 0; - return false; + return false; } object func; @@ -972,7 +973,7 @@ internal CallSite> HashSite { } private void EnsureHashSite() { - if(_hashSite == null) { + if (_hashSite == null) { Interlocked.CompareExchange( ref _hashSite, CallSite>.Create( @@ -1168,7 +1169,7 @@ internal bool IsHiddenMember(string name) { return !TryResolveSlot(DefaultContext.Default, name, out _) && TryResolveSlot(DefaultContext.DefaultCLS, name, out _); } - + internal LateBoundInitBinder GetLateBoundInitBinder(CallSignature signature) { Debug.Assert(!IsSystemType); // going to hold onto a PythonContext, shouldn't ever be a system type Debug.Assert(_pythonContext != null); @@ -1177,7 +1178,7 @@ internal LateBoundInitBinder GetLateBoundInitBinder(CallSignature signature) { Interlocked.CompareExchange(ref _lateBoundInitBinders, new Dictionary(), null); } - lock(_lateBoundInitBinders) { + lock (_lateBoundInitBinders) { LateBoundInitBinder res; if (!_lateBoundInitBinders.TryGetValue(signature, out res)) { _lateBoundInitBinders[signature] = res = new LateBoundInitBinder(this, signature); @@ -1241,7 +1242,7 @@ internal bool TryResolveSlot(CodeContext context, string name, out PythonTypeSlo if (UnderlyingSystemType.IsInterface) { return TypeCache.Object.TryResolveSlot(context, name, out slot); } - + slot = null; return false; @@ -1338,7 +1339,7 @@ internal static PythonTypeSlot ToTypeSlot(object value) { } // We could do more checks for things which aren't descriptors - if (value != null) { + if (value != null) { return new PythonTypeUserDescriptorSlot(value); } @@ -1483,7 +1484,7 @@ internal bool TryGetNonCustomMember(CodeContext context, object instance, string PythonDictionary dict = sdo.Dict; hasValue = dict != null && dict.TryGetValue(name, out value); - } + } // then check through all the descriptors. If we have a data // descriptor it takes priority over the value we found in the @@ -1496,7 +1497,7 @@ internal bool TryGetNonCustomMember(CodeContext context, object instance, string if (!hasValue || slot.IsSetDescriptor(context, this)) { if (slot.TryGetValue(context, instance, this, out object newValue)) value = newValue; - return true; + return true; } } } @@ -1610,7 +1611,7 @@ internal bool TrySetMember(CodeContext context, object instance, string name, ob } setAttrSite.Target(setAttrSite, context, setattr, instance, name, value); - return true; + return true; } return TrySetNonCustomMember(context, instance, name, value); @@ -1640,8 +1641,7 @@ internal bool TrySetNonCustomMember(CodeContext context, object instance, string if ((iac = sdo.SetDict(iac)) == null) { return false; } - } - else { + } else { return false; } } @@ -1851,14 +1851,14 @@ private void InitializeUserType(CodeContext/*!*/ context, string name, PythonTup // if we directly inherit from 2 types with slots then the indexes would // conflict so inheritance isn't allowed. int slotCount = pt.GetUsedSlotCount(); - + if (slotCount != 0) { if (hasSlots) { throw PythonOps.TypeError("multiple bases have instance lay-out conflict"); } hasSlots = true; } - + pt.AddSubType(this); } @@ -1917,7 +1917,7 @@ private void InitializeUserType(CodeContext/*!*/ context, string name, PythonTup bool isPythonType = false; foreach (ConstructorInfo ci in ctors) { ParameterInfo[] pis = ci.GetParameters(); - if((pis.Length > 1 && pis[0].ParameterType == typeof(CodeContext) && pis[1].ParameterType == typeof(PythonType)) || + if ((pis.Length > 1 && pis[0].ParameterType == typeof(CodeContext) && pis[1].ParameterType == typeof(PythonType)) || (pis.Length > 0 && pis[0].ParameterType == typeof(PythonType))) { isPythonType = true; break; @@ -1964,7 +1964,7 @@ internal IList GetTypeSlots() { if (_dict != null && _dict.TryGetValue("__slots__", out pts) && pts is PythonTypeUserDescriptorSlot) { return SlotsToList(((PythonTypeUserDescriptorSlot)pts).Value); } - return ArrayUtils.EmptyStrings; + return []; } internal static List GetSlots(PythonDictionary dict) { @@ -2033,7 +2033,7 @@ private void UpdateObjectNewAndInit(CodeContext context) { Debug.Assert(pt._objectInit != null && pt._objectNew != null); if (!pt._objectNew.Value) { - _objectNew = false; + _objectNew = false; } if (!pt._objectInit.Value) { @@ -2091,7 +2091,7 @@ private void PopulateDictionary(CodeContext/*!*/ context, string name, PythonTup if (slots != null) { slots.Remove("__classcell__"); _slots = slots.ToArray(); - + int index = _originalSlotCount; string typeName = IronPython.Compiler.Parser.GetPrivatePrefix(name); @@ -2117,7 +2117,7 @@ private void PopulateDictionary(CodeContext/*!*/ context, string name, PythonTup if (CheckForSlotWithDefault(context, _resolutionOrder, slots, "__dict__")) { _attrs |= PythonTypeAttributes.HasDictionary; bool inheritsDict = false; - for (int i = 1; i<_resolutionOrder.Count; i++) { + for (int i = 1; i < _resolutionOrder.Count; i++) { PythonType pt = _resolutionOrder[i]; if (pt.TryResolveSlot(context, "__dict__", out _)) { inheritsDict = true; @@ -2227,7 +2227,7 @@ private static void EnsureModule(CodeContext context, PythonDictionary dict) { } } } - + #endregion #region System type initialization @@ -2279,7 +2279,7 @@ private void AddSystemBases() { Type newType; if (TryReplaceExtensibleWithBase(curType, out newType)) { mro.Add(DynamicHelpers.GetPythonTypeFromType(newType)); - } else if(!curType.IsDefined(typeof(PythonHiddenBaseClassAttribute), false)) { + } else if (!curType.IsDefined(typeof(PythonHiddenBaseClassAttribute), false)) { mro.Add(DynamicHelpers.GetPythonTypeFromType(curType)); } curType = curType.BaseType; @@ -2316,7 +2316,7 @@ private void AddSystemInterfaces(List mro) { mro.Add(DynamicHelpers.GetPythonTypeFromType(typeof(ICollection))); mro.Add(DynamicHelpers.GetPythonTypeFromType(typeof(IEnumerable))); return; - } + } Type[] interfaces = _underlyingSystemType.GetInterfaces(); Dictionary methodMap = new Dictionary(); @@ -2325,7 +2325,7 @@ private void AddSystemInterfaces(List mro) { PythonType[] bases = new PythonType[_bases.Length + interfaces.Length]; Array.Copy(_bases, bases, _bases.Length); - for(int i = 0; i < interfaces.Length; i++) { + for (int i = 0; i < interfaces.Length; i++) { bases[i + _bases.Length] = PythonType.GetPythonType(interfaces[i]); } @@ -2353,11 +2353,11 @@ private void AddSystemInterfaces(List mro) { #endif InterfaceMapping mapping = _underlyingSystemType.GetInterfaceMap(iface); - + // grab all the interface methods which would hide other members for (int i = 0; i < mapping.TargetMethods.Length; i++) { MethodInfo target = mapping.TargetMethods[i]; - + if (target == null) { continue; } @@ -2393,7 +2393,7 @@ private void AddSystemInterfaces(List mro) { // no collisions so far... methodMap[iTarget.Name] = iface; } - } + } } } } @@ -2491,7 +2491,7 @@ private void EnsureDict() { null); } } - + /// /// Internal helper function to add a subtype /// @@ -2547,7 +2547,7 @@ private enum PythonTypeAttributes { /// The type has a ctor which does not accept PythonTypes. This is used /// for user defined types which implement __clrtype__ /// - SystemCtor = 0x20 + SystemCtor = 0x20 } #endregion @@ -2606,7 +2606,7 @@ internal WeakReferenceProxy(PythonContext context, PythonType type) { } public WeakRefTracker GetWeakRef() { - if(type.IsSystemType) { + if (type.IsSystemType) { return context.GetSystemPythonTypeWeakRef(type); } @@ -2615,7 +2615,7 @@ public WeakRefTracker GetWeakRef() { } public void SetFinalizer(WeakRefTracker value) { - if(type.IsSystemType) { + if (type.IsSystemType) { context.SetSystemPythonTypeFinalizer(type, value); } else { IWeakReferenceable weakref = (IWeakReferenceable)type; @@ -2624,10 +2624,10 @@ public void SetFinalizer(WeakRefTracker value) { } public bool SetWeakRef(WeakRefTracker value) { - if(type.IsSystemType) { + if (type.IsSystemType) { return context.SetSystemPythonTypeWeakRef(type, value); } - + IWeakReferenceable weakref = (IWeakReferenceable)type; return weakref.SetWeakRef(value); } @@ -2650,7 +2650,7 @@ public bool SetWeakRef(WeakRefTracker value) { /// internal WeakReference/*!*/ GetSharedWeakReference() { if (_weakRef == null) { - _weakRef = new WeakReference(this); + _weakRef = new WeakReference(this); } return _weakRef; @@ -2666,7 +2666,7 @@ T IFastSettable.MakeSetBinding(CallSite site, PythonSetMemberBinder binder if (!IsSystemType && !TryGetCustomSetAttr(Context.SharedContext, out _)) { CodeContext context = PythonContext.GetPythonContext(binder).SharedContext; string name = binder.Name; - + // optimized versions for possible literals that can show up in code. Type setType = typeof(T); if (setType == typeof(Func)) { @@ -2725,7 +2725,7 @@ internal class DebugProxy { public DebugProxy(PythonType type) { _type = type; } - + public PythonType[] __bases__ { get { return ArrayUtils.ToArray(_type.BaseTypes); @@ -2834,8 +2834,8 @@ public GetMemberDelegates(OptimizedGetKind getKind, PythonType type, PythonGetMe _fallback = fallback; _isNoThrow = binder.IsNoThrow; _extMethods = extMethods; - var optNames = type.GetOptimizedInstanceNames(); - + var optNames = type.GetOptimizedInstanceNames(); + switch (getKind) { case OptimizedGetKind.SlotDict: if (optNames != null) { @@ -2844,7 +2844,7 @@ public GetMemberDelegates(OptimizedGetKind getKind, PythonType type, PythonGetMe if (optNames != null && _dictIndex != -1) { _func = SlotDictOptimized; - _dictVersion = type.GetOptimizedInstanceVersion(); + _dictVersion = type.GetOptimizedInstanceVersion(); } else { _func = SlotDict; } @@ -2867,13 +2867,13 @@ public GetMemberDelegates(OptimizedGetKind getKind, PythonType type, PythonGetMe _func = UserSlotDictGetAttr; } else { _func = UserSlotDict; - } + } break; case OptimizedGetKind.UserSlotOnly: if (_getattrSlot != null) { _func = UserSlotOnlyGetAttr; } else { - _func = UserSlotOnly; + _func = UserSlotOnly; } break; default: throw new InvalidOperationException(); @@ -3097,7 +3097,7 @@ internal class SetMemberDelegates : FastSetBase { private readonly CodeContext _context; private readonly int _index, _keysVersion; - public SetMemberDelegates(CodeContext context, PythonType type, OptimizedSetKind kind, string name, int version, PythonTypeSlot slot, SlotSetValue slotFunc) + public SetMemberDelegates(CodeContext context, PythonType type, OptimizedSetKind kind, string name, int version, PythonTypeSlot slot, SlotSetValue slotFunc) : base(version) { _slot = slot; _name = name; @@ -3146,7 +3146,7 @@ public object SetDictOptimized(CallSite site, object self, TValue value) { return Update(site, self, value); } - + public object SetDict(CallSite site, object self, TValue value) { if (self is IPythonObject ipo && ipo.PythonType.Version == _version && ShouldUseNonOptimizedSite) { _hitCount++; @@ -3437,7 +3437,7 @@ public override bool Equals(CachedGetKey other) { if (!(other is CachedGetIdWeakRefExtensionMethod obj)) { return false; } - return obj._extMethodSet.Target == _extMethodSet.Target && + return obj._extMethodSet.Target == _extMethodSet.Target && obj.Name == Name; } diff --git a/Src/IronPython/Runtime/Types/ReflectedExtensionProperty.cs b/Src/IronPython/Runtime/Types/ReflectedExtensionProperty.cs index 8e879de9b..ced8d925a 100644 --- a/Src/IronPython/Runtime/Types/ReflectedExtensionProperty.cs +++ b/Src/IronPython/Runtime/Types/ReflectedExtensionProperty.cs @@ -4,7 +4,7 @@ using System; using System.Reflection; -using Microsoft.Scripting.Utils; + using IronPython.Runtime.Operations; namespace IronPython.Runtime.Types { @@ -29,14 +29,14 @@ internal override bool TryGetValue(CodeContext context, object instance, PythonT return false; } - value = CallGetter(context, null, instance, ArrayUtils.EmptyObjects); + value = CallGetter(context, null, instance, []); return true; } internal override bool TrySetValue(CodeContext context, object instance, PythonType owner, object value) { if (Setter.Length == 0 || instance == null) return false; - return CallSetter(context, null, instance, ArrayUtils.EmptyObjects, value); + return CallSetter(context, null, instance, [], value); } internal override bool TryDeleteValue(CodeContext context, object instance, PythonType owner) { diff --git a/Src/IronPython/Runtime/Types/ReflectedProperty.cs b/Src/IronPython/Runtime/Types/ReflectedProperty.cs index 558b172a6..31017a1a7 100644 --- a/Src/IronPython/Runtime/Types/ReflectedProperty.cs +++ b/Src/IronPython/Runtime/Types/ReflectedProperty.cs @@ -2,21 +2,19 @@ // 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.Linq.Expressions; - using System; using System.Diagnostics; using System.Dynamic; +using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; +using IronPython.Runtime.Binding; +using IronPython.Runtime.Operations; + using Microsoft.Scripting; using Microsoft.Scripting.Actions; using Microsoft.Scripting.Generation; -using Microsoft.Scripting.Utils; - -using IronPython.Runtime.Binding; -using IronPython.Runtime.Operations; using AstUtils = Microsoft.Scripting.Ast.Utils; @@ -55,7 +53,7 @@ internal override bool TrySetValue(CodeContext context, object instance, PythonT if (instance == null) { foreach (MethodInfo mi in Setter) { - if(mi.IsStatic && DeclaringType != owner.UnderlyingSystemType) { + if (mi.IsStatic && DeclaringType != owner.UnderlyingSystemType) { return false; } else if (mi.IsProtected()) { throw PythonOps.TypeErrorForProtectedMember(owner.UnderlyingSystemType, _info.Name); @@ -69,7 +67,7 @@ internal override bool TrySetValue(CodeContext context, object instance, PythonT } } - return CallSetter(context, context.LanguageContext.GetGenericCallSiteStorage(), instance, ArrayUtils.EmptyObjects, value); + return CallSetter(context, context.LanguageContext.GetGenericCallSiteStorage(), instance, [], value); } internal override Type DeclaringType { @@ -198,7 +196,7 @@ internal override void MakeGetExpression(PythonBinder/*!*/ binder, Expression/*! ).Expression, typeof(object) ) - ); + ); } } diff --git a/Src/IronPython/SerializationStubs.cs b/Src/IronPython/SerializationStubs.cs new file mode 100644 index 000000000..f86e2017c --- /dev/null +++ b/Src/IronPython/SerializationStubs.cs @@ -0,0 +1,31 @@ +// 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. + +#if !FEATURE_SERIALIZATION + +using System; +using System.Diagnostics; + +namespace IronPython { + [Conditional("STUB")] + internal class SerializableAttribute : Attribute { + } + + [Conditional("STUB")] + internal class NonSerializedAttribute : Attribute { + } + + namespace Runtime { + internal interface ISerializable { + } + + internal interface IDeserializationCallback { + } + } + + internal class SerializationException : Exception { + } +} + +#endif diff --git a/Src/IronPython/StringExtensions.cs b/Src/IronPython/StringExtensions.cs new file mode 100644 index 000000000..acbc2fbe5 --- /dev/null +++ b/Src/IronPython/StringExtensions.cs @@ -0,0 +1,15 @@ +using System; + +namespace IronPython { + internal static class StringExtensions { +#if !NETCOREAPP + public static bool EndsWith(this string str, char value) { + return str.EndsWith(value.ToString(), StringComparison.Ordinal); + } + + public static bool StartsWith(this string str, char value) { + return str.StartsWith(value.ToString(), StringComparison.Ordinal); + } +#endif + } +} diff --git a/Src/IronPythonConsole/IronPythonConsole.csproj b/Src/IronPythonConsole/IronPythonConsole.csproj index 73024a0c8..a933ddd3f 100644 --- a/Src/IronPythonConsole/IronPythonConsole.csproj +++ b/Src/IronPythonConsole/IronPythonConsole.csproj @@ -1,7 +1,7 @@  - net462;netcoreapp3.1;net6.0 + net462;netcoreapp3.1;net6.0;net8.0 false Exe diff --git a/Src/IronPythonTest/Cases/CPythonCases.cs b/Src/IronPythonTest/Cases/CPythonCases.cs index 90f740924..f3d568064 100644 --- a/Src/IronPythonTest/Cases/CPythonCases.cs +++ b/Src/IronPythonTest/Cases/CPythonCases.cs @@ -18,11 +18,12 @@ public override int Test(TestInfo testcase) { internal class CPythonCaseGenerator : CommonCaseGenerator { protected override IEnumerable GetTests() { + var libFolder = Path.Combine("Src", "StdLib", "Lib"); return GetFilenames(new [] { - System.Tuple.Create(category, Path.Combine("Src", "StdLib", "Lib", "test")), - System.Tuple.Create($"{category}.ctypes", Path.Combine("Src", "StdLib", "Lib", "ctypes", "test")), - System.Tuple.Create($"{category}.distutils", Path.Combine("Src", "StdLib", "Lib", "distutils", "tests")), - System.Tuple.Create($"{category}.unittest", Path.Combine("Src", "StdLib", "Lib", "unittest", "test")), + System.Tuple.Create(category, Path.Combine(libFolder, "test")), + System.Tuple.Create($"{category}.ctypes", Path.Combine(libFolder, "ctypes", "test")), + System.Tuple.Create($"{category}.distutils", Path.Combine(libFolder, "distutils", "tests")), + System.Tuple.Create($"{category}.unittest", Path.Combine(libFolder, "unittest", "test")), }) .OrderBy(testcase => testcase.Name); diff --git a/Src/IronPythonTest/Cases/CPythonCasesManifest.ini b/Src/IronPythonTest/Cases/CPythonCasesManifest.ini index 9e1506eec..9f8df720f 100644 --- a/Src/IronPythonTest/Cases/CPythonCasesManifest.ini +++ b/Src/IronPythonTest/Cases/CPythonCasesManifest.ini @@ -482,9 +482,6 @@ Ignore=true Ignore=true Reason=unittest.case.SkipTest: object has no attribute 'fork' -[CPython.test_format] -RunCondition=NOT $(IS_NETCOREAPP21) OR NOT $(IS_LINUX) # https://github.com/IronLanguages/ironpython3/issues/751 - [CPython.test_frame] Ignore=true @@ -572,9 +569,8 @@ Ignore=true Ignore=true Reason=ImportError: No module named _multiprocessing -[CPython.test_io] +[CPython.test_io] # IronPython.test_io_stdlib Ignore=true -Reason=StackOverflowException [CPython.test_ioctl] RunCondition=$(IS_POSIX) @@ -1025,7 +1021,7 @@ Reason=unittest.case.SkipTest: Cant test signal on win32 Ignore=true [CPython.test_timeout] -RunCondition=NOT $(IS_MONO) # https://github.com/IronLanguages/ironpython3/issues/1522 +RunCondition=NOT $(IS_MONO) AND NOT ($(IS_POSIX) AND $(IS_NETSTANDARD)) # https://github.com/IronLanguages/ironpython3/issues/1522 + other issues? [CPython.test_tix] # new in 3.5 Ignore=true diff --git a/Src/IronPythonTest/Cases/CaseGenerator.cs b/Src/IronPythonTest/Cases/CaseGenerator.cs index f678d0641..fea1754ed 100644 --- a/Src/IronPythonTest/Cases/CaseGenerator.cs +++ b/Src/IronPythonTest/Cases/CaseGenerator.cs @@ -108,7 +108,7 @@ private bool EvaluateExpression(string expression) { var replacements = new Dictionary() { // variables { "$(IS_NETCOREAPP)", IronPython.Runtime.ClrModule.IsNetCoreApp.ToString() }, - { "$(IS_NETCOREAPP21)", (IronPython.Runtime.ClrModule.IsNetCoreApp && IronPython.Runtime.ClrModule.FrameworkDescription.StartsWith(".NET Core 2.", StringComparison.Ordinal)).ToString() }, + { "$(IS_NETSTANDARD)", IronPython.Runtime.ClrModule.TargetFramework.StartsWith(".NETStandard", StringComparison.Ordinal).ToString() }, { "$(IS_MONO)", IronPython.Runtime.ClrModule.IsMono.ToString() }, { "$(IS_DEBUG)", IronPython.Runtime.ClrModule.IsDebug.ToString() }, { "$(IS_POSIX)", (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)).ToString() }, diff --git a/Src/IronPythonTest/Cases/IronPythonCases.cs b/Src/IronPythonTest/Cases/IronPythonCases.cs index 719cffd45..2cd431625 100644 --- a/Src/IronPythonTest/Cases/IronPythonCases.cs +++ b/Src/IronPythonTest/Cases/IronPythonCases.cs @@ -19,7 +19,7 @@ public override int Test(TestInfo testcase) { internal class IronPythonCaseGenerator : CommonCaseGenerator { protected override IEnumerable GetTests() { return GetFilenames(new[] { - System.Tuple.Create(category, Path.Combine("Tests")), + System.Tuple.Create(category, "Tests"), System.Tuple.Create($"{category}.scripts", Path.Combine("Src", "Scripts")), }) .OrderBy(testcase => testcase.Name); diff --git a/Src/IronPythonTest/Cases/IronPythonCasesManifest.ini b/Src/IronPythonTest/Cases/IronPythonCasesManifest.ini index dca4d4f92..c4c1f1882 100644 --- a/Src/IronPythonTest/Cases/IronPythonCasesManifest.ini +++ b/Src/IronPythonTest/Cases/IronPythonCasesManifest.ini @@ -61,6 +61,9 @@ Ignore=true Ignore=true Reason=Requires powershell +[IronPython.test_io_stdlib] +IsolationLevel=PROCESS # https://github.com/IronLanguages/ironpython3/issues/1808 + [IronPython.test_ipyc] Ignore=true Reason=New test needs to be written for new csharp version @@ -93,6 +96,9 @@ Reason=Needs to be redone as two tests Ignore=true Reason=StackOverflowException - https://github.com/IronLanguages/ironpython2/issues/182 +[IronPython.test_re_stdlib] +IsolationLevel=PROCESS # workaround for StackOverflowException on macOS on .NET 7 + [IronPython.test_regressions] IsolationLevel=PROCESS # https://github.com/IronLanguages/ironpython3/issues/489 RetryCount=2 diff --git a/Src/IronPythonTest/EncodingTest.cs b/Src/IronPythonTest/EncodingTest.cs index 53fab617a..7864f0a12 100644 --- a/Src/IronPythonTest/EncodingTest.cs +++ b/Src/IronPythonTest/EncodingTest.cs @@ -58,7 +58,7 @@ public class Utf8BrokenTest { [SetUp] public void SetUp() { - // 12 bytes: two valid UTF-8 2-byte chars, one non-decodable byte, + // 12 bytes: two valid UTF-8 2-byte chars, one non-decodable byte, // one UTF-8 2-byte char with a non-decodable byte inserted in between the UTF-8 bytes // and final valid UTF-8 2-byte char _bytes = "\xd0\x9f\xd0\xb8\x80\xd1\xff\x82\xd0\xbe\xd0\xbd".AsBytes(); @@ -77,13 +77,13 @@ private static void TestRoundTrip(Encoding enc, byte[] bytes) { char[] chars1 = new char[penc.GetCharCount(bytes)]; penc.GetChars(bytes, 0, bytes.Length, chars1, 0); char[] chars2 = penc.GetChars(bytes); - Assert.AreEqual(chars1, chars2); + Assert.That(chars1, Is.EqualTo(chars2)); byte[] bytes1 = penc.GetBytes(chars1); byte[] bytes2 = new byte[penc.GetByteCount(chars1, 0, chars1.Length)]; penc.GetBytes(chars1, 0, chars1.Length, bytes2, 0); - Assert.AreEqual(bytes1, bytes2); - Assert.AreEqual(bytes, bytes1); + Assert.That(bytes1, Is.EqualTo(bytes2)); + Assert.That(bytes, Is.EqualTo(bytes1)); } #endregion @@ -113,7 +113,7 @@ public void TestCompare256WithAscii() { Encoding penc = new PythonSurrogateEscapeEncoding(Encoding.ASCII); char[] chars = penc.GetChars(bytes); string python_chars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\udc80\udc81\udc82\udc83\udc84\udc85\udc86\udc87\udc88\udc89\udc8a\udc8b\udc8c\udc8d\udc8e\udc8f\udc90\udc91\udc92\udc93\udc94\udc95\udc96\udc97\udc98\udc99\udc9a\udc9b\udc9c\udc9d\udc9e\udc9f\udca0\udca1\udca2\udca3\udca4\udca5\udca6\udca7\udca8\udca9\udcaa\udcab\udcac\udcad\udcae\udcaf\udcb0\udcb1\udcb2\udcb3\udcb4\udcb5\udcb6\udcb7\udcb8\udcb9\udcba\udcbb\udcbc\udcbd\udcbe\udcbf\udcc0\udcc1\udcc2\udcc3\udcc4\udcc5\udcc6\udcc7\udcc8\udcc9\udcca\udccb\udccc\udccd\udcce\udccf\udcd0\udcd1\udcd2\udcd3\udcd4\udcd5\udcd6\udcd7\udcd8\udcd9\udcda\udcdb\udcdc\udcdd\udcde\udcdf\udce0\udce1\udce2\udce3\udce4\udce5\udce6\udce7\udce8\udce9\udcea\udceb\udcec\udced\udcee\udcef\udcf0\udcf1\udcf2\udcf3\udcf4\udcf5\udcf6\udcf7\udcf8\udcf9\udcfa\udcfb\udcfc\udcfd\udcfe\udcff"; - Assert.AreEqual(python_chars, chars); + Assert.That(chars, Is.EqualTo(python_chars)); } @@ -122,7 +122,7 @@ public void TestCompare256WithLatin1() { Encoding penc = new PythonSurrogateEscapeEncoding(StringOps.Latin1Encoding); char[] chars = penc.GetChars(bytes); string python_chars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0¡¢£¤¥¦§¨©ª«¬\xad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"; - Assert.AreEqual(python_chars, chars); + Assert.That(chars, Is.EqualTo(python_chars)); } @@ -132,24 +132,24 @@ public void TestCompare256WithUtf8() { Encoding penc = new PythonSurrogateEscapeEncoding(Encoding.UTF8); char[] chars = penc.GetChars(bytes); string python_chars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\udc80\udc81\udc82\udc83\udc84\udc85\udc86\udc87\udc88\udc89\udc8a\udc8b\udc8c\udc8d\udc8e\udc8f\udc90\udc91\udc92\udc93\udc94\udc95\udc96\udc97\udc98\udc99\udc9a\udc9b\udc9c\udc9d\udc9e\udc9f\udca0\udca1\udca2\udca3\udca4\udca5\udca6\udca7\udca8\udca9\udcaa\udcab\udcac\udcad\udcae\udcaf\udcb0\udcb1\udcb2\udcb3\udcb4\udcb5\udcb6\udcb7\udcb8\udcb9\udcba\udcbb\udcbc\udcbd\udcbe\udcbf\udcc0\udcc1\udcc2\udcc3\udcc4\udcc5\udcc6\udcc7\udcc8\udcc9\udcca\udccb\udccc\udccd\udcce\udccf\udcd0\udcd1\udcd2\udcd3\udcd4\udcd5\udcd6\udcd7\udcd8\udcd9\udcda\udcdb\udcdc\udcdd\udcde\udcdf\udce0\udce1\udce2\udce3\udce4\udce5\udce6\udce7\udce8\udce9\udcea\udceb\udcec\udced\udcee\udcef\udcf0\udcf1\udcf2\udcf3\udcf4\udcf5\udcf6\udcf7\udcf8\udcf9\udcfa\udcfb\udcfc\udcfd\udcfe\udcff"; - Assert.AreEqual(python_chars, chars); + Assert.That(chars, Is.EqualTo(python_chars)); } // Compare Windows-1252 (Western European Windows, variant of ISO-8859-1) handling with CPython results [Test] public void TestCompare256WithWindows1252() { Encoding penc = new PythonSurrogateEscapeEncoding(Encoding.GetEncoding(1252)); - Assert.AreEqual("windows-1252", penc.WebName.ToLowerInvariant()); + Assert.That(penc.WebName.ToLowerInvariant(), Is.EqualTo("windows-1252")); char[] chars = penc.GetChars(bytes); string python_chars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f€\udc81‚ƒ„…†‡ˆ‰Š‹Œ\udc8dŽ\udc8f\udc90‘’“”•–—˜™š›œ\udc9džŸ\xa0¡¢£¤¥¦§¨©ª«¬\xad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"; string encoded = new string(chars); - Assert.AreEqual(python_chars.Length, encoded.Length); + Assert.That(encoded.Length, Is.EqualTo(python_chars.Length)); for (int i = 0; i < encoded.Length; i++) { if (encoded[i] != python_chars[i]) { // Known differences between Windows and Python (Unicode) implementation of Windows-1252 // https://en.wikipedia.org/wiki/Windows-1252 - CollectionAssert.Contains(new[] { 0x81, 0x8d, 0x8f, 0x90, 0x9d }, i); + Assert.That(new[] { 0x81, 0x8d, 0x8f, 0x90, 0x9d }, Has.Member(i)); } } } @@ -158,12 +158,12 @@ public void TestCompare256WithWindows1252() { [Test] public void TestCompare256WithIso8859_1() { Encoding penc = new PythonSurrogateEscapeEncoding(Encoding.GetEncoding(28591)); - Assert.AreEqual("iso-8859-1", penc.WebName); + Assert.That(penc.WebName, Is.EqualTo("iso-8859-1")); char[] chars = penc.GetChars(bytes); string python_chars = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0¡¢£¤¥¦§¨©ª«¬\xad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"; string encoded = new string(chars); - Assert.AreEqual(python_chars, encoded); + Assert.That(encoded, Is.EqualTo(python_chars)); } // Compare UTF-7 handling with CPython results @@ -180,13 +180,13 @@ public void TestCompare256WithUtf7() { // Let's try again without the '+' bytes = bytes.Where(i => i != (byte)'+').ToArray(); char[] chars = penc.GetChars(bytes); - Assert.AreEqual(python_chars, chars); + Assert.That(chars, Is.EqualTo(python_chars)); // Now the encoding part byte[] encoded_bytes = penc.GetBytes(chars); byte[] expected_bytes = "+AAAAAQACAAMABAAFAAYABwAI-\t\n+AAsADA-\r+AA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAf- !\"#$%&'()*,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[+AFw-]^_`abcdefghijklmnopqrstuvwxyz{|}+AH4Af9yA3IHcgtyD3ITchdyG3IfciNyJ3Irci9yM3I3cjtyP3JDckdyS3JPclNyV3Jbcl9yY3Jncmtyb3Jzcndye3J/coNyh3KLco9yk3KXcptyn3Kjcqdyq3KvcrNyt3K7cr9yw3LHcstyz3LTctdy23LfcuNy53Lrcu9y83L3cvty/3MDcwdzC3MPcxNzF3Mbcx9zI3MncytzL3MzczdzO3M/c0NzR3NLc09zU3NXc1tzX3Njc2dza3Nvc3Nzd3N7c39zg3OHc4tzj3OTc5dzm3Ofc6Nzp3Orc69zs3O3c7tzv3PDc8dzy3PPc9Nz13Pbc99z43Pnc+tz73Pzc/dz+3P8-" .Select(c => (byte)c).ToArray(); - Assert.AreEqual(expected_bytes, encoded_bytes); + Assert.That(encoded_bytes, Is.EqualTo(expected_bytes)); // Encoding the given chars with CPython produces the following byte string byte[] python_bytes = "+AAAAAQACAAMABAAFAAYABwAI\t\n+AAsADA\r+AA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAf !\"#$%&'()*,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[+AFw]^_`abcdefghijklmnopqrstuvwxyz{|}+AH4Af9yA3IHcgtyD3ITchdyG3IfciNyJ3Irci9yM3I3cjtyP3JDckdyS3JPclNyV3Jbcl9yY3Jncmtyb3Jzcndye3J/coNyh3KLco9yk3KXcptyn3Kjcqdyq3KvcrNyt3K7cr9yw3LHcstyz3LTctdy23LfcuNy53Lrcu9y83L3cvty/3MDcwdzC3MPcxNzF3Mbcx9zI3MncytzL3MzczdzO3M/c0NzR3NLc09zU3NXc1tzX3Njc2dza3Nvc3Nzd3N7c39zg3OHc4tzj3OTc5dzm3Ofc6Nzp3Orc69zs3O3c7tzv3PDc8dzy3PPc9Nz13Pbc99z43Pnc+tz73Pzc/dz+3P8-" @@ -197,10 +197,10 @@ public void TestCompare256WithUtf7() { // However, they both decode to the same text, although, again, CPython's version cannot be decoded using surrogateescape char[] dotnet_decoded = penc.GetChars(encoded_bytes); char[] python_decoded = utf7.GetChars(python_bytes); - Assert.AreEqual(chars, python_decoded); - Assert.AreEqual(chars, dotnet_decoded); + Assert.That(chars, Is.EqualTo(python_decoded)); + Assert.That(chars, Is.EqualTo(dotnet_decoded)); dotnet_decoded = utf7.GetChars(encoded_bytes); - Assert.AreEqual(chars, dotnet_decoded); + Assert.That(chars, Is.EqualTo(dotnet_decoded)); } // Compare UTF-16 handling with CPython results @@ -210,11 +210,11 @@ public void TestCompare256Utf16() { char[] chars = penc.GetChars(bytes); char[] python_chars = (new[] { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e, 0x1110, 0x1312, 0x1514, 0x1716, 0x1918, 0x1b1a, 0x1d1c, 0x1f1e, 0x2120, 0x2322, 0x2524, 0x2726, 0x2928, 0x2b2a, 0x2d2c, 0x2f2e, 0x3130, 0x3332, 0x3534, 0x3736, 0x3938, 0x3b3a, 0x3d3c, 0x3f3e, 0x4140, 0x4342, 0x4544, 0x4746, 0x4948, 0x4b4a, 0x4d4c, 0x4f4e, 0x5150, 0x5352, 0x5554, 0x5756, 0x5958, 0x5b5a, 0x5d5c, 0x5f5e, 0x6160, 0x6362, 0x6564, 0x6766, 0x6968, 0x6b6a, 0x6d6c, 0x6f6e, 0x7170, 0x7372, 0x7574, 0x7776, 0x7978, 0x7b7a, 0x7d7c, 0x7f7e, 0x8180, 0x8382, 0x8584, 0x8786, 0x8988, 0x8b8a, 0x8d8c, 0x8f8e, 0x9190, 0x9392, 0x9594, 0x9796, 0x9998, 0x9b9a, 0x9d9c, 0x9f9e, 0xa1a0, 0xa3a2, 0xa5a4, 0xa7a6, 0xa9a8, 0xabaa, 0xadac, 0xafae, 0xb1b0, 0xb3b2, 0xb5b4, 0xb7b6, 0xb9b8, 0xbbba, 0xbdbc, 0xbfbe, 0xc1c0, 0xc3c2, 0xc5c4, 0xc7c6, 0xc9c8, 0xcbca, 0xcdcc, 0xcfce, 0xd1d0, 0xd3d2, 0xd5d4, 0xd7d6, 0xdcd8, 0xdcd9, 0x1069dc, 0xdcde, 0xdcdf, 0xe1e0, 0xe3e2, 0xe5e4, 0xe7e6, 0xe9e8, 0xebea, 0xedec, 0xefee, 0xf1f0, 0xf3f2, 0xf5f4, 0xf7f6, 0xf9f8, 0xfbfa, 0xfdfc, 0xfffe }) .SelectMany(i => i <= 0xffff ? ((char)i).ToString() : char.ConvertFromUtf32(i)).ToArray(); - Assert.AreEqual(python_chars, chars); + Assert.That(python_chars, Is.EqualTo(chars)); // byte[] python_bytes = ??? - CPython fails to encode the string it decoded itself; a bug in CPython? byte[] bytes1 = penc.GetBytes(chars); - Assert.AreEqual(bytes, bytes1); + Assert.That(bytes, Is.EqualTo(bytes1)); } } @@ -235,11 +235,11 @@ public void TesWithUtf16() { char[] chars = penc.GetChars(bytes); char[] python_chars = (new[] { 0x0000dcd8, 0x0000dcd9, 0x001069dc, 0x0000dcde, 0x0000dcdf }) .SelectMany(i => i <= 0xffff ? ((char)i).ToString() : char.ConvertFromUtf32(i)).ToArray(); - Assert.AreEqual(python_chars, chars); + Assert.That(python_chars, Is.EqualTo(chars)); // byte[] python_bytes = ??? - CPython fails on encoding the string it decoded itself; a bug in CPython? byte[] bytes1 = penc.GetBytes(chars); - Assert.AreEqual(bytes, bytes1); + Assert.That(bytes, Is.EqualTo(bytes1)); } [Test] @@ -248,11 +248,11 @@ public void TestWithUtf32() { char[] chars = penc.GetChars(bytes); char[] python_chars = (new[] { 0x0000dcd8, 0x0000dcd9, 0x0000dcda, 0x0000dcdb, 0x0000dcdc, 0x0000dcdd, 0x0000dcde, 0x0000dcdf }) .SelectMany(i => i <= 0xffff ? ((char)i).ToString() : char.ConvertFromUtf32(i)).ToArray(); - Assert.AreEqual(python_chars, chars); + Assert.That(python_chars, Is.EqualTo(chars)); // byte[] python_bytes = ??? - CPython fails on encoding the string it decoded itself; a bug in CPython? byte[] bytes1 = penc.GetBytes(chars); - Assert.AreEqual(bytes, bytes1); + Assert.That(bytes, Is.EqualTo(bytes1)); } } @@ -320,21 +320,21 @@ public void SetUp() { [Test] public void TestEndiannessWithUtf16LE() { Encoding penc = new PythonSurrogateEscapeEncoding(Encoding.Unicode); - Assert.AreEqual("\u000a\u0000", penc.GetChars(_bytes1)); - Assert.AreEqual("\u0000\u0a00", penc.GetChars(_bytes2)); + Assert.That("\u000a\u0000", Is.EqualTo(penc.GetChars(_bytes1))); + Assert.That("\u0000\u0a00", Is.EqualTo(penc.GetChars(_bytes2))); } [Test] public void TestEndiannessWithUtf16BE() { Encoding penc = new PythonSurrogateEscapeEncoding(Encoding.BigEndianUnicode); - Assert.AreEqual("\u0a00\u0000", penc.GetChars(_bytes1)); - Assert.AreEqual("\u0000\u000a", penc.GetChars(_bytes2)); + Assert.That("\u0a00\u0000", Is.EqualTo(penc.GetChars(_bytes1))); + Assert.That("\u0000\u000a", Is.EqualTo(penc.GetChars(_bytes2))); } [Test] public void TestEndiannessWithUtf32LE() { Encoding penc = new PythonSurrogateEscapeEncoding(new UTF32Encoding(bigEndian: false, byteOrderMark: false)); - Assert.AreEqual("\u000a", penc.GetChars(_bytes1)); + Assert.That("\u000a", Is.EqualTo(penc.GetChars(_bytes1))); Assert.Throws(() => penc.GetChars(_bytes2)); } @@ -342,7 +342,7 @@ public void TestEndiannessWithUtf32LE() { public void TestEndiannessWithUtf32BE() { Encoding penc = new PythonSurrogateEscapeEncoding(new UTF32Encoding(bigEndian: true, byteOrderMark: false)); Assert.Throws(() => penc.GetChars(_bytes1)); - Assert.AreEqual("\u000a", penc.GetChars(_bytes2)); + Assert.That("\u000a", Is.EqualTo(penc.GetChars(_bytes2))); } } @@ -404,7 +404,7 @@ public void TestAscii() { Encoding penc = new PythonSurrogatePassEncoding(Encoding.ASCII); // clean ASCII - Assert.AreEqual("abc".AsBytes(), penc.GetBytes("abc")); + Assert.That(penc.GetBytes("abc"), Is.EqualTo("abc".AsBytes())); // Attempting to encode surrogates to ASCII will throw an exception. // Note that this is CPython 3.5 behaviour, CPython 3.4 will happily contaminate ASCII with UTF-8 encoded surrogates. @@ -427,13 +427,13 @@ public void TestUtf7() { Encoding penc = new PythonSurrogatePassEncoding(new UTF7Encoding(allowOptionals: true)); // lone high surrogate - Assert.AreEqual("abc+2BA-xyz".AsBytes(), penc.GetBytes("abc\ud810xyz")); + Assert.That(penc.GetBytes("abc\ud810xyz"), Is.EqualTo("abc+2BA-xyz".AsBytes())); // lone low surrogate - Assert.AreEqual("abc+3Ao-xyz".AsBytes(), penc.GetBytes("abc\udc0axyz")); + Assert.That(penc.GetBytes("abc\udc0axyz"), Is.EqualTo("abc+3Ao-xyz".AsBytes())); // invalid surrogate pair (low, high) - Assert.AreEqual("abc+3lHaLw-xyz".AsBytes(), penc.GetBytes("abc\ude51\uda2fxyz")); + Assert.That(penc.GetBytes("abc\ude51\uda2fxyz"), Is.EqualTo("abc+3lHaLw-xyz".AsBytes())); } [Test] @@ -441,13 +441,13 @@ public void TestUtf8() { Encoding penc = new PythonSurrogatePassEncoding(Encoding.UTF8); // lone high surrogate - Assert.AreEqual("abc\xed\xa0\x90xyz".AsBytes(), penc.GetBytes("abc\ud810xyz")); + Assert.That(penc.GetBytes("abc\ud810xyz"), Is.EqualTo("abc\xed\xa0\x90xyz".AsBytes())); // lone low surrogate - Assert.AreEqual("abc\xed\xb0\x8axyz".AsBytes(), penc.GetBytes("abc\udc0axyz")); + Assert.That(penc.GetBytes("abc\udc0axyz"), Is.EqualTo("abc\xed\xb0\x8axyz".AsBytes())); // invalid surrogate pair (low, high) - Assert.AreEqual("abc\xed\xb9\x91\xed\xa8\xafxyz".AsBytes(), penc.GetBytes("abc\ude51\uda2fxyz")); + Assert.That(penc.GetBytes("abc\ude51\uda2fxyz"), Is.EqualTo("abc\xed\xb9\x91\xed\xa8\xafxyz".AsBytes())); } [Test] @@ -455,13 +455,13 @@ public void TestUtf16LE() { Encoding penc = new PythonSurrogatePassEncoding(Encoding.Unicode); // lone high surrogate - Assert.AreEqual("\x10\xd8".AsBytes(), penc.GetBytes("\ud810")); + Assert.That(penc.GetBytes("\ud810"), Is.EqualTo("\x10\xd8".AsBytes())); // lone low surrogate - Assert.AreEqual("\n\xdc".AsBytes(), penc.GetBytes("\udc0a")); + Assert.That(penc.GetBytes("\udc0a"), Is.EqualTo("\n\xdc".AsBytes())); // invalid surrogate pair (low, high) - Assert.AreEqual("Q\xde/\xda".AsBytes(), penc.GetBytes("\ude51\uda2f")); + Assert.That(penc.GetBytes("\ude51\uda2f"), Is.EqualTo("Q\xde/\xda".AsBytes())); } [Test] @@ -469,13 +469,13 @@ public void TestUtf16BE() { Encoding penc = new PythonSurrogatePassEncoding(Encoding.BigEndianUnicode); // lone high surrogate - Assert.AreEqual("\xd8\x10".AsBytes(), penc.GetBytes("\ud810")); + Assert.That(penc.GetBytes("\ud810"), Is.EqualTo("\xd8\x10".AsBytes())); // lone low surrogate - Assert.AreEqual("\xdc\n".AsBytes(), penc.GetBytes("\udc0a")); + Assert.That(penc.GetBytes("\udc0a"), Is.EqualTo("\xdc\n".AsBytes())); // invalid surrogate pair (low, high) - Assert.AreEqual("\xdeQ\xda/".AsBytes(), penc.GetBytes("\ude51\uda2f")); + Assert.That(penc.GetBytes("\ude51\uda2f"), Is.EqualTo("\xdeQ\xda/".AsBytes())); } [Test] @@ -483,13 +483,13 @@ public void TestUtf32LE() { Encoding penc = new PythonSurrogatePassEncoding(new UTF32Encoding(bigEndian: false, byteOrderMark: false)); // lone high surrogate - Assert.AreEqual("\x10\xd8\x00\x00".AsBytes(), penc.GetBytes("\ud810")); + Assert.That(penc.GetBytes("\ud810"), Is.EqualTo("\x10\xd8\x00\x00".AsBytes())); // lone low surrogate - Assert.AreEqual("\n\xdc\x00\x00".AsBytes(), penc.GetBytes("\udc0a")); + Assert.That(penc.GetBytes("\udc0a"), Is.EqualTo("\n\xdc\x00\x00".AsBytes())); // invalid surrogate pair (low, high) - Assert.AreEqual("Q\xde\x00\x00/\xda\x00\x00".AsBytes(), penc.GetBytes("\ude51\uda2f")); + Assert.That(penc.GetBytes("\ude51\uda2f"), Is.EqualTo("Q\xde\x00\x00/\xda\x00\x00".AsBytes())); } [Test] @@ -497,13 +497,13 @@ public void TestUtf32BE() { Encoding penc = new PythonSurrogatePassEncoding(new UTF32Encoding(bigEndian: true, byteOrderMark: false)); // lone high surrogate - Assert.AreEqual("\x00\x00\xd8\x10".AsBytes(), penc.GetBytes("\ud810")); + Assert.That(penc.GetBytes("\ud810"), Is.EqualTo("\x00\x00\xd8\x10".AsBytes())); // lone low surrogate - Assert.AreEqual("\x00\x00\xdc\n".AsBytes(), penc.GetBytes("\udc0a")); + Assert.That(penc.GetBytes("\udc0a"), Is.EqualTo("\x00\x00\xdc\n".AsBytes())); // invalid surrogate pair (low, high) - Assert.AreEqual("\x00\x00\xdeQ\x00\x00\xda/".AsBytes(), penc.GetBytes("\ude51\uda2f")); + Assert.That(penc.GetBytes("\ude51\uda2f"), Is.EqualTo("\x00\x00\xdeQ\x00\x00\xda/".AsBytes())); } } @@ -516,7 +516,7 @@ public void TestAscii() { Encoding penc = new PythonSurrogatePassEncoding(Encoding.ASCII); // clean ASCII - Assert.AreEqual("abc", penc.GetChars("abc".AsBytes())); + Assert.That(penc.GetChars("abc".AsBytes()), Is.EqualTo("abc")); // Attempting to decode surrogates from ASCII will throw an exception. // Note that this is CPython 3.5 behaviour, CPython 3.4 will will blindly extract UTF-8 encoded surrogates from ASCII. @@ -539,13 +539,13 @@ public void TestUtf7() { Encoding penc = new PythonSurrogatePassEncoding(new UTF7Encoding(allowOptionals: true)); // lone high surrogate - Assert.AreEqual("abc\ud810xyz", penc.GetChars("abc+2BA-xyz".AsBytes())); + Assert.That(penc.GetChars("abc+2BA-xyz".AsBytes()), Is.EqualTo("abc\ud810xyz")); // lone low surrogate - Assert.AreEqual("abc\udc0axyz", penc.GetChars("abc+3Ao-xyz".AsBytes())); + Assert.That(penc.GetChars("abc+3Ao-xyz".AsBytes()), Is.EqualTo("abc\udc0axyz")); // invalid surrogate pair (low, high) - Assert.AreEqual("abc\ude51\uda2fxyz", penc.GetChars("abc+3lHaLw-xyz".AsBytes())); + Assert.That(penc.GetChars("abc+3lHaLw-xyz".AsBytes()), Is.EqualTo("abc\ude51\uda2fxyz")); } [Test] @@ -553,16 +553,16 @@ public void TestUtf8() { Encoding penc = new PythonSurrogatePassEncoding(Encoding.UTF8); // lone high surrogate - Assert.AreEqual("abc\ud810xyz", penc.GetChars("abc\xed\xa0\x90xyz".AsBytes())); + Assert.That(penc.GetChars("abc\xed\xa0\x90xyz".AsBytes()), Is.EqualTo("abc\ud810xyz")); // lone low surrogate - Assert.AreEqual("abc\udc0axyz", penc.GetChars("abc\xed\xb0\x8axyz".AsBytes())); + Assert.That(penc.GetChars("abc\xed\xb0\x8axyz".AsBytes()), Is.EqualTo("abc\udc0axyz")); // invalid surrogate pair (low, high) - Assert.AreEqual("abc\ude51\uda2fxyz", penc.GetChars("abc\xed\xb9\x91\xed\xa8\xafxyz".AsBytes())); + Assert.That(penc.GetChars("abc\xed\xb9\x91\xed\xa8\xafxyz".AsBytes()), Is.EqualTo("abc\ude51\uda2fxyz")); // valid surrogate pair (high, low) - Assert.AreEqual("abc\uda2f\ude51xyz", penc.GetChars("abc\xed\xa8\xaf\xed\xb9\x91xyz".AsBytes())); + Assert.That(penc.GetChars("abc\xed\xa8\xaf\xed\xb9\x91xyz".AsBytes()), Is.EqualTo("abc\uda2f\ude51xyz")); var chars = new char[9]; @@ -640,13 +640,13 @@ public void TestUtf16LE() { Encoding penc = new PythonSurrogatePassEncoding(Encoding.Unicode); // lone high surrogate - Assert.AreEqual("\ud810", penc.GetChars("\x10\xd8".AsBytes())); + Assert.That(penc.GetChars("\x10\xd8".AsBytes()), Is.EqualTo("\ud810")); // lone low surrogate - Assert.AreEqual("\udc0a", penc.GetChars("\n\xdc".AsBytes())); + Assert.That(penc.GetChars("\n\xdc".AsBytes()), Is.EqualTo("\udc0a")); // invalid surrogate pair (low, high) - Assert.AreEqual("\ude51\uda2f", penc.GetChars("Q\xde/\xda".AsBytes())); + Assert.That(penc.GetChars("Q\xde/\xda".AsBytes()), Is.EqualTo("\ude51\uda2f")); } [Test] @@ -654,13 +654,13 @@ public void TestUtf16BE() { Encoding penc = new PythonSurrogatePassEncoding(Encoding.BigEndianUnicode); // lone high surrogate - Assert.AreEqual("\ud810", penc.GetChars("\xd8\x10".AsBytes())); + Assert.That(penc.GetChars("\xd8\x10".AsBytes()), Is.EqualTo("\ud810")); // lone low surrogate - Assert.AreEqual("\udc0a", penc.GetChars("\xdc\n".AsBytes())); + Assert.That(penc.GetChars("\xdc\n".AsBytes()), Is.EqualTo("\udc0a")); // invalid surrogate pair (low, high) - Assert.AreEqual("\ude51\uda2f", penc.GetChars("\xdeQ\xda/".AsBytes())); + Assert.That(penc.GetChars("\xdeQ\xda/".AsBytes()), Is.EqualTo("\ude51\uda2f")); } [Test] @@ -668,13 +668,13 @@ public void TestUtf32LE() { Encoding penc = new PythonSurrogatePassEncoding(new UTF32Encoding(bigEndian: false, byteOrderMark: false)); // lone high surrogate - Assert.AreEqual("\ud810", penc.GetChars("\x10\xd8\x00\x00".AsBytes())); + Assert.That(penc.GetChars("\x10\xd8\x00\x00".AsBytes()), Is.EqualTo("\ud810")); // lone low surrogate - Assert.AreEqual("\udc0a", penc.GetChars("\n\xdc\x00\x00".AsBytes())); + Assert.That(penc.GetChars("\n\xdc\x00\x00".AsBytes()), Is.EqualTo("\udc0a")); // invalid surrogate pair (low, high) - Assert.AreEqual("\ude51\uda2f", penc.GetChars("Q\xde\x00\x00/\xda\x00\x00".AsBytes())); + Assert.That(penc.GetChars("Q\xde\x00\x00/\xda\x00\x00".AsBytes()), Is.EqualTo("\ude51\uda2f")); } [Test] @@ -682,13 +682,13 @@ public void TestUtf32BE() { Encoding penc = new PythonSurrogatePassEncoding(new UTF32Encoding(bigEndian: true, byteOrderMark: false)); // lone high surrogate - Assert.AreEqual("\ud810", penc.GetChars("\x00\x00\xd8\x10".AsBytes())); + Assert.That(penc.GetChars("\x00\x00\xd8\x10".AsBytes()), Is.EqualTo("\ud810")); // lone low surrogate - Assert.AreEqual("\udc0a", penc.GetChars("\x00\x00\xdc\n".AsBytes())); + Assert.That(penc.GetChars("\x00\x00\xdc\n".AsBytes()), Is.EqualTo("\udc0a")); // invalid surrogate pair (low, high) - Assert.AreEqual("\ude51\uda2f", penc.GetChars("\x00\x00\xdeQ\x00\x00\xda/".AsBytes())); + Assert.That(penc.GetChars("\x00\x00\xdeQ\x00\x00\xda/".AsBytes()), Is.EqualTo("\ude51\uda2f")); } } @@ -697,7 +697,7 @@ public class IncrementalTests { [Test] public void TestIncrementalWithUtf16() { - // In UTF-16LE: lone low surrogate (invalid) Lone high surrogate (invalid), surrogate pair: high-low (valid), + // In UTF-16LE: lone low surrogate (invalid) Lone high surrogate (invalid), surrogate pair: high-low (valid), var bytes = new byte[] { 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf }; Encoding penc = new PythonSurrogatePassEncoding(Encoding.Unicode); SurrogateTestHelpers.IncrementalTest(penc, bytes, roundTrip: false); @@ -735,7 +735,7 @@ public static void IncrementalTest(Encoding penc, byte[] bytes, bool roundTrip) for (int splitBytesAt = 0; splitBytesAt <= expBytes.Length; splitBytesAt += 1) { // From https://docs.microsoft.com/en-us/dotnet/api/system.text.decoder.getchars?view=netframework-4.5: // The application should call GetCharCount on a block of data immediately before calling GetChars on the same block, - // so that any trailing bytes from the previous block are included in the calculation. + // so that any trailing bytes from the previous block are included in the calculation. var dec = penc.GetDecoder(); char[] chars1 = new char[dec.GetCharCount(expBytes, 0, splitBytesAt, flush: false)]; dec.GetChars(expBytes, 0, splitBytesAt, chars1, 0, flush: false); @@ -743,7 +743,7 @@ public static void IncrementalTest(Encoding penc, byte[] bytes, bool roundTrip) dec.GetChars(expBytes, splitBytesAt, expBytes.Length - splitBytesAt, chars2, 0, flush: true); char[] total_chars = chars1.Concat(chars2).ToArray(); - Assert.AreEqual(expChars, total_chars, "Splitting bytes at {0}", splitBytesAt); + Assert.That(total_chars, Is.EqualTo(expChars), $"Splitting bytes at {splitBytesAt}"); for (int splitCharsAt = 0; splitCharsAt <= total_chars.Length; splitCharsAt += 1) { // From https://docs.microsoft.com/en-us/dotnet/api/system.text.encoder.getbytecount?view=netframework-4.5: @@ -757,7 +757,7 @@ public static void IncrementalTest(Encoding penc, byte[] bytes, bool roundTrip) enc.GetBytes(total_chars, splitCharsAt, total_chars.Length - splitCharsAt, bytes2, 0, flush: true); byte[] total_bytes = bytes1.Concat(bytes2).ToArray(); - Assert.AreEqual(expBytes, total_bytes, "Splitting chars at {0}", splitCharsAt); + Assert.That(total_bytes, Is.EqualTo(expBytes), $"Splitting chars at {splitCharsAt}"); } } } diff --git a/Src/IronPythonTest/EngineTest.cs b/Src/IronPythonTest/EngineTest.cs index cc70bb36d..f6cd8b21f 100644 --- a/Src/IronPythonTest/EngineTest.cs +++ b/Src/IronPythonTest/EngineTest.cs @@ -260,7 +260,7 @@ private void TestRuntimes(Dictionary options, ScriptRuntime[] ru private void TestEngine(ScriptEngine scriptEngine, Dictionary options) { // basic smoke tests that the engine is alive and working - Assert.AreEqual((int)(object)scriptEngine.Execute("42"), 42); + Assert.That(42, Is.EqualTo((int)(object)scriptEngine.Execute("42"))); if (options != null) { // TODO: @@ -272,18 +272,18 @@ private void TestEngine(ScriptEngine scriptEngine, Dictionary op ); #pragma warning restore 618 - Assert.AreEqual(po.StripDocStrings, true); - Assert.AreEqual(po.Optimize, true); - Assert.AreEqual(po.RecursionLimit, 42); - Assert.AreEqual(po.WarningFilters[0], "warnonme"); + Assert.That(true, Is.EqualTo(po.StripDocStrings)); + Assert.That(true, Is.EqualTo(po.Optimize)); + Assert.That(42, Is.EqualTo(po.RecursionLimit)); + Assert.That("warnonme", Is.EqualTo(po.WarningFilters[0])); } - Assert.AreEqual(Python.GetSysModule(scriptEngine).GetVariable("platform"), "cli"); - Assert.AreEqual(Python.GetBuiltinModule(scriptEngine).GetVariable("True"), true); + Assert.That("cli", Is.EqualTo(Python.GetSysModule(scriptEngine).GetVariable("platform"))); + Assert.That(true, Is.EqualTo(Python.GetBuiltinModule(scriptEngine).GetVariable("True"))); if (System.Environment.OSVersion.Platform == System.PlatformID.Unix) { - Assert.AreEqual(Python.ImportModule(scriptEngine, "posix").GetVariable("F_OK"), 0); + Assert.That(0, Is.EqualTo(Python.ImportModule(scriptEngine, "posix").GetVariable("F_OK"))); } else { - Assert.AreEqual(Python.ImportModule(scriptEngine, "nt").GetVariable("F_OK"), 0); + Assert.That(0, Is.EqualTo(Python.ImportModule(scriptEngine, "nt").GetVariable("F_OK"))); } Assert.Throws(() => { Python.ImportModule(scriptEngine, "non_existant_module"); @@ -293,19 +293,19 @@ private void TestEngine(ScriptEngine scriptEngine, Dictionary op private void TestRuntime(ScriptRuntime runtime, Dictionary options) { // basic smoke tests that the runtime is alive and working runtime.Globals.SetVariable("hello", 42); - Assert.NotNull(runtime.GetEngine("py")); + Assert.That(runtime.GetEngine("py"), Is.Not.Null); if (options != null) { - Assert.AreEqual(runtime.Setup.DebugMode, true); - Assert.AreEqual(runtime.Setup.PrivateBinding, true); + Assert.That(true, Is.EqualTo(runtime.Setup.DebugMode)); + Assert.That(true, Is.EqualTo(runtime.Setup.PrivateBinding)); } - Assert.AreEqual(Python.GetSysModule(runtime).GetVariable("platform"), "cli"); - Assert.AreEqual(Python.GetBuiltinModule(runtime).GetVariable("True"), true); + Assert.That("cli", Is.EqualTo(Python.GetSysModule(runtime).GetVariable("platform"))); + Assert.That(true, Is.EqualTo(Python.GetBuiltinModule(runtime).GetVariable("True"))); if (System.Environment.OSVersion.Platform == System.PlatformID.Unix) { - Assert.AreEqual(Python.ImportModule(runtime, "posix").GetVariable("F_OK"), 0); + Assert.That(0, Is.EqualTo(Python.ImportModule(runtime, "posix").GetVariable("F_OK"))); } else { - Assert.AreEqual(Python.ImportModule(runtime, "nt").GetVariable("F_OK"), 0); + Assert.That(0, Is.EqualTo(Python.ImportModule(runtime, "nt").GetVariable("F_OK"))); } Assert.Throws(() => { @@ -388,14 +388,14 @@ public void ScenarioDynamicObjectAsScope() { var source = engine.CreateScriptSourceFromString("x = 42", SourceCodeKind.File); source.Compile().Execute(scope); - Assert.AreEqual(myScope._members.ContainsKey("__doc__"), true); - Assert.AreEqual(myScope._members.ContainsKey("x"), true); - Assert.AreEqual(myScope._members.ContainsKey("__file__"), true); + Assert.That(true, Is.EqualTo(myScope._members.ContainsKey("__doc__"))); + Assert.That(true, Is.EqualTo(myScope._members.ContainsKey("x"))); + Assert.That(true, Is.EqualTo(myScope._members.ContainsKey("__file__"))); source = engine.CreateScriptSourceFromString("'hello world'", SourceCodeKind.File); source.Compile().Execute(scope); - Assert.AreEqual(myScope._members["__doc__"], "hello world"); + Assert.That("hello world", Is.EqualTo(myScope._members["__doc__"])); } // tests where __doc__ gets assigned into a field/property @@ -406,13 +406,13 @@ public void ScenarioDynamicObjectAsScope() { var source = engine.CreateScriptSourceFromString("'hello world'\nx=42\n", SourceCodeKind.File); source.Compile().Execute(scope); - Assert.AreEqual(((ScopeDynamicObject4)myScope).__doc__, "hello world"); + Assert.That("hello world", Is.EqualTo(((ScopeDynamicObject4)myScope).__doc__)); myScope = new ScopeDynamicObject5(); scope = engine.CreateScope(myScope); source.Compile().Execute(scope); - Assert.AreEqual(((ScopeDynamicObject5)myScope).__doc__, "hello world"); + Assert.That("hello world", Is.EqualTo(((ScopeDynamicObject5)myScope).__doc__)); } } @@ -435,7 +435,7 @@ public void ScenarioCodePlex20472() { // Opening the file with explicitly specifying the correct encoding should work CompiledCode prog = _pe.CreateScriptSourceFromFile(fileName, Encoding.GetEncoding(1251)).Compile(); prog.Execute(); - Assert.AreEqual(prog.DefaultScope.GetVariable("s"), "\u041F\u0436\u0451"); + Assert.That(prog.DefaultScope.GetVariable("s"), Is.EqualTo("\u041F\u0436\u0451")); } [Test] @@ -449,7 +449,7 @@ public void ScenarioInterpreterNestedVariables() { ); var vars = CompilerHelpers.LightCompile(argBody)(42); - Assert.AreEqual(vars[0], 42); + Assert.That(42, Is.EqualTo(vars[0])); ParameterExpression tmp = Expression.Parameter(typeof(object), "tmp"); var body = Expression.Lambda>( @@ -465,8 +465,8 @@ public void ScenarioInterpreterNestedVariables() { ) ); - Assert.AreEqual(body.Compile()(), ClrModule.IsNetCoreApp || ClrModule.IsMono ? (object)42 : null); // https://github.com/IronLanguages/ironpython3/issues/908 - Assert.AreEqual(CompilerHelpers.LightCompile(body)(), null); + Assert.That(ClrModule.IsNetCoreApp || ClrModule.IsMono ? (object)42 : null, Is.EqualTo(body.Compile()())); // https://github.com/IronLanguages/ironpython3/issues/908 + Assert.That(null, Is.EqualTo(CompilerHelpers.LightCompile(body)())); body = Expression.Lambda>( Expression.Block( @@ -482,8 +482,8 @@ public void ScenarioInterpreterNestedVariables() { ) ) ); - Assert.AreEqual(CompilerHelpers.LightCompile(body)(), null); - Assert.AreEqual(body.Compile()(), null); + Assert.That(null, Is.EqualTo(CompilerHelpers.LightCompile(body)())); + Assert.That(null, Is.EqualTo(body.Compile()())); } public class TestCodePlex23562 { @@ -506,7 +506,7 @@ public void ScenarioCodePlex23562() { _pe.Execute(pyCode, scope); TestCodePlex23562 temp = scope.GetVariable("test"); - Assert.True(temp.MethodCalled); + Assert.That(temp.MethodCalled); } [Test] @@ -524,12 +524,12 @@ global py_func_called _pe.Execute(pyCode, scope); IList str_tuple = scope.GetVariable>("str_tuple"); - Assert.AreEqual(str_tuple.Count, 2); + Assert.That(2, Is.EqualTo(str_tuple.Count)); IList str_list = scope.GetVariable>("str_list"); - Assert.AreEqual(str_list.Count, 3); + Assert.That(3, Is.EqualTo(str_list.Count)); VoidDelegate py_func = scope.GetVariable("py_func"); py_func(); - Assert.AreEqual(scope.GetVariable("py_func_called"), true); + Assert.That(true, Is.EqualTo(scope.GetVariable("py_func_called"))); } [Test] @@ -547,7 +547,7 @@ def __init__(self, a, b, c): object KKlass = scope.GetVariable("K"); object[] Kparams = new object[] { 1, 3.14, "abc" }; _pe.Operations.CreateInstance(KKlass, Kparams); - Assert.AreEqual(scope.GetVariable("A"), 1); + Assert.That(1, Is.EqualTo(scope.GetVariable("A"))); } // Execute @@ -562,12 +562,12 @@ public void ScenarioExecute() { // field: assign and get back _pe.Execute("clsPart.Field = 100", scope); _pe.Execute("if 100 != clsPart.Field: raise AssertionError('test failed')", scope); - Assert.AreEqual(100, clsPart.Field); + Assert.That(clsPart.Field, Is.EqualTo(100)); // property: assign and get back _pe.Execute("clsPart.Property = clsPart.Field", scope); _pe.Execute("if 100 != clsPart.Property: raise AssertionError('test failed')", scope); - Assert.AreEqual(100, clsPart.Property); + Assert.That(clsPart.Property, Is.EqualTo(100)); // method: Event not set yet _pe.Execute("a = clsPart.Method(2)", scope); @@ -596,7 +596,7 @@ public void ScenarioExecute() { // reset the same variable with integer scope.SetVariable(clspartName, 1); _pe.Execute("if 1 != clsPart: raise AssertionError('test failed')", scope); - Assert.AreEqual((int)(object)scope.GetVariable(clspartName), 1); + Assert.That(1, Is.EqualTo((int)(object)scope.GetVariable(clspartName))); ScriptSource su = _pe.CreateScriptSourceFromString(""); Assert.Throws(() => { @@ -609,8 +609,8 @@ public static void ScenarioTryGetMember() { var engine = Python.CreateEngine(); var str = ClrModule.GetPythonType(typeof(string)); object result; - Assert.AreEqual(engine.Operations.TryGetMember(str, "Equals", out result), true); - Assert.AreEqual(result.ToString(), "IronPython.Runtime.Types.BuiltinFunction"); + Assert.That(true, Is.EqualTo(engine.Operations.TryGetMember(str, "Equals", out result))); + Assert.That("IronPython.Runtime.Types.BuiltinFunction", Is.EqualTo(result.ToString())); } [Test] @@ -640,7 +640,7 @@ public static void ScenarioInterfaceExtensions() { ScriptSource src = engine.CreateScriptSourceFromString("x.Bar()"); ScriptScope scope = engine.CreateScope(); scope.SetVariable("x", new Fooable()); - Assert.AreEqual((object)src.Execute(scope), "Bar Called"); + Assert.That("Bar Called", Is.EqualTo((object)src.Execute(scope))); } private class MyInvokeMemberBinder : InvokeMemberBinder { @@ -939,20 +939,20 @@ class EmptyNC(object): pass foreach (var test in tests) { var result = new List(doc.GetOverloads(test.Obj)); - Assert.AreEqual(result.Count, test.Result.Length); + Assert.That(test.Result.Length, Is.EqualTo(result.Count)); for (int i = 0; i < result.Count; i++) { var received = result[i]; ; var expected = test.Result[i]; - Assert.AreEqual(received.Parameters.Count, expected.Length); + Assert.That(expected.Length, Is.EqualTo(received.Parameters.Count)); var recvParams = new List(received.Parameters); for (int j = 0; j < expected.Length; j++) { var receivedParam = recvParams[j]; var expectedParam = expected[j]; - Assert.AreEqual(receivedParam.Flags, expectedParam.ParamAttrs); - Assert.AreEqual(receivedParam.Name, expectedParam.ParamName); + Assert.That(expectedParam.ParamAttrs, Is.EqualTo(receivedParam.Flags)); + Assert.That(expectedParam.ParamName, Is.EqualTo(receivedParam.Name)); } } } @@ -996,7 +996,7 @@ class EmptyNC(object): pass private void ContainsMemberName(ICollection members, string name, MemberKind kind) { foreach (var member in members) { if (member.Name == name) { - Assert.AreEqual(member.Kind, kind); + Assert.That(kind, Is.EqualTo(member.Kind)); return; } } @@ -1284,74 +1284,74 @@ def Invokable(*args, **kwargs): // if it lives on a system type we should do a fallback invoke member var site = CallSite>.Create(new MyInvokeMemberBinder("Count", new CallInfo(0))); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("alinst")), "FallbackInvokeMember"); + Assert.That("FallbackInvokeMember", Is.EqualTo(site.Target(site, (object)scope.GetVariable("alinst")))); // invoke a function that's a member on an object foreach (object inst in allObjects) { site = CallSite>.Create(new MyInvokeMemberBinder("TestFunc", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "TestFunc"); + Assert.That("TestFunc", Is.EqualTo(site.Target(site, inst))); } // invoke a field / property that's on an object foreach (object inst in allObjects) { site = CallSite>.Create(new MyInvokeMemberBinder("InstVal", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeInstVal"); + Assert.That("FallbackInvokeInstVal", Is.EqualTo(site.Target(site, inst))); site = CallSite>.Create(new MyInvokeMemberBinder("ClassVal", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeClassVal"); + Assert.That("FallbackInvokeClassVal", Is.EqualTo(site.Target(site, inst))); if (!(inst is PythonFunction)) { site = CallSite>.Create(new MyInvokeMemberBinder("SomeMethodThatNeverExists", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeMember"); + Assert.That("FallbackInvokeMember", Is.EqualTo(site.Target(site, inst))); } } // invoke a field / property that's not defined on objects w/ __getattr__ foreach (object inst in getattrObjects) { site = CallSite>.Create(new MyInvokeMemberBinder("DoesNotExist", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeDoesNotExist"); + Assert.That("FallbackInvokeDoesNotExist", Is.EqualTo(site.Target(site, inst))); } // invoke a field / property that's not defined on objects w/ __getattribute__ foreach (object inst in getattributeObjects) { site = CallSite>.Create(new MyInvokeMemberBinder("DoesNotExist", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeDoesNotExist"); + Assert.That("FallbackInvokeDoesNotExist", Is.EqualTo(site.Target(site, inst))); site = CallSite>.Create(new MyInvokeMemberBinder("Count", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeCount"); + Assert.That("FallbackInvokeCount", Is.EqualTo(site.Target(site, inst))); site = CallSite>.Create(new MyInvokeMemberBinder("TestFunc", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeTestFunc"); + Assert.That("FallbackInvokeTestFunc", Is.EqualTo(site.Target(site, inst))); site = CallSite>.Create(new MyInvokeMemberBinder("InstVal", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeInstVal"); + Assert.That("FallbackInvokeInstVal", Is.EqualTo(site.Target(site, inst))); site = CallSite>.Create(new MyInvokeMemberBinder("ClassVal", new CallInfo(0))); - Assert.AreEqual(site.Target(site, inst), "FallbackInvokeClassVal"); + Assert.That("FallbackInvokeClassVal", Is.EqualTo(site.Target(site, inst))); } foreach (object inst in indexableObjects) { var site2 = CallSite>.Create(new MyGetIndexBinder(new CallInfo(1))); - Assert.AreEqual(site2.Target(site2, inst, "index"), "index"); + Assert.That("index", Is.EqualTo(site2.Target(site2, inst, "index"))); var site3 = CallSite>.Create(new MySetIndexBinder(new CallInfo(1))); - Assert.AreEqual(site3.Target(site3, inst, "index", "value"), "value"); + Assert.That("value", Is.EqualTo(site3.Target(site3, inst, "index", "value"))); site = CallSite>.Create(new MyGetMemberBinder("LastSetItem")); IList res = (IList)site.Target(site, inst); - Assert.AreEqual(res.Count, 2); - Assert.AreEqual(res[0], "index"); - Assert.AreEqual(res[1], "value"); + Assert.That(2, Is.EqualTo(res.Count)); + Assert.That("index", Is.EqualTo(res[0])); + Assert.That("value", Is.EqualTo(res[1])); } foreach (object inst in unindexableObjects) { var site2 = CallSite>.Create(new MyGetIndexBinder(new CallInfo(1))); //Console.WriteLine(inst); - Assert.AreEqual(site2.Target(site2, inst, "index"), "FallbackGetIndexindex"); + Assert.That("FallbackGetIndexindex", Is.EqualTo(site2.Target(site2, inst, "index"))); var site3 = CallSite>.Create(new MySetIndexBinder(new CallInfo(1))); - Assert.AreEqual(site3.Target(site3, inst, "index", "value"), "FallbackSetIndexindexvalue"); + Assert.That("FallbackSetIndexindexvalue", Is.EqualTo(site3.Target(site3, inst, "index", "value"))); } foreach (object inst in invokableObjects) { @@ -1374,7 +1374,7 @@ def Invokable(*args, **kwargs): foreach (object inst in convertableObjects) { // These may be invalid according to the DLR (wrong ret type) but currently work today. site = CallSite>.Create(new MyConvertBinder(typeof(string))); - Assert.AreEqual(site.Target(site, inst), "Python"); + Assert.That("Python", Is.EqualTo(site.Target(site, inst))); var dlgsiteo = CallSite>.Create(new MyConvertBinder(typeof(Func), null)); VerifyFunction(new[] { "foo" }, Array.Empty(), ((Func)(dlgsiteo.Target(dlgsiteo, inst)))("foo")); @@ -1384,24 +1384,24 @@ def Invokable(*args, **kwargs): // strongly typed return versions var ssite = CallSite>.Create(new MyConvertBinder(typeof(string))); - Assert.AreEqual(ssite.Target(ssite, inst), "Python"); + Assert.That("Python", Is.EqualTo(ssite.Target(ssite, inst))); // this call site works only if __int__ happens to return an Int32 instance or a BigInteger instance that fits in 32 bits var isite = CallSite>.Create(new MyConvertBinder(typeof(int), 23)); - Assert.AreEqual(isite.Target(isite, inst), 42); + Assert.That(42, Is.EqualTo(isite.Target(isite, inst))); var dsite = CallSite>.Create(new MyConvertBinder(typeof(double), 23.0)); - Assert.AreEqual(dsite.Target(dsite, inst), 42.0); + Assert.That(42.0, Is.EqualTo(dsite.Target(dsite, inst))); var csite = CallSite>.Create(new MyConvertBinder(typeof(Complex), new Complex(0, 23))); - Assert.AreEqual(csite.Target(csite, inst), new Complex(0, 42)); + Assert.That(new Complex(0, 42), Is.EqualTo(csite.Target(csite, inst))); var bsite = CallSite>.Create(new MyConvertBinder(typeof(bool), true)); - Assert.AreEqual(bsite.Target(bsite, inst), false); + Assert.That(false, Is.EqualTo(bsite.Target(bsite, inst))); // this call site works regardless whether __int__ returns a BigInteger or Int32 instance var bisite = CallSite>.Create(new MyConvertBinder(typeof(BigInteger), (BigInteger)23)); - Assert.AreEqual(bisite.Target(bisite, inst), (BigInteger)42); + Assert.That((BigInteger)42, Is.EqualTo(bisite.Target(bisite, inst))); var dlgsite = CallSite>>.Create(new MyConvertBinder(typeof(Func), null)); VerifyFunction(new[] { "foo" }, Array.Empty(), dlgsite.Target(dlgsite, inst)("foo")); @@ -1413,26 +1413,26 @@ def Invokable(*args, **kwargs): foreach (object inst in unconvertableObjects) { // These may be invalid according to the DLR (wrong ret type) but currently work today. site = CallSite>.Create(new MyConvertBinder(typeof(string))); - Assert.AreEqual(site.Target(site, inst), "Converted"); + Assert.That("Converted", Is.EqualTo(site.Target(site, inst))); // strongly typed return versions var ssite = CallSite>.Create(new MyConvertBinder(typeof(string))); - Assert.AreEqual(ssite.Target(ssite, inst), "Converted"); + Assert.That("Converted", Is.EqualTo(ssite.Target(ssite, inst))); var isite = CallSite>.Create(new MyConvertBinder(typeof(int), 23)); - Assert.AreEqual(isite.Target(isite, inst), 23); + Assert.That(23, Is.EqualTo(isite.Target(isite, inst))); var dsite = CallSite>.Create(new MyConvertBinder(typeof(double), 23.0)); - Assert.AreEqual(dsite.Target(dsite, inst), 23.0); + Assert.That(23.0, Is.EqualTo(dsite.Target(dsite, inst))); var csite = CallSite>.Create(new MyConvertBinder(typeof(Complex), new Complex(0, 23.0))); - Assert.AreEqual(csite.Target(csite, inst), new Complex(0, 23.0)); + Assert.That(new Complex(0, 23.0), Is.EqualTo(csite.Target(csite, inst))); var bsite = CallSite>.Create(new MyConvertBinder(typeof(bool), true)); - Assert.AreEqual(bsite.Target(bsite, inst), true); + Assert.That(true, Is.EqualTo(bsite.Target(bsite, inst))); var bisite = CallSite>.Create(new MyConvertBinder(typeof(BigInteger), (BigInteger)23)); - Assert.AreEqual(bisite.Target(bisite, inst), (BigInteger)23); + Assert.That((BigInteger)23, Is.EqualTo(bisite.Target(bisite, inst))); } // get on .NET member should fallback @@ -1440,84 +1440,84 @@ def Invokable(*args, **kwargs): if (!ClrModule.IsMono && !ClrModule.IsNetCoreApp) { // property site = CallSite>.Create(new MyGetMemberBinder("AllowDrop")); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("controlinst")), "FallbackGetMember"); + Assert.That("FallbackGetMember", Is.EqualTo(site.Target(site, (object)scope.GetVariable("controlinst")))); // method site = CallSite>.Create(new MyGetMemberBinder("BringToFront")); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("controlinst")), "FallbackGetMember"); + Assert.That("FallbackGetMember", Is.EqualTo(site.Target(site, (object)scope.GetVariable("controlinst")))); // protected method site = CallSite>.Create(new MyGetMemberBinder("OnParentChanged")); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("controlinst")), "FallbackGetMember"); + Assert.That("FallbackGetMember", Is.EqualTo(site.Target(site, (object)scope.GetVariable("controlinst")))); // event site = CallSite>.Create(new MyGetMemberBinder("DoubleClick")); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("controlinst")), "FallbackGetMember"); + Assert.That("FallbackGetMember", Is.EqualTo(site.Target(site, (object)scope.GetVariable("controlinst")))); } site = CallSite>.Create(new MyInvokeMemberBinder("something", new CallInfo(0))); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("ns_getattrinst")), "FallbackInvokegetattrsomething"); + Assert.That("FallbackInvokegetattrsomething", Is.EqualTo(site.Target(site, (object)scope.GetVariable("ns_getattrinst")))); foreach (object inst in iterableObjects) { // converting a type which implements __iter__ var enumsite = CallSite>.Create(new MyConvertBinder(typeof(IEnumerable))); IEnumerable ie = enumsite.Target(enumsite, inst); IEnumerator ator = ie.GetEnumerator(); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 1); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 2); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 3); - Assert.AreEqual(ator.MoveNext(), false); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(1, Is.EqualTo(ator.Current)); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(2, Is.EqualTo(ator.Current)); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(3, Is.EqualTo(ator.Current)); + Assert.That(false, Is.EqualTo(ator.MoveNext())); var enumobjsite = CallSite>.Create(new MyConvertBinder(typeof(IEnumerable))); ie = (IEnumerable)enumobjsite.Target(enumobjsite, inst); ator = ie.GetEnumerator(); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 1); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 2); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 3); - Assert.AreEqual(ator.MoveNext(), false); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(1, Is.EqualTo(ator.Current)); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(2, Is.EqualTo(ator.Current)); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(3, Is.EqualTo(ator.Current)); + Assert.That(false, Is.EqualTo(ator.MoveNext())); var enumatorsite = CallSite>.Create(new MyConvertBinder(typeof(IEnumerator))); ator = enumatorsite.Target(enumatorsite, inst); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 1); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 2); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 3); - Assert.AreEqual(ator.MoveNext(), false); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(1, Is.EqualTo(ator.Current)); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(2, Is.EqualTo(ator.Current)); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(3, Is.EqualTo(ator.Current)); + Assert.That(false, Is.EqualTo(ator.MoveNext())); var enumatorobjsite = CallSite>.Create(new MyConvertBinder(typeof(IEnumerator))); ator = (IEnumerator)enumatorobjsite.Target(enumatorobjsite, inst); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 1); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 2); - Assert.AreEqual(ator.MoveNext(), true); - Assert.AreEqual(ator.Current, 3); - Assert.AreEqual(ator.MoveNext(), false); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(1, Is.EqualTo(ator.Current)); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(2, Is.EqualTo(ator.Current)); + Assert.That(true, Is.EqualTo(ator.MoveNext())); + Assert.That(3, Is.EqualTo(ator.Current)); + Assert.That(false, Is.EqualTo(ator.MoveNext())); } site = CallSite>.Create(new MyUnaryBinder(ExpressionType.Not)); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("nsinst")), true); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("ns_nonzero_inst")), false); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("ns_len0_inst")), true); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("ns_len1_inst")), false); + Assert.That(true, Is.EqualTo(site.Target(site, (object)scope.GetVariable("nsinst")))); + Assert.That(false, Is.EqualTo(site.Target(site, (object)scope.GetVariable("ns_nonzero_inst")))); + Assert.That(true, Is.EqualTo(site.Target(site, (object)scope.GetVariable("ns_len0_inst")))); + Assert.That(false, Is.EqualTo(site.Target(site, (object)scope.GetVariable("ns_len1_inst")))); site = CallSite>.Create(new MyInvokeMemberBinder("ToString", new CallInfo(0))); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("range")), "FallbackInvokeMember"); + Assert.That("FallbackInvokeMember", Is.EqualTo(site.Target(site, (object)scope.GetVariable("range")))); // invoke a function defined as a member of a function site = CallSite>.Create(new MyInvokeMemberBinder("SubFunc", new CallInfo(0))); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("TestFunc")), "TestFunc"); + Assert.That("TestFunc", Is.EqualTo(site.Target(site, (object)scope.GetVariable("TestFunc")))); site = CallSite>.Create(new MyInvokeMemberBinder("DoesNotExist", new CallInfo(0))); - Assert.AreEqual(site.Target(site, (object)scope.GetVariable("TestFunc")), "FallbackInvokeMember"); + Assert.That("FallbackInvokeMember", Is.EqualTo(site.Target(site, (object)scope.GetVariable("TestFunc")))); } private class MyDynamicObject : DynamicObject { @@ -1626,7 +1626,7 @@ public void ScenarioDlrInterop_ConsumeDynamicObject() { }; foreach (var test in tests) { - Assert.AreEqual(test.Result, (object)_pe.Execute(test.TestCase, scope)); + Assert.That((object)_pe.Execute(test.TestCase, scope), Is.EqualTo(test.Result)); } var tests2 = new[] { @@ -1638,22 +1638,22 @@ public void ScenarioDlrInterop_ConsumeDynamicObject() { foreach (var test in tests2) { _pe.Execute(test.TestCase, scope); - Assert.AreEqual(test.Last, dynObj.Last); + Assert.That(dynObj.Last, Is.EqualTo(test.Last)); } } private void VerifyFunction(object[] results, string[] names, object value) { IList res = (IList)value; - Assert.AreEqual(res.Count, 2); + Assert.That(2, Is.EqualTo(res.Count)); IList positional = (IList)res[0]; IDictionary kwargs = (IDictionary)res[1]; for (int i = 0; i < positional.Count; i++) { - Assert.AreEqual(positional[i], results[i]); + Assert.That(results[i], Is.EqualTo(positional[i])); } for (int i = positional.Count; i < results.Length; i++) { - Assert.AreEqual(kwargs[names[i - positional.Count]], results[i]); + Assert.That(results[i], Is.EqualTo(kwargs[names[i - positional.Count]])); } } @@ -1669,24 +1669,24 @@ public void ScenarioEvaluateInAnonymousEngineModule() { scope3.SetVariable("x", 2); - Assert.AreEqual(0, _pe.Execute("x", scope1)); - Assert.AreEqual(0, (int)(object)scope1.GetVariable("x")); + Assert.That(_pe.Execute("x", scope1), Is.EqualTo(0)); + Assert.That((int)(object)scope1.GetVariable("x"), Is.EqualTo(0)); - Assert.AreEqual(1, _pe.Execute("x", scope2)); - Assert.AreEqual(1, (int)(object)scope2.GetVariable("x")); + Assert.That(_pe.Execute("x", scope2), Is.EqualTo(1)); + Assert.That((int)(object)scope2.GetVariable("x"), Is.EqualTo(1)); - Assert.AreEqual(2, _pe.Execute("x", scope3)); - Assert.AreEqual(2, (int)(object)scope3.GetVariable("x")); + Assert.That(_pe.Execute("x", scope3), Is.EqualTo(2)); + Assert.That((int)(object)scope3.GetVariable("x"), Is.EqualTo(2)); } [Test] public void ScenarioObjectOperations() { var ops = _pe.Operations; - Assert.AreEqual("(1, 2, 3)", ops.Format(new PythonTuple(new object[] { 1, 2, 3 }))); + Assert.That(ops.Format(new PythonTuple(new object[] { 1, 2, 3 })), Is.EqualTo("(1, 2, 3)")); var scope = _pe.CreateScope(); scope.SetVariable("ops", ops); - Assert.AreEqual("[1, 2, 3]", _pe.Execute("ops.Format([1,2,3])", scope)); + Assert.That(_pe.Execute("ops.Format([1,2,3])", scope), Is.EqualTo("[1, 2, 3]")); ScriptSource src = _pe.CreateScriptSourceFromString("def f(*args): return args", SourceCodeKind.Statements); src.Execute(scope); @@ -1698,7 +1698,7 @@ public void ScenarioObjectOperations() { inp[j] = j; } - Assert.AreEqual((object)ops.Invoke(f, inp), PythonTuple.MakeTuple(inp)); + Assert.That(PythonTuple.MakeTuple(inp), Is.EqualTo((object)ops.Invoke(f, inp))); } ScriptScope mod = _env.CreateScope(); @@ -1717,9 +1717,9 @@ def __init__(self, x, y): object foo = ops.CreateInstance(klass, 123, 444); - Assert.AreEqual(ops.GetMember(foo, "abc"), 3); - Assert.AreEqual(ops.GetMember(foo, "x"), 123); - Assert.AreEqual(ops.GetMember(foo, "y"), 444); + Assert.That(3, Is.EqualTo(ops.GetMember(foo, "abc"))); + Assert.That(123, Is.EqualTo(ops.GetMember(foo, "x"))); + Assert.That(444, Is.EqualTo(ops.GetMember(foo, "y"))); } [Test] @@ -1737,7 +1737,7 @@ public void ScenarioCP712() { public void ScenarioCP24784() { var code = _pe.CreateScriptSourceFromString("def f():\r\n \r\n print(1)", SourceCodeKind.InteractiveCode); - Assert.AreEqual(code.GetCodeProperties(), ScriptCodeParseResult.IncompleteStatement); + Assert.That(ScriptCodeParseResult.IncompleteStatement, Is.EqualTo(code.GetCodeProperties())); } public delegate int CP19724Delegate(double p1); @@ -1756,8 +1756,8 @@ global X src.Execute(scope1); CP19724Delegate tDelegate = scope1.GetVariable("k"); - Assert.AreEqual(7, tDelegate(3.14)); - Assert.AreEqual(42, scope1.GetVariable("X")); + Assert.That(tDelegate(3.14), Is.EqualTo(7)); + Assert.That(scope1.GetVariable("X"), Is.EqualTo(42)); } [Test] @@ -1775,17 +1775,17 @@ public void ScenarioEvaluateInPublishedEngineModule() { // Ensure that the default EngineModule is not affected x = pc.CreateSnippet("x", SourceCodeKind.Expression).Execute(otherModule.Scope); - Assert.AreEqual(0, (int)x); + Assert.That((int)x, Is.EqualTo(0)); // Ensure that the published context has been updated as expected x = pc.CreateSnippet("x", SourceCodeKind.Expression).Execute(publishedModule.Scope); - Assert.AreEqual(1, (int)x); + Assert.That((int)x, Is.EqualTo(1)); // Ensure that the published context is accessible from other contexts using sys.modules // TODO: do better: // pe.Import("sys", ScriptDomainManager.CurrentManager.DefaultModule); pc.CreateSnippet("from published_context_test import x", SourceCodeKind.Statements).Execute(otherModule.Scope); x = pc.CreateSnippet("x", SourceCodeKind.Expression).Execute(otherModule.Scope); - Assert.AreEqual(1, (int)x); + Assert.That((int)x, Is.EqualTo(1)); } private class CustomDictionary : IDictionary { @@ -1909,19 +1909,19 @@ public void ScenarioCustomDictionary() { ScriptScope customModule = _pe.Runtime.CreateScope(new ObjectDictionaryExpando(customGlobals)); // Evaluate - Assert.AreEqual(_pe.Execute("customSymbol + 1", customModule), CustomDictionary.customSymbolValue + 1); + Assert.That(CustomDictionary.customSymbolValue + 1, Is.EqualTo(_pe.Execute("customSymbol + 1", customModule))); // Execute _pe.Execute("customSymbolPlusOne = customSymbol + 1", customModule); - Assert.AreEqual(_pe.Execute("customSymbolPlusOne", customModule), CustomDictionary.customSymbolValue + 1); - Assert.AreEqual(customModule.GetVariable("customSymbolPlusOne"), CustomDictionary.customSymbolValue + 1); + Assert.That(CustomDictionary.customSymbolValue + 1, Is.EqualTo(_pe.Execute("customSymbolPlusOne", customModule))); + Assert.That(CustomDictionary.customSymbolValue + 1, Is.EqualTo(customModule.GetVariable("customSymbolPlusOne"))); // Compile CompiledCode compiledCode = _pe.CreateScriptSourceFromString("customSymbolPlusTwo = customSymbol + 2").Compile(); compiledCode.Execute(customModule); - Assert.AreEqual(_pe.Execute("customSymbolPlusTwo", customModule), CustomDictionary.customSymbolValue + 2); - Assert.AreEqual(customModule.GetVariable("customSymbolPlusTwo"), CustomDictionary.customSymbolValue + 2); + Assert.That(CustomDictionary.customSymbolValue + 2, Is.EqualTo(_pe.Execute("customSymbolPlusTwo", customModule))); + Assert.That(CustomDictionary.customSymbolValue + 2, Is.EqualTo(customModule.GetVariable("customSymbolPlusTwo"))); // check overriding of Add try { @@ -1949,7 +1949,7 @@ public void ScenarioCustomDictionary() { // vars() IDictionary vars = _pe.Execute("vars()", customModule); - Assert.AreEqual(true, vars.Contains("customSymbol")); + Assert.That(vars.Contains("customSymbol"), Is.EqualTo(true)); // Miscellaneous APIs //IntIntDelegate d = pe.CreateLambda("customSymbol + arg", customModule); @@ -1973,8 +1973,8 @@ def __call__(self, arg): b = Y()", SourceCodeKind.Statements).Execute(scope); var a = scope.GetVariable>("a"); var b = scope.GetVariable>("b"); - Assert.AreEqual(a(42), 42); - Assert.AreEqual(b(42), 42); + Assert.That(42, Is.EqualTo(a(42))); + Assert.That(42, Is.EqualTo(b(42))); } // Evaluate @@ -1982,43 +1982,43 @@ def __call__(self, arg): public void ScenarioEvaluate() { ScriptScope scope = _env.CreateScope(); - Assert.AreEqual(10, _pe.CreateScriptSourceFromString("4+6").Execute(scope)); - Assert.AreEqual(null, (object)_pe.CreateScriptSourceFromString("if True: pass").Execute(scope)); + Assert.That(_pe.CreateScriptSourceFromString("4+6").Execute(scope), Is.EqualTo(10)); + Assert.That((object)_pe.CreateScriptSourceFromString("if True: pass").Execute(scope), Is.EqualTo(null)); - Assert.AreEqual(10, _pe.CreateScriptSourceFromString("4+6", SourceCodeKind.AutoDetect).Execute(scope)); - Assert.AreEqual(null, (object)_pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.AutoDetect).Execute(scope)); + Assert.That(_pe.CreateScriptSourceFromString("4+6", SourceCodeKind.AutoDetect).Execute(scope), Is.EqualTo(10)); + Assert.That((object)_pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.AutoDetect).Execute(scope), Is.EqualTo(null)); - Assert.AreEqual(10, _pe.CreateScriptSourceFromString("4+6", SourceCodeKind.Expression).Execute(scope)); + Assert.That(_pe.CreateScriptSourceFromString("4+6", SourceCodeKind.Expression).Execute(scope), Is.EqualTo(10)); Assert.Throws(() => _pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.Expression).Execute(scope)); - Assert.AreEqual(null, (object)_pe.CreateScriptSourceFromString("4+6", SourceCodeKind.File).Execute(scope)); - Assert.AreEqual(null, (object)_pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.File).Execute(scope)); + Assert.That((object)_pe.CreateScriptSourceFromString("4+6", SourceCodeKind.File).Execute(scope), Is.EqualTo(null)); + Assert.That((object)_pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.File).Execute(scope), Is.EqualTo(null)); - Assert.AreEqual(null, (object)_pe.CreateScriptSourceFromString("4+6", SourceCodeKind.SingleStatement).Execute(scope)); - Assert.AreEqual(null, (object)_pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.SingleStatement).Execute(scope)); + Assert.That((object)_pe.CreateScriptSourceFromString("4+6", SourceCodeKind.SingleStatement).Execute(scope), Is.EqualTo(null)); + Assert.That((object)_pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.SingleStatement).Execute(scope), Is.EqualTo(null)); - Assert.AreEqual(null, (object)_pe.CreateScriptSourceFromString("4+6", SourceCodeKind.Statements).Execute(scope)); - Assert.AreEqual(null, (object)_pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.Statements).Execute(scope)); + Assert.That((object)_pe.CreateScriptSourceFromString("4+6", SourceCodeKind.Statements).Execute(scope), Is.EqualTo(null)); + Assert.That((object)_pe.CreateScriptSourceFromString("if True: pass", SourceCodeKind.Statements).Execute(scope), Is.EqualTo(null)); - Assert.AreEqual(10, (int)(object)_pe.Execute("4+6", scope)); - Assert.AreEqual(10, _pe.Execute("4+6", scope)); + Assert.That((int)(object)_pe.Execute("4+6", scope), Is.EqualTo(10)); + Assert.That(_pe.Execute("4+6", scope), Is.EqualTo(10)); - Assert.AreEqual("abab", (string)(object)_pe.Execute("'ab' * 2", scope)); - Assert.AreEqual("abab", _pe.Execute("'ab' * 2", scope)); + Assert.That((string)(object)_pe.Execute("'ab' * 2", scope), Is.EqualTo("abab")); + Assert.That(_pe.Execute("'ab' * 2", scope), Is.EqualTo("abab")); ClsPart clsPart = new ClsPart(); scope.SetVariable(clspartName, clsPart); - Assert.AreEqual(clsPart, ((object)_pe.Execute("clsPart", scope)) as ClsPart); - Assert.AreEqual(clsPart, _pe.Execute("clsPart", scope)); + Assert.That(((object)_pe.Execute("clsPart", scope)) as ClsPart, Is.EqualTo(clsPart)); + Assert.That(_pe.Execute("clsPart", scope), Is.EqualTo(clsPart)); _pe.Execute("clsPart.Field = 100", scope); - Assert.AreEqual(100, (int)(object)_pe.Execute("clsPart.Field", scope)); - Assert.AreEqual(100, _pe.Execute("clsPart.Field", scope)); + Assert.That((int)(object)_pe.Execute("clsPart.Field", scope), Is.EqualTo(100)); + Assert.That(_pe.Execute("clsPart.Field", scope), Is.EqualTo(100)); // Ensure that we can get back a delegate to a Python method _pe.Execute("def IntIntMethod(a): return a * 100", scope); IntIntDelegate d = _pe.Execute("IntIntMethod", scope); - Assert.AreEqual(d(2), 2 * 100); + Assert.That(2 * 100, Is.EqualTo(d(2))); } [Test] @@ -2057,10 +2057,10 @@ def f(): pass ncinstnames.Sort(); fnames.Sort(); - Assert.AreEqual(ncnames.ToArray(), new[] { "__class__", "__delattr__", "__dict__", "__doc__", "__eq__", "__format__", "__ge__", "__getattribute__", "__gt__", "__hash__", "__init__", "__le__", "__lt__", "__module__", "__ne__", "__new__", "__reduce__", "__reduce_ex__", "__repr__", "__setattr__", "__sizeof__", "__str__", "__subclasshook__", "__weakref__", "abc", "classmethod", "foo", "staticfunc" }); - Assert.AreEqual(ncinstnames.ToArray(), new[] { "__class__", "__delattr__", "__dict__", "__doc__", "__eq__", "__format__", "__ge__", "__getattribute__", "__gt__", "__hash__", "__init__", "__le__", "__lt__", "__module__", "__ne__", "__new__", "__reduce__", "__reduce_ex__", "__repr__", "__setattr__", "__sizeof__", "__str__", "__subclasshook__", "__weakref__", "abc", "baz", "classmethod", "foo", "staticfunc" }); + Assert.That(new[] { "__class__", "__delattr__", "__dict__", "__doc__", "__eq__", "__format__", "__ge__", "__getattribute__", "__gt__", "__hash__", "__init__", "__le__", "__lt__", "__module__", "__ne__", "__new__", "__reduce__", "__reduce_ex__", "__repr__", "__setattr__", "__sizeof__", "__str__", "__subclasshook__", "__weakref__", "abc", "classmethod", "foo", "staticfunc" }, Is.EqualTo(ncnames.ToArray())); + Assert.That(new[] { "__class__", "__delattr__", "__dict__", "__doc__", "__eq__", "__format__", "__ge__", "__getattribute__", "__gt__", "__hash__", "__init__", "__le__", "__lt__", "__module__", "__ne__", "__new__", "__reduce__", "__reduce_ex__", "__repr__", "__setattr__", "__sizeof__", "__str__", "__subclasshook__", "__weakref__", "abc", "baz", "classmethod", "foo", "staticfunc" }, Is.EqualTo(ncinstnames.ToArray())); - Assert.AreEqual(fnames.ToArray(), new[] { "foo" }); + Assert.That(new[] { "foo" }, Is.EqualTo(fnames.ToArray())); } [Test] @@ -2070,19 +2070,19 @@ public void ScenarioTokenCategorizer() { categorizer.Initialize(null, source, SourceLocation.MinValue); TokenInfo token = categorizer.ReadToken(); - Assert.AreEqual(token.Category, TokenCategory.Identifier); + Assert.That(TokenCategory.Identifier, Is.EqualTo(token.Category)); token = categorizer.ReadToken(); - Assert.AreEqual(token.Category, TokenCategory.EndOfStream); + Assert.That(TokenCategory.EndOfStream, Is.EqualTo(token.Category)); source = _pe.CreateScriptSourceFromString("\"sys\"", SourceCodeKind.Statements); categorizer.Initialize(null, source, SourceLocation.MinValue); token = categorizer.ReadToken(); - Assert.AreEqual(token.Category, TokenCategory.StringLiteral); + Assert.That(TokenCategory.StringLiteral, Is.EqualTo(token.Category)); token = categorizer.ReadToken(); - Assert.AreEqual(token.Category, TokenCategory.EndOfStream); + Assert.That(TokenCategory.EndOfStream, Is.EqualTo(token.Category)); } private static string ListsToString(IList left, IList right) { @@ -2118,10 +2118,10 @@ def __call__(self): src.Execute(scope); Func t = scope.GetVariable>("inst"); - Assert.AreEqual(42, t()); + Assert.That(t(), Is.EqualTo(42)); t = scope.GetVariable>("instOC"); - Assert.AreEqual(42, t()); + Assert.That(t(), Is.EqualTo(42)); } // ExecuteFile @@ -2184,22 +2184,22 @@ public void Scenario542() { tempFile1.Execute(scope); - Assert.AreEqual(-1, _pe.CreateScriptSourceFromString("M1()").Execute(scope)); - Assert.AreEqual(+1, _pe.CreateScriptSourceFromString("M2()").Execute(scope)); + Assert.That(_pe.CreateScriptSourceFromString("M1()").Execute(scope), Is.EqualTo(-1)); + Assert.That(_pe.CreateScriptSourceFromString("M2()").Execute(scope), Is.EqualTo(+1)); - Assert.AreEqual(-1, (int)(object)_pe.CreateScriptSourceFromString("M1()").Execute(scope)); - Assert.AreEqual(+1, (int)(object)_pe.CreateScriptSourceFromString("M2()").Execute(scope)); + Assert.That((int)(object)_pe.CreateScriptSourceFromString("M1()").Execute(scope), Is.EqualTo(-1)); + Assert.That((int)(object)_pe.CreateScriptSourceFromString("M2()").Execute(scope), Is.EqualTo(+1)); _pe.CreateScriptSourceFromString("if M1() != -1: raise AssertionError('test failed')", SourceCodeKind.SingleStatement).Execute(scope); _pe.CreateScriptSourceFromString("if M2() != +1: raise AssertionError('test failed')", SourceCodeKind.SingleStatement).Execute(scope); _pe.CreateScriptSourceFromString("c = C()", SourceCodeKind.SingleStatement).Execute(scope); - Assert.AreEqual(-1, _pe.CreateScriptSourceFromString("c.M1()").Execute(scope)); - Assert.AreEqual(+1, _pe.CreateScriptSourceFromString("c.M2()").Execute(scope)); + Assert.That(_pe.CreateScriptSourceFromString("c.M1()").Execute(scope), Is.EqualTo(-1)); + Assert.That(_pe.CreateScriptSourceFromString("c.M2()").Execute(scope), Is.EqualTo(+1)); - Assert.AreEqual(-1, (int)(object)_pe.CreateScriptSourceFromString("c.M1()").Execute(scope)); - Assert.AreEqual(+1, (int)(object)_pe.CreateScriptSourceFromString("c.M2()").Execute(scope)); + Assert.That((int)(object)_pe.CreateScriptSourceFromString("c.M1()").Execute(scope), Is.EqualTo(-1)); + Assert.That((int)(object)_pe.CreateScriptSourceFromString("c.M2()").Execute(scope), Is.EqualTo(+1)); _pe.CreateScriptSourceFromString("if c.M1() != -1: raise AssertionError('test failed')", SourceCodeKind.SingleStatement).Execute(scope); _pe.CreateScriptSourceFromString("if c.M2() != +1: raise AssertionError('test failed')", SourceCodeKind.SingleStatement).Execute(scope); @@ -2220,8 +2220,8 @@ public void Scenario542() { public void Scenario167() { ScriptScope scope = _env.CreateScope(); _pe.CreateScriptSourceFromString("a=1\r\nb=-1", SourceCodeKind.Statements).Execute(scope); - Assert.AreEqual(1, _pe.CreateScriptSourceFromString("a").Execute(scope)); - Assert.AreEqual(-1, _pe.CreateScriptSourceFromString("b").Execute(scope)); + Assert.That(_pe.CreateScriptSourceFromString("a").Execute(scope), Is.EqualTo(1)); + Assert.That(_pe.CreateScriptSourceFromString("b").Execute(scope), Is.EqualTo(-1)); } // AddToPath @@ -2279,7 +2279,7 @@ public void ScenarioPartialTrust() { // execute some simple code ScriptScope scope = engine.CreateScope(); ScriptSource source = engine.CreateScriptSourceFromString("2 + 2"); - Assert.AreEqual(source.Execute(scope), 4); + Assert.That(4, Is.EqualTo(source.Execute(scope))); // import all of the built-in modules & make sure we can reflect on them... source = engine.CreateScriptSourceFromString(@" @@ -2356,7 +2356,7 @@ public void ScenarioStackFrameLineInfo() { TestLineInfo(scope, lineNumber); // Ensure that all APIs work - Assert.AreEqual(scope.GetVariable("x"), 1); + Assert.That(1, Is.EqualTo(scope.GetVariable("x"))); //IntIntDelegate d = pe.CreateLambda("arg + x"); // Assert.AreEqual(d(100), 101); @@ -2389,9 +2389,9 @@ public void ScenarioCompileAndRun() { compiledCode = _pe.CreateScriptSourceFromString("f()").Compile(); compiledCode.Execute(scope); - Assert.AreEqual(10, clsPart.Field); + Assert.That(clsPart.Field, Is.EqualTo(10)); compiledCode.Execute(scope); - Assert.AreEqual(20, clsPart.Field); + Assert.That(clsPart.Field, Is.EqualTo(20)); } // [Test] // https://github.com/IronLanguages/ironpython3/issues/906 @@ -2415,7 +2415,7 @@ public void ScenarioStreamRedirect() { stdin.Write(bytes, 0, bytes.Length); stdin.Position = 0; _pe.CreateScriptSourceFromString("output = sys.__stdin__.readline()", SourceCodeKind.Statements).Execute(scope); - Assert.AreEqual(str, _pe.CreateScriptSourceFromString("output").Execute(scope)); + Assert.That(_pe.CreateScriptSourceFromString("output").Execute(scope), Is.EqualTo(str)); _pe.CreateScriptSourceFromString("sys.__stdout__.write(output)", SourceCodeKind.Statements).Execute(scope); stdout.Flush(); @@ -2424,7 +2424,7 @@ public void ScenarioStreamRedirect() { // deals with BOM: using (StreamReader reader = new StreamReader(stdout, true)) { string s = reader.ReadToEnd(); - Assert.AreEqual(str, s); + Assert.That(s, Is.EqualTo(str)); } _pe.CreateScriptSourceFromString("sys.__stderr__.write(\"This is stderr\")", SourceCodeKind.Statements).Execute(scope); @@ -2435,7 +2435,7 @@ public void ScenarioStreamRedirect() { // deals with BOM: using (StreamReader reader = new StreamReader(stderr, true)) { string s = reader.ReadToEnd(); - Assert.AreEqual("This is stderr", s); + Assert.That(s, Is.EqualTo("This is stderr")); } } finally { _pe.Runtime.IO.RedirectToConsole(); @@ -2616,14 +2616,14 @@ private static Action VerifyStringKey(int value) { if (!dict.Contains(key)) { Console.WriteLine(PythonOps.Repr(DefaultContext.Default, dict)); } - Assert.True(dict.Contains(key)); - Assert.AreEqual((string)dict[key], key); + Assert.That(dict.Contains(key)); + Assert.That(key, Is.EqualTo((string)dict[key])); }; } private static Action VerifyNoKeys(int value) { return (dict) => { - Assert.AreEqual(dict.Count, 0); + Assert.That(0, Is.EqualTo(dict.Count)); }; } @@ -2765,7 +2765,7 @@ void Test1() { var engine = Python.CreateEngine(); engine.Runtime.IO.SetOutput(memoryStream, Encoding.UTF8); engine.Execute("print('Hello world')"); - Assert.AreEqual(Encoding.UTF8.GetString(memoryStream.ToArray()).Trim(), "Hello world"); + Assert.That("Hello world", Is.EqualTo(Encoding.UTF8.GetString(memoryStream.ToArray()).Trim())); } void Test2() { @@ -2774,7 +2774,7 @@ void Test2() { var engine = Python.CreateEngine(); engine.Runtime.IO.SetOutput(memoryStream, writer); engine.Execute("print('Hello world')"); - Assert.AreEqual(Encoding.UTF8.GetString(memoryStream.ToArray()).Trim(), "Hello world"); + Assert.That("Hello world", Is.EqualTo(Encoding.UTF8.GetString(memoryStream.ToArray()).Trim())); } } } diff --git a/Src/IronPythonTest/IronPythonTest.csproj b/Src/IronPythonTest/IronPythonTest.csproj index 118756389..95d56194d 100644 --- a/Src/IronPythonTest/IronPythonTest.csproj +++ b/Src/IronPythonTest/IronPythonTest.csproj @@ -1,7 +1,7 @@  - net462;netcoreapp3.1;net6.0 + net462;netcoreapp3.1;net6.0;net8.0 false true @@ -17,8 +17,8 @@ - - + + diff --git a/Src/IronPythonTest/Stress/Engine.cs b/Src/IronPythonTest/Stress/Engine.cs index d16d43ba2..6ca08769c 100644 --- a/Src/IronPythonTest/Stress/Engine.cs +++ b/Src/IronPythonTest/Stress/Engine.cs @@ -4,8 +4,11 @@ using System; using System.Diagnostics; +using System.Runtime.InteropServices; using Microsoft.Scripting.Generation; using Microsoft.Scripting.Hosting; + +using IronPython; using IronPython.Hosting; using NUnit.Framework; @@ -50,7 +53,7 @@ public void ScenarioXGC() { ScriptScope scope = _pe.CreateScope(); scope.SetVariable("x", "Hello"); _pe.CreateScriptSourceFromFile(System.IO.Path.Combine(Common.InputTestDirectory, "simpleCommand.py")).Execute(scope); - Assert.AreEqual(_pe.CreateScriptSourceFromString("x").Execute(scope), 1); + Assert.That(1, Is.EqualTo(_pe.CreateScriptSourceFromString("x").Execute(scope))); scope = null; } @@ -65,8 +68,14 @@ public void ScenarioXGC() { if (!emitsUncollectibleCode) { System.Console.WriteLine("ScenarioGC used {0} bytes of memory.", memoryUsed); - if (memoryUsed > memoryThreshold) - throw new Exception(String.Format("ScenarioGC used {0} bytes of memory. The threshold is {1} bytes", memoryUsed, memoryThreshold)); + if (memoryUsed > memoryThreshold) { + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { + // during CI on macOS .NET 8 + System.Console.WriteLine(String.Format("ScenarioGC used {0} bytes of memory. The threshold is {1} bytes", memoryUsed, memoryThreshold)); + } else { + throw new Exception(String.Format("ScenarioGC used {0} bytes of memory. The threshold is {1} bytes", memoryUsed, memoryThreshold)); + } + } } else { System.Console.WriteLine("Skipping memory usage test under SaveSnippets and/or Debug mode."); diff --git a/Src/Scripts/generate_alltypes.py b/Src/Scripts/generate_alltypes.py index 3d8721a0b..75514671c 100644 --- a/Src/Scripts/generate_alltypes.py +++ b/Src/Scripts/generate_alltypes.py @@ -30,6 +30,19 @@ def __init__(self, type): except: self.is_float = True + try: + class _(type): pass + self.is_extensible = True + except: + self.is_extensible = False + + if self.is_float: + self.cast_type = "double" + elif self.max > Int32.MaxValue: + self.cast_type = "BigInteger" + else: + self.cast_type = "int" + def get_dict(self): toObj = "(%s)" % self.name toObjFooter = "" @@ -107,6 +120,9 @@ def is_implicit(self, oty): unchecked_cast_method = """ public static %(cast_type)s %(method_name)s(%(type)s x) => unchecked((%(cast_type)s)x);""" +getnewargs_method = """ +public static PythonTuple __getnewargs__(%(type)s self) => PythonTuple.MakeTuple(unchecked((%(cast_type)s)self));""" + identity_method = """ [SpecialName] public static %(type)s %(method_name)s(%(type)s x) => x;""" @@ -173,17 +189,17 @@ def gen_unaryops(cw, ty): cw.writeline() cw.write('public static string __repr__(%s x) => x.ToString(CultureInfo.InvariantCulture);' % (ty.name)) + # for extensible types, this is handled in another Ops file + if not ty.is_extensible: + cw.write(getnewargs_method, type=ty.name, cast_type=ty.cast_type) + if ty.is_float: cw.write(float_trunc, type=ty.name) else: cw.write(simple_identity_method, type=ty.name, method_name="__trunc__") - if ty.max > Int32.MaxValue: - cw.write(unchecked_cast_method, type=ty.name, method_name="__int__", cast_type="BigInteger") - cw.write(unchecked_cast_method, type=ty.name, method_name="__index__", cast_type="BigInteger") - else: - cw.write(unchecked_cast_method, type=ty.name, method_name="__int__", cast_type="int") - cw.write(unchecked_cast_method, type=ty.name, method_name="__index__", cast_type="int") + cw.write(unchecked_cast_method, type=ty.name, method_name="__int__", cast_type=ty.cast_type) + cw.write(unchecked_cast_method, type=ty.name, method_name="__index__", cast_type=ty.cast_type) cw.writeline() cw.enter_block('public static int __hash__(%s x)' % (ty.name)) diff --git a/Src/StdLib/Lib/subprocess.py b/Src/StdLib/Lib/subprocess.py index 01180be3a..4ea1c26ea 100644 --- a/Src/StdLib/Lib/subprocess.py +++ b/Src/StdLib/Lib/subprocess.py @@ -967,7 +967,7 @@ def _get_handles(self, stdin, stdout, stderr): errread, errwrite = _winapi.CreatePipe(None, 0) errread, errwrite = Handle(errread), Handle(errwrite) elif stderr == STDOUT: - errwrite = c2pwrite + errwrite = int(c2pwrite) # ironpython: cast to int to prevent closing in _make_inheritable elif stderr == DEVNULL: errwrite = msvcrt.get_osfhandle(self._get_devnull()) elif isinstance(stderr, int): diff --git a/Src/StdLib/Lib/test/test_struct.py b/Src/StdLib/Lib/test/test_struct.py index be0047589..cf1d56796 100644 --- a/Src/StdLib/Lib/test/test_struct.py +++ b/Src/StdLib/Lib/test/test_struct.py @@ -530,13 +530,13 @@ def test_trailing_counter(self): # format lists containing only count spec should result in an error self.assertRaises(struct.error, struct.pack, '12345') - self.assertRaises(struct.error, struct.unpack, '12345', '') + self.assertRaises(struct.error, struct.unpack, '12345', b'') self.assertRaises(struct.error, struct.pack_into, '12345', store, 0) self.assertRaises(struct.error, struct.unpack_from, '12345', store, 0) # Format lists with trailing count spec should result in an error self.assertRaises(struct.error, struct.pack, 'c12345', 'x') - self.assertRaises(struct.error, struct.unpack, 'c12345', 'x') + self.assertRaises(struct.error, struct.unpack, 'c12345', b'x') self.assertRaises(struct.error, struct.pack_into, 'c12345', store, 0, 'x') self.assertRaises(struct.error, struct.unpack_from, 'c12345', store, @@ -545,7 +545,7 @@ def test_trailing_counter(self): # Mixed format tests self.assertRaises(struct.error, struct.pack, '14s42', 'spam and eggs') self.assertRaises(struct.error, struct.unpack, '14s42', - 'spam and eggs') + b'spam and eggs') self.assertRaises(struct.error, struct.pack_into, '14s42', store, 0, 'spam and eggs') self.assertRaises(struct.error, struct.unpack_from, '14s42', store, 0) diff --git a/Tests/modules/network_related/test__ssl.py b/Tests/modules/network_related/test__ssl.py index 31a0bc797..e4a6cf1b5 100644 --- a/Tests/modules/network_related/test__ssl.py +++ b/Tests/modules/network_related/test__ssl.py @@ -15,7 +15,7 @@ from iptest import IronPythonTestCase, is_cli, is_netcoreapp, retryOnFailure, run_test, skipUnlessIronPython SSL_URL = "www.python.org" -SSL_ISSUER = "CN=GlobalSign Atlas R3 DV TLS CA 2023 Q2, O=GlobalSign nv-sa, C=BE" +SSL_ISSUER = "CN=GlobalSign Atlas R3 DV TLS CA 2024 Q2, O=GlobalSign nv-sa, C=BE" SSL_SERVER = "www.python.org" SSL_PORT = 443 SSL_REQUEST = b"GET /en-us HTTP/1.0\r\nHost: www.python.org\r\n\r\n" diff --git a/Tests/test_array.py b/Tests/test_array.py index de04efac0..6287ff46a 100644 --- a/Tests/test_array.py +++ b/Tests/test_array.py @@ -180,7 +180,7 @@ def test_nonzero_lowerbound(self): self.assertEqual(a[2:4], System.Array[int]((2,3))) self.assertEqual(a[-1], 4) - self.assertEqual(repr(a), 'Array[int]((0, 1, 2, 3, 4))') + self.assertEqual(repr(a), 'Array[int]((0, 1, 2, 3, 4), base: 5)') a = System.Array.CreateInstance(int, (5,), (15,)) b = System.Array.CreateInstance(int, (5,), (20,)) @@ -279,4 +279,90 @@ def test_tuple_indexer(self): array1[0,0] = 5 self.assertEqual(array1[0,0], array1[(0,0)]) + def test_equality(self): + a = System.Array.CreateInstance(int, 5) + a2 = System.Array.CreateInstance(int, 5) # same as a + b = System.Array.CreateInstance(int, 5, 6) # different rank + c = System.Array.CreateInstance(int, 6) # different length + d = System.Array.CreateInstance(int, (5,), (1,)) # different base + e = System.Array.CreateInstance(System.Int32, 5) # different element type + l = [0] * 5 # different type + + self.assertTrue(a == a2) + self.assertTrue(a2 == a) + self.assertFalse(a != a2) + self.assertFalse(a2 != a) + + self.assertFalse(a == b) + self.assertFalse(b == a) + self.assertTrue(a != b) + self.assertTrue(b != a) + + self.assertFalse(a == c) + self.assertFalse(c == a) + self.assertTrue(a != c) + self.assertTrue(c != a) + + self.assertFalse(a == d) + self.assertFalse(d == a) + self.assertTrue(a != d) + self.assertTrue(d != a) + + self.assertFalse(a == e) + self.assertFalse(e == a) + self.assertTrue(a != e) + self.assertTrue(e != a) + + self.assertFalse(a == l) + self.assertFalse(l == a) + self.assertTrue(a != l) + self.assertTrue(l != a) + + def test_equality_base(self): + a = System.Array.CreateInstance(int, (5,), (5,)) + a2 = System.Array.CreateInstance(int, (5,), (5,)) + b = System.Array.CreateInstance(int, (6,), (5,)) + c = System.Array.CreateInstance(int, (5,), (6,)) + d = System.Array.CreateInstance(int, (6,), (6,)) + + self.assertTrue(a == a2) + self.assertFalse(a == b) + self.assertFalse(a == c) + self.assertFalse(a == d) + + self.assertFalse(a != a2) + self.assertTrue(a != b) + self.assertTrue(a != c) + self.assertTrue(a != d) + + def test_equality_rank(self): + a = System.Array.CreateInstance(int, 5, 6) + a2 = System.Array.CreateInstance(int, 5, 6) + b = System.Array.CreateInstance(int, 5, 6) + b[0, 0] = 1 + c = System.Array.CreateInstance(int, (6, 5), (0, 0)) + c[0, 0] = 1 + d = System.Array.CreateInstance(int, (6, 5), (1, 1)) + d[1, 1] = 1 + d1 = System.Array.CreateInstance(int, (6, 5), (1, 1)) + d1[1, 1] = 1 + + self.assertTrue(a == a2) + self.assertFalse(a == b) # different element + self.assertFalse(a == c) # different rank + self.assertFalse(a == d) # different rank + self.assertFalse(b == c) # different shape + self.assertFalse(b == d) # different shape & base + self.assertFalse(c == d) # different base + self.assertTrue(d == d1) + + self.assertFalse(a != a2) + self.assertTrue(a != b) + self.assertTrue(a != c) + self.assertTrue(a != d) + self.assertTrue(b != c) + self.assertTrue(b != d) + self.assertTrue(c != d) + self.assertFalse(d != d1) + run_test(__name__) diff --git a/Tests/test_cliclass.py b/Tests/test_cliclass.py index 771628c52..0306a9205 100644 --- a/Tests/test_cliclass.py +++ b/Tests/test_cliclass.py @@ -4,7 +4,7 @@ import sys import unittest -from iptest import IronPythonTestCase, is_cli, is_debug, is_mono, is_netcoreapp, is_netcoreapp21, is_posix, big, run_test, skipUnlessIronPython +from iptest import IronPythonTestCase, is_cli, is_debug, is_mono, is_net70, is_net80, is_netcoreapp, is_netcoreapp21, is_posix, big, run_test, skipUnlessIronPython if is_cli: import clr @@ -1191,14 +1191,15 @@ def test_serialization(self): System.Int32(1), System.UInt32(1), System.Int16(1), System.UInt16(1), System.Byte(1), System.SByte(1), - #System.IntPtr(-1), System.UIntPtr(2), # TODO: IntPtrOps.cs + System.IntPtr(-1), + None if is_mono else System.UIntPtr(2), # fails to deserialize on Mono... System.Decimal(1), System.Single(1.0), System.Char.MaxValue, System.DBNull.Value, System.DateTime.Now, None, {}, (), [], {'a': 2}, (42, ), [42, ], System.StringSplitOptions.RemoveEmptyEntries, ] - if is_netcoreapp and not is_netcoreapp21: + if is_netcoreapp and not is_netcoreapp21 and not is_net80: clr.AddReference("System.Text.Json") data.append(System.Text.Json.JsonValueKind.Object) # byte-based enum @@ -1242,9 +1243,14 @@ def __init__(self): data.append(d1) data.append(d2) + if hasattr(clr, "Serialize"): + clr_roundtrip = lambda x: clr.Deserialize(*clr.Serialize(x)) + else: + clr_roundtrip = lambda x: x + for value in data: # use cPickle & clr.Serialize/Deserialize directly - for newVal in (pickle.loads(pickle.dumps(value)), clr.Deserialize(*clr.Serialize(value))): + for newVal in (pickle.loads(pickle.dumps(value)), clr_roundtrip(value)): self.assertEqual(type(newVal), type(value)) try: self.assertEqual(newVal, value) @@ -1254,38 +1260,40 @@ def __init__(self): self.assertTrue(type(newVal) is list or type(newVal) is dict) # passing an unknown format raises... - self.assertRaises(ValueError, clr.Deserialize, "unknown", "foo") + if hasattr(clr, "Deserialize"): + self.assertRaises(ValueError, clr.Deserialize, "unknown", "foo") - al = System.Collections.ArrayList() - al.Add(2) + if not is_net80: + al = System.Collections.ArrayList() + al.Add(2) - gl = System.Collections.Generic.List[int]() - gl.Add(2) + gl = System.Collections.Generic.List[int]() + gl.Add(2) - # lists... - for value in (al, gl): - for newX in (pickle.loads(pickle.dumps(value)), clr.Deserialize(*clr.Serialize(value))): - self.assertEqual(value.Count, newX.Count) - for i in range(value.Count): - self.assertEqual(value[i], newX[i]) + # lists... + for value in (al, gl): + for newX in (pickle.loads(pickle.dumps(value)), clr_roundtrip(value)): + self.assertEqual(value.Count, newX.Count) + for i in range(value.Count): + self.assertEqual(value[i], newX[i]) - ht = System.Collections.Hashtable() - ht['foo'] = 'bar' + ht = System.Collections.Hashtable() + ht['foo'] = 'bar' - gd = System.Collections.Generic.Dictionary[str, str]() - gd['foo'] = 'bar' + gd = System.Collections.Generic.Dictionary[str, str]() + gd['foo'] = 'bar' - # dictionaries - for value in (ht, gd): - for newX in (pickle.loads(pickle.dumps(value)), clr.Deserialize(*clr.Serialize(value))): - self.assertEqual(value.Count, newX.Count) - for key in value.Keys: - self.assertEqual(value[key], newX[key]) + # dictionaries + for value in (ht, gd): + for newX in (pickle.loads(pickle.dumps(value)), clr_roundtrip(value)): + self.assertEqual(value.Count, newX.Count) + for key in value.Keys: + self.assertEqual(value[key], newX[key]) - # interesting cases - for tempX in [System.Exception("some message")]: - for newX in (pickle.loads(pickle.dumps(tempX)), clr.Deserialize(*clr.Serialize(tempX))): - self.assertEqual(newX.Message, tempX.Message) + # interesting cases + for tempX in [System.Exception("some message")]: + for newX in (pickle.loads(pickle.dumps(tempX)), clr_roundtrip(tempX)): + self.assertEqual(newX.Message, tempX.Message) try: exec(" print 1") @@ -1301,13 +1309,13 @@ class K(System.Exception): other = "something else" tempX = K() #CodePlex 16415 - #for newX in (cPickle.loads(cPickle.dumps(tempX)), clr.Deserialize(*clr.Serialize(tempX))): + #for newX in (pickle.loads(pickle.dumps(tempX)), clr_roundtrip(tempX)): # self.assertEqual(newX.Message, tempX.Message) # self.assertEqual(newX.other, tempX.other) #CodePlex 16415 tempX = System.Exception - #for newX in (cPickle.loads(cPickle.dumps(System.Exception)), clr.Deserialize(*clr.Serialize(System.Exception))): + #for newX in (pickle.loads(pickle.dumps(tempX)), clr_roundtrip(tempX)): # temp_except = newX("another message") # self.assertEqual(temp_except.Message, "another message") @@ -1421,6 +1429,7 @@ def test_clr_dir(self): self.assertTrue('IndexOf' not in clr.Dir('abc')) self.assertTrue('IndexOf' in clr.DirClr('abc')) + @unittest.skipIf(is_net70 or is_net80, "TODO") # TODO: https://github.com/IronLanguages/ironpython3/issues/1485 def test_int32_bigint_equivalence(self): import math @@ -2056,6 +2065,4 @@ def test_extension_method(self): os.unlink(fname) sys.path = [x for x in old_path] - - run_test(__name__) diff --git a/Tests/test_int.py b/Tests/test_int.py index 8fcbe5404..e2c60e145 100644 --- a/Tests/test_int.py +++ b/Tests/test_int.py @@ -4,7 +4,7 @@ import sys -from iptest import IronPythonTestCase, is_cli, is_netstandard, is_mono, big, myint, skipUnlessIronPython, run_test +from iptest import IronPythonTestCase, is_cli, is_net70, is_net80, is_netstandard, is_mono, big, myint, skipUnlessIronPython, run_test class IntNoClrTest(IronPythonTestCase): """Must be run before IntTest because it depends on CLR API not being visible.""" @@ -27,14 +27,19 @@ def test_instance_set(self): self.assertSetEqual(set(dir(j)) - set(dir(i)), {'GetByteCount', 'TryWriteBytes'}) self.assertSetEqual(set(dir(int)) - set(dir(Int32)), {'GetByteCount', 'TryWriteBytes'}) - # these two assertions fail on IronPython compiled for .NET Standard - if not is_netstandard: - self.assertSetEqual(set(dir(i)) - set(dir(j)), {'MaxValue', 'MinValue'}) - self.assertSetEqual(set(dir(Int32)) - set(dir(int)), {'MaxValue', 'MinValue'}) - - # weaker assertions that should always hold - self.assertTrue((set(dir(i)) - set(dir(j))).issubset({'MaxValue', 'MinValue', 'GetByteCount', 'TryWriteBytes', 'GetBitLength'})) - self.assertTrue((set(dir(Int32)) - set(dir(int))).issubset({'MaxValue', 'MinValue', 'GetByteCount', 'TryWriteBytes', 'GetBitLength'})) + if is_net70 or is_net80: # https://github.com/IronLanguages/ironpython3/issues/1485 + diff = {'TryConvertToChecked', 'MinValue', 'TryConvertFromChecked', 'MaxValue', 'TryConvertFromTruncating', 'WriteBigEndian', 'GetShortestBitLength', 'TryWriteLittleEndian', 'WriteLittleEndian', 'TryConvertToSaturating', 'TryConvertFromSaturating', 'TryWriteBigEndian', 'TryConvertToTruncating'} + self.assertSetEqual(set(dir(i)) - set(dir(j)), diff) + self.assertSetEqual(set(dir(Int32)) - set(dir(int)), diff) + else: + # these two assertions fail on IronPython compiled for .NET Standard + if not is_netstandard: + self.assertSetEqual(set(dir(i)) - set(dir(j)), {'MaxValue', 'MinValue'}) + self.assertSetEqual(set(dir(Int32)) - set(dir(int)), {'MaxValue', 'MinValue'}) + + # weaker assertions that should always hold + self.assertTrue((set(dir(i)) - set(dir(j))).issubset({'MaxValue', 'MinValue', 'GetByteCount', 'TryWriteBytes', 'GetBitLength'})) + self.assertTrue((set(dir(Int32)) - set(dir(int))).issubset({'MaxValue', 'MinValue', 'GetByteCount', 'TryWriteBytes', 'GetBitLength'})) def test_from_bytes(self): self.assertEqual(type(int.from_bytes(b"abc", "big")), int) diff --git a/Tests/test_io_stdlib.py b/Tests/test_io_stdlib.py new file mode 100644 index 000000000..f3e66d691 --- /dev/null +++ b/Tests/test_io_stdlib.py @@ -0,0 +1,152 @@ +# 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. + +## +## Run selected tests from test_io from StdLib +## + +from iptest import is_ironpython, is_mono, generate_suite, run_test + +import test.test_io + +def load_tests(loader, standard_tests, pattern): + tests = loader.loadTestsFromModule(test.test_io) + + if is_ironpython: + failing_tests = [ + test.test_io.CIOTest('test_BufferedIOBase_destructor'), # AssertionError: Lists differ: [2, 3, 1, 2] != [1, 2, 3] + test.test_io.CIOTest('test_IOBase_destructor'), # AssertionError: Lists differ: [2, 3, 1, 2] != [1, 2, 3] + test.test_io.CIOTest('test_RawIOBase_destructor'), # AssertionError: Lists differ: [2, 3, 1, 2] != [1, 2, 3] + test.test_io.CIOTest('test_RawIOBase_read'), # TypeError: expected int, got NoneType + test.test_io.CIOTest('test_TextIOBase_destructor'), # AssertionError: Lists differ: [1, 2, 3, 2] != [1, 2, 3] + test.test_io.CIOTest('test_destructor'), # AssertionError: Lists differ: [2, 3, 1, 2] != [1, 2, 3] + test.test_io.CIOTest('test_flush_error_on_close'), # AssertionError: OSError not raised by close + test.test_io.CIOTest('test_garbage_collection'), # AssertionError: filter ('', ResourceWarning) did not catch any warning + test.test_io.CIOTest('test_invalid_operations'), # OSError: can't do nonzero cur-relative seeks + test.test_io.CIOTest('test_open_handles_NUL_chars'), # ValueError: Illegal characters in path. + test.test_io.PyIOTest('test_destructor'), # AssertionError: Lists differ: [2, 3, 1, 2] != [1, 2, 3] + test.test_io.PyIOTest('test_flush_error_on_close'), # AssertionError: OSError not raised by close + test.test_io.PyIOTest('test_garbage_collection'), # AssertionError: filter ('', ResourceWarning) did not catch any warning + test.test_io.PyIOTest('test_open_handles_NUL_chars'), # ValueError: Illegal characters in path. + test.test_io.CBufferedReaderTest('test_args_error'), # AssertionError: "BufferedReader" does not match "__init__() takes at most 2 arguments (4 given)" + test.test_io.CBufferedReaderTest('test_buffering'), # TypeError: BufferedReader() takes at least 0 arguments (2 given) + test.test_io.CBufferedReaderTest('test_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedReaderTest('test_garbage_collection'), # AssertionError: filter ('', ResourceWarning) did not catch any warning + test.test_io.CBufferedReaderTest('test_initialization'), # AssertionError: ValueError not raised by read + test.test_io.CBufferedReaderTest('test_misbehaved_io_read'), # AssertionError: OSError not raised by read + test.test_io.CBufferedReaderTest('test_nonnormalized_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedReaderTest('test_override_destructor'), # AssertionError: Lists differ: [1, 2, 3, 2] != [1, 2, 3] + test.test_io.CBufferedReaderTest('test_read_non_blocking'), # AssertionError: b'' is not None + test.test_io.CBufferedReaderTest('test_read_on_closed'), # AssertionError: ValueError not raised by read1 + test.test_io.CBufferedReaderTest('test_readonly_attributes'), # AssertionError: AttributeError not raised + test.test_io.CBufferedReaderTest('test_uninitialized'), # AssertionError: (, ) not raised by read + test.test_io.PyBufferedReaderTest('test_nonnormalized_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.PyBufferedReaderTest('test_read_on_closed'), # AssertionError: ValueError not raised by read1 + test.test_io.CBufferedWriterTest('test_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedWriterTest('test_garbage_collection'), # AssertionError: filter ('', ResourceWarning) did not catch any warning + test.test_io.CBufferedWriterTest('test_initialization'), # AssertionError: ValueError not raised by write + test.test_io.CBufferedWriterTest('test_max_buffer_size_removal'), # AssertionError: TypeError not raised + test.test_io.CBufferedWriterTest('test_nonnormalized_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedWriterTest('test_readonly_attributes'), # AssertionError: AttributeError not raised + test.test_io.CBufferedWriterTest('test_uninitialized'), # TypeError: BufferedWriter() takes at least 1 argument (0 given) + test.test_io.CBufferedWriterTest('test_write_error_on_close'), # AssertionError: OSError not raised by close + test.test_io.CBufferedWriterTest('test_write_non_blocking'), # TypeError: expected int, got NoneType + test.test_io.PyBufferedWriterTest('test_nonnormalized_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedRWPairTest('test_constructor_max_buffer_size_removal'), # AssertionError: TypeError not raised + test.test_io.CBufferedRWPairTest('test_reader_writer_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedRWPairTest('test_uninitialized'), # TypeError: BufferedRWPair() takes at least 2 arguments (0 given) + test.test_io.PyBufferedRWPairTest('test_reader_writer_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedRandomTest('test_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedRandomTest('test_garbage_collection'), # AssertionError: filter ('', ResourceWarning) did not catch any warning + test.test_io.CBufferedRandomTest('test_max_buffer_size_removal'), # AssertionError: TypeError not raised + test.test_io.CBufferedRandomTest('test_nonnormalized_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.CBufferedRandomTest('test_read_non_blocking'), # AssertionError: b'' is not None + test.test_io.CBufferedRandomTest('test_read_on_closed'), # AssertionError: ValueError not raised by read1 + test.test_io.CBufferedRandomTest('test_readonly_attributes'), # AssertionError: AttributeError not raised + test.test_io.CBufferedRandomTest('test_repr'), # AssertionError: '' != '<_io.BufferedRandom>' + test.test_io.CBufferedRandomTest('test_uninitialized'), # TypeError: BufferedRandom() takes at least 1 argument (0 given) + test.test_io.CBufferedRandomTest('test_write_error_on_close'), # AssertionError: OSError not raised by close + test.test_io.CBufferedRandomTest('test_write_non_blocking'), # TypeError: expected int, got NoneType + test.test_io.PyBufferedRandomTest('test_nonnormalized_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.PyBufferedRandomTest('test_read_on_closed'), # AssertionError: ValueError not raised by read1 + test.test_io.CTextIOWrapperTest('test_append_bom'), # AssertionError: b'\xef\xbb\xbfaaa\xef\xbb\xbfxxx' != b'\xef\xbb\xbfaaaxxx' + test.test_io.CTextIOWrapperTest('test_close_error_on_close'), # AssertionError: OSError not raised + test.test_io.CTextIOWrapperTest('test_encoded_writes'), # UnicodeEncodeError + test.test_io.CTextIOWrapperTest('test_flush_error_on_close'), # AssertionError: OSError not raised by close + test.test_io.CTextIOWrapperTest('test_garbage_collection'), # AssertionError: filter ('', ResourceWarning) did not catch any warning + test.test_io.CTextIOWrapperTest('test_initialization'), # AssertionError: ValueError not raised by read + test.test_io.CTextIOWrapperTest('test_non_text_encoding_codecs_are_rejected'), # AssertionError: LookupError not raised + test.test_io.CTextIOWrapperTest('test_nonnormalized_close_error_on_close'), # AssertionError: NameError not raised + test.test_io.CTextIOWrapperTest('test_rawio'), # AttributeError: 'CMockRawIO' object has no attribute 'read1' + test.test_io.CTextIOWrapperTest('test_read_nonbytes'), # AttributeError: 'StringIO' object has no attribute 'read1' + test.test_io.CTextIOWrapperTest('test_seek_append_bom'), # OSError: [Errno -2146232800] Unable seek backward to overwrite data that previously existed in a file opened in Append mode. + test.test_io.CTextIOWrapperTest('test_seek_bom'), # AssertionError: b'\xef\xbb\xbfbbb\xef\xbb\xbfzzz' != b'\xef\xbb\xbfbbbzzz' + test.test_io.CTextIOWrapperTest('test_uninitialized'), # AssertionError: Exception not raised by repr + test.test_io.CTextIOWrapperTest('test_unseekable'), # OSError: underlying stream is not seekable + test.test_io.PyTextIOWrapperTest('test_nonnormalized_close_error_on_close'), # AssertionError: None is not an instance of + test.test_io.PyTextIOWrapperTest('test_seek_append_bom'), # OSError: [Errno -2146232800] Unable seek backward to overwrite data that previously existed in a file opened in Append mode. + test.test_io.CMiscIOTest('test_io_after_close'), # AttributeError: 'TextIOWrapper' object has no attribute 'read1' + test.test_io.CMiscIOTest('test_nonblock_pipe_write_bigbuf'), # AttributeError: 'module' object has no attribute 'fcntl' + test.test_io.CMiscIOTest('test_nonblock_pipe_write_smallbuf'), # AttributeError: 'module' object has no attribute 'fcntl' + test.test_io.CMiscIOTest('test_pickling'), # AssertionError: TypeError not raised by _dumps + test.test_io.CMiscIOTest('test_readinto_buffer_overflow'), # IndexError: Index was outside the bounds of the array. + test.test_io.CMiscIOTest('test_warn_on_dealloc'), # AssertionError: ResourceWarning not triggered + test.test_io.CMiscIOTest('test_warn_on_dealloc_fd'), # AssertionError: ResourceWarning not triggered + test.test_io.PyMiscIOTest('test_io_after_close'), # AttributeError: 'FileIO' object has no attribute 'read1' + test.test_io.PyMiscIOTest('test_nonblock_pipe_write_bigbuf'), # AttributeError: 'module' object has no attribute 'fcntl' + test.test_io.PyMiscIOTest('test_nonblock_pipe_write_smallbuf'), # AttributeError: 'module' object has no attribute 'fcntl' + test.test_io.PyMiscIOTest('test_pickling'), # AssertionError: TypeError not raised by _dumps + test.test_io.PyMiscIOTest('test_warn_on_dealloc'), # AssertionError: ResourceWarning not triggered + test.test_io.PyMiscIOTest('test_warn_on_dealloc_fd'), # AssertionError: ResourceWarning not triggered + ] + + if is_mono: + failing_tests += [ + test.test_io.CBufferedRandomTest('test_destructor'), # IndexError: index out of range: 0 + ] + + skip_tests = [ + test.test_io.CBufferedWriterTest('test_override_destructor'), # StackOverflowException + test.test_io.CBufferedRandomTest('test_override_destructor'), # StackOverflowException + test.test_io.CTextIOWrapperTest('test_bufio_write_through'), # StackOverflowException + test.test_io.CTextIOWrapperTest('test_override_destructor'), # StackOverflowException + + # __del__ not getting called on shutdown? + test.test_io.CTextIOWrapperTest('test_create_at_shutdown_with_encoding'), + test.test_io.CTextIOWrapperTest('test_create_at_shutdown_without_encoding'), + test.test_io.PyTextIOWrapperTest('test_create_at_shutdown_with_encoding'), + test.test_io.PyTextIOWrapperTest('test_create_at_shutdown_without_encoding'), + test.test_io.CMiscIOTest('test_daemon_threads_shutdown_stderr_deadlock'), + test.test_io.CMiscIOTest('test_daemon_threads_shutdown_stdout_deadlock'), + + # AttributeError: 'module' object has no attribute 'SIGALRM' + test.test_io.CSignalsTest('test_interrupted_read_retry_buffered'), + test.test_io.CSignalsTest('test_interrupted_read_retry_text'), + test.test_io.CSignalsTest('test_interrupted_write_buffered'), + test.test_io.CSignalsTest('test_interrupted_write_retry_buffered'), + test.test_io.CSignalsTest('test_interrupted_write_retry_text'), + test.test_io.CSignalsTest('test_interrupted_write_text'), + test.test_io.CSignalsTest('test_interrupted_write_unbuffered'), + test.test_io.CSignalsTest('test_reentrant_write_buffered'), + test.test_io.CSignalsTest('test_reentrant_write_text'), + test.test_io.PySignalsTest('test_interrupted_read_retry_buffered'), + test.test_io.PySignalsTest('test_interrupted_read_retry_text'), + test.test_io.PySignalsTest('test_interrupted_write_buffered'), + test.test_io.PySignalsTest('test_interrupted_write_retry_buffered'), + test.test_io.PySignalsTest('test_interrupted_write_retry_text'), + test.test_io.PySignalsTest('test_interrupted_write_text'), + test.test_io.PySignalsTest('test_interrupted_write_unbuffered'), + + # failure prevents files from closing + test.test_io.CTextIOWrapperTest('test_seek_and_tell'), # TypeError: NoneType is not callable + test.test_io.CMiscIOTest('test_attributes'), # AssertionError: 'r' != 'U' + test.test_io.PyMiscIOTest('test_attributes'), # AssertionError: 'wb+' != 'rb+' + ] + + return generate_suite(tests, failing_tests, skip_tests) + + else: + return tests + +run_test(__name__) diff --git a/Tests/test_methodbinder1.py b/Tests/test_methodbinder1.py index 800be2f68..b670dc856 100644 --- a/Tests/test_methodbinder1.py +++ b/Tests/test_methodbinder1.py @@ -8,7 +8,7 @@ import unittest -from iptest import IronPythonTestCase, is_cli, is_mono, is_netcoreapp, run_test, skipUnlessIronPython +from iptest import IronPythonTestCase, is_mono, is_net70, is_net80, is_netcoreapp, run_test, skipUnlessIronPython from iptest.type_util import * from System import Int32 @@ -102,7 +102,7 @@ def test_this_matrix(self): funcnames = "M201 M680 M202 M203 M681 M204 M205 M301 M302 M303 M304 M310 M311 M312 M313 M320 M321 M400".split() - matrix = ( + matrix = [ #### M201 M680 M202 M203 M681 M204 M205 M301 M302 M303 M304 M310 M311 M312 M313 M320 M321 M400 #### int int? double bigint bigint? bool str sbyte i16 i64 single byte ui16 ui32 ui64 char decm obj ( "SByteMax", True, True, True, True, True, True, TypeE, True, True, True, True, True, True, True, True, TypeE, True, True, ), @@ -172,16 +172,17 @@ def test_this_matrix(self): ( (3+0j), TypeE, TypeE, TypeE, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, True, ), ( (3+1j), TypeE, TypeE, TypeE, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, True, ), ( mycomplex1, TypeE, TypeE, TypeE, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, True, ) - ) + ] - InvariantCulture = System.Globalization.CultureInfo.InvariantCulture - matrix = list(matrix) + + ch2bi = True if is_net70 or is_net80 else TypeE # .NET 7 adds an implicit cast from Char to BigInteger ################################################## pass in char ######################################################### #### M201 M680 M202 M203 M681 M204 M205 M301 M302 M303 M304 M310 M311 M312 M313 M320 M321 M400 #### int int? double bigint bigint? bool str sbyte i16 i64 single byte ui16 ui32 ui64 char decm obj - matrix.append((System.Char.Parse('A'), TypeE, TypeE, TypeE, TypeE, TypeE, True, True, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, True, True, True, )) + matrix.append((System.Char.Parse('A'), TypeE, TypeE, TypeE, ch2bi, ch2bi, True, True, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, TypeE, True, True, True, )) + InvariantCulture = System.Globalization.CultureInfo.InvariantCulture ################################################## pass in float ######################################################### #### single/double becomes Int32/BigInteger, but this does not apply to other primitive types #### M201 M680 M202 M203 M681 M204 M205 M301 M302 M303 M304 M310 M311 M312 M313 M320 M321 M400 @@ -190,7 +191,6 @@ def test_this_matrix(self): matrix.append((System.Double.Parse("10.2", InvariantCulture), TypeE, TypeE, True, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, TypeE, True, True, )) matrix.append((System.Single.Parse("-8.1", InvariantCulture), TypeE, TypeE, True, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, TypeE, True, True, )) matrix.append((System.Double.Parse("-1.8", InvariantCulture), TypeE, TypeE, True, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, True, TypeE, TypeE, TypeE, TypeE, TypeE, True, True, )) - matrix = tuple(matrix) for scenario in matrix: if isinstance(scenario[0], str): diff --git a/Tests/test_regressions.py b/Tests/test_regressions.py index 4ac3ff57d..b9ab08ab9 100644 --- a/Tests/test_regressions.py +++ b/Tests/test_regressions.py @@ -1710,4 +1710,15 @@ def test_ipy3_gh1649(self): def test_map_type_int(self): self.assertEqual(list(map(type, [0])), [type(0)]) + def test_ipy3_gh1135(self): + # https://github.com/IronLanguages/ironpython3/issues/1135 + import sys + import subprocess + with subprocess.Popen([sys.executable, '-c', 'print("aaa", end="")'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as p: + out, err = p.communicate() + + # ensure out is the expected value and not empty + self.assertEqual(out, b"aaa") + + run_test(__name__) diff --git a/Tests/test_struct_stdlib.py b/Tests/test_struct_stdlib.py index f66b4947a..c98f5c266 100644 --- a/Tests/test_struct_stdlib.py +++ b/Tests/test_struct_stdlib.py @@ -6,7 +6,7 @@ ## Run selected tests from test_struct from StdLib ## -from iptest import is_ironpython, generate_suite, run_test, is_net60 +from iptest import is_ironpython, generate_suite, run_test, is_net60, is_net80 import test.test_struct @@ -15,13 +15,11 @@ def load_tests(loader, standard_tests, pattern): if is_ironpython: failing_tests = [ - test.test_struct.StructTest('test_bool'), # TODO: figure out - test.test_struct.StructTest('test_calcsize'), # TODO: figure out - test.test_struct.StructTest('test_count_overflow'), # TODO: figure out - test.test_struct.StructTest('test_trailing_counter'), # TODO: figure out - test.test_struct.UnpackIteratorTest('test_construct'), # TODO: figure out + test.test_struct.StructTest('test_bool'), # struct.error: expected bool value got IronPython.NewTypes.System.Object_1$1 + test.test_struct.StructTest('test_calcsize'), # AssertionError: 4 not greater than or equal to 8 + test.test_struct.StructTest('test_count_overflow'), # AssertionError: error not raised by calcsize ] - if not is_net60: + if not is_net60 and not is_net80: failing_tests += [ test.test_struct.UnpackIteratorTest('test_half_float'), # https://github.com/IronLanguages/ironpython3/issues/1458 ] diff --git a/WhatsNewInPython36.md b/WhatsNewInPython36.md index 799575dd0..34725b0e7 100644 --- a/WhatsNewInPython36.md +++ b/WhatsNewInPython36.md @@ -107,7 +107,7 @@ Deprecated New Keywords ------------ -- [ ]`async` and `await` are not recommended to be used as variable, class, function or module names. Introduced by PEP 492 in Python 3.5, they will become proper keywords in Python 3.7. Starting in Python 3.6, the use of `async` or `await` as names will generate a `DeprecationWarning`. +- [ ] `async` and `await` are not recommended to be used as variable, class, function or module names. Introduced by PEP 492 in Python 3.5, they will become proper keywords in Python 3.7. Starting in Python 3.6, the use of `async` or `await` as names will generate a `DeprecationWarning`. Deprecated Python Behavior -------------------------- diff --git a/make.ps1 b/make.ps1 index f14921289..16e082c1b 100755 --- a/make.ps1 +++ b/make.ps1 @@ -4,7 +4,7 @@ Param( [Parameter(Position=1)] [String] $target = "build", [String] $configuration = "Release", - [String[]] $frameworks=@('net462','netcoreapp3.1','net6.0'), + [String[]] $frameworks=@('net462','netcoreapp3.1','net6.0','net8.0'), [String] $platform = "x64", [switch] $runIgnored, [int] $jobs = [System.Environment]::ProcessorCount @@ -176,7 +176,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', '-l', "trx;LogFileName=$filtername-$framework-$configuration-result.trx", '-s', "$runSettings", "--filter=$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"); Write-Host "Enqueue [$framework $filtername]:" Write-Host "dotnet test $args" Write-Host